Commit bd044664 authored by Luc Hermitte's avatar Luc Hermitte

ENH: Contribute 2 S1TilingApps to OTB

parent e56355fe
......@@ -92,3 +92,13 @@ OTB_CREATE_APPLICATION(
NAME Mosaic
SOURCES otbMosaic.cxx
LINK_LIBRARIES ${${otb-module}_LIBRARIES})
OTB_CREATE_APPLICATION(
NAME ClampROI
SOURCES otbClampROI.cxx
LINK_LIBRARIES ${${otb-module}_LIBRARIES})
OTB_CREATE_APPLICATION(
NAME Synthetize
SOURCES otbSynthetize.cxx
LINK_LIBRARIES ${${otb-module}_LIBRARIES})
/*
* Copyright(C) 2005-2020 Centre National d'Etudes Spatiales(CNES)
*
* This file is part of Orfeo Toolbox
*
* https: //www.orfeo-toolbox.org/
*
* Licensed under the Apache License, Version 2.0(the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http: //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "otbClampROIFilter.h"
#include "otbWrapperApplication.h"
#include "otbWrapperApplicationFactory.h"
namespace otb
{
namespace Wrapper
{
/**
* Application that fills margins to 0.
*
* This application is similar to ExtractROI with the difference the margin is
* kept, and filled with 0.
*
* This application is used to implement the _cut_ processing in S1Tiling
* chain.
*
* \author Luc Hermitte (CS Group)
* \copyright CNES
*/
class ClampROI : public Application
{
public:
using Self = ClampROI;
using Pointer = itk::SmartPointer<Self>;
itkNewMacro(Self);
itkTypeMacro(ClampROI, otb::Wrapper::Application);
private:
void DoInit() override
{
SetName("ClampROI");
SetDescription("This is the ClampROI application, version X.X.X");
SetDocLongDescription(
"This application is similar to ExtractROI in the sense it extracts a Region of Interrest.\n"
"However, the region outside of the ROI isn't trimmed, but set to 0.\n"
"\n"
"The filter set lines of index < threshold.y, and of index >= threshold.y to 0\n"
"The filter set columns of index < threshold.x, and of index >= threshold.x to 0");
SetDocLimitations("This application only works on scalar (and complex) images.");
SetDocAuthors("Luc Hermitte (CS Group)");
SetDocSeeAlso("ManageNoData, ExtractROI");
AddDocTag("otb::Wrapper::Tags::Manip");
AddParameter(ParameterType_InputImage, "in", "Input image");
SetParameterDescription("in", "Scalar Input image");
AddParameter(ParameterType_OutputImage, "out", "Output Image");
SetParameterDescription("out", "Scalar Output image");
AddParameter(ParameterType_Group, "threshold", "threshold group");
AddParameter(ParameterType_Group, "threshold.y", "threshold group");
MandatoryOff("threshold");
MandatoryOff("threshold.y");
AddParameter(ParameterType_Int, "threshold.x", "Column index threshold");
SetParameterDescription("threshold.x", "Column index threshold");
SetDefaultParameterInt("threshold.x", 0);
AddParameter(ParameterType_Int, "threshold.y.start", "Top line index threshold");
SetParameterDescription("threshold.y.start", "Top line index threshold");
SetDefaultParameterInt("threshold.y.start", 0);
AddParameter(ParameterType_Int, "threshold.y.end", "Bottom line index threshold");
SetParameterDescription("threshold.y.end", "Bottom line index threshold");
SetDefaultParameterInt("threshold.y.end", 0);
AddRAMParameter();
}
void DoUpdateParameters() override
{}
void DoExecute() override
{
auto const thrX = GetParameterInt("threshold.x");
auto const thrYtop = GetParameterInt("threshold.y.start");
auto const thrYbot = GetParameterInt("threshold.y.end");
if (thrX < 0)
itkExceptionMacro("The column threshold is expected to be positive");
if (thrYtop < 0)
itkExceptionMacro("The top line threshold is expected to be positive");
if (thrYbot < 0)
itkExceptionMacro("The bottom line threshold is expected to be positive");
if (thrX == 0 && thrYtop == 0 && thrYbot == 0)
itkExceptionMacro("Don't use ClampROI to clamp nothing!");
auto filter = ClampROIFilter<FloatImageType>::New();
assert(thrX >= 0);
assert(thrYtop >= 0);
assert(thrYbot >= 0);
filter->SetThresholdX(thrX);
filter->SetThresholdYtop(thrYtop);
filter->SetThresholdYbot(thrYbot);
filter->SetInput(GetParameterFloatImage("in"));
SetParameterOutputImage("out", filter->GetOutput());
RegisterPipeline();
}
};
} // otb::Wrapper namespace
} // otb namespace
OTB_APPLICATION_EXPORT(otb::Wrapper::ClampROI)
/*
* Copyright(C) 2005-2020 Centre National d'Etudes Spatiales(CNES)
*
* This file is part of Orfeo Toolbox
*
* https: //www.orfeo-toolbox.org/
*
* Licensed under the Apache License, Version 2.0(the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http: //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include "otbSynthetizeFilter.h"
#include "otbWrapperApplication.h"
#include "otbWrapperApplicationFactory.h"
#include "otbImageFileReader.h"
#include <set>
namespace otb
{
namespace Wrapper
{
/**
* This application synthetizes/reduces multiple inputs into a single one.
* In that particular case, for each output pixel, this application will
* consider the corresponding pixels from all the input images, and keep the
* first one that isn't equal to 0.
*
* This application is used to implement the _concatenate_ processing in
* S1Tiling chain.
*
* \author Luc Hermitte (CS Group)
* \copyright CNES
* \todo find a better name for the application. Alas `otbConcatenate` is
* already used...
*/
class Synthetize : public Application
{
public:
using Self = Synthetize;
using Pointer = itk::SmartPointer<Self>;
itkNewMacro(Self);
itkTypeMacro(Synthetize, otb::Wrapper::Application);
private:
using ReaderType = otb::ImageFileReader<FloatImageType>;
void DoInit() override
{
SetName("Synthetize");
SetDescription("This is the Synthetize application, version X.X.X");
SetDocLongDescription("Concatenate a list of images of the same size into a single single-channel image.\n\
It keeps the first non-null pixel value found in the input list.");
SetDocLimitations("This application will break incoming pipelines.");
SetDocAuthors("Luc Hermitte (CS Group)");
SetDocSeeAlso("");
AddDocTag("otb::Wrapper::Tags::Manip");
AddParameter(ParameterType_StringList, "il", "Input images list");
SetParameterDescription("il", "Input image list");
AddParameter(ParameterType_OutputImage, "out", "Output Image");
SetParameterDescription("out","Output image.");
AddRAMParameter();
}
void DoUpdateParameters() override
{}
void DoExecute() override
{
// Get the input image list
auto inNameList = GetParameterStringList("il");
// checking the input images list validity
auto const nbImages = inNameList.size();
if (nbImages == 0)
{
itkExceptionMacro("No input Image set...; please set at least one input image");
}
auto functor = [](auto input) {
assert(!input.empty());
auto const wh = std::find_if(
input.begin(), input.end()-1,
[](auto v){ return v != 0;});
return *wh;
};
auto filter = MakeSynthetizeFilter<FloatImageType, FloatImageType>(functor);
for (unsigned int i = 0; i < nbImages; i++)
{
// Given the explicit use of a Reader, this application cannot be used in
// a in-memory pipeline
auto reader = ReaderType::New();
// currentImage->SetExtendedFileName(inNameList[i]);
reader->SetFileName(inNameList[i]);
auto currentImage = reader->GetOutput();
currentImage->UpdateOutputInformation();
otbAppLogINFO(<< "Image #" << i + 1 << " has " << currentImage->GetNumberOfComponentsPerPixel() << " components");
filter->SetInput(i, currentImage);
m_Cache.insert(reader);
}
SetParameterOutputImage("out", filter->GetOutput());
RegisterPipeline(); // TODO: check!!
}
// Needed to register the inputs handled manually
// and not with a VectorImageList through GetParameterImageList
std::set<ReaderType::Pointer> m_Cache;
};
} // otb::Wrapper namespace
} // otb namespace
OTB_APPLICATION_EXPORT(otb::Wrapper::Synthetize)
/*
* Copyright(C) 2005-2020 Centre National d'Etudes Spatiales(CNES)
*
* This file is part of Orfeo Toolbox
*
* https: //www.orfeo-toolbox.org/
*
* Licensed under the Apache License, Version 2.0(the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http: //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef otbInterval_h
#define otbInterval_h
#include "itkIntTypes.h"
#include <cassert>
#include <ostream>
namespace otb
{
/** Simplified index interval.
* Inspired by `boost::numeric::interval`.
*
* \invariant Can be empty.
* \invariant lower <= upper
* \author Luc Hermitte (CS Group)
* \copyright CNES
* \ingroup OTBCommon
*/
class Interval
{
public:
using IndexType = itk::IndexValueType;
using SizeType = itk::SizeValueType;
/** Init constructor from the pair of its extremities. */
constexpr Interval(IndexType l, IndexType u) noexcept
: m_lower(l), m_upper(u)
{
assert(l <= u);
}
/** Alternate factory function from a position and a length. */
static constexpr Interval OfLength(IndexType low, SizeType len) noexcept{
return Interval{low, IndexType(low+len)};
}
constexpr SizeType size() const noexcept
{ return m_upper - m_lower; }
constexpr bool empty() const noexcept
{ return m_lower == m_upper; }
constexpr IndexType lower() const noexcept
{ return m_lower; }
constexpr IndexType upper() const noexcept
{ return m_upper; }
/** Computes the intersection between two interals.
* @return their intersection
* @return {0,0} if theyr don't intersect.
*
* @note this function is an hidden friend
*/
friend constexpr Interval intersect(
Interval const& lhs, Interval const& rhs) noexcept
{
auto const low = std::max(lhs.lower(), rhs.lower());
auto const upp = std::min(lhs.upper(), rhs.upper());
return low <= upp ? Interval{low, upp} : Interval{0,0};
}
/** Stream inserter for intervals.
* @note this function is an hidden friend
*/
friend std::ostream & operator<<(std::ostream & os, Interval const& v)
{
return os << '[' << v.lower() << ".." << v.upper() << '[';
}
private:
IndexType m_lower;
IndexType m_upper;
};
} // otb namespace
#endif // otbInterval_h
/*
* Copyright(C) 2005-2020 Centre National d'Etudes Spatiales(CNES)
*
* This file is part of Orfeo Toolbox
*
* https: //www.orfeo-toolbox.org/
*
* Licensed under the Apache License, Version 2.0(the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http: //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef otbLogHelpers_h
#define otbLogHelpers_h
#include "itkImageRegion.h"
#include <ostream>
namespace otb
{
/** Helper class to log region in a more human readable way:
* e.g.
* \code
x ∈ [0..42[, y ∈ [12..24[, size=42x12 @(0, 12)
* \endcode
* \author Luc Hermitte (CS Group)
* \copyright CNES
* \ingroup OTBCommon
*/
struct NeatRegionLogger
{
using RegionType = itk::ImageRegion<2u>;
NeatRegionLogger(RegionType const& region) : m_region(region) {}
friend std::ostream & operator<<(std::ostream & os, NeatRegionLogger const& r)
{
auto const& size = r.m_region.GetSize();
auto const& idx = r.m_region.GetIndex();
auto const idx_x1 = idx[0];
int const idx_x2 = idx[0] + size[0];
int const idx_y1 = idx[1];
auto const idx_y2 = idx[1] + size[1];
os
<< "x ∈ ["<<idx_x1 << ".." << idx_x2 << '['
<< ", y ∈ ["<<idx_y1 << ".." << idx_y2 << '['
<< ", size=" << size[0]<<'x'<<size[1] << " @("<<idx_x1<<", "<<idx_y1<<')'
;
return os ;
}
RegionType const& m_region;
};
} // otb namespace
#endif // otbLogHelpers_h
/*
* Copyright(C) 2005-2020 Centre National d'Etudes Spatiales(CNES)
*
* This file is part of Orfeo Toolbox
*
* https: //www.orfeo-toolbox.org/
*
* Licensed under the Apache License, Version 2.0(the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http: //www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#ifndef Span_h
#define Span_h
#include <type_traits>
#include <iterator>
#include <cassert>
namespace otb
{
/** Span class inspired by C++20 standard.
* \todo fix RW / RO interface
* \author Luc Hermitte (CS Group)
* \copyright CNES
* \ingroup OTBCommon
*/
template <typename T> struct Span
{
/**\name Typedefs */
//@{
using element_type = T;
using value_type = std::remove_cv_t<T>;
using index_type = std::size_t;
using difference_type = std::ptrdiff_t;
using pointer = T*;
using const_pointer = T const*;
using reference = T&;
using const_reference = T const&;
using iterator = T*;
using const_iterator = T const*;
using reverse_iterator = std::reverse_iterator<iterator>;
using const_reverse_iterator = std::reverse_iterator<const_iterator>;
//@}
/**\name Constructors */
//@{
constexpr Span() noexcept = default;
constexpr Span(pointer ptr, index_type count) noexcept
: m_buffer(ptr), m_size(count)
{
assert(! (!ptr) xor (!count));
}
constexpr Span(pointer first, pointer last) noexcept
: Span(first, last - first)
{
assert(! (!first) xor (!last));
assert(first <= last);
}
template <std::size_t N> constexpr Span(element_type (&arr)[N]) noexcept
: Span(arr, N)
{}
/** Converting constructor from a contiguous container.
* \pre The Container shall be contiguous
* \warning The lifetime of the span shall not exceed the one of the container.
* Be sure to not store the span locally, and initialize it from a rvalue.
* The use case where a span is initialize from a rvalue shall be restricted
* to function parameters.
* \code
* std::vector<T> f();
* void g(Span<T> sp);
* ...
* Span<T> sp(f()); // NO!!! Use after release
* g(f()); // OK!!
* \endcode
*
* \todo static_assert the container is contiguous
*/
template <class Container> constexpr Span(Container&& cont) noexcept
: Span(&cont[0], cont.size())
{
// We cannot use op[] which has an assertion sometimes.
// assert(&const[size()] == (&cont[0] + size()));
}
template <class U> constexpr Span(const otb::Span<U>& s) noexcept
: Span(s.data(), s.size())
{}
constexpr Span(const Span& other) noexcept = default;
//@}
/// shallow assignment
Span& operator=(Span const&) noexcept = default;
/// No-op destructor
~Span() = default;
/**\name Iterators */
//@{
constexpr iterator begin () noexcept { return data(); }
constexpr iterator end () noexcept { return data()+size(); }
constexpr const_iterator begin () const noexcept { return data(); }
constexpr const_iterator end () const noexcept { return data()+size(); }
constexpr const_iterator cbegin() const noexcept { return data(); }
constexpr const_iterator cend () const noexcept { return data()+size(); }
constexpr reverse_iterator rbegin () noexcept { return reverse_iterator(end()); }
constexpr reverse_iterator rend () noexcept { return reverse_iterator(begin()); }
constexpr const_reverse_iterator crbegin() const noexcept { return reverse_const_iterator(cend()); }
constexpr const_reverse_iterator crend () const noexcept { return reverse_const_iterator(cbegin()); }
//@}
/**\name Element access */
//@{
constexpr pointer data () noexcept { return m_buffer; }
constexpr const_pointer data () const noexcept { return m_buffer; }
constexpr reference front() noexcept { assert(!empty()); return *data(); }
constexpr const_reference front() const noexcept { assert(!empty()); return *data(); }
constexpr reference back () noexcept { assert(!empty()); return *data()+size()-1; }
constexpr const_reference back () const noexcept { assert(!empty()); return *data()+size()-1; }
constexpr reference operator[](index_type p) noexcept
{
assert(p < size());
return data()[p];
}
constexpr const_reference operator[](index_type p) const noexcept
{
assert(p < size());
return data()[p];
}
//@}
/**\name Observers */
//@{
constexpr index_type size () const noexcept { return m_size; }
constexpr bool empty() const noexcept { return size() == 0; }
//@}
/**\name Subviews */
//@{
constexpr Span first(index_type n) const noexcept
{ assert(n < size()); return Span(data(), n);}
constexpr Span last(index_type n) const noexcept
{ assert(n < size()); return Span(data()-n, n);}
//@}
private:
pointer m_buffer = nullptr;
index_type m_size = 0;
};
/**
* Helper function to make a span from a range defined with pointers.
* Compensate the fact we are not have access to C++17 `span{ptr1, ptr2}`.
* \tparam T Auto deduced type of the elements
* \param[in] first start of the memory zone
* \param[in] last end of the memory zone
* \return a span over `[first, last)`
* \throw None
* \pre `NOT first != nullptr XOR last != nullptr`
* \pre `first < last`
* \pre `[first, last)` can be iterated
* \see `otb::Span<>`
* \author Luc Hermitte (CS Group)
* \copyright CNES
* \ingroup OTBCommon
*/
template <typename T>
inline
auto make_span(T* first, T* last) noexcept
{
return Span<T>(first, last);
}
/**