Skip to content
Snippets Groups Projects
Commit bd044664 authored by Luc Hermitte's avatar Luc Hermitte
Browse files

ENH: Contribute 2 S1TilingApps to OTB

parent e56355fe
No related branches found
No related tags found
No related merge requests found
Showing
with 1716 additions and 1 deletion
...@@ -92,3 +92,13 @@ OTB_CREATE_APPLICATION( ...@@ -92,3 +92,13 @@ OTB_CREATE_APPLICATION(
NAME Mosaic NAME Mosaic
SOURCES otbMosaic.cxx SOURCES otbMosaic.cxx
LINK_LIBRARIES ${${otb-module}_LIBRARIES}) 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);
}
/**
* Helper function to make a span from a range defined with a pointer plus a
* size.
* Compensate the fact we are not have access to C++17 `span{ptr, count}`.
* \tparam T Auto deduced type of the elements
* \param[in] first start of the memory zone
* \param[in] count number of elements in the span.
* \return a span over `[first, first+count)`
* \throw None
* \pre `NOT first != nullptr XOR count != 0`
* \see `otb::Span<>`
* \author Luc Hermitte (CS Group)
* \copyright CNES
* \ingroup OTBCommon
*/
template <typename T>
inline
auto make_span(T* first, std::size_t count) noexcept
{
return Span<T>(first, count);
}
/**
* Helper function to make a span from a static array.
* Compensate the fact we are not have access to C++17 `span{array}`.
* \tparam T Auto deduced type of the elements
* \tparam N Auto deduced number of elements in the array
* \param[in] array static array
* \return a span over `[&array[0], &array[N])`
* \throw None
* \see `otb::Span<>`
* \author Luc Hermitte (CS Group)
* \copyright CNES
* \ingroup OTBCommon
*/
template <typename T, std::size_t N>
inline
auto make_span(T (&arr)[N]) noexcept
{
return Span<T>(arr);
}
/**
* Helper function to make a span from a contiguous container.
* Compensate the fact we are not have access to C++17 `span{container}`.
* \tparam ContiguousContainer Auto deduced type of the container
* \param[in] cont container of contiguous elements
* \return a span over `[c.data(), c.size())`
* \throw None
* \see `otb::Span<>`
* \author Luc Hermitte (CS Group)
* \copyright CNES
* \ingroup OTBCommon
*/
template <typename ContiguousContainer>
inline
auto make_span(ContiguousContainer & c) noexcept
{
return Span<decltype(*c.data())>(c);
}
}
// otb namespace
#endif // Span_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 otbZipIterator_h
#define otbZipIterator_h
#include "otbSpan.h"
#include "itkMacro.h"
#include <type_traits>
#include <vector>
#include <cassert>
namespace otb
{
namespace internals
{
struct ConstTag {};
struct MutableTag {};
/**
* Wrapper to present list of iterators as a single iterator.
*
* \invariant This class shall not be inherited.
* \invariant All sub iterators are always synchronised (same region, size...)
* \invariant `!m_iterators.empty()`
* \author Luc Hermitte (CS Group)
* \copyright CNES
* \ingroup OTBCommon
*/
template <typename TImageIterator, typename ConstOrMutable>
class ZipIterator
{
public:
/**\name ITK Constants and Typedefs */
//@{
/** Iterator type for zipped iterators. */
using ImageIteratorType = TImageIterator;
/** Image type alias support */
using ImageType = typename TImageIterator::ImageType;
/** Dimension of the image the iterator walks. This constant is needed so
* functions that are templated over image iterator type (as opposed to
* being templated over pixel type and dimension) can have compile time
* access to the dimension of the image that the iterator walks. */
static constexpr unsigned int ImageIteratorDimension = ImageIteratorType::ImageIteratorDimension;
using Self = ZipIterator;
/** Run-time type information (and related methods). */
itkTypeMacroNoParent(ZipIterator);
/** Index type alias support */
using IndexType = typename ImageIteratorType::IndexType;
/** Size type alias support */
using SizeType = typename ImageIteratorType::SizeType;
/** Offset type alias support */
using OffsetType = typename ImageIteratorType::OffsetType;
/** Region type alias support */
using RegionType = typename ImageIteratorType::RegionType;
/** PixelContainer type alias support. Used to refer to the container for
* the pixel data. While this was already typdef'ed in the superclass
* it needs to be redone here for this subclass to compile properly with gcc. */
using PixelContainer = typename ImageIteratorType::PixelContainer;
using PixelContainerPointer = typename PixelContainer::Pointer;
/** Internal Pixel Type */
using InternalPixelType = typename ImageIteratorType::InternalPixelType;
/** External Pixel Type */
using PixelType = typename ImageIteratorType::PixelType;
/** Accessor type that convert data between internal and external
* representations. */
using AccessorType = typename ImageIteratorType::AccessorType;
using AccessorFunctorType = typename ImageIteratorType::AccessorFunctorType;
//@}
/**\name Constructions & Destruction
*
* This class follows the rule of 0/5
*/
//@{
ZipIterator () = default;
~ZipIterator () = default;
ZipIterator (ZipIterator const&) = default;
ZipIterator (ZipIterator &&) = default;
ZipIterator& operator=(ZipIterator const&) = default;
ZipIterator& operator=(ZipIterator &&) = default;
/** Convertion constructor.
* Converts from mutable to const iterator
* \see https://quuxplusone.github.io/blog/2018/12/01/const-iterator-antipatterns/
*/
template <bool IsConst_ = std::is_same<ConstOrMutable, ConstTag>::value, class = std::enable_if<IsConst_>>
ZipIterator(ZipIterator<ImageIteratorType, MutableTag> const& rhs)
: m_iterators(rhs.m_iterators())
{}
/** Convertion move constructor.
* Move converts from mutable to const iterator
* \see https://quuxplusone.github.io/blog/2018/12/01/const-iterator-antipatterns/
*/
template <bool IsConst_ = std::is_same<ConstOrMutable, ConstTag>::value, class = std::enable_if<IsConst_>>
ZipIterator(ZipIterator<ImageIteratorType, MutableTag> && rhs)
: m_iterators(move(rhs.m_iterators()))
{}
/**
* Init Constructor.
* Constructs a `ZipIterator` from a list of Images and a Region.
* \param[in,out] images List of images
* \param[in] region Region to iterate over
* \pre There should be at least one image
*/
ZipIterator(Span<ImageType * const> images, RegionType const& region)
{
assert(! images.empty());
m_iterators.reserve(images.size());
for (auto & im: images)
m_iterators.emplace_back(im, region);
}
// static_assert(std::is_copy_constructible<Self>::value, "Requires copy construction");
// static_assert(std::is_trivially_copy_constructible<Self>::value, "Requires trivial copy construction");
//@}
/**\name Comparison */
//@{
friend bool operator==(ZipIterator const& lhs, ZipIterator const& rhs)
{
assert(!lhs.m_iterators.empty());
assert(lhs.m_iterators.size() == rhs.m_iterators.size());
return lhs.m_iterators.front() == rhs.m_iterators.front();
}
friend bool operator!=(ZipIterator const& lhs, ZipIterator const& rhs)
{ return ! (lhs == rhs); }
friend bool operator<=(ZipIterator const& lhs, ZipIterator const& rhs)
{
assert(!lhs.m_iterators.empty());
assert(lhs.m_iterators.size() == rhs.m_iterators.size());
return lhs.m_iterators.front() <= rhs.m_iterators.front();
}
friend bool operator<(ZipIterator const& lhs, ZipIterator const& rhs)
{
assert(!lhs.m_iterators.empty());
assert(lhs.m_iterators.size() == rhs.m_iterators.size());
return lhs.m_iterators.front() < rhs.m_iterators.front();
}
friend bool operator>=(ZipIterator const& lhs, ZipIterator const& rhs)
{ return ! (lhs < rhs); }
friend bool operator>(ZipIterator const& lhs, ZipIterator const& rhs)
{ return ! (lhs <= rhs); }
//@}
/**\name ITK iterator interface */
//@{
// What about GetIndex() and SetIndex ?
/** Fetch the region iterated by the iterator. */
auto const& GetRegion() const
{
assert(!m_iterators.empty());
return m_iterators.front().GetRegion();
}
/** Set the region iterated by the iterator. */
void SetRegion(RegionType const& region)
{
for (auto & it : m_iterators)
it.SetRegion(region);
}
/** Moves the iterator to the begin of the region iterated. */
Self& GoToBegin() {
for (auto & it : m_iterators)
it.GoToBegin();
return *this;
}
/** Moves the iterator to the end of the region iterated. */
Self& GoToEnd() {
for (auto & it : m_iterators)
it.GoToEnd();
return *this;
}
/** Tells whether the iterator is at the begin of the region iterated. */
bool IsAtBegin() const {
assert(!m_iterators.empty());
return m_iterators.front().IsAtBegin();
}
/** Tells the iterator is at the end of the region iterated. */
bool IsAtEnd() const {
assert(!m_iterators.empty());
return m_iterators.front().IsAtEnd();
}
/** Pre-increment the iterator.
* As post-increment is less efficient, it hasn't been provided.
*/
Self& operator++() {
assert(!IsAtEnd());
for (auto & it : m_iterators)
++it;
return *this;
}
/** Removed post-increment operator.
* Please use the preincrement operator!
*/
Self operator++(int) = delete;
/** Internal typedef to the type holding the list of ITK iterators. */
using ImageIteratorList_t = std::vector<ImageIteratorType>;
/** Internal Pixel Proxy Type returned by `ZipIterator`.
* \author Luc Hermitte (CS Group)
* \copyright CNES
* \ingroup OTBCommon
*/
struct PixelListProxy
{
/** Init constructor.
* @param[in] iterators List of ITK iterators
*/
explicit PixelListProxy(ImageIteratorList_t const& iterators) noexcept
: m_iterators(iterators)
{}
bool empty() const noexcept {return m_iterators.empty();}
auto size() const noexcept {return m_iterators.size();}
/** Internal C++ iterator over the components of the Pixel Proxy.
* \author Luc Hermitte (CS Group)
* \copyright CNES
* \ingroup OTBCommon
*/
struct iterator__
{
using difference_type = typename ImageIteratorList_t::difference_type;
using value_type = decltype(typename ImageIteratorList_t::const_iterator{}->Get());
using pointer = value_type*;
using reference = value_type&;
using iterator_category = std::forward_iterator_tag;
explicit iterator__(typename ImageIteratorList_t::const_iterator ref)
: reference_to_value(ref){}
friend bool operator==(iterator__ const& lhs, iterator__ const& rhs) noexcept
{ return lhs.reference_to_value == rhs.reference_to_value;}
friend bool operator!=(iterator__ const& lhs, iterator__ const& rhs) noexcept
{ return ! (lhs == rhs);}
iterator__ & operator++() noexcept {
++reference_to_value;
return *this;
}
iterator__ & operator--() noexcept {
--reference_to_value;
return *this;
}
iterator__ operator+(std::ptrdiff_t offset) const noexcept{
return iterator__{reference_to_value + offset};
}
iterator__ operator-(std::ptrdiff_t offset) const noexcept{
return iterator__{reference_to_value - offset};
}
decltype(auto) operator*() const {
return reference_to_value->Get();
}
private:
typename ImageIteratorList_t::const_iterator reference_to_value;
};
auto begin() noexcept { return iterator__(m_iterators.begin()); }
auto end() noexcept { return iterator__{m_iterators.end()}; }
auto begin() const noexcept { return iterator__{m_iterators.begin()}; }
auto end() const noexcept { return iterator__{m_iterators.end()}; }
auto cbegin() const noexcept { return iterator__{m_iterators.cbegin()}; }
auto cend() const noexcept { return iterator__{m_iterators.cend()}; }
decltype(auto) operator[](std::size_t idx) const {
assert(idx < size());
return m_iterators[idx].Get();
}
decltype(auto) operator[](std::size_t idx) {
assert(idx < size());
return m_iterators[idx].Get();
}
decltype(auto) front() const {
assert(!empty());
return m_iterators.front().Get();
}
decltype(auto) front() {
assert(!empty());
return m_iterators.front().Get();
}
decltype(auto) back() const {
assert(!empty());
return m_iterators.back().Get();
}
decltype(auto) back() {
assert(!empty());
return m_iterators.back().Get();
}
private:
ImageIteratorList_t const& m_iterators;
};
/** Fetches the value of the current pixel.
* \return an iterable proxy over the pixel made of all images.
*/
PixelListProxy Get() const {
return PixelListProxy{m_iterators};
}
//@}
/**\name Mutable Iterator Interface */
//@{
template <typename MultiCompPixelType>
void Set(MultiCompPixelType const& p)
{
assert(p.size() == m_iterators.size());
for (std::size_t i = 0; i!=m_iterators.size(); ++i)
{
m_iterators[i].Set(p[i]);
}
}
// PixelType & Value(); -- cannot be defined and still preserve direct access
// to memory => we don't provide it.
// ImageType * GetImages();
//@}
/**\name ScanLine Iterator Interface */
//@{
/** Moves iterator to next line. */
Self& NextLine() {
for (auto & it : m_iterators)
it.NextLine();
return *this;
}
/** Moves iterator to the beginning of the current line. */
Self& GoToBeginOfLine() {
for (auto & it : m_iterators)
it.GoToBeginOfLine();
return *this;
}
/** Moves iterator to the end of the current line. */
Self& GoToEndOfLine() {
for (auto & it : m_iterators)
it.GoToEndOfLine();
return *this;
}
/** Tells whether the iterator is a the end of a line.
* \pre `!m_iterators.empty()`
*/
bool IsAtEndOfLine() const {
assert(!m_iterators.empty());
// Const qualifier has been added to ScanLineIterator::IsAtEndOfLine in ITK
// 5.1 => Use const_cast in the mean time...
return const_cast<typename ImageIteratorList_t::value_type &>(m_iterators.front()).IsAtEndOfLine();
}
//@}
private:
ImageIteratorList_t m_iterators;
};
} // otb::internal namespace
/** Typedef for a ZipIterator.
* ZipIterator presents a single iterator over a list of image iterators.
* \author Luc Hermitte (CS Group)
* \copyright CNES
* \ingroup OTBCommon
* \see `otb::internals::ZipIterator<>`
*/
template <typename TImageIterator>
using ZipIterator = internals::ZipIterator<TImageIterator, internals::MutableTag>;
/** Typedef for a ZipConstIterator.
* ZipConstIterator presents a single iterator over a list of const image iterators.
* \author Luc Hermitte (CS Group)
* \copyright CNES
* \ingroup OTBCommon
* \see `otb::internals::ZipIterator<>`
*/
template <typename TImageIterator>
using ZipConstIterator = internals::ZipIterator<TImageIterator, internals::ConstTag>;
} // otb namespace
#endif // otbZipIterator_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 otbSynthetizeFilter_h
#define otbSynthetizeFilter_h
#include "otbZipIterator.h"
#include "itkImageToImageFilter.h"
#include "itkImageScanlineConstIterator.h"
#include "itkImageScanlineIterator.h"
#include "itkProgressReporter.h"
namespace otb
{
/**
* Filter that reduces/synthetize multiple input into a single output.
*
* This filter makes sure to avoid VectorImages. Instead it works on a
* collection of scalar images.
* \tparam TInputImage Type of the input images
* \tparam TOutputImage Type of the output image
* \tparam TFunctor Type of the functor, meant to be auto-deduced by
* `MakeSynthetizeFilter()`
*
* \author Luc Hermitte (CS Group)
* \copyright CNES
* \see for instance `otb::Wrapper::Synthetize`
*/
template <typename TInputImage, typename TOutputImage, typename TFunctor>
class SynthetizeFilter : public itk::ImageToImageFilter<TInputImage, TOutputImage>
{
public:
/**\name Convenient typedefs for simplifying declarations */
//@{
using InputImageType = TInputImage;
using OutputImageType = TOutputImage;
using FunctorType = TFunctor;
//@}
/**\name Extract dimension from input and output images */
//@{
itkStaticConstMacro(InputImageDimension, unsigned int, InputImageType::ImageDimension);
itkStaticConstMacro(OutputImageDimension, unsigned int, OutputImageType::ImageDimension);
//@}
/**\name Standard class typedefs */
//@{
using Self = SynthetizeFilter;
using Superclass = itk::ImageToImageFilter<InputImageType, OutputImageType>;
using Pointer = itk::SmartPointer<Self>;
using ConstPointer = itk::SmartPointer<const Self>;
//@}
/** Method for creation through the object factory. */
static Pointer New(FunctorType functor)
{
Pointer smartPtr = new Self(std::move(functor));
smartPtr->UnRegister();
return smartPtr;
}
/** Run-time type information (and related methods). */
itkTypeMacro(SynthetizeFilter, ImageToImageFilter);
/**\name Image typedef support */
//@{
using InputPixelType = typename InputImageType::PixelType;
using OutputPixelType = typename OutputImageType::PixelType;
using InputRealType = typename itk::NumericTraits<InputPixelType>::RealType;
using InputImageRegionType = typename InputImageType::RegionType;
using OutputImageRegionType = typename OutputImageType::RegionType;
using InputSizeType = typename InputImageType::SizeType;
using OutputIndexType = typename OutputImageType::IndexType;
using OutputSizeType = typename OutputImageType::SizeType;
static_assert(InputImageDimension == OutputImageDimension, "Images have the same number of components");
using DataObjectPointerArraySizeType = itk::ProcessObject::DataObjectPointerArraySizeType;
//@}
/**\name Access to N-th Input
*
* Set/Get the nth filter input with or without a specified associated
* variable name.
*/
//@{
using Superclass::SetNthInput;
using Superclass::GetInput;
/** Return a pointer on the nth filter input */
InputImageType* GetNthInput(DataObjectPointerArraySizeType idx)
{
return const_cast<InputImageType*>(this->GetInput(idx));
}
/** Returns a vector of input images. */
std::vector<InputImageType const*> GetInputs() const
{
std::vector<InputImageType const*> res;
auto const nbInputImages = this->GetNumberOfInputs();
res.reserve(nbInputImages);
for (std::size_t i = 0 ; i != nbInputImages ; ++i)
res.push_back(this->GetInput(i));
return res;
}
//@}
protected:
/** Init constructor. */
explicit SynthetizeFilter(FunctorType functor)
: m_functor(functor){}
~SynthetizeFilter() = default;
/** Overrides `GenerateOutputInformation` to check images consistency. */
void GenerateOutputInformation() override
{
Superclass::GenerateOutputInformation();
CheckInputImageDimensions();
}
// void GenerateInputRequestedRegion() override;
// +-> TODO: detect neighborhood to apply pad radius
/**
* Main computation function called by each thread.
* \param[in] outputRegionForThread Specified output region to compute
* \param[in] threadId Id of the computing threads
*/
void ThreadedGenerateData(
OutputImageRegionType const& outputRegionForThread,
itk::ThreadIdType threadId) override
{
using ImageScanlineConstIteratorType = itk::ImageScanlineConstIterator<InputImageType const>;
using OutImageScanlineConstIteratorType = itk::ImageScanlineIterator<OutputImageType>;
using OutputIterator = itk::ImageScanlineIterator<OutputImageType>;
using InputIterator = ZipConstIterator<ImageScanlineConstIteratorType>;
auto const regSizeY = outputRegionForThread.GetSize()[1];
itk::ProgressReporter progress( this, threadId, outputRegionForThread.GetNumberOfPixels() / regSizeY );
InputIterator inputIterator(this->GetInputs(), outputRegionForThread);
OutputIterator outputIterator(this->GetOutput(), outputRegionForThread);
inputIterator.GoToBegin();
outputIterator.GoToBegin();
for (
; !inputIterator.IsAtEnd()
; inputIterator.NextLine(), outputIterator.NextLine())
{
assert(! outputIterator.IsAtEnd());
// inputIterator.GoToBeginOfLine();
// outputIterator.GoToBeginOfLine();
for (
; !inputIterator.IsAtEndOfLine()
; ++inputIterator, ++outputIterator)
{
assert(!outputIterator.IsAtEndOfLine());
outputIterator.Set(m_functor(inputIterator.Get()));
}
progress.CompletedPixel(); // Completed...Line()
}
}
private:
void CheckInputImageDimensions()
{
// Check if input image dimensions match
auto const nbInputImages = this->GetNumberOfInputs();
auto const& inputSize = this->GetInput(0)->GetLargestPossibleRegion().GetSize();
for (auto p = 1U; p < nbInputImages; ++p)
{
auto const& regionSize = this->GetInput(p)->GetLargestPossibleRegion().GetSize();
if (inputSize != regionSize)
{
itkExceptionMacro(<< "Input images must have the same dimensions.\n"
<< "band #1 is [" << inputSize[0] << ";" << inputSize[1] << "]\n"
<< "band #" << p + 1 << " is [" << this->GetInput(p)->GetLargestPossibleRegion().GetSize(0) << ";"
<< regionSize << "]");
}
}
}
/** Internal functor.
* Can only be set at filter creation through call to `New`.
*/
FunctorType m_functor;
};
/**
* Factory function for `SynthetizeFilter`.
* `SynthetizeFilter` objects are best made thanks to this factory function
* that'll automatically deduce the type of the functor parameter.
*
* Actually, there is no other to create a `SynthetizeFilter<>` that'll call a
* lambda on each pixel.
* \tparam TInputImage Type of the input images
* \tparam TOutputImage Type of the output image
* \tparam TFunctor Type of the functor
* \param[in] functor The functor
*
* \return a new `SynthetizeFilter` object.
* \sa `SynthetizeFilter`
*/
template <typename TInputImage, typename TOutputImage, typename TFunctor>
auto MakeSynthetizeFilter(TFunctor functor)
{
auto filter = SynthetizeFilter<TInputImage, TOutputImage, TFunctor>::New(std::move(functor));
return filter;
}
} // otb namespace
#ifndef OTB_MANUAL_INSTANTIATION
// #include "otbSynthetizeFilter.hxx"
#endif
#endif // otbSynthetizeFilter_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 otbClampROIFilter_h
#define otbClampROIFilter_h
#include "itkImageToImageFilter.h"
namespace otb
{
/**
* Region clamping filter.
* This filter is a kind of ROI pass filter. Data within the ROI is kept with
* its original value. Data outside ROI is forced to 0.
*
* Also, this filter propagate the exact ROI upstream in the pipeline. This
* way, if it's piped after another filter, the upstream filter isn't executed
* on the data outside the ROI.
*
* \tparam TImage Image type.
* \sa `otb::ExtractROI<>`
* \author Luc Hermitte (CS Group)
* \copyright CNES
*/
template <typename TImage>
class ClampROIFilter : public itk::ImageToImageFilter<TImage, TImage>
{
public:
/**\name Convenient typedefs for simplifying declarations */
//@{
using InputImageType = TImage;
using OutputImageType = TImage;
//@}
/**\name Extract dimension from input and output images */
//@{
itkStaticConstMacro(InputImageDimension, unsigned int, InputImageType::ImageDimension);
itkStaticConstMacro(OutputImageDimension, unsigned int, OutputImageType::ImageDimension);
//@}
/**\name Standard class typedefs */
//@{
using Self = ClampROIFilter;
using Superclass = itk::ImageToImageFilter<InputImageType, OutputImageType>;
using Pointer = itk::SmartPointer<Self>;
using ConstPointer = itk::SmartPointer<const Self>;
//@}
/** Method for creation through the object factory. */
itkNewMacro(Self);
/** Run-time type information (and related methods). */
itkTypeMacro(ClampROIFilter, unused);
/**\name Image typedef support */
//@{
using InputPixelType = typename InputImageType::PixelType;
using OutputPixelType = typename OutputImageType::PixelType;
using InputRealType = typename itk::NumericTraits<InputPixelType>::RealType;
using InputImageRegionType = typename InputImageType::RegionType;
using OutputImageRegionType = typename OutputImageType::RegionType;
using InputIndexType = typename InputImageType::IndexType;
using InputSizeType = typename InputImageType::SizeType;
using OutputIndexType = typename OutputImageType::IndexType;
using OutputSizeType = typename OutputImageType::SizeType;
static_assert(InputImageDimension == OutputImageDimension, "Images have the same number of components");
//@}
/** Column threshold setter. */
void SetThresholdX(long threshold) noexcept
{ m_thresholdX = threshold; }
/** Column threshold getter. */
long GetThresholdX() const noexcept
{ return m_thresholdX;}
/** Top line threshold setter. */
void SetThresholdYtop(long threshold) noexcept
{ m_thresholdYtop = threshold; }
/** Top line threshold getter. */
long GetThresholdYtop() const noexcept
{ return m_thresholdYtop;}
/** Bottom line threshold setter. */
void SetThresholdYbot(long threshold) noexcept
{ m_thresholdYbot = threshold; }
/** Bottom line threshold getter. */
long GetThresholdYbot() const noexcept
{ return m_thresholdYbot;}
protected:
/// Hidden constructor
ClampROIFilter() = default;
InputImageType * GetInputImage() { return const_cast<InputImageType*>(this->GetInput()); }
InputImageType const* GetInputImage() const { return this->GetInput(); }
/** otbClampROIFilter doesn't need an input requested region as large as the
* output requested region.
* \sa ImageToImageFilter::GenerateInputRequestedRegion()
*/
void CallCopyOutputRegionToInputRegion(
InputImageRegionType & destRegion,
OutputImageRegionType const& srcRegion) override
{
destRegion = OutputRegionToInputRegion(srcRegion);
}
/**
* Functional implementation of `CallCopyOutputRegionToInputRegion()`.
*/
InputImageRegionType OutputRegionToInputRegion(
OutputImageRegionType const& srcRegion);
/**
* Main computation function called by each thread.
* \param[in] outputRegionForThread Specified output region to compute
* \param[in] threadId Id of the computing threads
*/
void ThreadedGenerateData(
OutputImageRegionType const& outputRegionForThread,
itk::ThreadIdType threadId) override;
private:
long m_thresholdX = 0;
long m_thresholdYtop = 0;
long m_thresholdYbot = 0;
};
} // otb namespace
#ifndef OTB_MANUAL_INSTANTIATION
#include "otbClampROIFilter.hxx"
#endif
#endif // otbClampROIFilter_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 otbClampROIFilter_hxx
#define otbClampROIFilter_hxx
#include "otbClampROIFilter.h"
#include "otbInterval.h"
#include "otbMacro.h"
#include "otbLogHelpers.h"
#include "itkImageScanlineConstIterator.h"
#include "itkImageScanlineIterator.h"
#include "itkProgressReporter.h"
#include <boost/numeric/interval.hpp>
#include <algorithm>
#include <cassert>
#include <ostream>
template <typename T, typename P>
inline
std::ostream & operator<<(std::ostream & os, boost::numeric::interval<T,P> const& v)
{
return os << '[' << v.lower() << ".." << v.upper() << '[';
}
namespace otb
{
template<typename TImage>
void
ClampROIFilter<TImage>
::ThreadedGenerateData(
OutputImageRegionType const& outputRegionForThread,
itk::ThreadIdType threadId)
{
// otbMsgDevMacro("ThreadedGenerateData begin("<<NeatRegionLogger{outputRegionForThread}<<")");
using InputIterator = itk::ImageScanlineConstIterator<InputImageType const>;
using OutputIterator = itk::ImageScanlineIterator<OutputImageType>;
auto const* input = this->GetInput();
auto * output = this->GetOutput();
assert(input);
assert(output);
InputIterator inputIterator (input, OutputRegionToInputRegion(outputRegionForThread));
OutputIterator outputIterator(output, outputRegionForThread);
auto const& imgRegion = output->GetLargestPossibleRegion();
auto const imgSizeX = imgRegion.GetSize()[0];
auto const imgSizeY = imgRegion.GetSize()[1];
itk::IndexValueType const imgEndX = imgRegion.GetIndex()[0] + imgSizeX;
itk::IndexValueType const imgEndY = imgRegion.GetIndex()[1] + imgSizeY;
auto const& size = outputRegionForThread.GetSize();
auto const& index = outputRegionForThread.GetIndex();
auto const sizeX = size[0];
auto const sizeY = size[1];
auto const startX = index[0];
auto const startY = index[1];
itk::IndexValueType const endX = startX + sizeX;
itk::IndexValueType const endY = startY + sizeY;
auto const thrX1 = std::min(endX, m_thresholdX);
auto const thrX2 = std::min(endX, imgEndX - m_thresholdX);
auto const thrY1 = std::min(endY, m_thresholdYtop);
auto const thrY2 = std::min(endY, imgEndY - m_thresholdYbot);
assert(thrX1 <= endX && "Iterations shall stay within requested region");
assert(thrX2 <= endX && "Iterations shall stay within requested region");
assert(thrY1 <= endY && "Iterations shall stay within requested region");
assert(thrY2 <= endY && "Iterations shall stay within requested region");
// using interval_t = boost::numeric::interval<long>;
using interval_t = Interval;
auto const region = interval_t{startX, endX};
auto const zero_left = intersect(interval_t{startX, thrX1}, region);
auto const copy_middle = intersect(interval_t{thrX1, thrX2}, region);
auto const zero_right = intersect(interval_t{thrX2, endX}, region);
otbMsgDevMacro("X in " << zero_left << " <<-- 0");
otbMsgDevMacro("X in " << copy_middle << " <<-- copy input");
otbMsgDevMacro("X in " << zero_right << " <<-- 0");
otbMsgDevMacro("Y in ["<<startY<<".."<<thrY1<<"[ <<--- 0");
auto const nb_z_l = zero_left.upper() - zero_left.lower();
auto const nb_c_m = copy_middle.upper() - copy_middle.lower();
auto const nb_z_r = zero_right.upper() - zero_right.lower();
assert(nb_z_l + nb_c_m + nb_z_r == sizeX);
itk::ProgressReporter progress( this, threadId, outputRegionForThread.GetNumberOfPixels() / sizeY );
outputIterator.GoToBegin();
// TODO: Can we consider that lines are contiguous in memory?
// If so, we could have only 2 fill_n and one copy_n!
auto y = startY;
for (
; y < thrY1
; ++y, outputIterator.NextLine())
{
// If there is any trimming of first lines, the inputIterator iterator will
// directly point to the right region. we shall not increment it!
// otbMsgDevMacro("o(" << y << ") <-- 0");
assert(! outputIterator.IsAtEnd());
outputIterator.GoToBeginOfLine();
std::fill_n(&outputIterator.Value(), sizeX, OutputPixelType{});
progress.CompletedPixel(); // Completed...Line()
}
assert(y == thrY1 || y == startY);
otbMsgDevMacro("Y in ["<<thrY1<<".."<<thrY2<<"[ <<--- Input");
inputIterator.GoToBegin();
for (
; y < thrY2
; ++y, inputIterator.NextLine(), outputIterator.NextLine())
{
// otbMsgDevMacro("o(" << y << ") <-- Input");
assert(! inputIterator.IsAtEnd());
assert(! outputIterator.IsAtEnd());
inputIterator.GoToBeginOfLine();
outputIterator.GoToBeginOfLine();
auto const t1 = std::fill_n(&outputIterator.Value(), nb_z_l, OutputPixelType{});
// If there is any trimming of first columns, the inputIterator iterator
// will directly point to the right region. we shall not apply an offset!
auto const t2 = std::copy_n(&inputIterator.Value(), nb_c_m, t1);
std::fill_n(t2, nb_z_r, OutputPixelType{});
progress.CompletedPixel(); // Completed...Line()
}
assert(y == thrY2 || y == startY);
otbMsgDevMacro("Y in ["<<thrY2<<".."<<endY<<"[ <<--- 0");
for (
; y < endY
; ++y, outputIterator.NextLine())
{
// If there is any trimming of last lines, the inputIterator iterator will
// directly point to the right region. we shall not increment it!
// otbMsgDevMacro("o(" << y << ") <-- 0");
assert(! outputIterator.IsAtEnd());
outputIterator.GoToBeginOfLine();
std::fill_n(&outputIterator.Value(), sizeX, OutputPixelType{});
progress.CompletedPixel(); // Completed...Line()
}
assert(y == endY);
otbMsgDevMacro("ThreadedGenerateData end");
}
template<typename TImage>
typename ClampROIFilter<TImage>::InputImageRegionType
ClampROIFilter<TImage>
::OutputRegionToInputRegion(OutputImageRegionType const& srcRegion)
{
auto const* output = this->GetOutput();
assert(output);
auto const& maxRegion = output->GetLargestPossibleRegion();
auto const& maxSize = maxRegion.GetSize();
auto const& maxStart = maxRegion.GetIndex();
auto const& reqRegion = srcRegion;
auto const& reqSize = reqRegion.GetSize();
auto const& reqStart = reqRegion.GetIndex();
// using interval_t = boost::numeric::interval<long>;
using interval_t = Interval;
auto const maxRegionX = interval_t{
maxStart[0]+m_thresholdX,
static_cast<itk::IndexValueType>(maxStart[0]+maxSize[0]-m_thresholdX)
};
auto const maxRegionY = interval_t{
maxStart[1]+m_thresholdYtop,
static_cast<itk::IndexValueType>(maxStart[1]+maxSize[1]-m_thresholdYbot)
};
auto const reqRegionX = interval_t::OfLength(reqStart[0], reqSize[0]);
auto const reqRegionY = interval_t::OfLength(reqStart[1], reqSize[1]);
#if 0
otbMsgDevMacro("OutputRegionToInputRegion: "
<< "out="<< NeatRegionLogger{reqRegion}
<< "; max: x="<<maxRegionX << " y="<<maxRegionY
<< "; req: x="<<reqRegionX << " y="<<reqRegionY
);
#endif
auto const inRegionX = intersect(reqRegionX, maxRegionX);
auto const inRegionY = intersect(reqRegionY, maxRegionY);
// otbMsgDevMacro(" --> ∩X: " << inRegionX << " ∩Y: " << inRegionY);
const InputIndexType inStart{inRegionX.lower(), inRegionY.lower()};
assert(inRegionX.lower() <= inRegionX.upper());
assert(inRegionY.lower() <= inRegionY.upper());
const InputSizeType inSize{
static_cast<unsigned long>(inRegionX.upper()-inRegionX.lower()),
static_cast<unsigned long>(inRegionY.upper()-inRegionY.lower())
};
auto const inRegion = InputImageRegionType{inStart, inSize};
otbMsgDevMacro("OutputRegionToInputRegion: out="<< NeatRegionLogger{reqRegion}<<" --> in="<<NeatRegionLogger{inRegion});
return inRegion;
}
} // otb namespace
#endif // otbClampROIFilter_hxx
...@@ -27,5 +27,5 @@ https://gitlab.orfeo-toolbox.org/s1-tiling/s1tilingsupportapplications ...@@ -27,5 +27,5 @@ https://gitlab.orfeo-toolbox.org/s1-tiling/s1tilingsupportapplications
" "
GIT_REPOSITORY https://gitlab.orfeo-toolbox.org/s1-tiling/s1tilingsupportapplications GIT_REPOSITORY https://gitlab.orfeo-toolbox.org/s1-tiling/s1tilingsupportapplications
# Commit on master branch # Commit on master branch
GIT_TAG master GIT_TAG 2.0.0
) )
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment