otbFunctorImageFilter.h 13 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
/*
 * Copyright (C) 2005-2017 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 otbFunctorImageFilter_h
#define otbFunctorImageFilter_h

24
#include "otbVariadicInputsImageFilter.h"
25 26
#include "otbImage.h"
#include "otbVectorImage.h"
27 28 29
#include "itkRGBPixel.h"
#include "itkRGBAPixel.h"
#include "itkFixedArray.h"
Julien Michel's avatar
Julien Michel committed
30
#include "itkDefaultConvertPixelTraits.h"
31 32 33 34
#include <type_traits>

namespace otb
{
35 36
/**  
 * \struct IsNeighborhood 
37 38
 * \brief Struct testing if T is a neighborhood
 * 
39 40 41 42
 * Provides:
 * - ValueType type set to false_type or true_type
 * - value set to true or false
 */
43
template <class T> struct IsNeighborhood
44 45 46 47 48
{
  using ValueType = std::false_type;
  static constexpr bool value = false;
};

49
/// Partial specialisation for itk::Neighborhood<T>
50 51 52 53 54 55
template <class T> struct IsNeighborhood<itk::Neighborhood<T>>
{
  using ValueType = std::true_type;
  static constexpr bool value = true;
};

56

57
/// Partial specialisation for const itk::Neighborhood<T> &
58
template <class T> struct IsNeighborhood<const itk::Neighborhood<T>&>
59 60 61
{
  using ValueType = std::true_type;
  static constexpr bool value = true;
62 63
};

64 65 66 67 68 69 70 71 72 73 74
/**
 * \struct IsSuitableType
 * \brief Helper struct to check if a type can be used as pixel type.
 *
 * ::value maps to true if type can be used and false otherwhise.
 */
template <class T> struct IsSuitableType
{
  static constexpr bool value = std::is_scalar<T>::value;
};

75
/// Unwrap complex
76 77 78
template <class T> struct IsSuitableType<std::complex<T>> {
  static constexpr bool value = IsSuitableType<T>::value;
};
79 80

/// Unwrap VariableLengthVector
81 82 83
template <class T> struct IsSuitableType<itk::VariableLengthVector<T>> {
  static constexpr bool value = IsSuitableType<T>::value;
};
84 85

/// Unwrap FixedArray
86
template <class T, size_t N> struct IsSuitableType<itk::FixedArray<T,N>> {
87 88
  static constexpr bool value = IsSuitableType<T>::value;
};
89 90

/// Unwrap RGBPixel
91 92 93
template <class T> struct IsSuitableType<itk::RGBPixel<T>> {
  static constexpr bool value = IsSuitableType<T>::value;
};
94 95

/// Unwrap RGBAPixel
96 97 98
template <class T> struct IsSuitableType<itk::RGBAPixel<T>> {
  static constexpr bool value = IsSuitableType<T>::value;
};
99

100 101 102 103 104 105 106 107 108 109 110
/// Discard const qualifier
template <class T> struct IsSuitableType<const T>{
  static constexpr bool value = IsSuitableType<T>::value;
};

/// Discard reference
template <class T> struct IsSuitableType<T &>{
  static constexpr bool value = IsSuitableType<T>::value;
};


111 112 113 114 115
/**
 * \struct PixelTypeDeduction
 * \brief Helper struct to derive PixelType from template parameter.
 * 
 * T                           -> PixelType = T
116 117
 * itk::Neighborhood<T>        -> PixelType = T
 * const itk::Neighborhood<T>& -> PixelType = T
118 119 120
*/
template <class T> struct PixelTypeDeduction
{
121
  static_assert(IsSuitableType<T>::value,"T can not be used as a template parameter for Image or VectorImage classes.");
122 123 124 125 126 127
  using PixelType = T;
};

