fast_gaussian.hxx

00001 // Copyright (C) 2001, 2002, 2003, 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, 59 Temple Place - Suite 330, Boston,
00016 // MA 02111-1307, 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 // Gaussian filter implementation from
00030 // "Recursively implementing the gaussian and its derivatives"
00031 // Deriche 93 INRIA REPORT
00032 //
00033 
00034 #include <ntg/utils/cast.hh>
00035 #include <oln/convol/fast_gaussian_coefficient.hh>
00036 #include <vector>
00037 
00038 namespace oln {
00039   namespace convol {
00040     namespace fast {
00043       namespace internal {
00044 
00065         template <class WorkType, class FloatType, class I>
00066         void
00067         recursivefilter_(I& image,
00068                          const recursivefilter_coef_<FloatType>& c,
00069                          const oln_point_type(I)& start,
00070                          const oln_point_type(I)& finish,
00071                          coord len,
00072                          const oln_dpoint_type(I)& d)
00073         {
00074           std::vector<WorkType> tmp1(len);
00075           std::vector<WorkType> tmp2(len);
00076 
00077           // The fourth degree approximation implies to have a special
00078           // look on the four first points we consider that there is
00079           // no signal before 0 (to be discussed)
00080 
00081           // --
00082           // Causal part
00083 
00084           tmp1[0] =
00085             c.n[0]*image[start];
00086 
00087           tmp1[1] =
00088               c.n[0]*image[start + d]
00089             + c.n[1]*image[start]
00090             - c.d[1]*tmp1[0];
00091 
00092           tmp1[2] =
00093               c.n[0]*image[start + d + d]
00094             + c.n[1]*image[start + d]
00095             + c.n[2]*image[start]
00096             - c.d[1]*tmp1[1]
00097             - c.d[2]*tmp1[0];
00098 
00099           tmp1[3] =
00100               c.n[0]*image[start + d + d + d]
00101             + c.n[1]*image[start + d + d]
00102             + c.n[2]*image[start + d]
00103             + c.n[3]*image[start]
00104             - c.d[1]*tmp1[2] - c.d[2]*tmp1[1]
00105             - c.d[3]*tmp1[0];
00106 
00107           oln_point_type(I) current(start + d + d + d + d);
00108           for (coord i = 4; i < len; ++i)
00109             {
00110               tmp1[i] =
00111                   c.n[0]*image[current]
00112                 + c.n[1]*image[current - d]
00113                 + c.n[2]*image[current - d - d]
00114                 + c.n[3]*image[current - d - d - d]
00115                 - c.d[1]*tmp1[i - 1] - c.d[2]*tmp1[i - 2]
00116                 - c.d[3]*tmp1[i - 3] - c.d[4]*tmp1[i - 4];
00117               current += d;
00118             }
00119 
00120           // Non causal part
00121 
00122           tmp2[len - 1] = 0;
00123 
00124           tmp2[len - 2] =
00125             c.nm[1]*image[finish];
00126 
00127           tmp2[len - 3] =
00128               c.nm[1]*image[finish - d]
00129             + c.nm[2]*image[finish]
00130             - c.dm[1]*tmp2[len-2];
00131 
00132           tmp2[len - 4] =
00133               c.nm[1]*image[finish - d - d]
00134             + c.nm[2]*image[finish - d]
00135             + c.nm[3]*image[finish]
00136             - c.dm[1]*tmp2[len-3]
00137             - c.dm[2]*tmp2[len-2];
00138 
00139           current = finish - d - d - d ;
00140 
00141           for (coord i = len - 5; i >= 0; --i)
00142             {
00143               tmp2[i] =
00144                   c.nm[1]*image[current]
00145                 + c.nm[2]*image[current + d]
00146                 + c.nm[3]*image[current + d + d]
00147                 + c.nm[4]*image[current + d + d + d]
00148                 - c.dm[1]*tmp2[i+1] - c.dm[2]*tmp2[i+2]
00149                 - c.dm[3]*tmp2[i+3] - c.dm[4]*tmp2[i+4];
00150               current -= d;
00151             }
00152 
00153           // Combine results from causal and non-causal parts.
00154 
00155           current = start;
00156           for (coord i = 0; i < len; ++i)
00157             {
00158               image[current] = ntg::cast::force<oln_value_type(I)>(tmp1[i] + tmp2[i]);
00159               current += d;
00160             }
00161         }
00162 
00168         template<unsigned dim>
00169         struct gaussian_ {};
00170 
00171 
00182         template<>
00183         struct gaussian_<1>
00184         {
00185           template <class I, class F> static
00186           void
00187           doit(abstract::image_with_dim<1, I>& img, const F& coef)
00188           {
00189 
00190             // Apply on columns.
00191             recursivefilter_<float>(img, coef,
00192                                     oln_point_type(I)(-img.border()),
00193                                     oln_point_type(I)(img.ncols() - 1 + img.border()),
00194                                     img.ncols() + 2 * img.border(),
00195                                     oln_dpoint_type(I)(1));
00196           }
00197         };
00198 
00199 
00210         template<>
00211         struct gaussian_<2>
00212         {
00213           template <class I, class F> static
00214           void
00215           doit(abstract::image_with_dim<2, I>& img, const F& coef)
00216           {
00217             // Apply on rows.
00218             for (coord j = 0; j < img.ncols(); ++j)
00219               recursivefilter_<float>(img, coef,
00220                                       oln_point_type(I)(-img.border(), j),
00221                                       oln_point_type(I)(img.nrows() - 1 + img.border(), j),
00222                                       img.nrows() + 2 * img.border(),
00223                                       oln_dpoint_type(I)(1, 0));
00224 
00225             // Apply on columns.
00226             for (coord i = 0; i < img.nrows(); ++i)
00227               recursivefilter_<float>(img, coef,
00228                                       oln_point_type(I)(i, -img.border()),
00229                                       oln_point_type(I)(i, img.ncols() - 1 + img.border()),
00230                                       img.ncols() + 2 * img.border(),
00231                                       oln_dpoint_type(I)(0, 1));
00232           }
00233         };
00234 
00245         template<>
00246         struct gaussian_<3>
00247         {
00248           template <class I, class F> static
00249           void
00250           doit(abstract::image_with_dim<3, I>& img, const F& coef)
00251           {
00252             // Apply on slices.
00253             for (coord j = 0; j < img.nrows(); ++j)
00254               for (coord k = 0; k < img.ncols(); ++k)
00255                 recursivefilter_<float>(img, coef,
00256                                         oln_point_type(I)(-img.border(), j, k),
00257                                         oln_point_type(I)(img.nslices() - 1 + img.border(), j, k),
00258                                         img.ncols() + 2 * img.border(),
00259                                         oln_dpoint_type(I)(1, 0, 0));
00260 
00261             // Apply on rows.
00262             for (coord i = 0; i < img.nslices(); ++i)
00263               for (coord k = 0; k < img.ncols(); ++k)
00264                 recursivefilter_<float>(img, coef,
00265                                         oln_point_type(I)(i, -img.border(), k),
00266                                         oln_point_type(I)(i, img.nrows() - 1 + img.border(), k),
00267                                         img.nrows() + 2 * img.border(),
00268                                         oln_dpoint_type(I)(0, 1, 0));
00269 
00270             // Apply on columns.
00271             for (coord i = 0; i < img.nslices(); ++i)
00272               for (coord j = 0; j < img.nrows(); ++j)
00273                 recursivefilter_<float>(img, coef,
00274                                         oln_point_type(I)(i, j, -img.border()),
00275                                         oln_point_type(I)(i, j, img.ncols() - 1 + img.border()),
00276                                         img.ncols() + 2 * img.border(),
00277                                         oln_dpoint_type(I)(0, 0, 1));
00278           }
00279         };
00280 
00295         template <class C, class B, class I, class F, class BE>
00296         typename mute<I, typename convoutput<C,B,oln_value_type(I)>::ret>::ret
00297         gaussian_common_(const convert::abstract::conversion<C,B>& c,
00298                          const abstract::image<I>& in,
00299                          const F& coef,
00300                          ntg::float_s sigma,
00301                          const abstract::behavior<BE> &behavior)
00302         {
00303           typename mute<I, ntg::float_s>::ret work_img(in.size());
00304 
00305           oln_iter_type(I) it(in);
00306           for_all(it)
00307             work_img[it] = ntg::cast::force<ntg::float_s>(in[it]);
00308 
00309           // On tiny sigma, Derich algorithm doesn't work.
00310           // It is the same thing that to convolve with a Dirac.
00311           if (sigma > 0.006)
00312             {
00313               /* FIXME: relation between sigma and the border shouldn't
00314                  be linear, so when sigma is big enougth, the signal may
00315                  be parasitized by the non signal values.
00316               */
00317               behavior.adapt_border(work_img, ntg::cast::round<coord>(5 * sigma));
00318 
00319               gaussian_<I::dim>::doit(work_img, coef);
00320             }
00321           /* Convert the result image to the user-requested datatype.
00322              FIXME: We are making an unnecessary copy in case the
00323              user expects a ntg::float_s image.  */
00324           typename mute<I, typename convoutput<C,B,oln_value_type(I)>::ret>::ret
00325             out_img(in.size());
00326 
00327           for_all(it)
00328             out_img[it] = c(work_img[it]);
00329 
00330           return out_img;
00331         }
00332 
00333       } // internal
00334 
00335       template <class C, class B, class I, class BE>
00336       typename mute<I, typename convoutput<C,B,oln_value_type(I)>::ret>::ret
00337       gaussian(const convert::abstract::conversion<C,B>& c,
00338                const abstract::image<I>& in, ntg::float_s sigma,
00339                const abstract::behavior<BE> &behavior)
00340       {
00341         internal::recursivefilter_coef_<float>
00342           coef(1.68f, 3.735f,
00343                1.783f, 1.723f,
00344                -0.6803f, -0.2598f,
00345                0.6318f, 1.997f,
00346                sigma,
00347                internal::recursivefilter_coef_<float>::DericheGaussian);
00348 
00349         return internal::gaussian_common_(c, in, coef, sigma, behavior);
00350       }
00351 
00352       template <class C, class B, class I, class BE>
00353       typename mute<I, typename convoutput<C,B,oln_value_type(I)>::ret>::ret
00354       gaussian_derivative(const convert::abstract::conversion<C,B>& c,
00355                           const abstract::image<I>& in, ntg::float_s sigma,
00356                           const abstract::behavior<BE> &behavior)
00357       {
00358         internal::recursivefilter_coef_<float>
00359           coef(-0.6472f, -4.531f,
00360                1.527f, 1.516f,
00361                0.6494f, 0.9557f,
00362                0.6719f, 2.072f,
00363                sigma,
00364                internal::recursivefilter_coef_<float>
00365                ::DericheGaussianFirstDerivative);
00366 
00367         return internal::gaussian_common_(c, in, coef, sigma, behavior);
00368       }
00369 
00370       template <class C, class B, class I, class BE>
00371       typename mute<I, typename convoutput<C,B,oln_value_type(I)>::ret>::ret
00372       gaussian_second_derivative(const convert::abstract::conversion<C,B>& c,
00373                                  const abstract::image<I>& in, ntg::float_s sigma,
00374                                  const abstract::behavior<BE> &behavior)
00375       {
00376         internal::recursivefilter_coef_<float>
00377           coef(-1.331f, 3.661f,
00378                1.24f, 1.314f,
00379                0.3225f, -1.738f,
00380                0.748f, 2.166f,
00381                sigma,
00382                internal::recursivefilter_coef_<float>
00383                ::DericheGaussianSecondDerivative);
00384 
00385         return internal::gaussian_common_(c, in, coef, sigma, behavior);
00386       }
00387 
00388     } // fast
00389   } // convol
00390 } // oln

Generated on Thu Apr 15 20:13:09 2004 for Olena by doxygen 1.3.6-20040222