extrema_killer.hh

00001 // Copyright (C) 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_EXTREMA_KILLER_HH
00029 # define OLENA_MORPHO_EXTREMA_KILLER_HH
00030 
00031 # include <oln/config/system.hh>
00032 # include <oln/basics2d.hh>
00033 # include <ntg/all.hh>
00034 # include <oln/morpho/extrema.hh>
00035 # include <oln/arith/ops.hh>
00036 # include <oln/morpho/watershed.hh>
00037 
00038 # include <oln/level/connected.hh>
00039 # include <oln/level/lut.hh>
00040 
00041 # include <oln/level/fill.hh>
00042 
00043 # include <set>
00044 # include <algorithm>
00045 
00046 
00047 namespace oln {
00048 
00049   namespace morpho {
00050 
00061     template<class I, class N>
00062     typename mute<I, ntg::bin>::ret
00063     internal_kill_cc_area(const abstract::binary_image_with_dim<2, I>& input,
00064                           const unsigned int area,
00065                           const abstract::neighborhood<N>& Ng)
00066     {
00067       typename mute<I, ntg::int_u<20> >::ret cc = level::connected_component<ntg::int_u<20> >(input, Ng);
00068       // label 0 is background
00069       ntg::int_u<20> max_label = 0;
00070       image2d<ntg::int_u<20> >::iter_type p(cc);
00071       for_all(p)
00072         if (cc[p] > max_label)
00073           max_label = cc[p];
00074       level::hlut_def<ntg::int_u<20> > region_area;
00075       for_all(p)
00076         region_area.set(cc[p], ntg::cast::force<ntg::int_u<20> >(region_area(cc[p]) + 1));
00077       image2d<ntg::bin> output(input.size());
00078       for_all(p)
00079         if (input[p] == true)
00080           {
00081             if (region_area(cc[p]) >= ntg::int_u<20> (area))
00082               output[p] = true;
00083             else
00084               output[p] = false;
00085           }
00086         else
00087           output[p] = false;
00088       return output;
00089     }
00090 
00091 
00092     // SURE VERSIONS
00093 
00130     template<class I, class N>
00131     oln_concrete_type(I)
00132       sure_maxima_killer(const abstract::non_vectorial_image<I>& input,
00133                          const unsigned int area,
00134                          const abstract::neighborhood<N>& Ng)
00135     {
00136       mlc::eq<I::dim, N::dim>::ensure();
00137       typedef typename mute<I, ntg::bin >::ret ima_bin_type;
00138 
00139       ima_bin_type* cc_level_sets = new (image2d<ntg::bin> [256]);
00140       for (unsigned int i=0; i <= 255; ++i)
00141         {
00142           image2d<ntg::bin> level_sets_i(input.size());
00143           image2d<ntg::int_u8>::iter_type p(input);
00144           for_all(p)
00145             if (input[p] >=oln_value_type(I) (i))
00146               level_sets_i[p] = true;
00147             else
00148               level_sets_i[p] = false;
00149           cc_level_sets[i] = internal_kill_cc_area(level_sets_i, area, Ng);
00150         }
00151       image2d<ntg::int_u8> output(input.size());
00152       for (int i=0; i < 255 ; ++i)
00153         {
00154           image2d<ntg::int_u8>::iter_type p(input);
00155           for_all(p)
00156             {
00157               if ((cc_level_sets[i])[p] == true)
00158                 output[p] = i;
00159             }
00160         }
00161       delete[] cc_level_sets;
00162 
00163       return output;
00164     }
00165 
00166 
00203     template<class I, class N>
00204     image2d<ntg::int_u8>
00205     sure_minima_killer(const abstract::non_vectorial_image<I>& input,
00206                        const unsigned int area,
00207                        const abstract::neighborhood<N>& Ng)
00208     {
00209       mlc::eq<I::dim, N::dim>::ensure();
00210 
00211       typedef image2d<ntg::bin> ima_bin_type;
00212 
00213       ima_bin_type* cc_level_sets = new (image2d<ntg::bin> [256]);
00214       for (unsigned int i=0; i <= 255; ++i)
00215         {
00216           image2d<ntg::bin> level_sets_i(input.size());
00217           image2d<ntg::int_u8>::iter_type p(input);
00218           for_all(p)
00219             if (input[p] <=oln_value_type(I) (i))
00220               level_sets_i[p] = true;
00221             else
00222               level_sets_i[p] = false;
00223           cc_level_sets[i] = internal_kill_cc_area(level_sets_i, area, Ng);
00224         }
00225       image2d<ntg::int_u8> output(input.size());
00226       for (int i=255; i >= 0 ; --i)
00227         {
00228           image2d<ntg::int_u8>::iter_type p(input);
00229           for_all(p)
00230             {
00231               if ((cc_level_sets[i])[p] == true)
00232                 output[p] = i;
00233             }
00234         }
00235       delete[] cc_level_sets;
00236 
00237       return output;
00238     }
00239 
00240     // END OF SURE VERSION
00241 
00242 
00243     // FAST VERSIONS
00244 
00257     template<class P, class I, class N>
00258     //    inline
00259     static bool
00260     is_a_strict_minimum(const abstract::point<P>& p,
00261                         const abstract::non_vectorial_image<I>& input,
00262                         const abstract::neighborhood<N>& Ng)
00263     {
00264       mlc::eq<I::dim, N::dim>::ensure();
00265       mlc::eq<P::dim, N::dim>::ensure();
00266 
00267       bool is_p_lower = true;
00268       bool is_p_at_least_one_stricly_lower = false;
00269       oln_neighb_type(N) p_prime(Ng, p);
00270       for_all(p_prime) if (input.hold(p_prime))
00271         {
00272           if (input[p] < input[p_prime])
00273             is_p_at_least_one_stricly_lower = true;
00274           if (input[p] > input[p_prime])
00275             is_p_lower = false;
00276         }
00277       return (is_p_lower && is_p_at_least_one_stricly_lower);
00278     }
00279 
00292     template<class P, class I, class N>
00293     // inline
00294     static bool
00295     is_a_strict_maximum(const abstract::point<P>& p,
00296                         const abstract::non_vectorial_image<I>& input,
00297                         const abstract::neighborhood<N>& Ng)
00298     {
00299       mlc::eq<I::dim, N::dim>::ensure();
00300       mlc::eq<P::dim, N::dim>::ensure();
00301 
00302       bool is_p_upper = true;
00303       bool is_p_at_least_one_stricly_upper = false;
00304       oln_neighb_type(N) p_prime(Ng, p);
00305       for_all(p_prime) if (input.hold(p_prime))
00306         {
00307           if (input[p] > input[p_prime])
00308             is_p_at_least_one_stricly_upper = true;
00309           if (input[p] < input[p_prime])
00310             is_p_upper = false;
00311         }
00312       return (is_p_upper && is_p_at_least_one_stricly_upper);
00313     }
00314 
00315 
00357     template<class I, class N>
00358     oln_concrete_type(I)
00359       fast_minima_killer(const abstract::non_vectorial_image<I>& input,
00360                          const unsigned int area,
00361                          const abstract::neighborhood<N>& Ng)
00362     {
00363       mlc::eq<I::dim, N::dim>::ensure();
00364 
00365       std::vector<oln_point_type(I)> cur_minimum;
00366       cur_minimum.reserve(15000);
00367       oln_concrete_type(I) working_input = input.clone();
00368       typename mute<I, ntg::bin>::ret not_processed_map(input.size());
00369       level::fill(not_processed_map, true);
00370 
00371       // STEP 2: search for a local miminum
00372       oln_iter_type(I) p(working_input);
00373       for_all(p)
00374         {
00375           if (is_a_strict_minimum(p.cur(), working_input, Ng)
00376               && not_processed_map[p])
00377             {
00378               cur_minimum.push_back(p);
00379               oln_value_type(I) lambda = working_input[p];
00380 
00381               // FIXME: This should better be moved out of the loop.
00382               typename mute<I, ntg::bin>::ret is_visited(input.size());
00383               level::fill(is_visited, false);
00384               is_visited[p] = true;
00385               //STEP 3
00386               bool go_on = true; // FIXME: Use break instead of go_on = false.
00387               while (go_on)
00388                 {
00389                   typedef oln_value_type(I) I_type;
00390                   oln_point_type(I) arg_min = p;
00391                   oln_value_type(I) min =  ntg_max_val(I_type);
00392                   for (unsigned i = 0; i < cur_minimum.size(); ++i)
00393                     {
00394                       oln_neighb_type(N) p_prime(Ng, cur_minimum[i]);
00395                       for_all(p_prime) if (working_input.hold(p_prime) &&
00396                                            (is_visited[p_prime] == false))
00397                         {
00398                           if (working_input[p_prime] <= min)
00399                             {
00400                               min = working_input[p_prime];
00401                               arg_min = p_prime;
00402                             }
00403                         }
00404                     }
00405                   // go to step 4
00406                   if (working_input[arg_min] >= lambda)
00407                     {
00408                       // step 5
00409                       if (cur_minimum.size() < area)
00410                         {
00411                           lambda = working_input[arg_min]; // END MODIF2
00412                           cur_minimum.push_back(arg_min); //MODIF 1
00413                           is_visited[arg_min] = true;
00414                           // go to step 3
00415                         }
00416                       else
00417                         {
00418                           go_on = false;
00419                           //go to step 6
00420                         }
00421                     }
00422                   else
00423                     {
00424                       go_on = false; //go to step 6
00425                     }
00426                 } // end while "go on"
00427 
00428               // going  to step 6
00429               for (unsigned i = 0; i < cur_minimum.size(); ++i)
00430                 {
00431                   working_input[cur_minimum[i]] = lambda;
00432                   not_processed_map[cur_minimum[i]] = false;
00433                 }
00434               cur_minimum.erase(cur_minimum.begin(), cur_minimum.end());
00435 
00436               // STEP 7: look for a new minimum
00437             } // end processing current minimum
00438 
00439         } // END looking for minimum
00440       return working_input;
00441     }
00442 
00484     template<class I, class N>
00485     oln_concrete_type(I)
00486       fast_maxima_killer(const abstract::non_vectorial_image<I>& input,
00487                          const unsigned int area,
00488                          const abstract::neighborhood<N>& Ng)
00489     {
00490       mlc::eq<I::dim, N::dim>::ensure();
00491 
00492       std::vector<oln_point_type(I)> cur_maximum;
00493       oln_concrete_type(I) working_input = input.clone();
00494       typename mute<I, ntg::bin>::ret not_processed_map(input.size());
00495       level::fill(not_processed_map, true);
00496 
00497       // STEP 2: search for a local miminum
00498       oln_iter_type(I) p(working_input);
00499       for_all(p)
00500         {
00501           if (is_a_strict_maximum(p.cur(), working_input, Ng)
00502               && not_processed_map[p])
00503             {
00504               cur_maximum.push_back(p);
00505               oln_value_type(I) lambda = working_input[p];
00506 
00507               typename mute<I, ntg::bin>::ret is_visited(input.size());
00508               level::fill(is_visited, false);
00509               is_visited[p] = true;
00510               //STEP 3
00511               bool go_on = true; // FIXME: ditto
00512               while (go_on)
00513                 {
00514                   typedef oln_value_type(I) I_type;
00515                   oln_point_type(I) arg_max = p;
00516                   oln_value_type(I) max =  ntg_min_val(I_type);
00517                   for (unsigned i = 0; i < cur_maximum.size(); ++i)
00518                     {
00519                       oln_neighb_type(N) p_prime(Ng, cur_maximum[i]);
00520                       for_all(p_prime) if (working_input.hold(p_prime) &&
00521                                            (is_visited[p_prime] == false))
00522                         {
00523                           if (working_input[p_prime] >= max)
00524                             {
00525                               max = working_input[p_prime];
00526                               arg_max = p_prime;
00527                             }
00528                         }
00529                     }
00530                   // go to step 4
00531                   if (working_input[arg_max] <= lambda)
00532                     {
00533                       // step 5
00534                       if (cur_maximum.size() < area)
00535                         {
00536                           lambda = working_input[arg_max]; // END MODIF2
00537                           cur_maximum.push_back(arg_max); //MODIF 1
00538                           is_visited[arg_max] = true;
00539                           // go to step 3
00540                         }
00541                       else
00542                         {
00543                           go_on = false;
00544                           //go to step 6
00545                         }
00546                     }
00547                   else
00548                     {
00549                       go_on = false;
00550                       //go to step 6
00551                     }
00552                 } // end while "go on"
00553 
00554               // going  to step 6
00555               for (unsigned i = 0; i < cur_maximum.size(); ++i)
00556                 {
00557                   //          cout << cur_minimum[i] << "   " << lambda << endl;
00558                   working_input[cur_maximum[i]] = lambda;
00559                   not_processed_map[cur_maximum[i]] = false;
00560                 }
00561               cur_maximum.erase(cur_maximum.begin(), cur_maximum.end());
00562 
00563               // STEP 7: look for a new minimum
00564             } // end processing current minimum
00565 
00566         } // END looking for minimum
00567       return working_input;
00568     }
00569   }
00570 } // oln
00571 #endif

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