fast_morpho.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 #ifndef OLENA_MORPHO_FAST_MORPHO_HXX
00029 # define OLENA_MORPHO_FAST_MORPHO_HXX
00030 
00031 // Implementation of morphological operations from:
00032 // M. Van Droogenbroeck and H. Talbot.
00033 // "Fast computation of morphological operations with arbitrary
00034 // structuring elements". Pattern Recognition Letters,
00035 // 17(14):1451-1460, 1996.
00036 
00037 # include <mlc/is_a.hh>
00038 # include <oln/utils/histogram.hh>
00039 
00040 namespace oln {
00041   namespace morpho {
00042 
00045     namespace internal {
00046 
00056       template<class E1, class E2, class E3>
00057       void
00058       find_struct_elts(const abstract::struct_elt<E1>& se,
00059                        E2 se_add[mlc::exact<E1>::ret::dim],
00060                        E3 se_rem[mlc::exact<E1>::ret::dim])
00061       {
00062         mlc_is_a(E2, abstract::struct_elt)::ensure();
00063         mlc_is_a(E3, abstract::struct_elt)::ensure();
00064         const unsigned dim = E1::dim;
00065 
00066         // back[n] allows to move backward on coordinate `n'.
00067         oln_dpoint_type(E1) back[dim];
00068         for (unsigned n = 0; n < dim; ++n)
00069           back[n].nth(n) = -1;
00070 
00071         oln_iter_type(E1) dp(se);
00072         oln_iter_type(E1) dp_prime(se);
00073 
00074         for_all(dp)
00075           {
00076             bool add[dim];      // whether to add `dp' when moving forward
00077                                 // on coordinate `n'.
00078             bool rem[dim];      // whether to remove `dp'.
00079             for (unsigned n = 0; n < dim; ++n)
00080               add[n] = rem[n] = true;
00081 
00082             for_all(dp_prime)
00083               for (unsigned n = 0; n < dim; ++n)
00084                 {
00085                   if (dp_prime.cur() + back[n] == dp)
00086                     // DP_PRIME is already in SE: don't add it.
00087                     add[n] = false;
00088 
00089                   if (dp.cur() + back[n] == dp_prime)
00090                     // DP is still in SE: don't remove it.
00091                     rem[n] = false;
00092                 }
00093 
00094             for (unsigned n = 0; n < dim; ++n)
00095               {
00096                 if (add[n])
00097                   {
00098                     se_add[n].add(dp);
00099                   }
00100                 if (rem[n])
00101                   {
00102                     se_rem[n].add(dp.cur() + back[n]);
00103                   }
00104               }
00105           }
00106 
00107         for (unsigned n = 0; n < dim; ++n)
00108           postcondition(se_add[n].card() == se_rem[n].card());
00109       }
00110 
00117       template<class I, class E1, class E2, class H>
00118       // inline
00119       void
00120       hist_update(utils::abstract::histogram<H>& hist,
00121                   const abstract::non_vectorial_image<I>& input,
00122                   const oln_point_type(I)& p,
00123                   const abstract::struct_elt<E1>& se_rem,
00124                   const abstract::struct_elt<E2>& se_add)
00125       {
00126         {
00127           oln_iter_type(E1) dp(se_rem);
00128           for_all(dp)
00129             --hist[input[p + dp]];
00130         }
00131         {
00132           oln_iter_type(E2) dp(se_add);
00133           for_all(dp)
00134             ++hist[input[p + dp]];
00135         }
00136       }
00137 
00138 
00153       template<unsigned NP1,
00154                unsigned Dim,
00155                typename I,
00156                typename S,
00157                typename H,
00158                typename B,
00159                typename P,
00160                typename O>
00161       struct fast_morpho_inner {
00162 
00166         static void
00167         doit(I& input, S& size, H& hist,
00168              B* se_add, B* se_rem, B* se_add_back, B* se_rem_back,
00169              P& p, O& output, const unsigned* dims)
00170         {
00171           const unsigned N = *dims;
00172 
00173           fast_morpho_inner<NP1 + 1, Dim,
00174             I, S, H, B, P, O>::doit(input, size, hist,
00175                                     se_add, se_rem,
00176                                     se_add_back, se_rem_back, p,
00177                                     output, dims + 1);
00178           if (p.nth(N) == 0) {  // Go forward
00179             for(++p.nth(N); p.nth(N) < size.nth(N); ++p.nth(N)) {
00180               hist_update(hist, input, p, se_rem[N], se_add[N]);
00181               output[p] = hist.res();
00182               fast_morpho_inner<NP1 + 1, Dim,
00183                 I, S, H, B, P, O>::doit(input, size, hist,
00184                                         se_add, se_rem,
00185                                         se_add_back,
00186                                         se_rem_back,
00187                                         p, output, dims + 1);
00188             }
00189             --p.nth(N);
00190           } else {              // Go backward
00191             for(--p.nth(N); p.nth(N) >= 0; --p.nth(N)) {
00192               hist_update(hist, input, p, se_rem_back[N], se_add_back[N]);
00193               output[p] = hist.res();
00194               fast_morpho_inner<NP1 + 1, Dim,
00195                 I, S, H, B, P, O>::doit(input, size, hist,
00196                                         se_add, se_rem,
00197                                         se_add_back,
00198                                         se_rem_back,
00199                                         p, output, dims + 1);
00200             }
00201             ++p.nth(N);
00202           }
00203           return;
00204         }
00205       };
00206 
00207       template<unsigned Dim,
00208                typename I,
00209                typename S,
00210                typename H,
00211                typename B,
00212                typename P,
00213                typename O>
00214       struct fast_morpho_inner<Dim, Dim, I, S, H, B, P, O> {
00215         static void
00216         doit(I& input, S& size, H& hist,
00217              B* se_add, B* se_rem, B* se_add_back, B* se_rem_back,
00218              P& p, O& output, const unsigned* dims)
00219         {
00220           const unsigned N = *dims;
00221 
00222           if (p.nth(N) == 0) { // Go forward
00223             // Don't call hist_update because this would create new `dpr' and
00224             // `dpa' iterators for each points.
00225            oln_iter_type(B) dpr(se_rem[N]);
00226            oln_iter_type(B) dpa(se_add[N]);
00227             for(++p.nth(N);
00228                 p.nth(N) < size.nth(N);
00229                 ++p.nth(N)) {
00230               for_all(dpr)
00231                 --hist[input[p + dpr]];
00232               for_all(dpa)
00233                 ++hist[input[p + dpa]];
00234               output[p] = hist.res();
00235             }
00236             --p.nth(N);
00237           } else {              // Go backward
00238             // Don't call hist_update because this would create new `dpr' and
00239             // `dpa' iterators for each points.
00240            oln_iter_type(B) dpr(se_rem_back[N]);
00241            oln_iter_type(B) dpa(se_add_back[N]);
00242             for(--p.nth(N);
00243                 p.nth(N) >= 0;
00244                 --p.nth(N)) {
00245               for_all(dpr)
00246                 --hist[input[p + dpr]];
00247               for_all(dpa)
00248                 ++hist[input[p + dpa]];
00249               output[p] = hist.res();
00250             }
00251             ++p.nth(N);
00252           }
00253           return;
00254         }
00255       };
00256     } // internal
00257 
00261     template<class E>
00262     struct sort_dimensions
00263     {
00267       sort_dimensions(abstract::struct_elt<E> se[mlc::exact<E>::ret::dim])
00268         : se_(se) {}
00269 
00275       bool operator()(unsigned a, unsigned b)
00276       {
00277         return se_[a].card() > se_[b].card();
00278       }
00279 
00280     protected:
00281       abstract::struct_elt<E>* se_; 
00282     };
00283 
00314     template<class I, class E, class H>
00315     oln_concrete_type(I)
00316       fast_morpho(const abstract::non_vectorial_image<I>& input,
00317                   const abstract::struct_elt<E>& se)
00318     {
00319       enum { dim = E::dim };
00320 
00321       // prepare output
00322       oln_concrete_type(I) output(input.size());
00323       input.border_adapt_copy(se.delta());
00324 
00325       // compute delta structuring elements for forward movements
00326       E se_add[dim];
00327       E se_rem[dim];
00328       internal::find_struct_elts(se, se_add, se_rem);
00329 
00330       // compute delta structuring elements for backward movements
00331       E se_add_back[dim];
00332       E se_rem_back[dim];
00333       for (unsigned n = 0; n < dim; ++n)
00334         for (unsigned i = 0; i < se_add[n].card(); ++i)
00335         {
00336           oln_dpoint_type(I) dp = se_add[n].dp(i);
00337           dp.nth(n) += 1;
00338           se_rem_back[n].add(dp);
00339 
00340           dp = se_rem[n].dp(i);
00341           dp.nth(n) += 1;
00342           se_add_back[n].add(dp);
00343         }
00344 
00345       // Order dimensions
00346       unsigned dims[dim];
00347       for (unsigned n = 0; n < dim; ++n)
00348         dims[n] = n;
00349       sort_dimensions<E> s(se_add);
00350       std::sort(dims, dims + dim, s);
00351 
00352       const typename I::size_type size = input.size();
00353 
00354       // Initialize the histogram with the values around the first point.
00355       H hist;
00356       oln_point_type(I) p;
00357 
00358       //     oln_iter_type(E) dp(se);
00359       typename E::iter_type     dp(se);
00360       for_all(dp)
00361         ++hist[input[p + dp]];
00362 
00363       // Process the image.
00364       // ------------------
00365 
00366       output[p] = hist.res();   // First point.
00367 
00368       internal::fast_morpho_inner<1, E::dim, const I,
00369         const typename I::size_type, H,
00370         const E,oln_point_type(I),oln_concrete_type(I)>::doit(input.exact(), size, hist,
00371                                                               se_add, se_rem,
00372                                                               se_add_back, se_rem_back,
00373                                                               p, output, dims);
00374       return output;
00375     }
00376 
00377   } // morpho
00378 } // oln
00379 
00380 #endif // OLENA_MORPHO_FAST_MORPHO_HXX

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