/// Partial specialisation for itk::Neighborhood<T>
template <class T> struct PixelTypeDeduction<itk::Neighborhood<T>>
{
128
  static_assert(IsSuitableType<T>::value,"T can not be used as a template parameter for Image or VectorImage classes.");
129 130 131
  using PixelType = T;
};

132 133
/// Discard const qualifier
template <class T> struct PixelTypeDeduction<const  T>
134
{
135 136 137 138 139 140 141
  using PixelType = typename PixelTypeDeduction<T>::PixelType;
};

/// Discard reference
template <class T> struct PixelTypeDeduction<T &>
{
  using PixelType = typename PixelTypeDeduction<T>::PixelType;
142 143
};

144 145
  

146 147 148 149 150 151 152 153 154 155 156 157 158
/** 
 * \struct ImageTypeDeduction
 * \brief Helper struct to derive ImageType from template parameter
 * 
 * T                            -> ImageType = otb::Image<T>
 * itk::VariableLengthVector<T> -> ImageType = otb::VectorImage<T>
 * const T &                    -> ImageType = ImageTypeDeduction<T>::ImageType
 */
template <class T> struct ImageTypeDeduction 
{
  using ImageType = otb::Image<T>;
};

159
/// Partial specialisation for itk::VariableLengthVector<T>
160
template <class T> struct ImageTypeDeduction<itk::VariableLengthVector<T>>
161
{
162
  using ImageType = otb::VectorImage<T>;
163 164
};

165 166 167 168 169
// /// Partial specialisation for const T &
// template <class T> struct ImageTypeDeduction<const T &>
// {
//   using ImageType = typename ImageTypeDeduction<T>::ImageType;
// };
170

171

172 173
/**
* \struct FunctorFilterSuperclassHelper 
174 175 176
* \brief Struct allowing to derive the superclass prototype for the
*        FunctorImageFilter class
*
177 178 179 180 181 182 183
* Provides the following:
* - OutputImageType : type of the output image
* - FilterType : correct instanciation of VariadicInputsImageFilter from
* - the operator() prototype
* - InputHasNeighborhood a tuple of N false_type or true_type to denote
* - if Ith arg of operator() expects a neighborhood.
*/
184
template <typename T> struct FunctorFilterSuperclassHelper : public FunctorFilterSuperclassHelper<decltype(&T::operator())> {};
185

186
/// Partial specialisation for R(*)(T...)
187
template <typename R, typename... T> struct FunctorFilterSuperclassHelper<R(*)(T...)>
188
{
189 190
  using OutputImageType = typename ImageTypeDeduction<R>::ImageType;
  using FilterType = VariadicInputsImageFilter<OutputImageType,typename ImageTypeDeduction<typename PixelTypeDeduction<T>::PixelType>::ImageType...>;
191
  using InputHasNeighborhood = std::tuple<typename IsNeighborhood<T>::ValueType...>;
192 193
};

194
/// Partial specialisation for R(C::*)(T...) const
195
template <typename C, typename R, typename... T> struct FunctorFilterSuperclassHelper<R(C::*)(T...) const>
196
{
197 198
  using OutputImageType = typename ImageTypeDeduction<R>::ImageType;
  using FilterType = VariadicInputsImageFilter<OutputImageType,typename ImageTypeDeduction<typename PixelTypeDeduction<T>::PixelType>::ImageType...>;
199
  using InputHasNeighborhood = std::tuple<typename IsNeighborhood<T>::ValueType...>;
200 201
};

202
/// Partial specialisation for R(C::*)(T...)
203
template <typename C, typename R, typename... T> struct FunctorFilterSuperclassHelper<R(C::*)(T...)>
204
{ 
205 206
  using OutputImageType = typename ImageTypeDeduction<R>::ImageType;
  using FilterType = VariadicInputsImageFilter<OutputImageType,typename ImageTypeDeduction<typename PixelTypeDeduction<T>::PixelType>::ImageType...>;
207
  using InputHasNeighborhood = std::tuple<typename IsNeighborhood<T>::ValueType...>;
208
};
209

