watershed.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_WATERSHED_HXX
00029 # define OLENA_MORPHO_WATERSHED_HXX
00030 
00031 # include <oln/config/system.hh>
00032 # include <ntg/all.hh>
00033 # include <oln/level/fill.hh>
00034 # include <queue>
00035 # include <map>
00036 
00037 namespace oln {
00038   namespace morpho {
00039 
00040     /* GCC's optimizer is smart enough to compute these values at compile
00041        time and really use them as constants.  That's great.  */
00042 # define oln_morpho_declare_soille_watershed_consts_(DestValue)                         \
00043     const DestValue mask    = ntg::cast::force<DestValue >(ntg_max_val(DestValue) - 2); \
00044     const DestValue wshed   = ntg_max_val(DestValue);                                   \
00045     const DestValue init    = ntg::cast::force<DestValue >(ntg_max_val(DestValue) - 1); \
00046     const DestValue inqueue = ntg::cast::force<DestValue >(ntg_max_val(DestValue) - 3); \
00047     const DestValue maxlevel = ntg::cast::force<DestValue >(inqueue - 1) /* no ; */
00048 
00049     namespace internal {
00050 
00051       struct watershed_seg_point_handler_
00052       {
00053         template<class Fifo, class II, class IO, class N>
00054         static inline void
00055         process (Fifo& fifo, const II&, IO& im_o, const N& Ng)
00056         {
00057           typedef oln_value_type(IO) destvalue_type;
00058           oln_morpho_declare_soille_watershed_consts_(destvalue_type);
00059           (void) init; /* unused */
00060 
00061           oln_point_type(II) p = fifo.front();
00062           fifo.pop();
00063 
00064           oln_iter_type(N) p_prime(Ng);
00065 
00066           bool flag = false;
00067           for_all (p_prime)
00068             if (im_o.hold(p + p_prime))
00069               {
00070                 if (im_o[p + p_prime] <= maxlevel)
00071                   {
00072                     // (p + p_prime) belongs to an already labelled basin
00073                     if (im_o[p] == inqueue
00074                         || (im_o[p] == wshed && flag == true))
00075                       im_o[p] = im_o[p + p_prime];
00076                     else if (im_o[p] <= maxlevel
00077                              && (im_o[p] != im_o[p + p_prime]))
00078                       {
00079                         im_o[p] = wshed;
00080                         flag = false;
00081                       }
00082                   }
00083                 else if (im_o[p + p_prime] == wshed)
00084                   {
00085                     if (im_o[p] == inqueue)
00086                       {
00087                         im_o[p] = wshed;
00088                         flag = true;
00089                       }
00090                   }
00091                 else if (im_o[p + p_prime] == mask)
00092                   {
00093                     im_o[p + p_prime] = inqueue;
00094                     fifo.push(p + p_prime);
00095                   }
00096               }
00097         }
00098       };
00099 
00100       struct watershed_con_point_handler_
00101       {
00102         template<class Fifo, class II, class IO, class N>
00103         static inline void
00104         process (Fifo& fifo, const II& im_i, IO& im_o, const N& Ng)
00105         {
00106           typedef oln_value_type(IO) destvalue_type;
00107           oln_morpho_declare_soille_watershed_consts_(destvalue_type);
00108           (void) init; (void) wshed; /* unused */
00109 
00110           oln_point_type(II) p = fifo.front();
00111           fifo.pop();
00112 
00113           oln_neighb_type(N) p_prime(Ng, p);
00114 
00115           if (im_o[p] == inqueue)
00116             {
00117               // Find the labeled neighbor with the lower level
00118               for_all(p_prime)
00119                 if (im_o.hold(p_prime) && im_o[p_prime] <= maxlevel)
00120                   {
00121                     oln_point_type(II) l = p_prime;
00122 
00123                     for_all_remaining(p_prime)
00124                       if (im_o.hold(p_prime)
00125                           && im_o[p_prime] <= maxlevel
00126                           && im_i[p_prime] < im_i[l])
00127                         l = p_prime;
00128 
00129                     im_o[p] = im_o[l];
00130                     break;
00131                   }
00132             }
00133 
00134           /* Enqueue all masked neighbors */
00135           for_all (p_prime)
00136             if (im_o.hold(p_prime) && im_o[p_prime] == mask)
00137               {
00138                 im_o[p_prime] = inqueue;
00139                 fifo.push(p_prime);
00140               }
00141         }
00142       };
00143 
00148       template<class Point, class T> inline
00149       bool
00150       watershed_seg_sort_(const std::pair<Point, T>& p1,
00151                           const std::pair<Point, T>& p2)
00152       {
00153         return p1.second < p2.second;
00154       }
00155 
00159       template<class PointHandler, class DestValue, class I, class N>
00160       typename mute<I, DestValue>::ret
00161       soille_watershed_(const abstract::non_vectorial_image<I>& im_i,
00162                         const abstract::neighborhood<N>& Ng)
00163       {
00164         oln_morpho_declare_soille_watershed_consts_(DestValue);
00165 
00166         // Initializations
00167         typedef typename mute<I, DestValue>::ret result_type;
00168         result_type im_o(im_i.size());
00169         level::fill(im_o, init);
00170         std::queue<oln_point_type(I) > fifo;
00171         DestValue current_label = ntg_min_val(DestValue);
00172 
00173         // Sort the pixels of im_i in the increasing order of their grey
00174         // values.
00175         std::vector< std::pair<oln_point_type(I),oln_value_type(I)> >
00176           histo(im_i.npoints());
00177 
00178         {
00179           oln_iter_type(I) p(im_i);
00180           unsigned int i = 0;
00181           for_all (p)
00182             histo[i++] = std::pair<oln_point_type(I),oln_value_type(I)>(p, im_i[p]);
00183           // FIXME: We don't use a distrib_sort for now because that would
00184           // not work with float values.  We should have a specialized
00185           // sorting proc to handle this in the future.
00186           sort(histo.begin(), histo.end(),
00187                watershed_seg_sort_<oln_point_type(I),oln_value_type(I)>);
00188         }
00189 
00190         for (unsigned int i = 0; i < histo.size(); )
00191           // geodesic SKIZ of level h-1 inside level h
00192           {
00193             unsigned int level_start = i;       // First index for current level.
00194 
00195             oln_value_type(I) h = histo[i].second;
00196 
00197             oln_point_type(I) p;
00198             while (i < histo.size())
00199               {
00200                 p = histo[i].first;
00201                 if (im_i[p] != h)
00202                   break;
00203 
00204                 im_o[p] = mask;
00205                 oln_iter_type(N) p_prime(Ng);
00206                 bool flag_exist = false;
00207                 for_all (p_prime)
00208                   if (im_o.hold(p + p_prime))
00209                     {
00210                       if (im_o[p + p_prime] == wshed
00211                           || im_o[p + p_prime] <= maxlevel)
00212                         flag_exist = true;
00213                     }
00214                 if (flag_exist == true)
00215                   {
00216                     im_o[p] = inqueue;
00217                     fifo.push(p);
00218                   }
00219 
00220                 ++i;
00221               }
00222 
00223             // ================================================================
00224 
00225             while (!fifo.empty())
00226               PointHandler::process (fifo, im_i, im_o, Ng);
00227 
00228             // ================================================================
00229 
00230             /* Check for new minima.  */
00231 
00232             unsigned int j = level_start;
00233             while (j < histo.size())
00234               {
00235                 p = histo[j].first;
00236                 if (im_i[p] != h)
00237                   break;
00238 
00239                 if (im_o[p] == mask)
00240                   {
00241                     current_label += 1;
00242                     /* If we run out of labels, restart from the initial
00243                        value.  FIXME: We should have a mean to tell
00244                        the caller that such 'wrapping' occured.  */
00245                     if (current_label > maxlevel)
00246                       current_label = ntg_min_val(DestValue);
00247 
00248                     fifo.push(p);
00249                     im_o[p] = current_label;
00250                     while (!fifo.empty())
00251                       {
00252                         oln_point_type(I) p_prime = fifo.front();
00253                         fifo.pop();
00254                         oln_iter_type(N) p_pprime(Ng);
00255                         for (p_pprime = begin; p_pprime != end; ++ p_pprime)
00256                           if (im_o.hold(p_prime + p_pprime)
00257                               && im_o[p_prime + p_pprime] == mask)
00258                             {
00259                               fifo.push(p_prime + p_pprime);
00260                               im_o[p_prime + p_pprime] = current_label;
00261                             }
00262                       }
00263                   }
00264                 ++j;
00265               }
00266           }
00267         return im_o;
00268       }
00269 
00270     } // internal
00271 
00272 
00273     // Algorithm by Vincent and Soille
00274     template<class DestValue, class I, class N>
00275     typename mute<I, DestValue>::ret
00276     watershed_seg(const abstract::non_vectorial_image<I>& im_i,
00277                   const abstract::neighborhood<N>& Ng)
00278     {
00279       return internal::soille_watershed_<
00280         internal::watershed_seg_point_handler_, DestValue> (im_i, Ng);
00281     }
00282 
00283     template<class DestValue, class I, class N>
00284     typename mute<I, DestValue>::ret
00285     watershed_con(const abstract::non_vectorial_image<I>& im_i,
00286                   const abstract::neighborhood<N>& Ng)
00287     {
00288       return internal::soille_watershed_<
00289         internal::watershed_con_point_handler_, DestValue> (im_i, Ng);
00290     }
00291 
00292 
00299     template <class T>
00300     struct cmp_queue_elt
00301     {
00302       bool
00303       operator()(const std::pair<oln_point_type(T), oln_value_type(T)>& l,
00304                  const std::pair<oln_point_type(T), oln_value_type(T)>& r) const
00305       {
00306         return l.second > r.second;
00307       }
00308     };
00309 
00310     // version by D'Ornellas et al.
00311     template<class I1, class I2, class N> inline
00312     oln_concrete_type(I2)&
00313     watershed_seg_or(const abstract::non_vectorial_image<I1>& In,
00314                      abstract::non_vectorial_image<I2>& Labels,
00315                      const abstract::neighborhood<N>& Ng)
00316     {
00317 
00318       typedef oln_value_type(I2) value_type;
00319       const oln_value_type(I2) wshed   = ntg_max_val(value_type);
00320       const oln_value_type(I2) unknown = ntg_min_val(value_type);
00321 
00322       typedef std::pair<oln_point_type(I1), oln_value_type(I1)> queue_elt_type;
00323       std::priority_queue< queue_elt_type, std::vector< queue_elt_type >,
00324         cmp_queue_elt<I1> > PQ;
00325 
00326       // Initialization
00327       // Enqueue all labeled points which have a unlabeled neighbor.
00328       {
00329         oln_iter_type(I2) p(Labels);
00330         oln_neighb_type(N) p_prime(Ng, p);
00331         for_all(p)
00332           if (Labels[p] != unknown)
00333             for_all (p_prime)
00334               if (Labels.hold(p_prime) && Labels[p_prime] == unknown)
00335                 {
00336                   PQ.push(queue_elt_type(p, In[p]));
00337                   break;
00338                 }
00339       }
00340 
00341       // Propagation
00342 
00343       oln_point_type(I1) p;
00344       oln_neighb_type(N) p_prime(Ng, p);
00345       oln_neighb_type(N) p_second(Ng, p_prime);
00346       while (! PQ.empty())
00347         {
00348           // Get the lowest point in the queue.
00349           p = PQ.top().first;
00350           PQ.pop();
00351           // Consider all neighbors of p.
00352           for_all (p_prime) if (Labels.hold(p_prime))
00353             {
00354               // Focus on unlabeled neighbors of p.
00355               if (Labels[p_prime] == unknown)
00356                 {
00357                   // Since p_prime is a neighbor of p, it should
00358                   // be either labeled using the same label as p,
00359                   // or marked as watershed.
00360 
00361                   // It's a watershed if, among the neighbors of
00362                   // p_prime (which itself is a neighbor of p), there
00363                   // exists a point with a label different from the
00364                   // label of pt.  EXISTS is set to true in this case.
00365                   bool exists = false;
00366                   for_all (p_second)
00367                     // FIXME: We should not need the iterate over
00368                     // the neighbors of p_prime which are also
00369                     // neighbors of p, since none of these can have
00370                     // have a different label.  It should be possible
00371                     // to precompute an array of the resulting windows
00372                     // for each neighbor (of p).
00373                     if (Labels.hold(p_second)
00374                         && Labels[p_second] != unknown
00375                         && Labels[p_second] != wshed
00376                         && Labels[p_second] != Labels[p])
00377                       {
00378                         exists = true;
00379                         break;
00380                       }
00381                   if (exists)
00382                     Labels[p_prime] = wshed;
00383                   else
00384                     {
00385                       Labels[p_prime] = Labels[p];
00386                       PQ.push(queue_elt_type(p_prime, In[p_prime]));
00387                     }
00388                 }
00389             }
00390         }
00391       return Labels.exact();
00392     }
00393 
00394   } // morpho
00395 } // oln
00396 
00397 
00398 #endif // OLENA_MORPHO_WATERSHED_HXX

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