diff --git a/Modules/Filtering/ImageManipulation/include/otbClampImageFilter.h b/Modules/Filtering/ImageManipulation/include/otbClampImageFilter.h index 6fdd16e955a3b7a754779b6d1acd76de60e711d8..f09cd0c54f0b12f1737d32a8cc03c83425b36f2f 100644 --- a/Modules/Filtering/ImageManipulation/include/otbClampImageFilter.h +++ b/Modules/Filtering/ImageManipulation/include/otbClampImageFilter.h @@ -21,7 +21,8 @@ #ifndef otbClampImageFilter_h #define otbClampImageFilter_h -#include "itkImageToImageFilter.h" +#include "otbConvertTypeFunctor.h" +#include "itkUnaryFunctorImageFilter.h" namespace otb { @@ -45,61 +46,68 @@ namespace otb * \ingroup OTBImageManipulation */ template <class TInputImage, class TOutputImage=TInputImage> - class ITK_EXPORT ClampImageFilter : public itk::ImageToImageFilter<TInputImage, TOutputImage> + class ITK_EXPORT ClampImageFilter + : public itk::UnaryFunctorImageFilter< TInputImage , TOutputImage , + Functor::ConvertTypeFunctor <typename TInputImage::PixelType , + typename TOutputImage::PixelType> > { public: /** Standard class typedefs. */ - typedef ClampImageFilter Self; - typedef itk::ImageToImageFilter<TInputImage, TOutputImage> Superclass; - typedef itk::SmartPointer<Self> Pointer; - typedef itk::SmartPointer<const Self> ConstPointer; + typedef ClampImageFilter Self; + typedef itk::UnaryFunctorImageFilter< TInputImage , TOutputImage , + Functor::ConvertTypeFunctor <typename TInputImage::PixelType , + typename TOutputImage::PixelType> > Superclass; + typedef itk::SmartPointer<Self> Pointer; + typedef itk::SmartPointer<const Self> ConstPointer; /** Method for creation through the object factory. */ - itkNewMacro(Self); + itkNewMacro( Self ); /** Run-time type information (and related methods). */ - itkTypeMacro(ClampImageFilter, itk::ImageToImageFilter); + itkTypeMacro( ClampImageFilter , itk::UnaryFunctorImageFilter ); /** Some additional typedefs. */ typedef TInputImage InputImageType; - typedef typename InputImageType::ConstPointer InputImagePointer; typedef typename InputImageType::RegionType InputImageRegionType; typedef typename InputImageType::PixelType InputImagePixelType; /** Some additional typedefs. */ - typedef TOutputImage OutputImageType; - typedef typename OutputImageType::Pointer OutputImagePointer; - typedef typename OutputImageType::RegionType OutputImageRegionType; - typedef typename OutputImageType::PixelType OutputImagePixelType; + typedef TOutputImage OutputImageType; + typedef typename OutputImageType::RegionType OutputImageRegionType; + typedef typename OutputImageType::PixelType OutputImagePixelType; + typedef typename OutputImageType::InternalPixelType OutputInternalPixelType; + typedef typename itk::NumericTraits< OutputInternalPixelType >::ValueType OutputPixelValueType; /** The values greater than or equal to the value are set to OutsideValue. */ - void ClampAbove(const OutputImagePixelType &thresh); + void ClampAbove(const OutputPixelValueType &thresh); /** The values less than or equal to the value are set to OutsideValue. */ - void ClampBelow(const OutputImagePixelType &thresh); + void ClampBelow(const OutputPixelValueType &thresh); /** The values outside the range are set to OutsideValue. */ - void ClampOutside(const OutputImagePixelType &lower, const OutputImagePixelType &upper); + void ClampOutside(const OutputPixelValueType &lower, const OutputPixelValueType &upper); /** Set/Get methods to set the lower threshold */ - void SetLower(OutputImagePixelType val) + void SetLower(OutputPixelValueType val) { m_Lower = val; m_DLower = static_cast<double>(val); + this->GetFunctor().SetLowest( m_Lower ); this->Modified(); } - itkGetConstMacro(Lower, OutputImagePixelType); + itkGetConstMacro(Lower, OutputPixelValueType); /** Set/Get methods to set the upper threshold */ - void SetUpper(OutputImagePixelType val) + void SetUpper(OutputPixelValueType val) { m_Upper = val; m_DUpper = static_cast<double>(val); + this->GetFunctor().SetHighest( m_Upper ); this->Modified(); } - itkGetConstMacro(Upper, OutputImagePixelType); + itkGetConstMacro(Upper, OutputPixelValueType); protected: @@ -117,14 +125,23 @@ protected: * * \sa ImageToImageFilter::ThreadedGenerateData(), * ImageToImageFilter::GenerateData() */ - void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, - itk::ThreadIdType threadId ) ITK_OVERRIDE; + // void ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, + // itk::ThreadIdType threadId ) ITK_OVERRIDE; void GenerateOutputInformation(void) ITK_OVERRIDE { Superclass::GenerateOutputInformation(); - this->GetOutput()->SetNumberOfComponentsPerPixel( this->GetInput()->GetNumberOfComponentsPerPixel() ); + // typename InputImageType::IndexType index; + // index.Fill(0); + // InputImagePixelType px = ->GetPixel( index ); + + unsigned int sizeIn = this->GetInput()->GetNumberOfComponentsPerPixel(); + // sizeIn *= itk::NumericTraits < typename itk::NumericTraits< InputImagePixelType >::ValueType > + // :: GetLength(); + + this->GetOutput()->SetNumberOfComponentsPerPixel( + this->GetFunctor().GetOutputSize ( sizeIn ) ); } private: @@ -134,8 +151,8 @@ private: double m_DLower; double m_DUpper; - OutputImagePixelType m_Lower; - OutputImagePixelType m_Upper; + OutputPixelValueType m_Lower; + OutputPixelValueType m_Upper; }; diff --git a/Modules/Filtering/ImageManipulation/include/otbClampImageFilter.txx b/Modules/Filtering/ImageManipulation/include/otbClampImageFilter.txx index fd1ed1320ec1cbe7768eb8ccb44f7b9ba317d8f9..2deb3cd4a1cde1d1df699af3d382e126ea4325fe 100644 --- a/Modules/Filtering/ImageManipulation/include/otbClampImageFilter.txx +++ b/Modules/Filtering/ImageManipulation/include/otbClampImageFilter.txx @@ -25,6 +25,7 @@ #include "otbClampImageFilter.h" #include "itkImageRegionIterator.h" #include "itkNumericTraits.h" +#include <limits> #include "itkObjectFactory.h" #include "itkProgressReporter.h" @@ -38,8 +39,8 @@ template <class TInputImage, class TOutputImage> ClampImageFilter<TInputImage, TOutputImage> ::ClampImageFilter() { - m_Lower = itk::NumericTraits<OutputImagePixelType>::NonpositiveMin(); - m_Upper = itk::NumericTraits<OutputImagePixelType>::max(); + m_Lower = std::numeric_limits < OutputPixelValueType >::lowest(); + m_Upper = std::numeric_limits < OutputPixelValueType >::max(); m_DLower = static_cast<double>(m_Lower); m_DUpper = static_cast<double>(m_Upper); @@ -70,14 +71,16 @@ ClampImageFilter<TInputImage, TOutputImage> template <class TInputImage, class TOutputImage> void ClampImageFilter<TInputImage, TOutputImage> -::ClampAbove(const OutputImagePixelType &thresh) +::ClampAbove(const OutputPixelValueType &thresh) { if (m_Upper != thresh - || m_Lower > itk::NumericTraits<OutputImagePixelType>::NonpositiveMin()) + || m_Lower > std::numeric_limits < OutputPixelValueType >::lowest()) { - m_Lower = itk::NumericTraits<OutputImagePixelType>::NonpositiveMin(); + m_Lower = std::numeric_limits < OutputPixelValueType >::lowest(); m_Upper = thresh; m_DUpper = static_cast<double>(m_Upper); + this->GetFunctor().SetLowest( m_Lower ); + this->GetFunctor().SetHighest( m_Upper ); this->Modified(); } } @@ -88,13 +91,15 @@ ClampImageFilter<TInputImage, TOutputImage> template <class TInputImage, class TOutputImage> void ClampImageFilter<TInputImage, TOutputImage> -::ClampBelow(const OutputImagePixelType &thresh) +::ClampBelow(const OutputPixelValueType &thresh) { - if (m_Lower != thresh || m_Upper < itk::NumericTraits<OutputImagePixelType>::max()) + if (m_Lower != thresh || m_Upper < std::numeric_limits < OutputPixelValueType >::max()) { + m_Upper = std::numeric_limits < OutputPixelValueType >::max(); m_Lower = thresh; m_DLower = m_Lower; - m_Upper = itk::NumericTraits<InputImagePixelType>::max(); + this->GetFunctor().SetLowest( m_Lower ); + this->GetFunctor().SetHighest( m_Upper ); this->Modified(); } } @@ -106,7 +111,7 @@ ClampImageFilter<TInputImage, TOutputImage> template <class TInputImage, class TOutputImage> void ClampImageFilter<TInputImage, TOutputImage> -::ClampOutside(const OutputImagePixelType &lower, const OutputImagePixelType &upper) +::ClampOutside(const OutputPixelValueType &lower, const OutputPixelValueType &upper) { if (lower > upper) { @@ -120,6 +125,8 @@ ClampImageFilter<TInputImage, TOutputImage> m_Upper = upper; m_DLower = m_Lower; m_DUpper = m_Upper; + this->GetFunctor().SetLowest( m_Lower ); + this->GetFunctor().SetHighest( m_Upper ); this->Modified(); } } @@ -128,62 +135,62 @@ ClampImageFilter<TInputImage, TOutputImage> /** * */ -template <class TInputImage, class TOutputImage> -void -ClampImageFilter<TInputImage, TOutputImage> -::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, - itk::ThreadIdType threadId) -{ - itkDebugMacro(<<"Actually executing"); - - // Get the input and output pointers - InputImagePointer inputPtr = this->GetInput(); - OutputImagePointer outputPtr = this->GetOutput(0); - - // Define/declare an iterator that will walk the output region for this - // thread. - typedef itk::ImageRegionConstIterator<TInputImage> InputIterator; - typedef itk::ImageRegionIterator<TOutputImage> OutputIterator; - - InputIterator inIt(inputPtr, outputRegionForThread); - OutputIterator outIt(outputPtr, outputRegionForThread); - - // support progress methods/callbacks - itk::ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels()); - - // walk the regions, threshold each pixel - while( !outIt.IsAtEnd() && !inIt.IsAtEnd() ) - { - // Cast the value of the pixel to double in order to compare - // with the double version of the upper and the lower bounds of - // output image - const double value = static_cast<double>(inIt.Get()); - OutputImagePixelType outPix = m_Lower; - - if ( m_DLower <= value && value <= m_DUpper) - { - // pixel passes to output unchanged - outPix = static_cast<OutputImagePixelType>(value); - } - /* Already outPix is initialized with m_Lower even for preventing Warning. - * - else if ( value < m_DLower ) - { - outPix = m_Lower; - } - */ - else if ( value > m_DUpper) - { - outPix = m_Upper; - } - - outIt.Set( outPix ); - - ++inIt; - ++outIt; - progress.CompletedPixel(); - } -} +// template <class TInputImage, class TOutputImage> +// void +// ClampImageFilter<TInputImage, TOutputImage> +// ::ThreadedGenerateData(const OutputImageRegionType& outputRegionForThread, +// itk::ThreadIdType threadId) +// { +// itkDebugMacro(<<"Actually executing"); + +// // Get the input and output pointers +// typename InputImageType::ConstPointer inputPtr = this->GetInput(); +// typename OutputImageType::Pointer outputPtr = this->GetOutput(0); + +// // Define/declare an iterator that will walk the output region for this +// // thread. +// typedef itk::ImageRegionConstIterator<TInputImage> InputIterator; +// typedef itk::ImageRegionIterator<TOutputImage> OutputIterator; + +// InputIterator inIt(inputPtr, outputRegionForThread); +// OutputIterator outIt(outputPtr, outputRegionForThread); + +// // support progress methods/callbacks +// itk::ProgressReporter progress(this, threadId, outputRegionForThread.GetNumberOfPixels()); + +// // walk the regions, threshold each pixel +// while( !outIt.IsAtEnd() && !inIt.IsAtEnd() ) +// { +// // Cast the value of the pixel to double in order to compare +// // with the double version of the upper and the lower bounds of +// // output image +// const double value = static_cast<double>(inIt.Get()); +// OutputImagePixelType outPix = m_Lower; + +// if ( m_DLower <= value && value <= m_DUpper) +// { +// // pixel passes to output unchanged +// outPix = static_cast<OutputImagePixelType>(value); +// } +// /* Already outPix is initialized with m_Lower even for preventing Warning. +// * +// else if ( value < m_DLower ) +// { +// outPix = m_Lower; +// } +// */ +// else if ( value > m_DUpper) +// { +// outPix = m_Upper; +// } + +// outIt.Set( outPix ); + +// ++inIt; +// ++outIt; +// progress.CompletedPixel(); +// } +// } } // end namespace itk diff --git a/Modules/Filtering/ImageManipulation/include/otbConvertTypeFunctor.h b/Modules/Filtering/ImageManipulation/include/otbConvertTypeFunctor.h new file mode 100644 index 0000000000000000000000000000000000000000..c5360f2960f47554d9857c81fe7c5de0df0b9ca0 --- /dev/null +++ b/Modules/Filtering/ImageManipulation/include/otbConvertTypeFunctor.h @@ -0,0 +1,201 @@ +/* + * 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 otbConvertTypeFunctor_h +#define otbConvertTypeFunctor_h + +#include <limits> +#include <type_traits> +#include <boost/type_traits/is_complex.hpp> +#include <boost/type_traits/is_scalar.hpp> + +#include "itkVariableLengthVector.h" +#include "itkNumericTraits.h" +#include "otbDefaultConvertNewImpl.h" + +namespace otb +{ +namespace Functor +{ + +template < class TInputPixelType , class TOutputPixelType > +class ConvertTypeFunctor +{ +public: + typedef TInputPixelType InputPixelType; + typedef TOutputPixelType OutputPixelType; + typedef ConvertTypeFunctor Self; + + typedef typename itk::NumericTraits < InputPixelType > :: ValueType InputInternalPixelType; + typedef typename itk::NumericTraits < OutputPixelType > :: ValueType OutputInternalPixelType; + + typedef typename itk::NumericTraits < InputInternalPixelType > :: ValueType InputPixelValueType; + typedef typename itk::NumericTraits < OutputInternalPixelType > :: ValueType OutputPixelValueType; + + // template < class InternalPixelType > + unsigned int GetOutputSize( unsigned int sizeIn ) + { + m_CompIn = sizeIn ; + if ( m_cInPix || m_cInInternalPix ) + m_Scal = 2 * m_CompIn; + else + m_Scal = m_CompIn; + if ( m_cOutPix || m_cOutInternalPix ) + { + m_CompOut = sizeIn / 2 ; // ( sizeIn + 1 )/ 2 + return m_CompOut ; + } + else + { + m_CompOut = sizeIn ; + return m_CompOut ; + } + } + + void SetLowest( OutputPixelValueType & lowest ) + { + m_LowestB = lowest; + m_LowestBD = static_cast < double > ( m_LowestB ); + } + + void SetHighest( OutputPixelValueType & highest ) + { + m_HighestB = highest; + m_HighestBD = static_cast < double > ( m_HighestB ); + } + + ConvertTypeFunctor() + { + m_LowestB = std::numeric_limits < OutputPixelValueType >::lowest(); + m_HighestB = std::numeric_limits < OutputPixelValueType >::max(); + + m_LowestBD = static_cast < double > ( m_LowestB ); + m_HighestBD = static_cast < double > ( m_HighestB ); + + m_cInPix = boost::is_complex < InputPixelType > :: value ; + m_cOutPix = boost::is_complex < OutputPixelType > :: value ; + m_cInInternalPix = boost::is_complex < InputInternalPixelType > :: value ; + m_cOutInternalPix = boost::is_complex < OutputInternalPixelType > :: value ; + m_MultiCompIn = ! ( boost::is_complex < InputPixelType > :: value ) + || ! ( boost::is_scalar < InputPixelType > :: value) ; + m_MultiCompOut = ! ( boost::is_complex < OutputPixelType > :: value ) + || ! ( boost::is_scalar < OutputPixelType > :: value); + } + + + OutputPixelType operator() ( InputPixelType const & in ) const + { + std::vector < double > vPixel; + for ( unsigned int i = 0 ; i < m_CompIn ; i ++) + FillIn < InputPixelType > ( i , in , vPixel ); + Clamp( vPixel ); + OutputPixelType out; + int hack = 1; + if ( m_cOutPix && !m_MultiCompOut ) + hack += 1; // needed in case we have OutputPixelType == complex<t> as SetLength() will ask a length of 2! + itk::NumericTraits < OutputPixelType > :: SetLength( out , hack * m_CompOut ); + for ( unsigned int i = 0 ; i < m_CompOut ; i ++) + FillOut < OutputPixelType > ( i , out , vPixel ); + return out; + } + + ~ConvertTypeFunctor() {}; + +protected: + + template <class PixelType , + std::enable_if_t < std::is_arithmetic < PixelType > ::value , int > = 2 > + void FillIn( unsigned int i , InputPixelType const & pix , std::vector < double > & vPix ) const + { + vPix.push_back( DefaultConvertPixelTraitsTest < InputPixelType > :: + GetNthComponent( i , pix ) ); + } + + template <class PixelType , + std::enable_if_t < boost::is_complex < PixelType > :: value , int > = 1 > + void FillIn( unsigned int i , InputPixelType const & pix , std::vector < double > & vPix ) const + { + PixelType comp = DefaultConvertPixelTraitsTest < InputPixelType > :: + GetNthComponent( i , pix ); + vPix.push_back( static_cast < double > ( real( comp ) ) ); + vPix.push_back( static_cast < double > ( imag( comp ) ) ); + } + + template <class PixelType , + std::enable_if_t < !( boost::is_complex < PixelType > :: value || std::is_arithmetic < PixelType > ::value ) , int > = 0 > + void FillIn( unsigned int i , InputPixelType const & pix , std::vector < double > & vPix ) const + { + FillIn < InputInternalPixelType > ( i , pix , vPix ); + } + + void Clamp( std::vector < double > & vPixel ) const + { + assert( m_Scal == vPixel.size() ); + for ( double & comp : vPixel ) + { + if ( comp >= m_HighestBD ) + comp = m_HighestBD; + else if ( comp <= m_LowestBD ) + comp = m_LowestBD; + } + } + + template <class PixelType , + std::enable_if_t < std::is_arithmetic < PixelType > ::value , int > = 2 > + void FillOut( unsigned int i , OutputPixelType & pix , std::vector < double > & vPix ) const + { + DefaultConvertPixelTraitsTest < OutputPixelType > :: + SetNthComponent( i , pix , vPix[i] ); + } + + template <class PixelType , + std::enable_if_t < boost::is_complex < PixelType > :: value , int > = 1 > + void FillOut( unsigned int i , OutputPixelType & pix , std::vector < double > & vPix ) const + { + DefaultConvertPixelTraitsTest < OutputPixelType > :: + SetNthComponent( i , pix , + PixelType ( vPix[ 2 * i] , vPix[ 2 * i + 1] ) ); + } + + template <class PixelType , + std::enable_if_t < !( boost::is_complex < PixelType > :: value || std::is_arithmetic < PixelType > ::value ) , int > = 0 > + void FillOut( unsigned int i , OutputPixelType & pix , std::vector < double > & vPix ) const + { + FillOut < OutputInternalPixelType > ( i , pix , vPix ); + } + +private: + ConvertTypeFunctor(const Self &) = delete; + void operator =(const Self&) = delete; + + double m_LowestBD , m_HighestBD ; + OutputPixelValueType m_LowestB , m_HighestB ; + unsigned int m_CompIn , m_CompOut , m_Scal ; + bool m_cInPix , m_cInInternalPix , m_cOutPix , m_cOutInternalPix , + m_MultiCompIn , m_MultiCompOut ; + + +}; + +} //end namespace Functor + +} //end namespace otb + +#endif diff --git a/Modules/Filtering/ImageManipulation/include/otbDefaultConvertNewImpl.h b/Modules/Filtering/ImageManipulation/include/otbDefaultConvertNewImpl.h new file mode 100644 index 0000000000000000000000000000000000000000..44e9b17a598d6807aa354a1cbf5f6a0cd8585239 --- /dev/null +++ b/Modules/Filtering/ImageManipulation/include/otbDefaultConvertNewImpl.h @@ -0,0 +1,42 @@ +/*========================================================================= + * + * Copyright Insight Software Consortium + * + * 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.txt + * + * 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 otbDefaultConvertNewImp_h +#define otbDefaultConvertNewImp_h + +#include "itkDefaultConvertPixelTraits.h" + +namespace otb +{ +template < typename PixelType> +class DefaultConvertPixelTraitsTest : public itk::DefaultConvertPixelTraits < PixelType > +{ + +}; + +template < typename T > +class DefaultConvertPixelTraitsTest < std::complex < T > > : public itk::DefaultConvertPixelTraits < std::complex < T > > +{ +public: + typedef itk::DefaultConvertPixelTraits < std::complex < T > > SuperClass; + static typename SuperClass::TargetType GetNthComponent ( int , const typename SuperClass::TargetType & pixel ) + { + return pixel; + } +}; +} // end namespace +#endif