From 80175522b8008a3e802234b17d2c1f7c64ab17f4 Mon Sep 17 00:00:00 2001 From: Christophe Palmann <christophe.palmann@c-s.fr> Date: Tue, 30 Jun 2015 14:11:11 +0200 Subject: [PATCH] ENH: Frost filter with correct formula (SAR) --- .../ImageNoise/include/otbFrostImageFilter.h | 21 ++--- .../include/otbFrostImageFilter.txx | 82 +++++++++++-------- 2 files changed, 54 insertions(+), 49 deletions(-) diff --git a/Modules/Filtering/ImageNoise/include/otbFrostImageFilter.h b/Modules/Filtering/ImageNoise/include/otbFrostImageFilter.h index 487224a17e..15de095c98 100644 --- a/Modules/Filtering/ImageNoise/include/otbFrostImageFilter.h +++ b/Modules/Filtering/ImageNoise/include/otbFrostImageFilter.h @@ -29,18 +29,11 @@ namespace otb * \brief Anti-speckle image filter * * Uses a negative exponential convolution kernel. - * The output of the filter for pixel p is: - * \f$ \hat I_{s}=\sum_{p\in\eta_{p}} m_{p}I_{p} \f$ - * - * where : \f$ m_{p}=\frac{KC_{s}^{2}\exp(-KC_{s}^{2}d_{s, p})}{\sum_{p\in\eta_{p}} KC_{s}^{2}\exp(-KC_{s}^{2}d_{s, p})} \f$ - * and \f$ d_{s, p}=\sqrt{(i-i_{p})^2+(j-j_{p})^2} \f$ - * - * \f$ K \f$ : the decrease coefficient - * \f$ (i, j)\f$ : the coordinates of the pixel inside the region - * defined by \f$ \eta_{s} \f$ - * \f$ (i_{p}, j_{p})\f$ : the coordinates of the pixels belonging to \f$ \eta_{p} \subset \eta_{s} \f$ - * \f$ C_{s}\f$ : the variation coefficient computed over \f$ \eta_{p}\f$ - * + * The kernel is defined as follows: + * exp(-A*D), where + * D is the distance from the current pixel to the center pixel + * A = k*Ci*Ci with Ci = VAR[I]/ (E[I]*E[I]) + * The final result is normalized by the sum of the kernel coefficients. * * \ingroup OTBImageNoise */ @@ -92,9 +85,9 @@ public: /** Get the radius used to define the neighborhood for the filter calculation. */ itkGetConstReferenceMacro(Radius, SizeType); - /** Set The numbers of view used for the filter calculation. */ + /** Set the damping factor. */ itkSetMacro(Deramp, double); - /** Get The numbers of view used for the filter calculation. */ + /** Get the damping factor. */ itkGetConstReferenceMacro(Deramp, double); /** To be allowed to use the pipeline method FrostImageFilter needs diff --git a/Modules/Filtering/ImageNoise/include/otbFrostImageFilter.txx b/Modules/Filtering/ImageNoise/include/otbFrostImageFilter.txx index 17197ea98a..bca00f9c7d 100644 --- a/Modules/Filtering/ImageNoise/include/otbFrostImageFilter.txx +++ b/Modules/Filtering/ImageNoise/include/otbFrostImageFilter.txx @@ -38,7 +38,7 @@ template <class TInputImage, class TOutputImage> FrostImageFilter<TInputImage, TOutputImage>::FrostImageFilter() { m_Radius.Fill(1); - m_Deramp = 0.1; + m_Deramp = 2; } template <class TInputImage, class TOutputImage> @@ -135,54 +135,66 @@ void FrostImageFilter<TInputImage, TOutputImage>::ThreadedGenerateData( unsigned int neighborhoodSize = bit.Size(); it = itk::ImageRegionIterator<OutputImageType>(output, *fit); bit.OverrideBoundaryCondition(&nbc); + bit.GoToBegin(); + it.GoToBegin(); while (!bit.IsAtEnd()) { sum = itk::NumericTraits<InputRealType>::Zero; sum2 = itk::NumericTraits<InputRealType>::Zero; + for (i = 0; i < neighborhoodSize; ++i) { dPixel = static_cast<double>(bit.GetPixel(i)); sum += dPixel; - sum2 += dPixel * dPixel; } - Mean = sum / double(neighborhoodSize); - Variance = sum2 / double(neighborhoodSize) - Mean * Mean; - - if (Mean == 0) - { - Alpha = 0; - } - else - { - Alpha = m_Deramp * Variance / (Mean * Mean); - } - - NormFilter = 0.0; - FrostFilter = 0.0; - - const int rad_x = m_Radius[0]; - const int rad_y = m_Radius[1]; - - for (int x = -rad_x; x <= rad_x; ++x) + Mean = sum / static_cast<double>(neighborhoodSize); + + for (i = 0; i < neighborhoodSize; ++i) { - for (int y = -rad_y; y <= rad_y; ++y) - { - double Dist = vcl_sqrt(static_cast<double>(x * x + y * y)); - off[0] = x; - off[1] = y; - - dPixel = static_cast<double>(bit.GetPixel(off)); - - CoefFilter = Alpha * vcl_exp(-Alpha * Dist); - NormFilter += CoefFilter; - FrostFilter += (CoefFilter * dPixel); - } + dPixel = static_cast<double>(bit.GetPixel(i)); + sum2 += (dPixel-Mean) * (dPixel-Mean); } + Variance = sum2 / double(neighborhoodSize-1); - if (NormFilter == 0.) dPixel = 0.; - else dPixel = FrostFilter / NormFilter; + const double epsilon = 0.0000000001; + if (vcl_abs(Mean) < epsilon) + { + dPixel = itk::NumericTraits<OutputPixelType>::Zero; + } + else if (vcl_abs(Variance) < epsilon) + { + dPixel = Mean; + } + else + { + Alpha = m_Deramp * Variance / (Mean * Mean); + + NormFilter = 0.0; + FrostFilter = 0.0; + + const int rad_x = m_Radius[0]; + const int rad_y = m_Radius[1]; + + for (int x = -rad_x; x <= rad_x; ++x) + { + for (int y = -rad_y; y <= rad_y; ++y) + { + double Dist = vcl_sqrt(static_cast<double>(x * x + y * y)); + off[0] = x; + off[1] = y; + + dPixel = static_cast<double>(bit.GetPixel(off)); + + CoefFilter = vcl_exp(-Alpha * Dist); + NormFilter += CoefFilter; + FrostFilter += (CoefFilter * dPixel); + } + } + + dPixel = FrostFilter / NormFilter; + } it.Set(static_cast<OutputPixelType>(dPixel)); -- GitLab