210
/**
211
 * brief This helper method builds a fully functional FunctorImageFilter from a functor instance
212 213 214 215 216 217 218 219 220
 * 
 * Functor can be any operator() that matches the following:
 * - Accepts any number of arguments of T,
 * (const) itk::VariableLengthVector<T> (&),(const)
 * itk::Neighborhood<T> (&), (const)
 * itk::Neighborhood<itk::VariableLengthVector<T>> (&) with T a scalar type
 * - returns T or itk::VariableLengthVector<T>, with T a scalar type
 *
 * The returned filter is ready to use. Inputs can be set through the
221
 * SetVariadicInputs() method (see VariadicInputsImageFilter class for
222 223 224 225 226 227 228 229 230 231 232 233 234 235
 * details)
 * 
 * \param f the Functor to build the filter from
 * \param radius The size of neighborhood to use, if there is any
 * itk::Neighborhood<T> in the operator() arguments.
 * \return A ready to use OTB filter, which accepts n input image of
 * type derived from the operator() arguments, and producing an image
 * correpsonding to the operator() return type.
 *
 * Note that this function also works with a lambda as Functor,
 * provided it returns a scalar type. If your lambda returns a
 * VariableLengthVector, see the other NewFunctorFilter implementation.
 */
template <typename Functor> auto NewFunctorFilter(const Functor& f, itk::Size<2> radius = {{0,0}});
236

237

238
/** \class FunctorImageFilter
239 240 241 242
 * \brief A generic functor filter templated by its functor
 * 
 * \sa VariadicInputsImageFilter
 * \sa NewFunctorFilter
243 244
 * 
 * \ingroup IntensityImageFilters   Multithreaded Streamed
245
 *
Julien Michel's avatar
Julien Michel committed
246
 * \ingroup OTBFunctor
247
*/
248
template <class TFunction>
249
    class ITK_EXPORT FunctorImageFilter
250
  : public FunctorFilterSuperclassHelper<TFunction>::FilterType
251
{
252

253
public:
254
  // Standard typedefs
255 256 257 258
  using Self = FunctorImageFilter;
  using FunctorType = TFunction;
  using Pointer = itk::SmartPointer<Self>;
  using ConstPointer = itk::SmartPointer<const Self>;
259

260
  // Superclass through the helper struct
261 262
  using Superclass = typename FunctorFilterSuperclassHelper<TFunction>::FilterType;
  using OutputImageType = typename Superclass::OutputImageType;
263
  using OutputImageRegionType = typename OutputImageType::RegionType;
264
  
265 266
  using ProcessObjectType = itk::ProcessObject;

267 268
  // A tuple of bool of the same size as the number of arguments in
  // the functor
269
  using InputHasNeighborhood = typename FunctorFilterSuperclassHelper<TFunction>::InputHasNeighborhood;
270
  using InputTypesTupleType = typename Superclass::InputTypesTupleType;
271
  template<size_t I> using InputImageType = typename Superclass::template InputImageType<I>;
272
  using Superclass::NumberOfInputs;
273
  
274
  /** Run-time type information (and related methods). */
275
  itkTypeMacro(FunctorImageFilter, ImageToImageFilter);
276 277
  
  
278
  /** Get the functor object.  The functor is returned by reference.
279 280 281
   * (Functors do not have to derive from itk::LightObject, so they do
   * not necessarily have a reference count. So we cannot return a
   * SmartPointer.) */
282 283 284 285 286
  FunctorType& GetFunctor()
  {
    this->Modified();
    return m_Functor;
  }
287

288
  /** Get the functor object.  The functor is returned by reference.
289 290 291
   * (Functors do not have to derive from itk::LightObject, so they do
   * not necessarily have a reference count. So we cannot return a
   * SmartPointer.) */
292 293 294 295
  const FunctorType& GetFunctor() const
  {
    return m_Functor;
  }
296

297
protected:
298 299 300 301 302 303
  /// Constructor of functor filter, will copy the functor
  FunctorImageFilter(const FunctorType& f, itk::Size<2> radius) : m_Functor(f), m_Radius(radius) {};
  FunctorImageFilter(const Self &) = delete;
  void operator =(const Self&) = delete;
  ~FunctorImageFilter() = default;

304 305 306 307
private:
  /// Actual creation of the filter is handled by this free function
  friend auto NewFunctorFilter<TFunction>(const TFunction& f, itk::Size<2> radius);

308 309
  /** Overload of ThreadedGenerateData  */
  void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, itk::ThreadIdType threadId) override;
