dmap.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_TOPO_DMAP_HXX
00029 # define OLENA_TOPO_DMAP_HXX
00030 
00031 # include <mlc/array/2d.hh>
00032 # include <ntg/float.hh>
00033 # include <oln/arith/ops.hh>
00034 
00035 namespace oln {
00036 
00037   namespace topo {
00038 
00039 //     using mlc::lbrk;
00040 //     using mlc::end;
00041 //     using mlc::x;
00042 
00043     template <class T>
00044     chamfer<T>::chamfer(const w_window2d<T>& fwd,
00045                         const w_window2d<T>& bkd,
00046                         float              coef) :
00047       fwd(fwd),
00048       bkd(bkd),
00049       coef(coef)
00050     {}
00051 
00052     template <class T>
00053     coord
00054     chamfer<T>::delta() const
00055     {
00056       coord d = fwd.delta();
00057       invariant(bkd.delta() == d);
00058       return d;
00059     }
00060 
00061     // mk_chamfer...
00062     // FIXME: this is highly not thread safe !
00063     template<int d10, int d11> inline
00064     const chamfer<int>&
00065     mk_chamfer_3x3(float coef)
00066     {
00067       static const w_window2d<int> w_win_fwd = ( mlc::ints_2d =
00068                                                d11,      d10, d11, mlc::lbrk,
00069                                                d10, mlc::x(),   0, end );
00070       static const w_window2d<int> w_win_bkd = ( mlc::ints_2d =
00071                                                  0, mlc::x(),  d10, mlc::lbrk,
00072                                                d11,      d10,  d11, end );
00073       static const chamfer<int> ch_ = chamfer<int>(w_win_fwd, w_win_bkd, coef);
00074       return ch_;
00075     }
00076 
00077     inline // FIXME: how to define float by parameters?
00078     const chamfer<float>&
00079     mk_chamfer_3x3(float d10, float d11)
00080       // FIXME: add (?)  , float coef = 1.f
00081     {
00082       static const w_window2d<float> w_win_fwd = ( mlc::floats_2d =
00083                                                  d11, d10, d11, mlc::lbrk,
00084                                                  d10, mlc::x(), 0.f, end );
00085       static const w_window2d<float> w_win_bkd = ( mlc::floats_2d =
00086                                                  0.f, mlc::x(),  d10, mlc::lbrk,
00087                                                  d11, d10,  d11, end );
00088       static const chamfer<float> ch_ =
00089         chamfer<float>(w_win_fwd, w_win_bkd, 1.f);
00090       return ch_;
00091     }
00092 
00093     template<int d10, int d11, int d21> inline
00094     const chamfer<int>&
00095     mk_chamfer_5x5(float coef)
00096     {
00097       static const w_window2d<int> w_win_fwd = ( mlc::ints_2d =
00098                                                  0, d21,        0, d21,   0, mlc::lbrk,
00099                                                d21, d11,      d10, d11, d21,
00100                                                  0, d10, mlc::x(),   0,   0, end );
00101       static const w_window2d<int> w_win_bkd = ( mlc::ints_2d =
00102                                                  0,   0, mlc::x(), d10,   0, mlc::lbrk,
00103                                                d21, d11,      d10, d11, d21,
00104                                                  0, d21,        0, d21,   0, end );
00105       static const chamfer<int> ch_ = chamfer<int>(w_win_fwd, w_win_bkd, coef);
00106       return ch_;
00107     }
00108 
00109     inline
00110     const chamfer<float>&
00111     mk_chamfer_5x5(float d10, float d11, float d21)
00112     {
00113       const float O = 0.f;
00114       static const w_window2d<float> w_win_fwd = ( mlc::floats_2d =
00115                                                  O,   d21,        O, d21,   O, mlc::lbrk,
00116                                                  d21, d11,      d10, d11, d21,
00117                                                  O,   d10, mlc::x(),   O,   O, end );
00118       static const w_window2d<float> w_win_bkd = ( mlc::floats_2d =
00119                                                  O,     O, mlc::x(), d10,   O, mlc::lbrk,
00120                                                  d21, d11,      d10, d11, d21,
00121                                                  O,   d21,        O, d21,   O, end );
00122       static const chamfer<float> ch_ =
00123         chamfer<float>(w_win_fwd, w_win_bkd, 1.f);
00124       return ch_;
00125     }
00126 
00127     // REF: B.J.H. Verwer, Local distances for distance transformations
00128     // in two and three dimensions, Pattern Recognition Letters 12 (1991) 671-682
00129 
00130     // unbiased minimal mean square error for integer local distances (Table 5)
00131 # define oln_topo_chamfer2_(Name, I, J, D, E) \
00132     inline const chamfer<int>& Name##_##I##_##J()               \
00133      {                                                          \
00134        static const chamfer<int> tmp =                          \
00135           mk_chamfer_##D##x##D< I, J >(E);                      \
00136        return tmp;                                              \
00137      }
00138 
00139 # define oln_topo_chamfer3_(Name, I, J, K, D, E)                \
00140     inline const chamfer<int>& Name##_##I##_##J##_##K()         \
00141     {                                                           \
00142       static const chamfer<int> tmp =                           \
00143          mk_chamfer_##D##x##D< I, J, K >(E);                    \
00144       return tmp;                                               \
00145     }
00146 
00147     oln_topo_chamfer2_(chamfer, 1,   1,  3, 0.9003);
00148     oln_topo_chamfer2_(chamfer, 1,   2,  3, 1.2732);
00149     oln_topo_chamfer2_(chamfer,  2,   3,  3, 2.1736);
00150     oln_topo_chamfer2_(chamfer,  5,   7,  3, 5.2474);
00151     oln_topo_chamfer2_(chamfer, 12,  17,  3, 12.6684);
00152 
00153     inline const chamfer<int>&
00154     chessboard()
00155     {
00156       return chamfer_1_1();
00157     }
00158 
00159     inline const chamfer<int>&
00160     cityblock()
00161     {
00162       return chamfer_1_2();
00163     }
00164 
00165     oln_topo_chamfer3_(chamfer, 4,  6, 9, 5, 4.1203);
00166     oln_topo_chamfer3_(chamfer, 5,  7, 11, 5, 5.0206);
00167     oln_topo_chamfer3_(chamfer, 9,  13, 20, 5, 9.1409);
00168     oln_topo_chamfer3_(chamfer, 16, 23, 36, 5, 16.3351);
00169 
00170     inline const chamfer<float>& best_set_3x3()
00171     { return mk_chamfer_3x3(0.9481, 1.3408); }
00172     inline const chamfer<float>& best_set_5x5()
00173     { return mk_chamfer_5x5(0.9801, 1.4060, 2.2044); }
00174 
00175     // maximum absolute error for integer local distances (Table 2)
00176     oln_topo_chamfer2_(mchamfer, 1, 1, 3, 0.8536);
00177     oln_topo_chamfer2_(mchamfer, 1, 2, 3, 1.2071);
00178     oln_topo_chamfer2_(mchamfer, 2, 3, 3, 2.1180);
00179     oln_topo_chamfer2_(mchamfer, 5, 7, 3, 5.1675);
00180     oln_topo_chamfer2_(mchamfer, 12, 17, 3, 12.5000);
00181 
00182     inline const chamfer<int>& mchessboard()    { return mchamfer_1_1(); }
00183     inline const chamfer<int>& mcityblock()     { return mchamfer_1_2(); }
00184 
00185     oln_topo_chamfer3_(mchamfer, 4,  6,  9, 5, 4.1213);
00186     oln_topo_chamfer3_(mchamfer, 5,  7, 11, 5, 5.0092);
00187     oln_topo_chamfer3_(mchamfer, 9, 13, 20, 5, 9.0819);
00188     oln_topo_chamfer3_(mchamfer, 17, 24, 38, 5, 17.2174);
00189 
00190     inline const chamfer<float>& mbest_set_3x3() {
00191       const float coef = 1.0412;
00192       return mk_chamfer_3x3(1/coef, sqrt(2.f)/coef);
00193     }
00194     inline const chamfer<float>& mbest_set_5x5() {
00195       const float coef = 1.0137;
00196       return mk_chamfer_5x5(1/coef, sqrt(2.f)/coef, sqrt(5.f)/coef);
00197     }
00198 
00199 # undef oln_topo_chamfer2_
00200 # undef oln_topo_chamfer3_
00201 
00202     template <class T, class T2>
00203     dmap<T, T2>::dmap(const image2d_size&  size,
00204                       const chamfer<T2>& ch) :
00205       imap_(size),
00206       ch_(ch)
00207     {
00208       // FIXME: if T is float then precondition(ch.coef == 1.f)
00209     }
00210 
00211     template <class T, class T2>
00212     template <class V>
00213     void
00214     dmap<T, T2>::compute(const image2d<V>&      input,
00215                          float                  infty)
00216     {
00217       image2d<point_type> dummy(input.size());
00218       compute(input, dummy, infty);
00219     }
00220 
00221     template <class T, class T2>
00222     template <class V>
00223     void dmap<T, T2>::compute(const image2d<V>&     input,
00224                               image2d<point_type>&  nearest_point_map,
00225                               float                 infty)
00226     {
00227       precondition(input.size() == imap_.size());
00228       if (infty == 0.f)
00229         {
00230           inFty_ = ntg_max_val(T);
00231           infTy_ = ntg_max_val(T);
00232         }
00233       else
00234         {
00235           inFty_ = infty;
00236           infTy_ = T(infty); // FIXME: use ceil if T is integer!
00237         }
00238 
00239       // init
00240       {
00241         typename image2d<V>::iter_type p(input);
00242         for (p = begin; p != end; ++p)
00243           if (input[p] != ntg_zero_val(V))
00244             {
00245               imap_[p] = T(0);
00246               nearest_point_map[p] = p;
00247             }
00248           else
00249             imap_[p] = infTy_;
00250         imap_.border_adapt_copy(ch_.delta()); // FIXME: this is geodesic only!
00251       }
00252 
00253       // fwd
00254       {
00255         typename image2d<V>::fwd_iter_type p(input);
00256         for (p = begin; p != end; ++p)
00257           {
00258             if (imap_[p] == T(0))
00259               continue;
00260             T min = imap_[p];
00261             for (unsigned i = 0; i < ch_.fwd.card(); ++i)
00262               {
00263                 point_type q = p + ch_.fwd.dp(i);
00264                 if (imap_[q] == infTy_) // FIXME: || imap_[q] >= min
00265                   continue;
00266                 if (imap_[q] + ch_.fwd.w(i) < min)
00267                   {
00268                     nearest_point_map[p] = nearest_point_map[q];
00269                     min = imap_[q] + ch_.fwd.w(i);
00270                   }
00271               }
00272             imap_[p] = min;
00273           }
00274       }
00275 
00276       // bkd
00277       {
00278         typename image2d<V>::bkd_iter_type p(input);
00279         for_all(p)
00280           {
00281             if (imap_[p] == T(0))
00282               continue;
00283             T min = imap_[p];
00284             for (unsigned i = 0; i < ch_.bkd.card(); ++i)
00285               {
00286                 point_type q = p + ch_.bkd.dp(i);
00287                 if (imap_[q] == infTy_) // FIXME: || imap_[q] >= min
00288                   continue;
00289                 if (imap_[q] + ch_.bkd.w(i) < min)
00290                   {
00291                     nearest_point_map[p] = nearest_point_map[q];
00292                     min = imap_[q] + ch_.bkd.w(i);
00293                   }
00294               }
00295             imap_[p] = min;
00296           }
00297       }
00298     }
00299 
00300     template <class T, class T2>
00301     const image2d<T>&
00302     dmap<T, T2>::imap() const
00303     {
00304       return imap_;
00305     }
00306 
00307     template <class T, class T2>
00308     image2d<float>
00309     dmap<T, T2>::to_image() const
00310     {
00311       // FIXME: if T is float, call invariant(ch_.coef == 1.f);
00312       // and then return imap();
00313       // otherwise:     return arith::div(imap_, ch_.coef);
00314       image2d<float> output(imap_.size());
00315       typename image2d<float>::iter_type p(imap_);
00316       for_all(p)
00317         output[p] = (imap_[p] == infTy_ ?
00318                      inFty_ :
00319                      imap_[p] / ch_.coef);
00320       return output;
00321     }
00322 
00323     template <class T, class T2>
00324     const T&
00325     dmap<T, T2>::operator[](const point_type& p) const
00326     {
00327       return imap_[p] / ch_.coef;
00328     }
00329 
00330     template <class T, class T2>
00331     const T&
00332     dmap<T, T2>::operator()(coord row, coord col) const
00333     {
00334       return imap_(row, col) / ch_.coef;
00335     }
00336 
00337     inline float
00338     euclidian_dist2(const point2d& p1, const point2d& p2)
00339     {
00340       float dr = p1.row() - p2.row();
00341       float dc = p1.col() - p2.col();
00342       return dr * dr + dc * dc;
00343     }
00344 
00345     // FIXME: why abstract::image!
00346 
00347     template <class I>
00348     image2d<float>
00349     exact_dmap(const abstract::image<I>& input)
00350     {
00351       image2d<float> output(input.size());
00352       image2d<float>::fwd_iter_type p(input);
00353       for_all(p)
00354         {
00355           if (input[p] == true)
00356             {
00357               output[p] = 0.f;
00358               continue;
00359             }
00360           image2d<float>::fwd_iter_type q(input);
00361           bool found = false;
00362           float d = 0.f;
00363           for_all(q)
00364             {
00365               if (input[q] == false || q == p)
00366                 continue;
00367               if (! found)
00368                 {
00369                   d = euclidian_dist2(p, q);
00370                   found = true;
00371                   continue;
00372                 }
00373               d = std::min(euclidian_dist2(p, q), d);
00374             }
00375           output[p] = sqrt(d);
00376         }
00377       return output;
00378     }
00379 
00380   } // end of namespace topo
00381 
00382 } // end of namespace oln
00383 
00384 #endif // ! OLENA_TOPO_DMAP_HXX

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