diff --git a/Code/BasicFilters/otbMeanShiftImageFilter2.h b/Code/BasicFilters/otbMeanShiftImageFilter2.h index 34e7b13ddd7f134695751c14ace774b2d56a36b9..a952d1aba5b0eb0c6a57a962e8e54a668c0fdc06 100644 --- a/Code/BasicFilters/otbMeanShiftImageFilter2.h +++ b/Code/BasicFilters/otbMeanShiftImageFilter2.h @@ -91,33 +91,33 @@ class KernelUniform public: typedef double RealType; - KernelUniform() { - SetBandwidth(1.0); - } - + KernelUniform() {} ~KernelUniform() {} + inline RealType operator() (RealType x) { - return (x >= -m_Bandwidth || x <= m_Bandwidth) ? m_KernelUniformValue : 0.0; + return (x <= 1) ? 1.0 : 0.0; } - RealType GetRadius() { - return m_Radius; + RealType GetRadius(RealType bandwidth) { + return bandwidth; } +}; - RealType GetBandwidth() { - return m_Bandwidth; - } +class KernelGaussian +{ +public: + typedef double RealType; + + KernelGaussian() {} + ~KernelGaussian() {} - void SetBandwidth(RealType bw) { - m_Bandwidth = bw; - m_KernelUniformValue = 1.0 / (2.0 * m_Bandwidth); - m_Radius = m_Bandwidth; + inline RealType operator() (RealType x) { + return vcl_exp(-0.5*x); } -private: - RealType m_Radius; - RealType m_Bandwidth; - RealType m_KernelUniformValue; + RealType GetRadius(RealType bandwidth) { + return 3.0*bandwidth; + } }; class NormL2 @@ -183,6 +183,16 @@ public: * Finally, GetIterationOutput() will return the number of algorithm iterations * for each pixel. * + * The class template parameter TKernel allows one to choose how pixels in the + * spatial and spectral neighborhood of a given pixel participate in the + * smoothed result. By default, a uniform kernel is used (KernelUniform), giving + * an equal weight to all neighbor pixels. KernelGaussian can also be used, + * although the computation time is significantly higher. The TKernel class + * should define operator(), taking a squared norm as parameter and returning a + * real value between 0 and 1. It should also define GetRadius(), converting the + * spatial bandwidth parameter to the spatial radius defining how many pixels + * are in the processing window local to a pixel. + * * MeanShifVector squared norm is compared with Threshold (set using Get/Set accessor) to define pixel convergence (1e-3 by default). * MaxIterationNumber defines maximum iteration number for each pixel convergence (set using Get/Set accessor). Set to 4 by default. * ModeSearchOptimization is a boolean value, to choose between optimized and non optimized algorithm. If set to true (by default), assign mode value to each pixel on a path covered in convergence steps. @@ -360,9 +370,9 @@ private: /** Maximum number of iterations **/ unsigned int m_MaxIterationNumber; - /** KernelType to be defined **/ - KernelType m_SpatialKernel; - KernelType m_RangeKernel; + /** Kernel object, implementing operator() which returns a weight between 0 and 1 +* depending on the squared norm given in parameter **/ + KernelType m_Kernel; /** Number of components per pixel in the input image */ unsigned int m_NumberOfComponentsPerPixel; diff --git a/Code/BasicFilters/otbMeanShiftImageFilter2.txx b/Code/BasicFilters/otbMeanShiftImageFilter2.txx index 0b0071de8ac41f89c2c5a7c502ee4efded8507bf..a302fa05ec62cf96838149d16272833d61cd6362 100644 --- a/Code/BasicFilters/otbMeanShiftImageFilter2.txx +++ b/Code/BasicFilters/otbMeanShiftImageFilter2.txx @@ -225,9 +225,8 @@ MeanShiftImageFilter2<TInputImage, TOutputImage, TKernel, TNorm, TOutputIteratio // Pad by the appropriate radius RegionType inputRequestedRegion = outputRequestedRegion; - // Initializes the kernel bandwidth to calculate its radius - m_SpatialKernel.SetBandwidth(m_SpatialBandwidth); - m_SpatialRadius.Fill(m_SpatialKernel.GetRadius()); + // Initializes the spatial radius from kernel bandwidth + m_SpatialRadius.Fill(m_Kernel.GetRadius(m_SpatialBandwidth)); inputRequestedRegion.PadByRadius(m_SpatialRadius); @@ -273,10 +272,7 @@ MeanShiftImageFilter2<TInputImage, TOutputImage, TKernel, TNorm, TOutputIteratio typename InputImageType::PixelType inputPixel; RealVector jointPixel; - m_SpatialKernel.SetBandwidth(m_SpatialBandwidth); - m_RangeKernel.SetBandwidth(m_RangeBandwidth); - - m_SpatialRadius.Fill(m_SpatialKernel.GetRadius()); + m_SpatialRadius.Fill(m_Kernel.GetRadius(m_SpatialBandwidth)); m_NumberOfComponentsPerPixel = this->GetInput()->GetNumberOfComponentsPerPixel(); @@ -427,9 +423,7 @@ MeanShiftImageFilter2<TInputImage, TOutputImage, TKernel, TNorm, TOutputIteratio } // Compute pixel weight from kernel - // TODO : replace by the templated kernel - weight = (norm2 <= 1.0)? 1.0 : 0.0; - + weight = m_Kernel(norm2); /* // The following code is an alternative way to compute norm2 and weight // It separates the norms of spatial and range elements