Index: doc/ChangeLog from Simon Odou simon@lrde.epita.fr
* ref/out/exdoc.config.in: Add -DHAVE_CONFIG_H and libs (for fft).
Index: olena/ChangeLog from Simon Odou simon@lrde.epita.fr
* oln/convol/convolution.hh: Move to ... * oln/convol/slow_convolution.hh: ... Here. Convolve two images (convolution between image and w_window does not make sense). * oln/transforms/fft.hh: Shift the DFT. * tests/convol/Makefile.am: Add lib for fft test. * tests/convol/tests/slow_sum_2d_1: Fix include. * tests/convol/tests/slow_sum_2d_2: Likewise. * tests/convol/tests/sobel_gradient: Likewise. * oln/makefile.src: Add slow_convolution.hh and fast_convolution.hh. * oln/convol/slow_gaussian.hh: Adapt to new kernel (image). * oln/convol/slow_gaussian.hxx: Use image to compute convolution (not w_window). * oln/convol/fast_convolution.hh: New. Use fft to convolute. * tests/convol/tests/fast_convol: New.
Index: olena/oln/convol/slow_convolution.hh --- olena/oln/convol/convolution.hh Mon, 15 Mar 2004 17:40:54 +0100 van-vl_n (oln/f/39_convolutio 1.4.1.4.1.6.1.3 600) +++ olena/oln/convol/slow_convolution.hh Mon, 14 Jun 2004 06:05:43 +0200 odou_s (oln/f/39_convolutio 1.4.1.4.1.6.1.3 600) @@ -26,8 +26,8 @@ // Public License.
-#ifndef OLENA_CONVOL_CONVOLUTION_HH__ -# define OLENA_CONVOL_CONVOLUTION_HH__ +#ifndef OLENA_CONVOL_SLOW_CONVOLUTION_HH__ +# define OLENA_CONVOL_SLOW_CONVOLUTION_HH__
# include <oln/basics.hh> # include <oln/basics2d.hh> @@ -50,11 +50,13 @@ ** ** \param DestValue Data type of the output image you want. ** \param I Exact type of the input image. - ** \param Win Exact type of the window. ** ** \arg input The image to process. ** \arg win The window to convolve with. ** + ** \deprecated This function is obsolete, prefer : + ** convolve(const abstract::non_vectorial_image< I >& input, + ** const abstract::image< J >& k) ** \todo FIXME: we must always specify DestValue. */ template<class DestValue, class I, class Win> @@ -80,6 +82,58 @@ }
/*! + ** \brief Perform a convolution of two images. + ** + ** \param DestValue Data type of the output image you want. + ** \param I Exact type of the input image. + ** \param J Exact type of the input image (convolution kernel). + ** + ** \arg input The image to process. + ** \arg k The kernel to convolve with. + ** + ** \todo FIXME: we must always specify DestValue. + */ + template<class DestValue, class I, class J> + typename mute<I, DestValue>::ret + convolve(const abstract::non_vectorial_image< I >& input, + const abstract::image< J >& k) + { + mlc::eq<I::dim, J::dim>::ensure(); + + typename mute<I, DestValue>::ret output(input.size()); + + // Compute Delta. + // \todo FIXME: should be in the image hierarchy. + coord delta = 0; + for (unsigned i = 0; i < J::dim; i++) + if (k.size().nth(i) > delta) + delta = k.size().nth(i); + input.border_adapt_copy(delta); + + // Computer center of the kernel. + // \todo FIXME: should be in the image hierarchy. + oln_iter_type(I) p_im(input); + oln_iter_type(I) p_k(k); + oln_point_type(I) center; + unsigned i_center = 0; + unsigned real_center = k.npoints() % 2 ? k.npoints() / 2 + 1 : + k.npoints() / 2; + for_all(p_k) + if (++i_center == real_center) + center = p_k; + + for_all(p_im) + { + DestValue sum = ntg_zero_val(DestValue); + for_all(p_k) + sum += static_cast<DestValue> (k[p_k]) * + static_cast<DestValue> (input[p_im - (center - p_k)]); + output[p_im] = sum; + } + return output; + } + + /*! ** \brief Perform a convolution of an image and a window. ** ** \param DestValue Data type of the output image you want. @@ -107,4 +161,4 @@
} // end namespace oln
-#endif // OLENA_CONVOL_CONVOLUTION_HH__ +#endif // OLENA_CONVOL_SLOW_CONVOLUTION_HH__ Index: olena/oln/transforms/fft.hh --- olena/oln/transforms/fft.hh Fri, 19 Mar 2004 14:01:37 +0100 palma_g (oln/i/36_fft.hh 1.4.1.10 600) +++ olena/oln/transforms/fft.hh Mon, 14 Jun 2004 05:38:16 +0200 odou_s (oln/i/36_fft.hh 1.4.1.10 600) @@ -41,6 +41,7 @@ # include <ntg/basics.hh> # include <ntg/all.hh> # include <oln/basics2d.hh> +# include <oln/morpher/piece_morpher.hh>
namespace oln {
@@ -485,6 +486,84 @@ }
/*! + ** \brief Shift zero-frequency component of discrete Fourier transform + ** to center of spectrum. + ** + ** \param T1 The data type of the image returned. + ** + ** The zero-frequency component of discrete Fourier transform are moved + ** to center of the image : + ** + ** \htmlonly + ** <table> + ** <tr><td>1</td><td>2</td></tr> + ** <tr><td>3</td><td>4</td></tr> + ** </table> + ** becomes + ** <table> + ** <tr><td>4</td><td>3</td></tr> + ** <tr><td>2</td><td>1</td></tr> + ** </table> + ** \endhtmlonly + ** + */ + template <class T1> + image2d<T1> shift_transform_inv() + { + image2d<T1> t = transform_inv<T1>(); + image2d<T1> st(t.size()); + + // We have to exchange t_1 with t_1_dest and not directly t_3 because + // they have not he same size. + typedef morpher::piece_morpher< image2d<T1> > piece_t; + piece_t t_1(t, dpoint2d(0, 0), + image2d_size((t.size().nrows() - 1) / 2, + (t.size().ncols() - 1) / 2, + t.border())); + piece_t t_1_dest(st, dpoint2d(t.nrows() - t_1.nrows(), + t.ncols() - t_1.ncols()), + image2d_size(t_1.nrows(), t_1.ncols(), + t.border())); + piece_t t_2(t, dpoint2d(0, (t.size().ncols() - 1) / 2), + image2d_size((t.size().nrows() - 1) / 2, + t.size().ncols() - (t.size().ncols() - 1) / 2, + t.border())); + piece_t t_2_dest(st, dpoint2d(t.nrows() - t_2.nrows(), 0), + image2d_size(t_2.nrows(), t_2.ncols(), + t.border())); + piece_t t_3(t, dpoint2d((t.size().nrows() - 1) / 2, 0), + image2d_size(t.size().nrows() - (t.size().nrows() - 1) / 2, + (t.size().ncols() - 1) / 2, + t.border())); + piece_t t_3_dest(st, dpoint2d(0, t.ncols() - t_3.ncols()), + image2d_size(t_3.nrows(), t_3.ncols(), + t.border())); + piece_t t_4(t, dpoint2d((t.size().nrows() - 1) / 2, + (t.size().ncols() - 1) / 2), + image2d_size(t.size().nrows() - (t.size().nrows() - 1) / 2, + t.size().ncols() - (t.size().ncols() - 1) / 2, + t.border())); + piece_t t_4_dest(st, dpoint2d(0, 0), + image2d_size(t_4.nrows(), t_4.ncols(), + t.border())); + + oln_iter_type(piece_t) i1(t_1); + for_all(i1) + t_1_dest[i1] = t_1[i1]; + oln_iter_type(piece_t) i2(t_2); + for_all(i2) + t_2_dest[i2] = t_2[i2]; + oln_iter_type(piece_t) i3(t_3); + for_all(i3) + t_3_dest[i3] = t_3[i3]; + oln_iter_type(piece_t) i4(t_4); + for_all(i4) + t_4_dest[i4] = t_4[i4]; + + return st; + } + + /*! ** \brief Compute and return the invert transform. */ image2d<T> transform_inv() @@ -492,6 +571,15 @@ return transform_inv<T>(); }
+ /*! + ** \brief Shift zero-frequency component of discrete Fourier transform + ** to center of spectrum. + */ + image2d<T> shift_transform_inv() + { + return shift_transform_inv<T>(); + } + };
/*! Index: olena/tests/convol/Makefile.am --- olena/tests/convol/Makefile.am Tue, 05 Aug 2003 21:39:33 +0200 burrus_n (oln/f/38_Makefile.a 1.13 600) +++ olena/tests/convol/Makefile.am Mon, 14 Jun 2004 07:24:23 +0200 odou_s (oln/f/38_Makefile.a 1.13 600) @@ -1,4 +1,7 @@ include ../check/Makefile.runtests
+LDADD_RUNTESTS += $(FFTW_LDFLAGS) +CXXFLAGS_RUNTESTS += $(FFTW_CFLAGS) + EXTRA_DIST += sum_on_random.pgm CLEANFILES += lena-sobel.pgm Index: olena/tests/convol/tests/slow_sum_2d_1 --- olena/tests/convol/tests/slow_sum_2d_1 Tue, 20 Apr 2004 15:16:21 +0200 van-vl_n (oln/f/41_slow_sum_2 1.2.1.6 600) +++ olena/tests/convol/tests/slow_sum_2d_1 Mon, 14 Jun 2004 08:14:27 +0200 odou_s (oln/f/41_slow_sum_2 1.2.1.6 600) @@ -28,7 +28,7 @@
#include <oln/basics2d.hh> -#include <oln/convol/convolution.hh> +#include <oln/convol/slow_convolution.hh>
#include <oln/level/compare.hh>
Index: olena/tests/convol/tests/slow_sum_2d_2 --- olena/tests/convol/tests/slow_sum_2d_2 Tue, 20 Apr 2004 15:16:21 +0200 van-vl_n (oln/f/40_slow_sum_2 1.2.1.5 600) +++ olena/tests/convol/tests/slow_sum_2d_2 Mon, 14 Jun 2004 08:14:37 +0200 odou_s (oln/f/40_slow_sum_2 1.2.1.5 600) @@ -28,7 +28,7 @@
#include <oln/basics2d.hh> -#include <oln/convol/convolution.hh> +#include <oln/convol/slow_convolution.hh>
#include <oln/level/compare.hh>
Index: olena/tests/convol/tests/sobel_gradient --- olena/tests/convol/tests/sobel_gradient Tue, 20 Apr 2004 15:16:21 +0200 van-vl_n (oln/f/45_sobel_grad 1.3.1.7 600) +++ olena/tests/convol/tests/sobel_gradient Mon, 14 Jun 2004 08:15:02 +0200 odou_s (oln/f/45_sobel_grad 1.3.1.7 600) @@ -28,7 +28,7 @@
#include <oln/basics2d.hh> -#include <oln/convol/convolution.hh> +#include <oln/convol/slow_convolution.hh> #include <oln/convert/basics.hh>
#include "check.hh" Index: doc/ref/out/exdoc.config.in --- doc/ref/out/exdoc.config.in Fri, 09 Apr 2004 16:53:44 +0200 thivol_d (oln/k/7_exdoc.conf 1.7 600) +++ doc/ref/out/exdoc.config.in Mon, 14 Jun 2004 07:03:20 +0200 odou_s (oln/k/7_exdoc.conf 1.7 600) @@ -4,7 +4,8 @@ TAG_CLOSE = endcode CAPTIONS = cxx # We want to run cxx on the extracted files (see line below) ALIAS cxx = @CXX@ # Here, cxx means g++ but you can choose other compilers - OPTIONS = @DOC_CPPFLAGS@ @CXXFLAGS_OPTIMIZE@ @CXXFLAGS_STRICT_ERRORS@ -I@top_srcdir@/integre -I@top_builddir@/olena -I@top_srcdir@/olena -I@top_srcdir@/metalic $1 -o $2 -DIMG_OUT="../img/" -DIMG_IN="@top_srcdir@/olena/img/" # tell how to use the soft, i.e. where to put input and output arguments (default if not overriden) ($1: input, $2: output) FIXME: $* should have explicit name, chek flags + # FIXME: we should write the compilation line in the source file (for libs). + OPTIONS = -lz -lfftw -lrfftw @DOC_CPPFLAGS@ @CXXFLAGS_OPTIMIZE@ @CXXFLAGS_STRICT_ERRORS@ -I@top_srcdir@/integre -I@top_builddir@/olena -I@top_srcdir@/olena -I@top_srcdir@/metalic -I@top_builddir@ $1 -o $2 -DIMG_OUT="../img/" -DIMG_IN="@top_srcdir@/olena/img/" -DHAVE_CONFIG_H # tell how to use the soft, i.e. where to put input and output arguments (default if not overriden) ($1: input, $2: output) FIXME: $* should have explicit name, chek flags OUT = out # FIXME: should be obsolete EXT = cc # Extension of generated file STD_OUT_EXT = std # Extension of generated file standard output Index: olena/oln/makefile.src --- olena/oln/makefile.src Sun, 06 Jun 2004 23:17:15 +0200 thivol_d (oln/r/4_makefile.s 1.2 600) +++ olena/oln/makefile.src Fri, 11 Jun 2004 03:14:27 +0200 odou_s (oln/r/4_makefile.s 1.2 600) @@ -31,7 +31,8 @@ convert/rgbxyz.hh \ convert/stretch.hh \ convert/value_to_point.hh \ - convol/convolution.hh \ + convol/slow_convolution.hh \ + convol/fast_convolution.hh \ convol/fast_gaussian.hh \ convol/fast_gaussian.hxx \ convol/fast_gaussian_coefficient.hh \ Index: olena/oln/convol/slow_gaussian.hh --- olena/oln/convol/slow_gaussian.hh Wed, 09 Jun 2004 20:13:57 +0200 van-vl_n (oln/r/7_slow_gauss 1.2 644) +++ olena/oln/convol/slow_gaussian.hh Mon, 14 Jun 2004 08:31:10 +0200 odou_s (oln/r/7_slow_gauss 1.2 644) @@ -30,7 +30,7 @@ # define SLOW_GAUSSIAN_HH # include <oln/core/image.hh> # include <ntg/float.hh> -# include "convolution.hh" +# include <oln/convol/slow_convolution.hh> # include <oln/core/behavior.hh>
namespace oln { @@ -87,7 +87,14 @@ { const typename gaussian_kernel<I::dim>::ret k = gaussian_kernel<I::dim>::kernel(sigma, radius_factor); - behavior.adapt_border(in, coord(k.delta())); + + // Compute Delta. + // \todo FIXME: should be in the image hierarchy. + coord delta = 0; + for (unsigned i = 0; i < I::dim; i++) + if (in.size().nth(i) > delta) + delta = in.size().nth(i); + behavior.adapt_border(in, delta);
typename mute<I, ntg::float_d>::ret im = oln::convol::slow::convolventg::float_d (in, k); Index: olena/oln/convol/slow_gaussian.hxx --- olena/oln/convol/slow_gaussian.hxx Wed, 09 Jun 2004 20:13:57 +0200 van-vl_n (oln/r/8_slow_gauss 1.2 644) +++ olena/oln/convol/slow_gaussian.hxx Mon, 14 Jun 2004 05:42:37 +0200 odou_s (oln/r/8_slow_gauss 1.2 644) @@ -28,9 +28,9 @@
#ifndef SLOW_GAUSSIAN_HXX # define SLOW_GAUSSIAN_HXX -# include <oln/core/w_window1d.hh> -# include <oln/core/w_window2d.hh> -# include <oln/core/w_window3d.hh> +# include <oln/core/image1d.hh> +# include <oln/core/image2d.hh> +# include <oln/core/image3d.hh>
namespace oln { namespace convol { @@ -44,29 +44,31 @@ inline T normalise(const T &in) { - T w = in; + T w(in.size()); ntg::float_d sum = 0.; - for (unsigned i = 0; i < in.card(); ++i) - sum += in.w(i); + oln_iter_type(T) i(in); + for_all(i) + sum += in[i]; sum = 1. / sum; assert(finite(sum)); - for (unsigned i = 0; i < in.card(); ++i) - w.set(w.dp(i), in.w(i) * sum); + for_all(i) + w[i] = in[i] * sum; return w; }
+ }// End namespace internal
//! Kernel of a 1D Gaussian. template<> struct gaussian_kernel<1> { - typedef oln::w_window1dntg::float_d ret; + typedef oln::image1dntg::float_d ret; enum {dim = 1};
//! Return a discrete Gaussian kernel, that is equal to zero // at a distance of radius_factor * sigma. - static w_window1dntg::float_d + static image1dntg::float_d kernel(ntg::float_d sigma, ntg::float_d radius_factor) { @@ -79,20 +81,20 @@ // // Note: the integral is not equal to 1 (discrete grid and 0 outside // radius_factor * sigma). You should use kernel(sigma, radius_factor). - static w_window1dntg::float_d + static image1dntg::float_d kernel_values(ntg::float_d sigma, ntg::float_d radius_factor) { precondition(sigma > 0.); precondition(radius_factor >= 0.);
- w_window1dntg::float_d w; - const int size = int(sigma * radius_factor); + image1dntg::float_d w(size * 2 + 1); + const ntg::float_d inv_sigma_sqrt_2pi = 1. / (sigma * sqrt(M_PI * 2.)); - for (int x = -size; x <= +size; ++x) - w.add(x, inv_sigma_sqrt_2pi * exp(-x * x /(2 * sigma * sigma))); + for (int x = -size; x <= size; ++x) + w(x + size) = inv_sigma_sqrt_2pi * exp(-x * x /(2 * sigma * sigma)); return w; } }; @@ -101,12 +103,12 @@ template<> struct gaussian_kernel<2> { - typedef w_window2dntg::float_d ret; + typedef image2dntg::float_d ret; enum {dim = 2};
//! Return a discrete Gaussian kernel, that is equal to zero at a // distance of radius_factor * sigma. - static w_window2dntg::float_d + static image2dntg::float_d kernel(ntg::float_d sigma, ntg::float_d radius_factor) { @@ -120,26 +122,27 @@ // // Note: the integral is not equal to 1 (discrete grid and 0 outside // radius_factor * sigma). You should use kernel(sigma, radius_factor). - static w_window2dntg::float_d + static image2dntg::float_d kernel_values(ntg::float_d sigma, ntg::float_d radius_factor) { precondition(sigma > 0.); precondition(radius_factor >= 0.); - w_window2dntg::float_d w; - const int size = int(sigma * radius_factor); + image2dntg::float_d w = image2dntg::float_d(size * 2 + 1, + size * 2 + 1); + const ntg::float_d inv_sigma_sigma_pi_2 = 1. / (sigma * sigma * M_PI * 2.); - - for (int x = -size; x <= +size; ++x) - for (int y = -size; y <= +size; ++y) + for (int x = -size ; x <= size; ++x) + for (int y = -size ; y <= size; ++y) if (x * x + y * y <= size * size) - w.add(x, y, inv_sigma_sigma_pi_2 + w(x + size, y + size) = inv_sigma_sigma_pi_2 * exp(- (x * x + y * y) / ( 2. * sigma * sigma) - ) ); + else + w(x + size, y + size) = 0; return w; } }; @@ -148,12 +151,12 @@ template<> struct gaussian_kernel<3> { - typedef w_window3dntg::float_d ret; + typedef image3dntg::float_d ret; enum {dim = 3};
//! Return a discrete Gaussian kernel, that is equal to zero at a // distance of radius_factor * sigma. - static w_window3dntg::float_d + static image3dntg::float_d kernel(ntg::float_d sigma, ntg::float_d radius_factor) { @@ -168,16 +171,18 @@ // // Note: the integral is not equal to 1 (discrete grid and 0 outside // radius_factor * sigma). You should use kernel(sigma, radius_factor). - static w_window3dntg::float_d + static image3dntg::float_d kernel_values(ntg::float_d sigma, ntg::float_d radius_factor) { precondition(sigma > 0.); precondition(radius_factor >= 0.);
- w_window3dntg::float_d w; - const int size = int(sigma * radius_factor); + image3dntg::float_d w(size * 2 + 1, + size * 2 + 1, + size * 2 + 1); + const ntg::float_d k = 1. / (sigma * sigma * sigma * sqrt((M_PI * 2.) * (M_PI * 2.) * (M_PI * 2.))); @@ -186,9 +191,11 @@ for (int y = -size; y <= +size; ++y) for (int z = -size; z <= +size; ++z) if (x * x + y * y + z * z <= size) - w.add(x, y, z, k * + w(x + size, y + size, z + size) = k * exp(-(x * x + y * y + z * z) - ) / (2. * sigma * sigma)); + ) / (2. * sigma * sigma); + else + w(x + size, y + size, z + size) = 0; return w; } }; Index: olena/oln/convol/fast_convolution.hh --- olena/oln/convol/fast_convolution.hh Mon, 14 Jun 2004 09:04:45 +0200 odou_s () +++ olena/oln/convol/fast_convolution.hh Mon, 14 Jun 2004 07:40:15 +0200 odou_s (oln/r/12_fast_convo 644) @@ -0,0 +1,173 @@ +// Copyright (C) 2004 EPITA Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 59 Temple Place - Suite 330, Boston, +// MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + + +#ifndef OLENA_CONVOL_FAST_CONVOLUTION_HH__ +# define OLENA_CONVOL_FAST_CONVOLUTION_HH__ + +# include <oln/basics.hh> +# include <oln/basics2d.hh> +# include <ntg/all.hh> +# include <mlc/cmp.hh> +# include <mlc/array/all.hh> +# include <oln/transforms/fft.hh> +# include <oln/morpher/piece_morpher.hh> + +namespace oln { + + /*! \brief Algorithms related to convolution. + */ + namespace convol { + + /*! \brief Convolution algorithms. + */ + namespace fast { + + /*! + ** \brief Perform a convolution of two images. + ** + ** \param DestValue Data type of the output image you want. + ** \param I Exact type of the input image. + ** \param J Exact type of the input image (convolution kernel). + ** + ** \arg input The image to process. + ** \arg k The kernel to convolve with. + ** + ** \todo FIXME: the kernel could be bigger than the image. + ** \todo FIXME: supports only 2 dimensions (like the fft). + ** + ** The algorithm is just the convolution theorem application. + ** + ** This example compute a fast gaussian convolution : + ** \code + ** #include <oln/basics2d.hh> + ** #include <oln/convol/slow_gaussian.hh> + ** #include <oln/convol/fast_convolution.hh> + ** + ** using namespace oln; + ** using namespace ntg; + ** + ** int main() { + ** image2d<int_u8> src(IMG_IN "lena.pgm"); + ** float_d sigma = 2.5; + ** float_d radius = 3; + ** image2d<float_d> k = convol::slow::gaussian_kernel<2>::kernel(sigma, radius); + ** image2d<float_d> f_src(src.size()); + ** oln_iter_type_(image2d<float_d>) i(src); + ** for_all(i) + ** f_src[i] = float_d(src[i]); + ** image2d<float_d> tmp = convol::fast::convolve<float_d>(f_src, k); + ** for_all(i) + ** src[i] = int_u8(tmp[i]); + ** save(src, IMG_OUT "oln_convol_fast_convolve.pgm"); + ** } + ** \endcode + ** \image html lena_pgm.png + ** \image latex lena_pgm.png + ** => + ** \image html oln_convol_fast_convolve.pgm + ** \image latex oln_convol_fast_convole.pgm + ** + */ + template<class DestValue, class I, class J> + typename mute<I, DestValue>::ret + convolve(const abstract::image< I >& input, + const abstract::image< J >& k) + { + mlc::eq<I::dim, J::dim>::ensure(); + mlc::eq<I::dim, 2>::ensure(); + assert(input.npoints() > k.npoints()); + + // We compute k with a size of input (k is centered in big_k). + image2d<oln_value_type(J)> big_k(input.size()); +#define CENTER_DST(I) \ +((I) % 2 ? (I) / 2 + 1 : (I) / 2) +#define CENTER_SRC(I) \ +((I) % 2 ? (I) / 2 : ((I) - 1) / 2) + typedef morpher::piece_morpher< image2d<oln_value_type(J)> > piece_t; + piece_t piece_k(big_k, + dpoint2d(CENTER_DST(big_k.size().nrows()) - + CENTER_SRC(k.size().nrows()) - 1, + CENTER_DST(big_k.size().ncols()) - + CENTER_SRC(k.size().ncols()) - 1), + oln::image2d_size(k.size().nrows(), + k.size().ncols(), + big_k.border())); + oln_iter_type(piece_t) i_k(piece_k); + for_all(i_k) + piece_k[i_k] = k[i_k]; + + transforms::fft<oln_value_type(I), ntg::rect> tr_input(input.exact()); + transforms::fft<oln_value_type(J), ntg::rect> tr_k(big_k.exact()); + + tr_input.transform(); + typename mute<I, ntg::cplx<ntg::rect, ntg::float_d> >::ret& + Input = tr_input.transformed_image(); + const typename mute<J, ntg::cplx<ntg::rect, ntg::float_d> >::ret + K = tr_k.transform(); + + oln_iter_type(I) i_input(Input); + for_all(i_input) { + Input[i_input] *= K[i_input]; + // Scale. + Input[i_input] *= Input.size().nrows() * Input.size().ncols(); + } + + typename mute<I, DestValue>::ret output = tr_input.shift_transform_inv(); + + return output; + } + + /*! + ** \brief Perform a convolution of an image and a window. + ** + ** \param DestValue Data type of the output image you want. + ** \param I Exact type of the input image. + ** \param Info Informations about the array. + ** \param Win Data type of the array. + ** + ** \arg input The image to process. + ** \arg arr The array to convolve with. + ** + ** \todo FIXME: don't use array1d, ..., arraynd. + */ + template<class DestValue, class I, class Info, class Win> + typename mute<I, DestValue>::ret + convolve(const abstract::image < I >& input, + const mlc::array2d<Info, Win >& arr) + { + return convolve<DestValue>(input, static_cast< image2d<Win> >(arr)); + // FIXME: Should be abstract::w_window<T_arr>. Adjust #include once done. + } + + } // end namespace fast + + } // end namespace convol + +} // end namespace oln + +#endif // OLENA_CONVOL_FAST_CONVOLUTION_HH__ Index: olena/tests/convol/tests/fast_convol --- olena/tests/convol/tests/fast_convol Mon, 14 Jun 2004 09:04:45 +0200 odou_s () +++ olena/tests/convol/tests/fast_convol Mon, 14 Jun 2004 07:59:18 +0200 odou_s (oln/r/13_fast_convo 644) @@ -0,0 +1,33 @@ +#include "data.hh" +#include "check.hh" + +#include <oln/basics2d.hh> +#include <oln/convol/slow_gaussian.hh> +#include <oln/convol/fast_convolution.hh> +#include <oln/utils/md5.hh> + +using namespace oln; +using namespace ntg; + +int main() { + oln::utils::key::value_type data_key[] = + {0x7a, 0x42, 0xc0, 0xa5, 0xec, 0xc7, 0x14, 0xa, 0xc7, + 0x21, 0xd9, 0x1f, 0xdb, 0xfa, 0x54, 0xb9}; + oln::utils::key key(data_key); + + image2d<int_u8> src(rdata("lena.pgm")); + float_d sigma = 2.5; + float_d radius = 3; + image2d<float_d> k = convol::slow::gaussian_kernel<2>::kernel(sigma, radius); + image2d<float_d> f_src(src.size()); + oln_iter_type_(image2d<float_d>) i(src); + for_all(i) + f_src[i] = float_d(src[i]); + + image2d<float_d> tmp = convol::fast::convolve<float_d>(f_src, k); + + for_all(i) + src[i] = tmp[i]; + if (oln::utils::md5(src) != key) + return false; +}