310 311 312 313

  /**
   * Pad the input requested region by radius
   */
314
  void GenerateInputRequestedRegion(void) override;
315

316
  /**
317
   * Will use the OutputSize() method of the functor if output is VectorImage
318
   */
319
  void GenerateOutputInformation() override;
320 321 322


  // The functor member
323
  FunctorType m_Functor;
324

325
  // Radius if needed
326
  itk::Size<2> m_Radius;
327 328
};

329
// Actual implementation of NewFunctorFilter free function
330 331 332 333 334 335
template <typename Functor> auto NewFunctorFilter(const Functor& f, itk::Size<2> radius)
{
  using FilterType = FunctorImageFilter<Functor>;
  using PointerType = typename FilterType::Pointer;

  PointerType  p = new FilterType(f,radius);
336
  p->UnRegister();
337 338 339
  return p;
}

340 341 342 343 344 345 346 347 348 349 350
/** 
 * \struct NumberOfOutputBandsDecorator
 * \brief This struct allows to forward the operator of template
 *        parameter, while adding number of ouptut components service.
 * 
 * Its purpose is to enable the use of lambda or functor witht
 * Outputsize() method with FunctorImageFilter.
 * 
 * It is used internally in NewFunctorFilter version with
 * numberOfOutputBands parameter.
 */ 
351 352 353 354

template <typename F> struct NumberOfOutputBandsDecorator : F
{
public:
355
  constexpr NumberOfOutputBandsDecorator(const F t, unsigned int nbComp) : F(t), m_NumberOfOutputBands(nbComp) {}
356 357 358 359
  using F::operator();

  constexpr size_t OutputSize(...) const
  {
360
    return m_NumberOfOutputBands;
361 362 363
  }

private:
364
  unsigned int m_NumberOfOutputBands;
365 366
};

367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385
/** 
 * brief This helper method builds a fully functional
 * FunctorImageFilter from a functor instance which does not provide
 * the OutputSize() service, or a lambda, returing a VariableLengthVector
 * 
 * \param f the Functor to build the filter from
 * \param numberOfOutputBands The number of output bands that
 * this filter will return
 * \param radius The size of neighborhood to use, if there is any
 * itk::Neighborhood<T> in the operator() arguments.
 * \return A ready to use OTB filter, which accepts n input image of
 * type derived from the operator() arguments, and producing an image
 * correpsonding to the operator() return type.
 *
 * Note that this function also works with a lambda as Functor,
 * provided it returns a scalar type. If your lambda returns a
 * VariableLengthVector, see the other NewFunctorFilter implementation.

 */ 
386

387 388 389 390 391 392 393 394
template <typename Functor> auto NewFunctorFilter(const Functor& f, unsigned int numberOfOutputBands, itk::Size<2> radius)
{
  using FunctorType = NumberOfOutputBandsDecorator<Functor>;
  FunctorType decoratedF(f,numberOfOutputBands);
  return  NewFunctorFilter(decoratedF,radius);
}


395
}// namespace otb
396 397 398 399 400 401

#ifndef OTB_MANUAL_INSTANTIATION
#include "otbFunctorImageFilter.hxx"
#endif

#endif