slow_gaussian.hxx

00001 // Copyright (C) 2004  EPITA Research and Development Laboratory
00002 //
00003 // This file is part of the Olena Library.  This library is free
00004 // software; you can redistribute it and/or modify it under the terms
00005 // of the GNU General Public License version 2 as published by the
00006 // Free Software Foundation.
00007 //
00008 // This library is distributed in the hope that it will be useful,
00009 // but WITHOUT ANY WARRANTY; without even the implied warranty of
00010 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00011 // General Public License for more details.
00012 //
00013 // You should have received a copy of the GNU General Public License
00014 // along with this library; see the file COPYING.  If not, write to
00015 // the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
00016 // Boston, MA 02110-1301, USA.
00017 //
00018 // As a special exception, you may use this file as part of a free
00019 // software library without restriction.  Specifically, if other files
00020 // instantiate templates or use macros or inline functions from this
00021 // file, or you compile this file and link it with other files to
00022 // produce an executable, this file does not by itself cause the
00023 // resulting executable to be covered by the GNU General Public
00024 // License.  This exception does not however invalidate any other
00025 // reasons why the executable file might be covered by the GNU General
00026 // Public License.
00027 
00028 
00029 #ifndef SLOW_GAUSSIAN_HXX
00030 # define SLOW_GAUSSIAN_HXX
00031 # include <oln/core/image1d.hh>
00032 # include <oln/core/image2d.hh>
00033 # include <oln/core/image3d.hh>
00034 
00035 namespace oln {
00036   namespace convol {
00037     namespace slow {
00038       namespace internal {
00039         /* FIXME: The hierarchy w_window is a REAL mess.
00040            a w_window1d is not an abstract::w_window,
00041            and w_windownd does not supprot concrete_type, etc
00042         */
00043         template<class T>
00044         inline T
00045         normalise(const oln::abstract::non_vectorial_image<T> &in)
00046         {
00047           T w(in.size());
00048           ntg::float_d sum = 0.;
00049           oln_iter_type(T) i(in);
00050           for_all(i)
00051             sum += in[i];
00052           sum = 1. / sum;
00053           assert(finite(sum));
00054           for_all(i)
00055             w[i] = in[i] * sum;
00056           return w;
00057         }
00058 
00059 
00060       }// End namespace internal
00061 
00063       template<>
00064       struct gaussian_kernel<1>
00065       {
00066         typedef oln::image1d<ntg::float_d> ret;
00067         enum {dim = 1};
00068 
00070         // at a distance of radius_factor * sigma.
00071         static image1d<ntg::float_d>
00072         kernel(ntg::float_d sigma,
00073                ntg::float_d radius_factor)
00074         {
00075           precondition(sigma > 0.);
00076           precondition(radius_factor >= 0.);
00077           return internal::normalise(kernel_values(sigma, radius_factor));
00078         }
00079 
00081         //
00082         // Note: the integral is not equal to 1 (discrete grid and 0 outside
00083         // radius_factor * sigma). You should use kernel(sigma, radius_factor).
00084         static image1d<ntg::float_d>
00085         kernel_values(ntg::float_d sigma,
00086                       ntg::float_d radius_factor)
00087         {
00088           precondition(sigma > 0.);
00089           precondition(radius_factor >= 0.);
00090 
00091           const int size = int(sigma * radius_factor);
00092           image1d<ntg::float_d> w(size * 2 + 1);
00093 
00094           const ntg::float_d inv_sigma_sqrt_2pi
00095             = 1. / (sigma * sqrt(M_PI * 2.));
00096           for (int x = -size; x <= size; ++x)
00097             w(x + size) = inv_sigma_sqrt_2pi * exp(-x * x /(2 * sigma * sigma));
00098           return w;
00099         }
00100       };
00101 
00103       template<>
00104       struct gaussian_kernel<2>
00105       {
00106         typedef image2d<ntg::float_d> ret;
00107         enum {dim = 2};
00108 
00110         // distance of radius_factor * sigma.
00111         static image2d<ntg::float_d>
00112         kernel(ntg::float_d sigma,
00113                ntg::float_d radius_factor)
00114         {
00115           precondition(sigma > 0.);
00116           precondition(radius_factor >= 0.);
00117 
00118           return internal::normalise(kernel_values(sigma, radius_factor));
00119         }
00120 
00122         //
00123         // Note: the integral is not equal to 1 (discrete grid and 0 outside
00124         // radius_factor * sigma). You should use kernel(sigma, radius_factor).
00125         static image2d<ntg::float_d>
00126         kernel_values(ntg::float_d sigma,
00127                ntg::float_d radius_factor)
00128         {
00129           precondition(sigma > 0.);
00130           precondition(radius_factor >= 0.);
00131           const int size = int(sigma * radius_factor);
00132           image2d<ntg::float_d> w = image2d<ntg::float_d>(size * 2 + 1,
00133                                                           size * 2 + 1);
00134 
00135           const ntg::float_d inv_sigma_sigma_pi_2 = 1. / (sigma * sigma *
00136                                                           M_PI * 2.);
00137           for (int x = -size ; x <= size; ++x)
00138             for (int y = -size ; y <= size; ++y)
00139               if (x * x + y * y <= size * size)
00140                 w(x + size, y + size) = inv_sigma_sigma_pi_2
00141                   *  exp(- (x * x +     y * y)
00142                          / ( 2. * sigma * sigma)
00143                          );
00144               else
00145                 w(x + size, y + size) = 0;
00146           return w;
00147         }
00148       };
00149 
00151       template<>
00152       struct gaussian_kernel<3>
00153       {
00154         typedef image3d<ntg::float_d> ret;
00155         enum {dim = 3};
00156 
00158         // distance of radius_factor * sigma.
00159         static image3d<ntg::float_d>
00160         kernel(ntg::float_d sigma,
00161                     ntg::float_d radius_factor)
00162         {
00163           precondition(sigma > 0.);
00164           precondition(radius_factor >= 0.);
00165 
00166           return internal::normalise(kernel_values(sigma, radius_factor));
00167         }
00168 
00169 
00171         //
00172         // Note: the integral is not equal to 1 (discrete grid and 0 outside
00173         // radius_factor * sigma). You should use kernel(sigma, radius_factor).
00174         static image3d<ntg::float_d>
00175         kernel_values(ntg::float_d sigma,
00176                ntg::float_d radius_factor)
00177         {
00178           precondition(sigma > 0.);
00179           precondition(radius_factor >= 0.);
00180 
00181           const int size = int(sigma * radius_factor);
00182           image3d<ntg::float_d> w(size * 2 + 1,
00183                                   size * 2 + 1,
00184                                   size * 2 + 1);
00185 
00186           const ntg::float_d k = 1. / (sigma * sigma * sigma *
00187                                        sqrt((M_PI * 2.) * (M_PI * 2.) *
00188                                             (M_PI * 2.)));
00189 
00190           for (int x = -size; x <= +size; ++x)
00191             for (int y = -size; y <= +size; ++y)
00192               for (int z = -size; z <= +size; ++z)
00193                 if (x * x + y * y + z * z <= size)
00194                   w(x + size, y + size, z + size) = k *
00195                     exp(-(x * x + y * y + z * z)
00196                         ) / (2. * sigma * sigma);
00197                 else
00198                   w(x + size, y + size, z + size) = 0;
00199           return w;
00200         }
00201       };
00202 
00203     }//End namespace slow
00204   }// End namespace convol
00205 }// End namespace oln
00206 #endif // end SLOW_GAUSSIAN_HXX

Generated on Tue Feb 20 20:20:32 2007 for Olena by  doxygen 1.5.1