OTB  6.7.0
Orfeo Toolbox
otbFunctorImageFilter.hxx
Go to the documentation of this file.
1 /*
2  * Copyright (C) 2005-2019 Centre National d'Etudes Spatiales (CNES)
3  *
4  * This file is part of Orfeo Toolbox
5  *
6  * https://www.orfeo-toolbox.org/
7  *
8  * Licensed under the Apache License, Version 2.0 (the "License");
9  * you may not use this file except in compliance with the License.
10  * You may obtain a copy of the License at
11  *
12  * http://www.apache.org/licenses/LICENSE-2.0
13  *
14  * Unless required by applicable law or agreed to in writing, software
15  * distributed under the License is distributed on an "AS IS" BASIS,
16  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
17  * See the License for the specific language governing permissions and
18  * limitations under the License.
19  */
20 
21 #ifndef otbFunctorImageFilter_hxx
22 #define otbFunctorImageFilter_hxx
23 
24 #include "otbFunctorImageFilter.h"
25 #include "itkProgressReporter.h"
29 #include <array>
30 
31 namespace otb
32 {
33 namespace functor_filter_details
34 {
35 // Variadic SetRequestedRegion
36 
37 // This function sets the requested region for one image
38 template<class T> int SetInputRequestedRegion(const T * img, const itk::ImageRegion<2> & region, const itk::Size<2>& radius, bool pad)
39 {
40  assert(img&&"Input image is a nullptr");
41 
42  auto currentRegion = region;
43 
44  // Hopefully this will be optimized out by compiler
45  if(pad)
46  currentRegion.PadByRadius(radius);
47 
48  // The ugly cast in all ITK filters
49  T * nonConstImg = const_cast<T*>(img);
50 
51  if(currentRegion.Crop(img->GetLargestPossibleRegion()))
52  {
53  nonConstImg->SetRequestedRegion(currentRegion);
54  return 0;
55  }
56  else
57  {
58  nonConstImg->SetRequestedRegion(currentRegion);
59 
60  // build an exception
61  itk::InvalidRequestedRegionError e(__FILE__, __LINE__);
62  e.SetLocation("::SetInputRequestedRegion<>()");
63  e.SetDescription("Requested region is (at least partially) outside the largest possible region.");
64  e.SetDataObject(nonConstImg);
65  throw e;
66  }
67 }
68 
69 // Will be easier to write in c++17 with std::apply and fold expressions
70 template <typename HasNeighborhood, class Tuple, size_t...Is> auto SetInputRequestedRegionsImpl(Tuple & t, const itk::ImageRegion<2> & region, std::index_sequence<Is...>,const itk::Size<2> & radius)
71 {
72  return std::make_tuple(SetInputRequestedRegion(std::get<Is>(t),region,radius,typename std::tuple_element<Is,HasNeighborhood>::type::value_type())...);
73 }
74 
75 // Will be easier to write in c++17 with std::apply and fold expressions
76 template <typename HasNeighborhood,typename... T> auto SetInputRequestedRegions(std::tuple<T...> && t,const itk::ImageRegion<2> & region, const itk::Size<2> & radius)
77 {
78  return SetInputRequestedRegionsImpl<HasNeighborhood>(t,region,std::make_index_sequence<sizeof...(T)>{},radius);
79 }
80 
81 // Will be easier to write in c++17 with std::apply and fold expressions
82 template <class Tuple, size_t...Is> auto GetNumberOfComponentsPerInputImpl(Tuple & t, std::index_sequence<Is...>)
83 {
84  return std::array<size_t,sizeof...(Is)>{{std::get<Is>(t)->GetNumberOfComponentsPerPixel()...}};
85 }
86 
87 // Will be easier to write in c++17 with std::apply and fold expressions
88 template <typename ...T> auto GetNumberOfComponentsPerInput(std::tuple<T...> & t)
89 {
90  return GetNumberOfComponentsPerInputImpl(t, std::make_index_sequence<sizeof...(T)>{});
91 }
92 
93 template <typename N> struct MakeIterator {};
94 
95 template <> struct MakeIterator<std::false_type>
96 {
97  template <class T> static auto Make(const T * img, const itk::ImageRegion<2> & region, const itk::Size<2>&)
98  {
99  itk::ImageRegionConstIterator<T> it(img,region);
100  return it;
101  }
102 };
103 
104 template <> struct MakeIterator<std::true_type>
105 {
106  template <class T> static auto Make(const T * img, const itk::ImageRegion<2> & region, const itk::Size<2>& radius)
107  {
108  itk::ConstNeighborhoodIterator<T> it(radius,img,region);
109  return it;
110  }
111 };
112 
113 // Will be easier to write in c++17 with std::apply and fold expressions
114 template <class TNeigh, class Tuple, size_t...Is> auto MakeIteratorsImpl(const Tuple& t, const itk::ImageRegion<2> & region, const itk::Size<2> & radius, std::index_sequence<Is...>, TNeigh)
115 {
116  return std::make_tuple(MakeIterator<typename std::tuple_element<Is,TNeigh>::type >::Make(std::get<Is>(t),region,radius)...);
117 }
118 
119 // Will be easier to write in c++17 with std::apply and fold expressions
120 template<class TNeigh, typename... T> auto MakeIterators(std::tuple<T...> &&t,const itk::ImageRegion<2> & region, const itk::Size<2> & radius, TNeigh n)
121  {
122  return MakeIteratorsImpl(t,region,radius,std::make_index_sequence<sizeof...(T)>{},n);
123  }
124 
125 // Variadic call of operator from iterator tuple
126 template <typename T> struct GetProxy{};
127 
128 
129 template <typename T> struct GetProxy<itk::ImageRegionConstIterator<T> >
130 {
131  static decltype(auto) Get(const itk::ImageRegionConstIterator<T> & t)
132 {
133  return t.Get();
134 }
135 };
136 
137 template <typename T> struct GetProxy<itk::ConstNeighborhoodIterator<T> >
138 {
139  static decltype(auto) Get(const itk::ConstNeighborhoodIterator<T> & t)
140 {
141  return t;
142 }
143 };
144 
147 template <class Oper> struct OperProxy : public OperProxy<typename RetrieveOperator<Oper>::Type> {};
148 
149 template<class Out, class ... In> struct OperProxy<Out(*)(In...)>
150 {
151  template <class Oper> static void Compute(Oper& oper, Out& out, const In& ... in)
152  {
153  out = oper(in...);
154  }
155 };
156 
157 template<class C, class Out, class ... In> struct OperProxy<Out(C::*)(In...)>
158 {
159  template<class Oper> static void Compute(Oper& oper, Out& out, const In& ... in)
160  {
161  out = oper(in...);
162  }
163 };
164 
165 template<class C, class Out, class ... In> struct OperProxy<Out(C::*)(In...) const>
166 {
167  template<class Oper> static void Compute(Oper& oper, Out& out, const In& ... in)
168  {
169  out = oper(in...);
170  }
171 };
172 
173 template<class Out, class ... In> struct OperProxy<void(*)(Out&, In...)>
174 {
175  template<class Oper> static void Compute(Oper& oper, Out& out, const In& ... in)
176  {
177  oper(out,in...);
178  }
179 };
180 
181 template<class C, class Out, class ... In> struct OperProxy<void(C::*)(Out&, In...)>
182 {
183  template<class Oper> static void Compute(Oper& oper, Out& out, const In& ... in)
184  {
185  oper(out,in...);
186  }
187 };
188 
189 template<class C, class Out, class ... In> struct OperProxy<void(C::*)(Out&, In...) const>
190 {
191  template<class Oper> static void Compute(Oper& oper, Out& out, const In& ... in)
192  {
193  oper(out,in...);
194  }
195 };
196 
197 
198 // Will be easier to write in c++17 with std::apply and fold expressions
199 template <class Tuple, class Out, class Oper, size_t...Is> auto CallOperatorImpl(Tuple& t, Out & out, Oper & oper,std::index_sequence<Is...>)
200 {
201  OperProxy<Oper>::Compute(oper,out,GetProxy<typename std::remove_reference<decltype(std::get<Is>(t))>::type>::Get(std::get<Is>(t))...);
202 }
203 
204 // Will be easier to write in c++17 with std::apply and fold expressions
205 template <class Out, class Oper, typename ... Args> auto CallOperator(Out & out, Oper& oper, std::tuple<Args...> & t)
206 {
207  CallOperatorImpl(t,out,oper,std::make_index_sequence<sizeof...(Args)>{});
208 }
209 
210 // Variadic move of iterators
211 // Will be easier to write in c++17 with std::apply and fold expressions
212 template<class Tuple,size_t...Is> auto MoveIteratorsImpl(Tuple & t, std::index_sequence<Is...>)
213 {
214  return std::make_tuple(++(std::get<Is>(t) )...);
215 }
216 
217 template<typename ... Args> void MoveIterators(std::tuple<Args...> & t)
218 {
219  MoveIteratorsImpl(t,std::make_index_sequence<sizeof...(Args)>{});
220 }
221 
222 
223 // Default implementation does nothing
224 template <class F, class O, size_t N> struct NumberOfOutputComponents
225 {};
226 
227 template <class F, class T, size_t N> struct NumberOfOutputComponents<F,otb::Image<T>,N>
228  {
229  // We can not be here if output type is VectorImage
230  static void Set(const F&, otb::Image<T> *, std::array<size_t,N>){}
231 };
232 
233 // O is a VectorImage AND F has a fixed OuptutSize static constexrp size_t;
234 template <class F, class T, size_t N> struct NumberOfOutputComponents<F,otb::VectorImage<T>,N>
235 {
236  static void Set(const F & f, otb::VectorImage<T> * outputImage, std::array<size_t,N> inNbBands)
237  {
238  outputImage->SetNumberOfComponentsPerPixel(f.OutputSize(inNbBands));
239  }
240 };
241 
242 } // end namespace functor_filter_details
243 
244 template <class TFunction, class TNameMap>
245 void
248 {
249  // Get requested region for output
250  typename Superclass::OutputImagePointer outputPtr = this->GetOutput();
251  auto requestedRegion = outputPtr->GetRequestedRegion();
252 
253  // Propagate to each variadic inputs, including possible radius
254  // TODO: For now all inputs are padded with the radius, even if they
255  // are not neighborhood based
256  functor_filter_details::SetInputRequestedRegions<InputHasNeighborhood>(this->GetInputs(),requestedRegion, m_Radius);
257 }
258 
259 template <class TFunction, class TNameMap>
260 void
262 {
263  // Call Superclass implementation
264  Superclass::GenerateOutputInformation();
265 
266  // Get All variadic inputs
267  auto inputs = this->GetInputs();
268 
269  // Retrieve an array of number of components per input
270  auto inputNbComps = functor_filter_details::GetNumberOfComponentsPerInput(inputs);
271 
272  // Call the helper to set the number of components for the output image
273  functor_filter_details::NumberOfOutputComponents<TFunction,OutputImageType,inputNbComps.size()>::Set(m_Functor,this->GetOutput(),inputNbComps);
274 }
275 
279 template <class TFunction, class TNameMap>
280 void
282 ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, itk::ThreadIdType threadId)
283 {
284  const auto &regionSize = outputRegionForThread.GetSize();
285 
286  if( regionSize[0] == 0 )
287  {
288  return;
289  }
290  const auto numberOfLinesToProcess = outputRegionForThread.GetNumberOfPixels() / regionSize[0];
291  itk::ProgressReporter p(this, threadId, numberOfLinesToProcess);
292 
293  // Build output iterator
294  itk::ImageScanlineIterator<OutputImageType> outIt(this->GetOutput(),outputRegionForThread);
295 
296  // This will build a tuple of iterators to be used
297  auto inputIterators = functor_filter_details::MakeIterators(this->GetInputs(),outputRegionForThread, m_Radius,InputHasNeighborhood{});
298 
299  // Build a default value
300  typename OutputImageType::PixelType outputValueHolder;
301  itk::NumericTraits<typename OutputImageType::PixelType>::SetLength(outputValueHolder,this->GetOutput()->GetNumberOfComponentsPerPixel());
302 
303  while(!outIt.IsAtEnd())
304  {
305  // MoveIterartors will ++ all iterators in the tuple
306  for(;!outIt.IsAtEndOfLine();++outIt,functor_filter_details::MoveIterators(inputIterators))
307  {
308  // This will call the operator with inputIterators Get() results
309  // and fill outputValueHolder with the result.
310  functor_filter_details::CallOperator(outputValueHolder,m_Functor,inputIterators);
311  outIt.Set(outputValueHolder);
312  }
313  outIt.NextLine();
314  p.CompletedPixel(); // may throw
315  }
316 }
317 
318 } // end namespace otb
319 
320 #endif
static void Set(const F &, otb::Image< T > *, std::array< vcl_size_t, N >)
Creation of an "otb" vector image which contains metadata.
virtual void SetNumberOfComponentsPerPixel(unsigned int n) override
void SetDataObject(DataObject *dobj)
typename Superclass::OutputImageType OutputImageType
virtual void SetDescription(const std::string &s)
virtual void SetLocation(const std::string &s)
static auto Make(const T *img, const itk::ImageRegion< 2 > &region, const itk::Size< 2 > &radius)
static void Compute(Oper &oper, Out &out, const In &...in)
auto SetInputRequestedRegions(std::tuple< T...> &&t, const itk::ImageRegion< 2 > &region, const itk::Size< 2 > &radius)
void PadByRadius(OffsetValueType radius)
static void Compute(Oper &oper, Out &out, const In &...in)
*brief Mask an image with the negative of a mask **This class is templated over the types of the *input image type
void GenerateOutputInformation() override
typename SuperclassHelper::InputHasNeighborhood InputHasNeighborhood
auto MakeIteratorsImpl(const Tuple &t, const itk::ImageRegion< 2 > &region, const itk::Size< 2 > &radius, std::index_sequence< Is...>, TNeigh)
auto MoveIteratorsImpl(Tuple &t, std::index_sequence< Is...>)
auto MakeIterators(std::tuple< T...> &&t, const itk::ImageRegion< 2 > &region, const itk::Size< 2 > &radius, TNeigh n)
auto CallOperator(Out &out, Oper &oper, std::tuple< Args...> &t)
static auto Make(const T *img, const itk::ImageRegion< 2 > &region, const itk::Size< 2 > &)
static void Compute(Oper &oper, Out &out, const In &...in)
auto SetInputRequestedRegionsImpl(Tuple &t, const itk::ImageRegion< 2 > &region, std::index_sequence< Is...>, const itk::Size< 2 > &radius)
void ThreadedGenerateData(const OutputImageRegionType &outputRegionForThread, itk::ThreadIdType threadId) override
static void Compute(Oper &oper, Out &out, const In &...in)
Creation of an "otb" image which contains metadata.
Definition: otbImage.h:89
typename OutputImageType::RegionType OutputImageRegionType
static void SetLength(T &m, const unsigned int s)
int SetInputRequestedRegion(const T *img, const itk::ImageRegion< 2 > &region, const itk::Size< 2 > &radius, bool pad)
unsigned int ThreadIdType
void GenerateInputRequestedRegion(void) override
void Set(const PixelType &value) const
auto GetNumberOfComponentsPerInput(std::tuple< T...> &t)
static void Compute(Oper &oper, Out &out, const In &...in)
static void Set(const F &f, otb::VectorImage< T > *outputImage, std::array< vcl_size_t, N > inNbBands)
auto GetNumberOfComponentsPerInputImpl(Tuple &t, std::index_sequence< Is...>)
bool IsAtEnd(void) const
auto CallOperatorImpl(Tuple &t, Out &out, Oper &oper, std::index_sequence< Is...>)
void MoveIterators(std::tuple< Args...> &t)