
Ce code est sans doute redondant avec ce qu'offriront les canevas sur l'Union-Find, mais : 1. je vais en avoir besoin pour écrire des variantes du watershed ; 2. je ne voulais pas marcher sur les plates-bandes de Christophe et Nicolas ; d'où l'idée d'écrire les calculs des extrema locaux avec une variante à base de FIFO. (C'est très certainement (très) sub-optimal.) https://svn.lrde.epita.fr/svn/oln/prototypes/proto-1.0 ChangeLog | 13 +++ oln/level/extrema_components.hh | 124 +++++++++++++++++++++++++++++++++++ oln/level/level_components.hh | 83 +++++++++++++++++++++++ oln/morpho/lower_completion.hh | 5 - tests/level/tests/extrema_components | 42 +++++++++++ tests/morpho/tests/lower_completion | 1 6 files changed, 265 insertions(+), 3 deletions(-) Index: olena/ChangeLog from Roland Levillain <roland@lrde.epita.fr> Add (queue-based) level and extrema components computation. * oln/level/level_components.hh, oln/level/extrema_components.hh: New files. * tests/level/tests/extrema_components: New test. * oln/morpho/lower_completion.hh: Check that the input is a scalar image. * tests/morpho/tests/lower_completion: Don't include useless headers. Index: olena/tests/morpho/tests/lower_completion --- olena/tests/morpho/tests/lower_completion (revision 195) +++ olena/tests/morpho/tests/lower_completion (working copy) @@ -4,7 +4,6 @@ #include "oln/core/2d/image2d.hh" #include "oln/core/gen/image_with_nbh.hh" #include "oln/io/read_image.hh" -#include "oln/io/write_image.hh" #include "oln/morpho/lower_completion.hh" #include "oln/ops/cmp.hh" Index: olena/tests/level/tests/extrema_components --- olena/tests/level/tests/extrema_components (revision 0) +++ olena/tests/level/tests/extrema_components (revision 0) @@ -0,0 +1,42 @@ + // -*- C++ -*- +#include "data.hh" +#include "ntg/int.hh" +#include "oln/core/2d/image2d.hh" +#include "oln/core/gen/image_with_nbh.hh" +#include "oln/io/read_image.hh" +#include "oln/io/write_image.hh" +#include "oln/level/extrema_components.hh" +#include "oln/ops/cmp.hh" +#include "oln/utils/md5.hh" + +using namespace oln; + +bool check() +{ + image2d<ntg::int_u8> raw_input; + raw_input = io::read(rdata("16x16.pgm")); + typedef image_with_nbh<image2d<ntg::int_u8>, neighborhood2d> image_type; + image_type input = join(raw_input, neighb_c4()); + + // MD5 sum of the minima. + utils::key::value_type minima_data_key[16] = + { 0x72, 0xad, 0x21, 0xcc, 0xd9, 0x6a, 0x6a, 0x82, + 0xb8, 0xea, 0x60, 0x1f, 0xcf, 0x76, 0x45, 0x13 }; + utils::key minima_key(minima_data_key); + + image_type minima = level::minima_components<ntg::int_u8>(input); + if (utils::md5(minima) != minima_key) + return true; + + // MD5 sum of the maxima. + utils::key::value_type maxima_data_key[16] = + { 0x6e, 0x71, 0x74, 0x7c, 0xf8, 0xb, 0xfe, 0xa, + 0xa9, 0xd2, 0x84, 0x26, 0xa5, 0x3e, 0xfd, 0xba }; + utils::key maxima_key(maxima_data_key); + + image_type maxima = level::maxima_components<ntg::int_u8>(input); + if (utils::md5(maxima) != maxima_key) + return true; + + return false; +} Index: olena/oln/morpho/lower_completion.hh --- olena/oln/morpho/lower_completion.hh (revision 195) +++ olena/oln/morpho/lower_completion.hh (working copy) @@ -36,11 +36,12 @@ namespace morpho { - // FIXME: INPUT should be a scalar image. template <typename DestValue, typename I> typename ch_value_type<I, DestValue>::ret lower_completion(const abstract::image_with_nbh<I>& input) { + mlc_is_a(I, abstract::scalar_valued_image)::ensure(); + typedef oln_type_of(I, point) point_type; /*------------------------------------------. @@ -55,7 +56,7 @@ typename ch_value_type<I, unsigned>::ret distance(input.size()); unsigned cur_dist = 1; - oln_type_of(I, fwd_piter) p(input.size()); + oln_type_of(I, piter) p(input.size()); for_all_p (p) { distance[p] = 0; Index: olena/oln/level/extrema_components.hh --- olena/oln/level/extrema_components.hh (revision 0) +++ olena/oln/level/extrema_components.hh (revision 0) @@ -0,0 +1,124 @@ +// Copyright (C) 2005 EPITA Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 59 Temple Place - Suite 330, Boston, +// MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +#ifndef OLENA_MORPHO_EXTREMA_COMPONENTS_HH +# define OLENA_MORPHO_EXTREMA_COMPONENTS_HH + +# include <map> +# include <queue> +# include <functional> + +# include "oln/level/level_components.hh" + +namespace oln { + + namespace level { + + namespace internal { + + /// Find the extrema level components of \a input, using \param + /// Cmp as comparison function. + template <typename DestValue, typename Cmp, typename I> + typename ch_value_type<I, DestValue>::ret + extrema_components(const abstract::image_with_nbh<I>& input) + { + mlc_is_a(I, abstract::scalar_valued_image)::ensure(); + Cmp cmp; + + // Compute level components. + typename ch_value_type<I, DestValue>::ret comps = + level_components<DestValue>(input); + std::set<DestValue> extrema; + std::set<DestValue> non_extrema; + + // Search extrema components. + oln_type_of(I, piter) p(input.size()); + for_all_p (p) + { + DestValue comp = comps[p]; + if (non_extrema.find(comp) == non_extrema.end ()) + { + // A new level is a (potential) extrema by default. + extrema.insert(comp); + + oln_type_of(I, niter) n(input); + for_all_n_of_p (n, p) + if (input.hold(n) && cmp(input[n], input[p])) + { + extrema.erase(comp); + non_extrema.insert(comp); + } + } + } + + // Re-label the extrema. label_map hold the assigned labels. + std::map<DestValue, DestValue> label_map; + { + DestValue cur_label = ntg_min_val(DestValue) + 1; + for (typename std::set<DestValue>::const_iterator i = + extrema.begin(); i != extrema.end(); ++i, ++cur_label) + label_map[*i] = cur_label; + } + typename ch_value_type<I, DestValue>::ret output (input.size()); + level::fill (output, ntg_min_val(DestValue)); + for_all_p (p) + { + DestValue comp = comps[p]; + if (label_map.find(comp) != label_map.end()) + output[p] = label_map[comp]; + } + return output; + } + + } // end of namespace oln::level::internal. + + + /// Find the minima level components of \a input. + template <typename DestValue, typename I> + typename ch_value_type<I, DestValue>::ret + minima_components(const abstract::image_with_nbh<I>& input) + { + mlc_is_a(I, abstract::scalar_valued_image)::ensure(); + return internal::extrema_components< DestValue, + std::less<DestValue> >(input); + } + + /// Find the maxima level components of \a input. + template <typename DestValue, typename I> + typename ch_value_type<I, DestValue>::ret + maxima_components(const abstract::image_with_nbh<I>& input) + { + mlc_is_a(I, abstract::scalar_valued_image)::ensure(); + return internal::extrema_components< DestValue, + std::greater<DestValue> >(input); + } + + } // end of namespace oln::level. + +} // end of namespace oln. + +#endif // ! OLENA_MORPHO_EXTREMA_COMPONENTS_HH Index: olena/oln/level/level_components.hh --- olena/oln/level/level_components.hh (revision 0) +++ olena/oln/level/level_components.hh (revision 0) @@ -0,0 +1,83 @@ +// Copyright (C) 2005 EPITA Research and Development Laboratory +// +// This file is part of the Olena Library. This library is free +// software; you can redistribute it and/or modify it under the terms +// of the GNU General Public License version 2 as published by the +// Free Software Foundation. +// +// This library is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU +// General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this library; see the file COPYING. If not, write to +// the Free Software Foundation, 59 Temple Place - Suite 330, Boston, +// MA 02111-1307, USA. +// +// As a special exception, you may use this file as part of a free +// software library without restriction. Specifically, if other files +// instantiate templates or use macros or inline functions from this +// file, or you compile this file and link it with other files to +// produce an executable, this file does not by itself cause the +// resulting executable to be covered by the GNU General Public +// License. This exception does not however invalidate any other +// reasons why the executable file might be covered by the GNU General +// Public License. + +#ifndef OLENA_MORPHO_LEVEL_COMPONENTS_HH +# define OLENA_MORPHO_LEVEL_COMPONENTS_HH + +# include <queue> + +# include "oln/level/fill.hh" + +namespace oln { + + namespace level { + + /// Compute the level components of \a input. + template <typename DestValue, typename I> + typename ch_value_type<I, DestValue>::ret + level_components(const abstract::image_with_nbh<I>& input) + { + mlc_is_a(I, abstract::scalar_valued_image)::ensure(); + + typename ch_value_type<I, DestValue>::ret labels(input.size()); + typename ch_value_type<I, bool>::ret processed(input.size()); + level::fill (processed, false); + + DestValue cur_label = ntg_min_val(DestValue); + + typedef oln_type_of(I, point) point_type; + std::queue<point_type> q; + + oln_type_of(I, piter) p(input.size()); + for_all_p (p) + if (!processed[p]) + { + labels[p] = cur_label; + q.push(p); + while (!q.empty()) + { + point_type s = q.front(); + q.pop(); + oln_type_of(I, niter) n(input); + for_all_n_of_p (n, s) + if (input.hold(n) && input[n] == input[s] && !processed[n]) + { + labels[n] = cur_label; + processed[n] = true; + q.push(n); + } + } + ++cur_label; + } + return labels; + } + + } // end of namespace oln::level + +} // end of namespace oln + +#endif // ! OLENA_MORPHO_LEVEL_COMPONENTS_HH