3726: Start cleaning up linear gaussian filters.

https://svn.lrde.epita.fr/svn/oln/trunk/milena Index: ChangeLog from Thierry Geraud <thierry.geraud@lrde.epita.fr> Start cleaning up linear gaussian filters. * mln/linear/gaussian: New directory. * mln/linear/gaussian/internal: New directory. * mln/linear/gaussian.hh: Split code into... * mln/linear/gaussian/impl.hh, * mln/linear/gaussian/filter.hh, * mln/linear/gaussian/internal/coefficients.hh: ...those new files. * tests/linear/gaussian: New directory. * tests/linear/Makefile.am: Update. * tests/linear/gaussian/Makefile.am: New. * tests/linear/gaussian/filter.cc: New. Misc. * mln/labeling/compute.hh: . * mln/labeling/pack.hh (relabel_inplace): Fix missing renaming into... (pack_inplace): ...this. mln/labeling/compute.hh | 2 mln/labeling/pack.hh | 3 mln/linear/gaussian/filter.hh | 735 ------------------------- mln/linear/gaussian/impl.hh | 427 --------------- mln/linear/gaussian/internal/coefficients.hh | 768 ++++----------------------- tests/linear/Makefile.am | 4 tests/linear/gaussian/Makefile.am | 4 tests/linear/gaussian/filter.cc | 27 8 files changed, 185 insertions(+), 1785 deletions(-) Index: mln/linear/gaussian/impl.hh --- mln/linear/gaussian/impl.hh (revision 0) +++ mln/linear/gaussian/impl.hh (working copy) @@ -26,12 +26,12 @@ // reasons why the executable file might be covered by the GNU General // Public License. -#ifndef MLN_LINEAR_GAUSSIAN_HH -# define MLN_LINEAR_GAUSSIAN_HH +#ifndef MLN_LINEAR_GAUSSIAN_IMPL_HH +# define MLN_LINEAR_GAUSSIAN_IMPL_HH -/// \file mln/linear/gaussian.hh +/// \file mln/linear/gaussian/impl.hh /// -/// Gaussian filter. +/// Gaussian filter implementation. /// /// \todo Add a clean reference Rachid Deriche /// Recursively implementing the gaussian and its derivatives (1993) @@ -52,6 +52,8 @@ # include <mln/level/stretch.hh> # include <mln/algebra/vec.hh> +# include <mln/linear/gaussian/internal/coefficients.hh> + namespace mln { @@ -59,117 +61,20 @@ namespace linear { - /// Gaussian filter of an image \p input - /// - /// \pre output.domain = input.domain - /// - template <typename I> - mln_concrete(I) - gaussian(const Image<I>& input, float sigma); - - - template <typename I> - mln_concrete(I) - gaussian(const Image<I>& input, float sigma, int dir); - - -# ifndef MLN_INCLUDE_ONLY - - namespace impl - { - - typedef float norm_fun(float, float, - float, float, - float, float, - float, float, - float, float, - int&); - - struct recursivefilter_coef_ + namespace gaussian { - /// - /// Constructor. - /// - recursivefilter_coef_(float a0, float a1, - float b0, float b1, - float c0, float c1, - float w0, float w1, - float s, norm_fun norm); - std::vector<float> n, d, nm, dm; - }; - - inline - recursivefilter_coef_::recursivefilter_coef_(float a0, float a1, - float b0, float b1, - float c0, float c1, - float w0, float w1, - float s, norm_fun norm) - { - n.reserve(5); - d.reserve(5); - nm.reserve(5); - dm.reserve(5); - - b0 /= s; - b1 /= s; - w0 /= s; - w1 /= s; - - float sin0 = std::sin(w0); - float sin1 = std::sin(w1); - float cos0 = std::cos(w0); - float cos1 = std::cos(w1); - - int sign = 1; - float n_ = norm(a0, a1, b0, b1, c0, c1, cos0, sin0, cos1, sin1, sign); - - a0 /= n_; - a1 /= n_; - c0 /= n_; - c1 /= n_; - - n[3] = - std::exp(-b1 - 2*b0) * (c1 * sin1 - cos1 * c0) + - std::exp(-b0 - 2*b1) * (a1 * sin0 - cos0 * a0); - n[2] = - 2 * std::exp(-b0 - b1) * ((a0 + c0) * cos1 * cos0 - - cos1 * a1 * sin0 - - cos0 * c1 * sin1) + - c0 * std::exp(-2*b0) + a0 * std::exp(-2*b1); - n[1] = - std::exp(-b1) * (c1 * sin1 - (c0 + 2 * a0) * cos1) + - std::exp(-b0) * (a1 * sin0 - (2 * c0 + a0) * cos0); - n[0] = - a0 + c0; - - d[4] = - std::exp(-2 * b0 - 2 * b1); - d[3] = - -2 * cos0 * std::exp(-b0 - 2*b1) - - 2 * cos1 * std::exp(-b1 - 2*b0); - d[2] = - 4 * cos1 * cos0 * std::exp(-b0 - b1) + - std::exp(-2*b1) + std::exp(-2*b0); - d[1] = - -2 * std::exp(-b1) * cos1 - 2 * std::exp(-b0) * cos0; - - for (unsigned i = 1; i <= 3; ++i) + namespace impl { - dm[i] = d[i]; - nm[i] = float(sign) * (n[i] - d[i] * n[0]); - } - dm[4] = d[4]; - nm[4] = float(sign) * (-d[4] * n[0]); - } +# ifndef MLN_INCLUDE_ONLY template <class WorkType, class I> inline void recursivefilter_(I& ima, - const recursivefilter_coef_& c, + const internal::coefficients& c, const mln_psite(I)& start, const mln_psite(I)& finish, int len, @@ -264,104 +169,6 @@ } - inline - float gaussian_norm_coef_(float a0, float a1, - float b0, float b1, - float c0, float c1, - float cos0, float sin0, - float cos1, float sin1, - int& sign) - { - float expb0 = std::exp(b0); - float exp2b0 = std::exp(2.f * b0); - - float scale0 = 1 + exp2b0 - 2 * cos0 * expb0; - float scaleA = 2 * a1 * sin0 * expb0 - a0 * (1 - exp2b0); - - float expb1 = std::exp(b1); - float exp2b1 = std::exp(2.f * b1); - - float scale1 = 1 + exp2b1 - 2 * cos1 * expb1; - float scaleC = 2 * c1 * sin1 * expb1 - c0 * (1 - exp2b1); - - float sumA = scaleA / scale0; - float sumC = scaleC / scale1; - - sign = 1; - - return (sumA + sumC); - } - - inline - float gaussian_1st_deriv_coef_norm_(float a0, float a1, - float b0, float b1, - float c0, float c1, - float cos0, float sin0, - float cos1, float sin1, - int& sign) - { - float expb0 = std::exp(b0); - float exp2b0 = std::exp(2.f * b0); - - float scale0 = 1 + exp2b0 - 2 * cos0 * expb0; - scale0 *= scale0; - float scaleA = - 2 * a1 * sin0 * expb0 * (1 - exp2b0) + - 2 * a0 * expb0 * (2 * expb0 - cos0 * (1 + exp2b0)); - - float expb1 = std::exp(b1); - float exp2b1 = std::exp(2.f * b1); - - float scale1 = 1 + exp2b1 - 2 * cos1 * expb1; - scale1 *= scale1; - float scaleC = - 2 * c1 * sin1 * expb1 * (1 - exp2b1) + - 2 * c0 * expb1 * (2 * expb1 - cos1 * (1 + exp2b1)); - - float sumA = scaleA / scale0; - float sumC = scaleC / scale1; - - sign = -1; - - return (sumA + sumC); - } - - inline - float gaussian_2nd_deriv_coef_norm_(float a0, float a1, - float b0, float b1, - float c0, float c1, - float cos0, float sin0, - float cos1, float sin1, - int& sign) - { - float expb0 = std::exp(b0); - float exp2b0 = std::exp(2.f * b0); - - float scale0 = 1 + exp2b0 - 2 * cos0 * expb0; - scale0 *= scale0 * scale0; - - float scaleA = a1 * sin0 * expb0 * - (1 + expb0 * (2 * cos0 * (1 + exp2b0) + exp2b0 - 6)) + - a0 * expb0 * (2 * expb0 * (2 - cos0 * cos0) * - (1 - exp2b0) - cos0 * (1 - exp2b0 * exp2b0)); - - float expb1 = std::exp(b1); - float exp2b1 = std::exp(2.f * b1); - - float scale1 = 1 + exp2b1 - 2 * cos1 * expb1; - scale1 *= scale1 * scale1; - - float scaleC = c1 * sin1 * expb1 * - (1 + expb1 * (2 * cos1 * (1 + exp2b1) + exp2b1 - 6)) + - c0 * expb1 * (2 * expb1 * (2 - cos1 * cos1) * - (1 - exp2b1) - cos1 * (1 - exp2b1 * exp2b1)); - - float sumA = scaleA / scale0; - float sumC = scaleC / scale1; - sign = 1; - - return (sumA + sumC); - } - - template <class I, class F> inline void @@ -493,10 +300,10 @@ generic_filter_common_(trait::value::nature::floating, const Image<I>& in, const F& coef, - float sigma, + double sigma, Image<O>& out) { - mln_ch_value(O, float) work_img(exact(in).domain()); + mln_ch_value(O, double) work_img(exact(in).domain()); data::paste(in, work_img); extension::adjust_fill(work_img, 4, 0); @@ -517,11 +324,11 @@ generic_filter_common_(trait::value::nature::floating, const Image<I>& in, const F& coef, - float sigma, + double sigma, Image<O>& out, int dir) { - mln_ch_value(O, float) work_img(exact(in).domain()); + mln_ch_value(O, double) work_img(exact(in).domain()); data::paste(in, work_img); extension::adjust_fill(work_img, 4, 0); @@ -542,10 +349,10 @@ generic_filter_common_(trait::value::nature::scalar, const Image<I>& in, const F& coef, - float sigma, + double sigma, Image<O>& out) { - mln_ch_value(O, float) work_img(exact(in).domain()); + mln_ch_value(O, double) work_img(exact(in).domain()); data::paste(in, work_img); extension::adjust_fill(work_img, 4, 0); @@ -566,11 +373,11 @@ generic_filter_common_(trait::value::nature::scalar, const Image<I>& in, const F& coef, - float sigma, + double sigma, Image<O>& out, int dir) { - mln_ch_value(O, float) work_img(exact(in).domain()); + mln_ch_value(O, double) work_img(exact(in).domain()); data::paste(in, work_img); extension::adjust_fill(work_img, 4, 0); @@ -592,10 +399,10 @@ generic_filter_common_(trait::value::nature::vectorial, const Image<I>& in, const F& coef, - float sigma, + double sigma, Image<O>& out) { - // typedef algebra::vec<3, float> vec3f; + // typedef algebra::vec<3, double> vec3f; // mln_ch_value(O, vec3f) work_img(exact(in).domain()); // FIXME : paste does not work (rgb8 -> vec3f). data::paste(in, out); @@ -614,11 +421,11 @@ generic_filter_common_(trait::value::nature::vectorial, const Image<I>& in, const F& coef, - float sigma, + double sigma, Image<O>& out, int dir) { - // typedef algebra::vec<3, float> vec3f; + // typedef algebra::vec<3, double> vec3f; // mln_ch_value(O, vec3f) work_img(exact(in).domain()); // FIXME : paste does not work (rgb8 -> vec3f). data::paste(in, out); @@ -630,199 +437,17 @@ out, coef, dir); } - } // end of namespace mln::linear::impl - - // Facade. - /*! Apply an approximated gaussian filter of \p sigma on \p input. - * on a specific direction \p dir - * if \p dir = 0, the filter is applied on the first image dimension. - * if \p dir = 1, the filter is applied on the second image dimension. - * And so on... - * - * \pre input.is_valid - * \pre dir < dimension(input) - */ - template <typename I> - inline - mln_concrete(I) - gaussian(const Image<I>& input, float sigma, int dir) - { - mln_precondition(exact(input).is_valid()); - mln_precondition(dir < I::site::dim); - - mln_concrete(I) output; - initialize(output, input); - impl::recursivefilter_coef_ coef(1.68f, 3.735f, - 1.783f, 1.723f, - -0.6803f, -0.2598f, - 0.6318f, 1.997f, - sigma, impl::gaussian_norm_coef_); - - impl::generic_filter_common_(mln_trait_value_nature(mln_value(I))(), - input, coef, sigma, output, dir); - return output; - } - - - /*! Apply an approximated first derivative gaussian filter of \p sigma on - * \p input. - * on a specific direction \p dir - * if \p dir = 0, the filter is applied on the first image dimension. - * if \p dir = 1, the filter is applied on the second image dimension. - * And so on... - * - * \pre input.is_valid - * \pre dir < dimension(input) - */ - template <typename I> - inline - mln_concrete(I) - gaussian_1st_derivative(const Image<I>& input, float sigma, int dir) - { - mln_precondition(exact(input).is_valid()); - mln_precondition(dir < I::site::dim); - - mln_concrete(I) output; - initialize(output, input); - - impl::recursivefilter_coef_ - coef(-0.6472f, -4.531f, - 1.527f, 1.516f, - 0.6494f, 0.9557f, - 0.6719f, 2.072f, - sigma, impl::gaussian_1st_deriv_coef_norm_); - - impl::generic_filter_common_(mln_trait_value_nature(mln_value(I))(), - input, coef, sigma, output, dir); - return output; - } - - /*! Apply an approximated second derivative gaussian filter of \p sigma on - * \p input. - * on a specific direction \p dir - * if \p dir = 0, the filter is applied on the first image dimension. - * if \p dir = 1, the filter is applied on the second image dimension. - * And so on... - * - * \pre input.is_valid - * \pre dir < dimension(input) - */ - template <typename I> - inline - mln_concrete(I) - gaussian_2nd_derivative(const Image<I>& input, float sigma, int dir) - { - mln_precondition(exact(input).is_valid()); - mln_precondition(dir < I::site::dim); - - mln_concrete(I) output; - initialize(output, input); - - impl::recursivefilter_coef_ - coef(-1.331f, 3.661f, - 1.24f, 1.314f, - 0.3225f, -1.738f, - 0.748f, 2.166f, - sigma, impl::gaussian_2nd_deriv_coef_norm_); - - impl::generic_filter_common_(mln_trait_value_nature(mln_value(I))(), - input, coef, sigma, output, dir); - return output; - } - - - - - - /*! Apply an approximated gaussian filter of \p sigma on \p input. - * This filter is applied in all the input image direction. - * - * \pre input.is_valid - */ - template <typename I> - inline - mln_concrete(I) - gaussian(const Image<I>& input, float sigma) - { - mln_precondition(exact(input).is_valid()); - - mln_concrete(I) output; - initialize(output, input); - - impl::recursivefilter_coef_ - coef(1.68f, 3.735f, - 1.783f, 1.723f, - -0.6803f, -0.2598f, - 0.6318f, 1.997f, - sigma, impl::gaussian_norm_coef_); - impl::generic_filter_common_(mln_trait_value_nature(mln_value(I))(), - input, coef, sigma, output); - - return output; - } - - - /*! Apply an approximated first derivative gaussian filter of \p sigma on - * \p input - * This filter is applied in all the input image direction. - * - * \pre input.is_valid - */ - template <typename I> - inline - mln_concrete(I) - gaussian_1st_derivative(const Image<I>& input, float sigma) - { - mln_precondition(exact(input).is_valid()); - - mln_concrete(I) output; - initialize(output, input); - - impl::recursivefilter_coef_ - coef(-0.6472f, -4.531f, - 1.527f, 1.516f, - 0.6494f, 0.9557f, - 0.6719f, 2.072f, - sigma, impl::gaussian_1st_deriv_coef_norm_); - impl::generic_filter_common_(mln_trait_value_nature(mln_value(I))(), - input, coef, sigma, output); - return output; - } - - - /*! Apply an approximated second derivative gaussian filter of \p sigma on - * \p input - * This filter is applied in all the input image direction. - * - * \pre input.is_valid - */ - template <typename I> - inline - mln_concrete(I) - gaussian_2nd_derivative(const Image<I>& input, float sigma) - { - mln_precondition(exact(input).is_valid()); +# endif // ! MLN_INCLUDE_ONLY - mln_concrete(I) output; - initialize(output, input); - impl::recursivefilter_coef_ - coef(-1.331f, 3.661f, - 1.24f, 1.314f, - 0.3225f, -1.738f, - 0.748f, 2.166f, - sigma, impl::gaussian_2nd_deriv_coef_norm_); - impl::generic_filter_common_(mln_trait_value_nature(mln_value(I))(), - input, coef, sigma, output); - return output; - } + } // end of namespace mln::linear::gaussian::impl -# endif // ! MLN_INCLUDE_ONLY + } // end of namespace mln::linear::gaussian } // end of namespace mln::linear } // end of namespace mln -#endif // ! MLN_LINEAR_GAUSSIAN_HH +#endif // ! MLN_LINEAR_GAUSSIAN_IMPL_HH Property changes on: mln/linear/gaussian/impl.hh ___________________________________________________________________ Added: svn:mergeinfo Index: mln/linear/gaussian/filter.hh --- mln/linear/gaussian/filter.hh (revision 0) +++ mln/linear/gaussian/filter.hh (working copy) @@ -26,31 +26,19 @@ // reasons why the executable file might be covered by the GNU General // Public License. -#ifndef MLN_LINEAR_GAUSSIAN_HH -# define MLN_LINEAR_GAUSSIAN_HH +#ifndef MLN_LINEAR_GAUSSIAN_FILTER_HH +# define MLN_LINEAR_GAUSSIAN_FILTER_HH -/// \file mln/linear/gaussian.hh +/// \file mln/linear/gaussian/filter.hh /// /// Gaussian filter. /// /// \todo Add a clean reference Rachid Deriche /// Recursively implementing the gaussian and its derivatives (1993) -# include <vector> -# include <cmath> - # include <mln/core/concept/image.hh> -# include <mln/core/alias/point2d.hh> -# include <mln/core/alias/dpoint1d.hh> -# include <mln/core/alias/dpoint3d.hh> -# include <mln/extension/adjust_fill.hh> -# include <mln/geom/ncols.hh> -# include <mln/geom/nrows.hh> -# include <mln/geom/ninds.hh> -# include <mln/geom/nslis.hh> -# include <mln/data/paste.hh> -# include <mln/level/stretch.hh> -# include <mln/algebra/vec.hh> +# include <mln/linear/gaussian/impl.hh> +# include <mln/linear/gaussian/internal/coefficients.hh> namespace mln @@ -59,580 +47,28 @@ namespace linear { + namespace gaussian + { + /// Gaussian filter of an image \p input /// /// \pre output.domain = input.domain /// template <typename I> mln_concrete(I) - gaussian(const Image<I>& input, float sigma); + filter(const Image<I>& input, double sigma); template <typename I> mln_concrete(I) - gaussian(const Image<I>& input, float sigma, int dir); - - -# ifndef MLN_INCLUDE_ONLY - - namespace impl - { - - typedef float norm_fun(float, float, - float, float, - float, float, - float, float, - float, float, - int&); - - struct recursivefilter_coef_ - { - - /// - /// Constructor. - /// - recursivefilter_coef_(float a0, float a1, - float b0, float b1, - float c0, float c1, - float w0, float w1, - float s, norm_fun norm); - std::vector<float> n, d, nm, dm; - }; - - inline - recursivefilter_coef_::recursivefilter_coef_(float a0, float a1, - float b0, float b1, - float c0, float c1, - float w0, float w1, - float s, norm_fun norm) - { - n.reserve(5); - d.reserve(5); - nm.reserve(5); - dm.reserve(5); - - b0 /= s; - b1 /= s; - w0 /= s; - w1 /= s; - - float sin0 = std::sin(w0); - float sin1 = std::sin(w1); - float cos0 = std::cos(w0); - float cos1 = std::cos(w1); - - int sign = 1; - float n_ = norm(a0, a1, b0, b1, c0, c1, cos0, sin0, cos1, sin1, sign); - - a0 /= n_; - a1 /= n_; - c0 /= n_; - c1 /= n_; - - n[3] = - std::exp(-b1 - 2*b0) * (c1 * sin1 - cos1 * c0) + - std::exp(-b0 - 2*b1) * (a1 * sin0 - cos0 * a0); - n[2] = - 2 * std::exp(-b0 - b1) * ((a0 + c0) * cos1 * cos0 - - cos1 * a1 * sin0 - - cos0 * c1 * sin1) + - c0 * std::exp(-2*b0) + a0 * std::exp(-2*b1); - n[1] = - std::exp(-b1) * (c1 * sin1 - (c0 + 2 * a0) * cos1) + - std::exp(-b0) * (a1 * sin0 - (2 * c0 + a0) * cos0); - n[0] = - a0 + c0; - - d[4] = - std::exp(-2 * b0 - 2 * b1); - d[3] = - -2 * cos0 * std::exp(-b0 - 2*b1) - - 2 * cos1 * std::exp(-b1 - 2*b0); - d[2] = - 4 * cos1 * cos0 * std::exp(-b0 - b1) + - std::exp(-2*b1) + std::exp(-2*b0); - d[1] = - -2 * std::exp(-b1) * cos1 - 2 * std::exp(-b0) * cos0; - - for (unsigned i = 1; i <= 3; ++i) - { - dm[i] = d[i]; - nm[i] = float(sign) * (n[i] - d[i] * n[0]); - } - dm[4] = d[4]; - nm[4] = float(sign) * (-d[4] * n[0]); - } - - - - template <class WorkType, class I> - inline - void - recursivefilter_(I& ima, - const recursivefilter_coef_& c, - const mln_psite(I)& start, - const mln_psite(I)& finish, - int len, - const mln_deduce(I, psite, delta)& d) - { - std::vector<WorkType> tmp1(len); - std::vector<WorkType> tmp2(len); - - // The fourth degree approximation implies to have a special - // look on the four first points we consider that there is - // no signal before 0 (to be discussed) - - // -- - // Causal part - - tmp1[0] = - c.n[0] * ima(start); - - tmp1[1] = - c.n[0] * ima(start + d) - + c.n[1] * ima(start) - - c.d[1] * tmp1[0]; - - tmp1[2] = - c.n[0] * ima(start + d + d) - + c.n[1] * ima(start + d) - + c.n[2] * ima(start) - - c.d[1] * tmp1[1] - - c.d[2] * tmp1[0]; - - tmp1[3] = - c.n[0] * ima(start + d + d + d) - + c.n[1] * ima(start + d + d) - + c.n[2] * ima(start + d) - + c.n[3] * ima(start) - - c.d[1] * tmp1[2] - c.d[2] * tmp1[1] - - c.d[3] * tmp1[0]; - - mln_psite(I) current(start + d + d + d + d); - for (mln_deduce(I, site, coord) i = 4; i < len; ++i) - { - tmp1[i] = - c.n[0] * ima(current) - + c.n[1] * ima(current - d) - + c.n[2] * ima(current - d - d) - + c.n[3] * ima(current - d - d - d) - - c.d[1] * tmp1[i - 1] - c.d[2] * tmp1[i - 2] - - c.d[3] * tmp1[i - 3] - c.d[4] * tmp1[i - 4]; - current = current + d; - } - - // Non causal part - - tmp2[len - 1] = WorkType(); // FIXME : = 0, literal::zero ...? - - tmp2[len - 2] = - c.nm[1] * ima(finish); - - tmp2[len - 3] = - c.nm[1] * ima(finish - d) - + c.nm[2] * ima(finish) - - c.dm[1] * tmp2[len - 2]; - - tmp2[len - 4] = - c.nm[1] * ima(finish - d - d) - + c.nm[2] * ima(finish - d) - + c.nm[3] * ima(finish) - - c.dm[1] * tmp2[len - 3] - - c.dm[2] * tmp2[len - 2]; - - current = finish - d - d - d ; - - for (int i = len - 5; i >= 0; --i) - { - tmp2[i] = - c.nm[1] * ima(current) - + c.nm[2] * ima(current + d) - + c.nm[3] * ima(current + d + d) - + c.nm[4] * ima(current + d + d + d) - - c.dm[1] * tmp2[i + 1] - c.dm[2] * tmp2[i + 2] - - c.dm[3] * tmp2[i + 3] - c.dm[4] * tmp2[i + 4]; - current = current - d; - } - - // Combine results from causal and non-causal parts. - current = start; - for (int i = 0; i < len; ++i) - { - ima(current) = tmp1[i] + tmp2[i]; - current = current + d; - } - } - - - inline - float gaussian_norm_coef_(float a0, float a1, - float b0, float b1, - float c0, float c1, - float cos0, float sin0, - float cos1, float sin1, - int& sign) - { - float expb0 = std::exp(b0); - float exp2b0 = std::exp(2.f * b0); - - float scale0 = 1 + exp2b0 - 2 * cos0 * expb0; - float scaleA = 2 * a1 * sin0 * expb0 - a0 * (1 - exp2b0); - - float expb1 = std::exp(b1); - float exp2b1 = std::exp(2.f * b1); - - float scale1 = 1 + exp2b1 - 2 * cos1 * expb1; - float scaleC = 2 * c1 * sin1 * expb1 - c0 * (1 - exp2b1); - - float sumA = scaleA / scale0; - float sumC = scaleC / scale1; - - sign = 1; - - return (sumA + sumC); - } - - inline - float gaussian_1st_deriv_coef_norm_(float a0, float a1, - float b0, float b1, - float c0, float c1, - float cos0, float sin0, - float cos1, float sin1, - int& sign) - { - float expb0 = std::exp(b0); - float exp2b0 = std::exp(2.f * b0); - - float scale0 = 1 + exp2b0 - 2 * cos0 * expb0; - scale0 *= scale0; - float scaleA = - 2 * a1 * sin0 * expb0 * (1 - exp2b0) + - 2 * a0 * expb0 * (2 * expb0 - cos0 * (1 + exp2b0)); + filter(const Image<I>& input, double sigma, int dir); - float expb1 = std::exp(b1); - float exp2b1 = std::exp(2.f * b1); - float scale1 = 1 + exp2b1 - 2 * cos1 * expb1; - scale1 *= scale1; - float scaleC = - 2 * c1 * sin1 * expb1 * (1 - exp2b1) + - 2 * c0 * expb1 * (2 * expb1 - cos1 * (1 + exp2b1)); - float sumA = scaleA / scale0; - float sumC = scaleC / scale1; - - sign = -1; - - return (sumA + sumC); - } - - inline - float gaussian_2nd_deriv_coef_norm_(float a0, float a1, - float b0, float b1, - float c0, float c1, - float cos0, float sin0, - float cos1, float sin1, - int& sign) - { - float expb0 = std::exp(b0); - float exp2b0 = std::exp(2.f * b0); - - float scale0 = 1 + exp2b0 - 2 * cos0 * expb0; - scale0 *= scale0 * scale0; - - float scaleA = a1 * sin0 * expb0 * - (1 + expb0 * (2 * cos0 * (1 + exp2b0) + exp2b0 - 6)) + - a0 * expb0 * (2 * expb0 * (2 - cos0 * cos0) * - (1 - exp2b0) - cos0 * (1 - exp2b0 * exp2b0)); - - float expb1 = std::exp(b1); - float exp2b1 = std::exp(2.f * b1); - - float scale1 = 1 + exp2b1 - 2 * cos1 * expb1; - scale1 *= scale1 * scale1; - - float scaleC = c1 * sin1 * expb1 * - (1 + expb1 * (2 * cos1 * (1 + exp2b1) + exp2b1 - 6)) + - c0 * expb1 * (2 * expb1 * (2 - cos1 * cos1) * - (1 - exp2b1) - cos1 * (1 - exp2b1 * exp2b1)); - - float sumA = scaleA / scale0; - float sumC = scaleC / scale1; - sign = 1; - - return (sumA + sumC); - } - - - template <class I, class F> - inline - void - generic_filter_(trait::image::dimension::one_d, - Image<I>& img_, const F& coef, int dir) - { - I& img = exact(img_); - mln_precondition(dir < I::site::dim); - - - recursivefilter_<mln_value(I)>(img, coef, - point1d(static_cast<def::coord>(-img.border())), - point1d(static_cast<def::coord>(geom::ninds(img) - 1 + - img.border())), - geom::ninds(img) + 2 * img.border(), - dpoint1d(1)); - } - - template <class I, class F> - inline - void - generic_filter_(trait::image::dimension::two_d, - Image<I>& img_, const F& coef, int dir) - { - I& img = exact(img_); - - mln_precondition(dir < I::site::dim); - - - if (dir == 0) - { - // Apply on rows. - for (unsigned j = 0; j < geom::ncols(img); ++j) - recursivefilter_<mln_value(I)>(img, coef, - point2d(static_cast<def::coord>(-img.border()), - static_cast<def::coord>(j)), - point2d(static_cast<def::coord>(geom::nrows(img) - 1 + - img.border()), - static_cast<def::coord>(j)), - geom::nrows(img) + 2 * img.border(), - dpoint2d(1, 0)); - } - - if (dir == 1) - { - // Apply on columns. - for (unsigned i = 0; i < geom::nrows(img); ++i) - recursivefilter_<mln_value(I)>(img, coef, - point2d(static_cast<def::coord>(i), - static_cast<def::coord>(-img.border())), - point2d(static_cast<def::coord>(i), - static_cast<def::coord>(geom::ncols(img) - 1 + - img.border())), - geom::ncols(img) + 2 * img.border(), - dpoint2d(0, 1)); - } - } - - template <class I, class F> - inline - void - generic_filter_(trait::image::dimension::three_d, - Image<I>& img_, const F& coef, int dir) - { - I& img = exact(img_); - mln_precondition(dir < I::site::dim); - - if (dir == 0) - { - // Apply on slices. - for (unsigned j = 0; j < geom::nrows(img); ++j) - for (unsigned k = 0; k < geom::ncols(img); ++k) - recursivefilter_<mln_value(I)>(img, coef, - point3d(static_cast<def::coord>(-img.border()), - static_cast<def::coord>(j), - static_cast<def::coord>(k)), - point3d(static_cast<def::coord>(geom::nslis(img) - 1 + - img.border()), - static_cast<def::coord>(j), - static_cast<def::coord>(k)), - geom::nslis(img) + 2 * - img.border(), - dpoint3d(1, 0, 0)); - } - - - if (dir == 1) - { - // Apply on rows. - for (unsigned i = 0; i < geom::nslis(img); ++i) - for (unsigned k = 0; k < geom::ncols(img); ++k) - recursivefilter_<mln_value(I)>(img, coef, - point3d(static_cast<def::coord>(i), - static_cast<def::coord>(-img.border()), - static_cast<def::coord>(k)), - point3d(static_cast<def::coord>(i), - static_cast<def::coord>(geom::nrows(img) - 1 + - img.border()), - static_cast<def::coord>(k)), - geom::nrows(img) + 2 * - img.border(), - dpoint3d(0, 1, 0)); - } - - if (dir == 2) - { - // Apply on columns. - for (unsigned i = 0; i < geom::nslis(img); ++i) - for (unsigned j = 0; j < geom::nrows(img); ++i) - recursivefilter_<mln_value(I)>(img, coef, - point3d(static_cast<def::coord>(i), - static_cast<def::coord>(j), - static_cast<def::coord>(-img.border())), - point3d(static_cast<def::coord>(i), - static_cast<def::coord>(j), - static_cast<def::coord>(geom::ncols(img) - - 1 + img.border())), - geom::ncols(img) + 2 * - img.border(), - dpoint3d(0, 0, 1)); - } - } - - - - template <class I, class F, class O> - inline - void - generic_filter_common_(trait::value::nature::floating, - const Image<I>& in, - const F& coef, - float sigma, - Image<O>& out) - { - mln_ch_value(O, float) work_img(exact(in).domain()); - data::paste(in, work_img); - extension::adjust_fill(work_img, 4, 0); - - // On tiny sigma, Derich algorithm doesn't work. - // It is the same thing that to convolve with a Dirac. - if (sigma > 0.006) - for (int i = 0; i < I::site::dim; ++i) - generic_filter_(mln_trait_image_dimension(I)(), - work_img, coef, i); - - // We don't need to convert work_img - data::paste(work_img, out); - } - - template <class I, class F, class O> - inline - void - generic_filter_common_(trait::value::nature::floating, - const Image<I>& in, - const F& coef, - float sigma, - Image<O>& out, - int dir) - { - mln_ch_value(O, float) work_img(exact(in).domain()); - data::paste(in, work_img); - extension::adjust_fill(work_img, 4, 0); - - // On tiny sigma, Derich algorithm doesn't work. - // It is the same thing that to convolve with a Dirac. - if (sigma > 0.006) - generic_filter_(mln_trait_image_dimension(I)(), - work_img, coef, dir); - - // We don't need to convert work_img - data::paste(work_img, out); - } - - - template <class I, class F, class O> - inline - void - generic_filter_common_(trait::value::nature::scalar, - const Image<I>& in, - const F& coef, - float sigma, - Image<O>& out) - { - mln_ch_value(O, float) work_img(exact(in).domain()); - data::paste(in, work_img); - extension::adjust_fill(work_img, 4, 0); - - // On tiny sigma, Derich algorithm doesn't work. - // It is the same thing that to convolve with a Dirac. - if (sigma > 0.006) - for (int i = 0; i < I::site::dim; ++i) - generic_filter_(mln_trait_image_dimension(I)(), - work_img, coef, i); - - // Convert work_img into result type - data::paste(level::stretch(mln_value(I)(), work_img), out); - } - - template <class I, class F, class O> - inline - void - generic_filter_common_(trait::value::nature::scalar, - const Image<I>& in, - const F& coef, - float sigma, - Image<O>& out, - int dir) - { - mln_ch_value(O, float) work_img(exact(in).domain()); - data::paste(in, work_img); - extension::adjust_fill(work_img, 4, 0); - - // On tiny sigma, Derich algorithm doesn't work. - // It is the same thing that to convolve with a Dirac. - if (sigma > 0.006) - generic_filter_(mln_trait_image_dimension(I)(), - work_img, coef, dir); - - // Convert work_img into result type - data::paste(level::stretch(mln_value(I)(), work_img), out); - } - - - - template <class I, class F, class O> - inline - void - generic_filter_common_(trait::value::nature::vectorial, - const Image<I>& in, - const F& coef, - float sigma, - Image<O>& out) - { - // typedef algebra::vec<3, float> vec3f; - // mln_ch_value(O, vec3f) work_img(exact(in).domain()); - // FIXME : paste does not work (rgb8 -> vec3f). - data::paste(in, out); - - // On tiny sigma, Derich algorithm doesn't work. - // It is the same thing that to convolve with a Dirac. - if (sigma > 0.006) - for (int i = 0; i < I::site::dim; ++i) - generic_filter_(mln_trait_image_dimension(I)(), - out, coef, i); - } - - template <class I, class F, class O> - inline - void - generic_filter_common_(trait::value::nature::vectorial, - const Image<I>& in, - const F& coef, - float sigma, - Image<O>& out, - int dir) - { - // typedef algebra::vec<3, float> vec3f; - // mln_ch_value(O, vec3f) work_img(exact(in).domain()); - // FIXME : paste does not work (rgb8 -> vec3f). - data::paste(in, out); - - // On tiny sigma, Derich algorithm doesn't work. - // It is the same thing that to convolve with a Dirac. - if (sigma > 0.006) - generic_filter_(mln_trait_image_dimension(I)(), - out, coef, dir); - } +# ifndef MLN_INCLUDE_ONLY - } // end of namespace mln::linear::impl - // Facade. + // Facades. /*! Apply an approximated gaussian filter of \p sigma on \p input. * on a specific direction \p dir @@ -646,95 +82,28 @@ template <typename I> inline mln_concrete(I) - gaussian(const Image<I>& input, float sigma, int dir) + filter(const Image<I>& input, double sigma, int dir) { - mln_precondition(exact(input).is_valid()); - mln_precondition(dir < I::site::dim); + trace::entering("linear::gaussian::filter"); - mln_concrete(I) output; - initialize(output, input); - impl::recursivefilter_coef_ coef(1.68f, 3.735f, - 1.783f, 1.723f, - -0.6803f, -0.2598f, - 0.6318f, 1.997f, - sigma, impl::gaussian_norm_coef_); - - impl::generic_filter_common_(mln_trait_value_nature(mln_value(I))(), - input, coef, sigma, output, dir); - return output; - } - - - /*! Apply an approximated first derivative gaussian filter of \p sigma on - * \p input. - * on a specific direction \p dir - * if \p dir = 0, the filter is applied on the first image dimension. - * if \p dir = 1, the filter is applied on the second image dimension. - * And so on... - * - * \pre input.is_valid - * \pre dir < dimension(input) - */ - template <typename I> - inline - mln_concrete(I) - gaussian_1st_derivative(const Image<I>& input, float sigma, int dir) - { mln_precondition(exact(input).is_valid()); mln_precondition(dir < I::site::dim); mln_concrete(I) output; initialize(output, input); - impl::recursivefilter_coef_ - coef(-0.6472f, -4.531f, - 1.527f, 1.516f, - 0.6494f, 0.9557f, - 0.6719f, 2.072f, - sigma, impl::gaussian_1st_deriv_coef_norm_); + internal::coefficients coef = internal::coefficients_not_derivative(sigma); impl::generic_filter_common_(mln_trait_value_nature(mln_value(I))(), input, coef, sigma, output, dir); - return output; - } - - /*! Apply an approximated second derivative gaussian filter of \p sigma on - * \p input. - * on a specific direction \p dir - * if \p dir = 0, the filter is applied on the first image dimension. - * if \p dir = 1, the filter is applied on the second image dimension. - * And so on... - * - * \pre input.is_valid - * \pre dir < dimension(input) - */ - template <typename I> - inline - mln_concrete(I) - gaussian_2nd_derivative(const Image<I>& input, float sigma, int dir) - { - mln_precondition(exact(input).is_valid()); - mln_precondition(dir < I::site::dim); - mln_concrete(I) output; - initialize(output, input); - - impl::recursivefilter_coef_ - coef(-1.331f, 3.661f, - 1.24f, 1.314f, - 0.3225f, -1.738f, - 0.748f, 2.166f, - sigma, impl::gaussian_2nd_deriv_coef_norm_); - - impl::generic_filter_common_(mln_trait_value_nature(mln_value(I))(), - input, coef, sigma, output, dir); + trace::exiting("linear::gaussian::filter"); return output; } - /*! Apply an approximated gaussian filter of \p sigma on \p input. * This filter is applied in all the input image direction. * @@ -743,86 +112,32 @@ template <typename I> inline mln_concrete(I) - gaussian(const Image<I>& input, float sigma) + filter(const Image<I>& input, double sigma) { - mln_precondition(exact(input).is_valid()); - - mln_concrete(I) output; - initialize(output, input); - - impl::recursivefilter_coef_ - coef(1.68f, 3.735f, - 1.783f, 1.723f, - -0.6803f, -0.2598f, - 0.6318f, 1.997f, - sigma, impl::gaussian_norm_coef_); - impl::generic_filter_common_(mln_trait_value_nature(mln_value(I))(), - input, coef, sigma, output); + trace::entering("linear::gaussian::filter"); - return output; - } - - - /*! Apply an approximated first derivative gaussian filter of \p sigma on - * \p input - * This filter is applied in all the input image direction. - * - * \pre input.is_valid - */ - template <typename I> - inline - mln_concrete(I) - gaussian_1st_derivative(const Image<I>& input, float sigma) - { mln_precondition(exact(input).is_valid()); mln_concrete(I) output; initialize(output, input); - impl::recursivefilter_coef_ - coef(-0.6472f, -4.531f, - 1.527f, 1.516f, - 0.6494f, 0.9557f, - 0.6719f, 2.072f, - sigma, impl::gaussian_1st_deriv_coef_norm_); - impl::generic_filter_common_(mln_trait_value_nature(mln_value(I))(), - input, coef, sigma, output); - return output; - } - - - /*! Apply an approximated second derivative gaussian filter of \p sigma on - * \p input - * This filter is applied in all the input image direction. - * - * \pre input.is_valid - */ - template <typename I> - inline - mln_concrete(I) - gaussian_2nd_derivative(const Image<I>& input, float sigma) - { - mln_precondition(exact(input).is_valid()); - - mln_concrete(I) output; - initialize(output, input); + internal::coefficients coef = internal::coefficients_not_derivative(sigma); - impl::recursivefilter_coef_ - coef(-1.331f, 3.661f, - 1.24f, 1.314f, - 0.3225f, -1.738f, - 0.748f, 2.166f, - sigma, impl::gaussian_2nd_deriv_coef_norm_); impl::generic_filter_common_(mln_trait_value_nature(mln_value(I))(), input, coef, sigma, output); + + trace::exiting("linear::gaussian::filter"); return output; } + # endif // ! MLN_INCLUDE_ONLY + } // end of namespace mln::linear::gaussian + } // end of namespace mln::linear } // end of namespace mln -#endif // ! MLN_LINEAR_GAUSSIAN_HH +#endif // ! MLN_LINEAR_GAUSSIAN_FILTER_HH Property changes on: mln/linear/gaussian/filter.hh ___________________________________________________________________ Added: svn:mergeinfo Index: mln/linear/gaussian/internal/coefficients.hh --- mln/linear/gaussian/internal/coefficients.hh (revision 0) +++ mln/linear/gaussian/internal/coefficients.hh (working copy) @@ -26,12 +26,12 @@ // reasons why the executable file might be covered by the GNU General // Public License. -#ifndef MLN_LINEAR_GAUSSIAN_HH -# define MLN_LINEAR_GAUSSIAN_HH +#ifndef MLN_LINEAR_GAUSSIAN_INTERNAL_COEFFICIENTS_HH +# define MLN_LINEAR_GAUSSIAN_INTERNAL_COEFFICIENTS_HH -/// \file mln/linear/gaussian.hh +/// \file mln/linear/gaussian/internal/coefficients.hh /// -/// Gaussian filter. +/// Compute coefficients for recursive Gaussian filtering. /// /// \todo Add a clean reference Rachid Deriche /// Recursively implementing the gaussian and its derivatives (1993) @@ -39,18 +39,6 @@ # include <vector> # include <cmath> -# include <mln/core/concept/image.hh> -# include <mln/core/alias/point2d.hh> -# include <mln/core/alias/dpoint1d.hh> -# include <mln/core/alias/dpoint3d.hh> -# include <mln/extension/adjust_fill.hh> -# include <mln/geom/ncols.hh> -# include <mln/geom/nrows.hh> -# include <mln/geom/ninds.hh> -# include <mln/geom/nslis.hh> -# include <mln/data/paste.hh> -# include <mln/level/stretch.hh> -# include <mln/algebra/vec.hh> namespace mln @@ -59,52 +47,48 @@ namespace linear { - /// Gaussian filter of an image \p input - /// - /// \pre output.domain = input.domain - /// - template <typename I> - mln_concrete(I) - gaussian(const Image<I>& input, float sigma); - - - template <typename I> - mln_concrete(I) - gaussian(const Image<I>& input, float sigma, int dir); - - -# ifndef MLN_INCLUDE_ONLY + namespace gaussian + { - namespace impl + namespace internal { - typedef float norm_fun(float, float, - float, float, - float, float, - float, float, - float, float, + + typedef double norm_fun(double, double, + double, double, + double, double, + double, double, + double, double, int&); - struct recursivefilter_coef_ + struct coefficients { - - /// /// Constructor. - /// - recursivefilter_coef_(float a0, float a1, - float b0, float b1, - float c0, float c1, - float w0, float w1, - float s, norm_fun norm); - std::vector<float> n, d, nm, dm; + // + coefficients(double a0, double a1, + double b0, double b1, + double c0, double c1, + double w0, double w1, + double s, norm_fun norm); + std::vector<double> n, d, nm, dm; }; + + coefficients coefficients_not_derivative(double sigma); + coefficients coefficients_1st_derivative(double sigma); + coefficients coefficients_2nd_derivative(double sigma); + + + +# ifndef MLN_INCLUDE_ONLY + + inline - recursivefilter_coef_::recursivefilter_coef_(float a0, float a1, - float b0, float b1, - float c0, float c1, - float w0, float w1, - float s, norm_fun norm) + coefficients::coefficients(double a0, double a1, + double b0, double b1, + double c0, double c1, + double w0, double w1, + double s, norm_fun norm) { n.reserve(5); d.reserve(5); @@ -116,13 +100,13 @@ w0 /= s; w1 /= s; - float sin0 = std::sin(w0); - float sin1 = std::sin(w1); - float cos0 = std::cos(w0); - float cos1 = std::cos(w1); + double sin0 = std::sin(w0); + double sin1 = std::sin(w1); + double cos0 = std::cos(w0); + double cos1 = std::cos(w1); int sign = 1; - float n_ = norm(a0, a1, b0, b1, c0, c1, cos0, sin0, cos1, sin1, sign); + double n_ = norm(a0, a1, b0, b1, c0, c1, cos0, sin0, cos1, sin1, sign); a0 /= n_; a1 /= n_; @@ -157,672 +141,160 @@ for (unsigned i = 1; i <= 3; ++i) { dm[i] = d[i]; - nm[i] = float(sign) * (n[i] - d[i] * n[0]); + nm[i] = double(sign) * (n[i] - d[i] * n[0]); } dm[4] = d[4]; - nm[4] = float(sign) * (-d[4] * n[0]); - } - - - - template <class WorkType, class I> - inline - void - recursivefilter_(I& ima, - const recursivefilter_coef_& c, - const mln_psite(I)& start, - const mln_psite(I)& finish, - int len, - const mln_deduce(I, psite, delta)& d) - { - std::vector<WorkType> tmp1(len); - std::vector<WorkType> tmp2(len); - - // The fourth degree approximation implies to have a special - // look on the four first points we consider that there is - // no signal before 0 (to be discussed) - - // -- - // Causal part - - tmp1[0] = - c.n[0] * ima(start); - - tmp1[1] = - c.n[0] * ima(start + d) - + c.n[1] * ima(start) - - c.d[1] * tmp1[0]; - - tmp1[2] = - c.n[0] * ima(start + d + d) - + c.n[1] * ima(start + d) - + c.n[2] * ima(start) - - c.d[1] * tmp1[1] - - c.d[2] * tmp1[0]; - - tmp1[3] = - c.n[0] * ima(start + d + d + d) - + c.n[1] * ima(start + d + d) - + c.n[2] * ima(start + d) - + c.n[3] * ima(start) - - c.d[1] * tmp1[2] - c.d[2] * tmp1[1] - - c.d[3] * tmp1[0]; - - mln_psite(I) current(start + d + d + d + d); - for (mln_deduce(I, site, coord) i = 4; i < len; ++i) - { - tmp1[i] = - c.n[0] * ima(current) - + c.n[1] * ima(current - d) - + c.n[2] * ima(current - d - d) - + c.n[3] * ima(current - d - d - d) - - c.d[1] * tmp1[i - 1] - c.d[2] * tmp1[i - 2] - - c.d[3] * tmp1[i - 3] - c.d[4] * tmp1[i - 4]; - current = current + d; - } - - // Non causal part - - tmp2[len - 1] = WorkType(); // FIXME : = 0, literal::zero ...? - - tmp2[len - 2] = - c.nm[1] * ima(finish); - - tmp2[len - 3] = - c.nm[1] * ima(finish - d) - + c.nm[2] * ima(finish) - - c.dm[1] * tmp2[len - 2]; - - tmp2[len - 4] = - c.nm[1] * ima(finish - d - d) - + c.nm[2] * ima(finish - d) - + c.nm[3] * ima(finish) - - c.dm[1] * tmp2[len - 3] - - c.dm[2] * tmp2[len - 2]; - - current = finish - d - d - d ; - - for (int i = len - 5; i >= 0; --i) - { - tmp2[i] = - c.nm[1] * ima(current) - + c.nm[2] * ima(current + d) - + c.nm[3] * ima(current + d + d) - + c.nm[4] * ima(current + d + d + d) - - c.dm[1] * tmp2[i + 1] - c.dm[2] * tmp2[i + 2] - - c.dm[3] * tmp2[i + 3] - c.dm[4] * tmp2[i + 4]; - current = current - d; + nm[4] = double(sign) * (-d[4] * n[0]); } - // Combine results from causal and non-causal parts. - current = start; - for (int i = 0; i < len; ++i) - { - ima(current) = tmp1[i] + tmp2[i]; - current = current + d; - } - } inline - float gaussian_norm_coef_(float a0, float a1, - float b0, float b1, - float c0, float c1, - float cos0, float sin0, - float cos1, float sin1, + double norm_not_derivative(double a0, double a1, + double b0, double b1, + double c0, double c1, + double cos0, double sin0, + double cos1, double sin1, int& sign) { - float expb0 = std::exp(b0); - float exp2b0 = std::exp(2.f * b0); + double expb0 = std::exp(b0); + double exp2b0 = std::exp(2.f * b0); - float scale0 = 1 + exp2b0 - 2 * cos0 * expb0; - float scaleA = 2 * a1 * sin0 * expb0 - a0 * (1 - exp2b0); + double scale0 = 1 + exp2b0 - 2 * cos0 * expb0; + double scaleA = 2 * a1 * sin0 * expb0 - a0 * (1 - exp2b0); - float expb1 = std::exp(b1); - float exp2b1 = std::exp(2.f * b1); + double expb1 = std::exp(b1); + double exp2b1 = std::exp(2.f * b1); - float scale1 = 1 + exp2b1 - 2 * cos1 * expb1; - float scaleC = 2 * c1 * sin1 * expb1 - c0 * (1 - exp2b1); + double scale1 = 1 + exp2b1 - 2 * cos1 * expb1; + double scaleC = 2 * c1 * sin1 * expb1 - c0 * (1 - exp2b1); - float sumA = scaleA / scale0; - float sumC = scaleC / scale1; + double sumA = scaleA / scale0; + double sumC = scaleC / scale1; sign = 1; - return (sumA + sumC); + return sumA + sumC; } + inline - float gaussian_1st_deriv_coef_norm_(float a0, float a1, - float b0, float b1, - float c0, float c1, - float cos0, float sin0, - float cos1, float sin1, + double norm_1st_derivative(double a0, double a1, + double b0, double b1, + double c0, double c1, + double cos0, double sin0, + double cos1, double sin1, int& sign) { - float expb0 = std::exp(b0); - float exp2b0 = std::exp(2.f * b0); + double expb0 = std::exp(b0); + double exp2b0 = std::exp(2.f * b0); - float scale0 = 1 + exp2b0 - 2 * cos0 * expb0; + double scale0 = 1 + exp2b0 - 2 * cos0 * expb0; scale0 *= scale0; - float scaleA = - 2 * a1 * sin0 * expb0 * (1 - exp2b0) + + double scaleA = - 2 * a1 * sin0 * expb0 * (1 - exp2b0) + 2 * a0 * expb0 * (2 * expb0 - cos0 * (1 + exp2b0)); - float expb1 = std::exp(b1); - float exp2b1 = std::exp(2.f * b1); + double expb1 = std::exp(b1); + double exp2b1 = std::exp(2.f * b1); - float scale1 = 1 + exp2b1 - 2 * cos1 * expb1; + double scale1 = 1 + exp2b1 - 2 * cos1 * expb1; scale1 *= scale1; - float scaleC = - 2 * c1 * sin1 * expb1 * (1 - exp2b1) + + double scaleC = - 2 * c1 * sin1 * expb1 * (1 - exp2b1) + 2 * c0 * expb1 * (2 * expb1 - cos1 * (1 + exp2b1)); - float sumA = scaleA / scale0; - float sumC = scaleC / scale1; + double sumA = scaleA / scale0; + double sumC = scaleC / scale1; sign = -1; - return (sumA + sumC); + return sumA + sumC; } + inline - float gaussian_2nd_deriv_coef_norm_(float a0, float a1, - float b0, float b1, - float c0, float c1, - float cos0, float sin0, - float cos1, float sin1, + double norm_2nd_derivative(double a0, double a1, + double b0, double b1, + double c0, double c1, + double cos0, double sin0, + double cos1, double sin1, int& sign) { - float expb0 = std::exp(b0); - float exp2b0 = std::exp(2.f * b0); + double expb0 = std::exp(b0); + double exp2b0 = std::exp(2.f * b0); - float scale0 = 1 + exp2b0 - 2 * cos0 * expb0; + double scale0 = 1 + exp2b0 - 2 * cos0 * expb0; scale0 *= scale0 * scale0; - float scaleA = a1 * sin0 * expb0 * + double scaleA = a1 * sin0 * expb0 * (1 + expb0 * (2 * cos0 * (1 + exp2b0) + exp2b0 - 6)) + a0 * expb0 * (2 * expb0 * (2 - cos0 * cos0) * (1 - exp2b0) - cos0 * (1 - exp2b0 * exp2b0)); - float expb1 = std::exp(b1); - float exp2b1 = std::exp(2.f * b1); + double expb1 = std::exp(b1); + double exp2b1 = std::exp(2.f * b1); - float scale1 = 1 + exp2b1 - 2 * cos1 * expb1; + double scale1 = 1 + exp2b1 - 2 * cos1 * expb1; scale1 *= scale1 * scale1; - float scaleC = c1 * sin1 * expb1 * + double scaleC = c1 * sin1 * expb1 * (1 + expb1 * (2 * cos1 * (1 + exp2b1) + exp2b1 - 6)) + c0 * expb1 * (2 * expb1 * (2 - cos1 * cos1) * (1 - exp2b1) - cos1 * (1 - exp2b1 * exp2b1)); - float sumA = scaleA / scale0; - float sumC = scaleC / scale1; + double sumA = scaleA / scale0; + double sumC = scaleC / scale1; sign = 1; - return (sumA + sumC); + return sumA + sumC; } - template <class I, class F> inline - void - generic_filter_(trait::image::dimension::one_d, - Image<I>& img_, const F& coef, int dir) - { - I& img = exact(img_); - mln_precondition(dir < I::site::dim); - - - recursivefilter_<mln_value(I)>(img, coef, - point1d(static_cast<def::coord>(-img.border())), - point1d(static_cast<def::coord>(geom::ninds(img) - 1 + - img.border())), - geom::ninds(img) + 2 * img.border(), - dpoint1d(1)); - } - - template <class I, class F> - inline - void - generic_filter_(trait::image::dimension::two_d, - Image<I>& img_, const F& coef, int dir) - { - I& img = exact(img_); - - mln_precondition(dir < I::site::dim); - - - if (dir == 0) - { - // Apply on rows. - for (unsigned j = 0; j < geom::ncols(img); ++j) - recursivefilter_<mln_value(I)>(img, coef, - point2d(static_cast<def::coord>(-img.border()), - static_cast<def::coord>(j)), - point2d(static_cast<def::coord>(geom::nrows(img) - 1 + - img.border()), - static_cast<def::coord>(j)), - geom::nrows(img) + 2 * img.border(), - dpoint2d(1, 0)); - } - - if (dir == 1) + coefficients coefficients_not_derivative(double sigma) { - // Apply on columns. - for (unsigned i = 0; i < geom::nrows(img); ++i) - recursivefilter_<mln_value(I)>(img, coef, - point2d(static_cast<def::coord>(i), - static_cast<def::coord>(-img.border())), - point2d(static_cast<def::coord>(i), - static_cast<def::coord>(geom::ncols(img) - 1 + - img.border())), - geom::ncols(img) + 2 * img.border(), - dpoint2d(0, 1)); - } + coefficients tmp(+1.6800, +3.7350, + +1.7830, +1.7230, + -0.6803, -0.2598, + +0.6318, +1.9970, + sigma, + norm_not_derivative); + return tmp; } - template <class I, class F> - inline - void - generic_filter_(trait::image::dimension::three_d, - Image<I>& img_, const F& coef, int dir) - { - I& img = exact(img_); - mln_precondition(dir < I::site::dim); - - if (dir == 0) - { - // Apply on slices. - for (unsigned j = 0; j < geom::nrows(img); ++j) - for (unsigned k = 0; k < geom::ncols(img); ++k) - recursivefilter_<mln_value(I)>(img, coef, - point3d(static_cast<def::coord>(-img.border()), - static_cast<def::coord>(j), - static_cast<def::coord>(k)), - point3d(static_cast<def::coord>(geom::nslis(img) - 1 + - img.border()), - static_cast<def::coord>(j), - static_cast<def::coord>(k)), - geom::nslis(img) + 2 * - img.border(), - dpoint3d(1, 0, 0)); - } - - - if (dir == 1) - { - // Apply on rows. - for (unsigned i = 0; i < geom::nslis(img); ++i) - for (unsigned k = 0; k < geom::ncols(img); ++k) - recursivefilter_<mln_value(I)>(img, coef, - point3d(static_cast<def::coord>(i), - static_cast<def::coord>(-img.border()), - static_cast<def::coord>(k)), - point3d(static_cast<def::coord>(i), - static_cast<def::coord>(geom::nrows(img) - 1 + - img.border()), - static_cast<def::coord>(k)), - geom::nrows(img) + 2 * - img.border(), - dpoint3d(0, 1, 0)); - } - - if (dir == 2) - { - // Apply on columns. - for (unsigned i = 0; i < geom::nslis(img); ++i) - for (unsigned j = 0; j < geom::nrows(img); ++i) - recursivefilter_<mln_value(I)>(img, coef, - point3d(static_cast<def::coord>(i), - static_cast<def::coord>(j), - static_cast<def::coord>(-img.border())), - point3d(static_cast<def::coord>(i), - static_cast<def::coord>(j), - static_cast<def::coord>(geom::ncols(img) - - 1 + img.border())), - geom::ncols(img) + 2 * - img.border(), - dpoint3d(0, 0, 1)); - } - } - - - - template <class I, class F, class O> - inline - void - generic_filter_common_(trait::value::nature::floating, - const Image<I>& in, - const F& coef, - float sigma, - Image<O>& out) - { - mln_ch_value(O, float) work_img(exact(in).domain()); - data::paste(in, work_img); - extension::adjust_fill(work_img, 4, 0); - - // On tiny sigma, Derich algorithm doesn't work. - // It is the same thing that to convolve with a Dirac. - if (sigma > 0.006) - for (int i = 0; i < I::site::dim; ++i) - generic_filter_(mln_trait_image_dimension(I)(), - work_img, coef, i); - - // We don't need to convert work_img - data::paste(work_img, out); - } - template <class I, class F, class O> inline - void - generic_filter_common_(trait::value::nature::floating, - const Image<I>& in, - const F& coef, - float sigma, - Image<O>& out, - int dir) - { - mln_ch_value(O, float) work_img(exact(in).domain()); - data::paste(in, work_img); - extension::adjust_fill(work_img, 4, 0); - - // On tiny sigma, Derich algorithm doesn't work. - // It is the same thing that to convolve with a Dirac. - if (sigma > 0.006) - generic_filter_(mln_trait_image_dimension(I)(), - work_img, coef, dir); - - // We don't need to convert work_img - data::paste(work_img, out); - } - - - template <class I, class F, class O> - inline - void - generic_filter_common_(trait::value::nature::scalar, - const Image<I>& in, - const F& coef, - float sigma, - Image<O>& out) - { - mln_ch_value(O, float) work_img(exact(in).domain()); - data::paste(in, work_img); - extension::adjust_fill(work_img, 4, 0); - - // On tiny sigma, Derich algorithm doesn't work. - // It is the same thing that to convolve with a Dirac. - if (sigma > 0.006) - for (int i = 0; i < I::site::dim; ++i) - generic_filter_(mln_trait_image_dimension(I)(), - work_img, coef, i); - - // Convert work_img into result type - data::paste(level::stretch(mln_value(I)(), work_img), out); - } - - template <class I, class F, class O> - inline - void - generic_filter_common_(trait::value::nature::scalar, - const Image<I>& in, - const F& coef, - float sigma, - Image<O>& out, - int dir) - { - mln_ch_value(O, float) work_img(exact(in).domain()); - data::paste(in, work_img); - extension::adjust_fill(work_img, 4, 0); - - // On tiny sigma, Derich algorithm doesn't work. - // It is the same thing that to convolve with a Dirac. - if (sigma > 0.006) - generic_filter_(mln_trait_image_dimension(I)(), - work_img, coef, dir); - - // Convert work_img into result type - data::paste(level::stretch(mln_value(I)(), work_img), out); - } - - - - template <class I, class F, class O> - inline - void - generic_filter_common_(trait::value::nature::vectorial, - const Image<I>& in, - const F& coef, - float sigma, - Image<O>& out) - { - // typedef algebra::vec<3, float> vec3f; - // mln_ch_value(O, vec3f) work_img(exact(in).domain()); - // FIXME : paste does not work (rgb8 -> vec3f). - data::paste(in, out); - - // On tiny sigma, Derich algorithm doesn't work. - // It is the same thing that to convolve with a Dirac. - if (sigma > 0.006) - for (int i = 0; i < I::site::dim; ++i) - generic_filter_(mln_trait_image_dimension(I)(), - out, coef, i); - } - - template <class I, class F, class O> - inline - void - generic_filter_common_(trait::value::nature::vectorial, - const Image<I>& in, - const F& coef, - float sigma, - Image<O>& out, - int dir) - { - // typedef algebra::vec<3, float> vec3f; - // mln_ch_value(O, vec3f) work_img(exact(in).domain()); - // FIXME : paste does not work (rgb8 -> vec3f). - data::paste(in, out); - - // On tiny sigma, Derich algorithm doesn't work. - // It is the same thing that to convolve with a Dirac. - if (sigma > 0.006) - generic_filter_(mln_trait_image_dimension(I)(), - out, coef, dir); - } - - } // end of namespace mln::linear::impl - - // Facade. - - /*! Apply an approximated gaussian filter of \p sigma on \p input. - * on a specific direction \p dir - * if \p dir = 0, the filter is applied on the first image dimension. - * if \p dir = 1, the filter is applied on the second image dimension. - * And so on... - * - * \pre input.is_valid - * \pre dir < dimension(input) - */ - template <typename I> - inline - mln_concrete(I) - gaussian(const Image<I>& input, float sigma, int dir) + coefficients coefficients_1st_derivative(double sigma) { - mln_precondition(exact(input).is_valid()); - mln_precondition(dir < I::site::dim); - - mln_concrete(I) output; - initialize(output, input); - impl::recursivefilter_coef_ coef(1.68f, 3.735f, - 1.783f, 1.723f, - -0.6803f, -0.2598f, - 0.6318f, 1.997f, - sigma, impl::gaussian_norm_coef_); - - impl::generic_filter_common_(mln_trait_value_nature(mln_value(I))(), - input, coef, sigma, output, dir); - return output; + coefficients tmp(-0.6472, -4.5310, + +1.5270, +1.5160, + +0.6494, +0.9557, + +0.6719, +2.0720, + sigma, + norm_1st_derivative); + return tmp; } - /*! Apply an approximated first derivative gaussian filter of \p sigma on - * \p input. - * on a specific direction \p dir - * if \p dir = 0, the filter is applied on the first image dimension. - * if \p dir = 1, the filter is applied on the second image dimension. - * And so on... - * - * \pre input.is_valid - * \pre dir < dimension(input) - */ - template <typename I> inline - mln_concrete(I) - gaussian_1st_derivative(const Image<I>& input, float sigma, int dir) + coefficients coefficients_2nd_derivative(double sigma) { - mln_precondition(exact(input).is_valid()); - mln_precondition(dir < I::site::dim); - - mln_concrete(I) output; - initialize(output, input); - - impl::recursivefilter_coef_ - coef(-0.6472f, -4.531f, - 1.527f, 1.516f, - 0.6494f, 0.9557f, - 0.6719f, 2.072f, - sigma, impl::gaussian_1st_deriv_coef_norm_); - - impl::generic_filter_common_(mln_trait_value_nature(mln_value(I))(), - input, coef, sigma, output, dir); - return output; + coefficients tmp(-1.3310, +3.661, + +1.2400, +1.314, + +0.3225, -1.738, + +0.7480, +2.166, + sigma, + norm_2nd_derivative); } - /*! Apply an approximated second derivative gaussian filter of \p sigma on - * \p input. - * on a specific direction \p dir - * if \p dir = 0, the filter is applied on the first image dimension. - * if \p dir = 1, the filter is applied on the second image dimension. - * And so on... - * - * \pre input.is_valid - * \pre dir < dimension(input) - */ - template <typename I> - inline - mln_concrete(I) - gaussian_2nd_derivative(const Image<I>& input, float sigma, int dir) - { - mln_precondition(exact(input).is_valid()); - mln_precondition(dir < I::site::dim); - - mln_concrete(I) output; - initialize(output, input); - - impl::recursivefilter_coef_ - coef(-1.331f, 3.661f, - 1.24f, 1.314f, - 0.3225f, -1.738f, - 0.748f, 2.166f, - sigma, impl::gaussian_2nd_deriv_coef_norm_); - - impl::generic_filter_common_(mln_trait_value_nature(mln_value(I))(), - input, coef, sigma, output, dir); - return output; - } - - - - - - /*! Apply an approximated gaussian filter of \p sigma on \p input. - * This filter is applied in all the input image direction. - * - * \pre input.is_valid - */ - template <typename I> - inline - mln_concrete(I) - gaussian(const Image<I>& input, float sigma) - { - mln_precondition(exact(input).is_valid()); - - mln_concrete(I) output; - initialize(output, input); - - impl::recursivefilter_coef_ - coef(1.68f, 3.735f, - 1.783f, 1.723f, - -0.6803f, -0.2598f, - 0.6318f, 1.997f, - sigma, impl::gaussian_norm_coef_); - impl::generic_filter_common_(mln_trait_value_nature(mln_value(I))(), - input, coef, sigma, output); - - return output; - } - - - /*! Apply an approximated first derivative gaussian filter of \p sigma on - * \p input - * This filter is applied in all the input image direction. - * - * \pre input.is_valid - */ - template <typename I> - inline - mln_concrete(I) - gaussian_1st_derivative(const Image<I>& input, float sigma) - { - mln_precondition(exact(input).is_valid()); - - mln_concrete(I) output; - initialize(output, input); - - impl::recursivefilter_coef_ - coef(-0.6472f, -4.531f, - 1.527f, 1.516f, - 0.6494f, 0.9557f, - 0.6719f, 2.072f, - sigma, impl::gaussian_1st_deriv_coef_norm_); - impl::generic_filter_common_(mln_trait_value_nature(mln_value(I))(), - input, coef, sigma, output); - return output; - } - - - /*! Apply an approximated second derivative gaussian filter of \p sigma on - * \p input - * This filter is applied in all the input image direction. - * - * \pre input.is_valid - */ - template <typename I> - inline - mln_concrete(I) - gaussian_2nd_derivative(const Image<I>& input, float sigma) - { - mln_precondition(exact(input).is_valid()); - - mln_concrete(I) output; - initialize(output, input); +# endif // ! MLN_INCLUDE_ONLY - impl::recursivefilter_coef_ - coef(-1.331f, 3.661f, - 1.24f, 1.314f, - 0.3225f, -1.738f, - 0.748f, 2.166f, - sigma, impl::gaussian_2nd_deriv_coef_norm_); - impl::generic_filter_common_(mln_trait_value_nature(mln_value(I))(), - input, coef, sigma, output); - return output; - } + } // end of namespace mln::linear::gaussian::internal -# endif // ! MLN_INCLUDE_ONLY + } // end of namespace mln::linear::gaussian } // end of namespace mln::linear } // end of namespace mln -#endif // ! MLN_LINEAR_GAUSSIAN_HH +#endif // ! MLN_LINEAR_GAUSSIAN_INTERNAL_COEFFICIENTS_HH Property changes on: mln/linear/gaussian/internal/coefficients.hh ___________________________________________________________________ Added: svn:mergeinfo Index: mln/labeling/compute.hh --- mln/labeling/compute.hh (revision 3725) +++ mln/labeling/compute.hh (working copy) @@ -128,7 +128,7 @@ const mln_value(L)& nlabels) { mln_precondition(exact(label).is_valid()); - mlc_is_a(mln_value(L), mln::value::Symbolic)::check(); + // mlc_is_a(mln_value(L), mln::value::Symbolic)::check(); (void) a; (void) label; (void) nlabels; Index: mln/labeling/pack.hh --- mln/labeling/pack.hh (revision 3725) +++ mln/labeling/pack.hh (working copy) @@ -34,7 +34,6 @@ /// Remove components and relabel a labeled image in order to have a /// contiguous labeling. - # include <mln/core/concept/image.hh> # include <mln/make/relabelfun.hh> @@ -71,7 +70,7 @@ // template <typename I> void - relabel_inplace(Image<I>& label, mln_value(I)& new_nlabels); + pack_inplace(Image<I>& label, mln_value(I)& new_nlabels); Index: tests/linear/Makefile.am --- tests/linear/Makefile.am (revision 3725) +++ tests/linear/Makefile.am (working copy) @@ -2,7 +2,9 @@ include $(top_srcdir)/milena/tests/tests.mk -SUBDIRS = local +SUBDIRS = \ + gaussian \ + local check_PROGRAMS = \ convolve \ Index: tests/linear/gaussian/Makefile.am --- tests/linear/gaussian/Makefile.am (revision 0) +++ tests/linear/gaussian/Makefile.am (working copy) @@ -3,8 +3,8 @@ include $(top_srcdir)/milena/tests/tests.mk check_PROGRAMS = \ - convolve + filter -convolve_SOURCES = convolve.cc +filter_SOURCES = filter.cc TESTS = $(check_PROGRAMS) Property changes on: tests/linear/gaussian/Makefile.am ___________________________________________________________________ Added: svn:mergeinfo Index: tests/linear/gaussian/filter.cc --- tests/linear/gaussian/filter.cc (revision 0) +++ tests/linear/gaussian/filter.cc (working copy) @@ -1,5 +1,5 @@ -// Copyright (C) 2007, 2008 EPITA Research and Development Laboratory -// (LRDE) +// Copyright (C) 2007, 2008, 2009 EPITA Research and Development +// Laboratory (LRDE) // // This file is part of the Olena Library. This library is free // software; you can redistribute it and/or modify it under the terms @@ -26,27 +26,20 @@ // reasons why the executable file might be covered by the GNU General // Public License. -/// \file tests/linear/gaussian.cc +/// \file tests/linear/gaussian/filter.cc /// -/// Test on mln::linear::gaussian. +/// Test on mln::linear::gaussian::filter. #include <mln/core/image/image2d.hh> -#include <mln/value/int_u8.hh> -#include <mln/value/int_u_sat.hh> +#include <mln/value/int_u8.hh> #include <mln/io/pgm/load.hh> #include <mln/io/pgm/save.hh> -#include <mln/level/transform.hh> -#include <mln/data/paste.hh> -#include <mln/math/round.hh> - -#include <mln/linear/gaussian.hh> +#include <mln/linear/gaussian/filter.hh> #include "tests/data.hh" -#include <mln/trace/all.hh> - int main() @@ -56,12 +49,6 @@ image2d<value::int_u8> lena; io::pgm::load(lena, MLN_IMG_DIR "/lena.pgm"); - image2d<value::int_u8> out = linear::gaussian(lena, 5.1f); + image2d<value::int_u8> out = linear::gaussian::filter(lena, 5.1f); io::pgm::save(out, "out.pgm"); - - - image2d<float> lenaf(lena.domain()); - data::paste(lena, lenaf); - - image2d<float> outf = linear::gaussian(lenaf, 5.1f); } Property changes on: tests/linear/gaussian/filter.cc ___________________________________________________________________ Added: svn:mergeinfo
participants (1)
-
Thierry Geraud