milena r1877: Test a simple fllt

URL: https://svn.lrde.epita.fr/svn/oln/trunk/milena ChangeLog: 2008-04-20 Matthieu Garrigues <garrigues@lrde.epita.fr> Test a simple fllt. * sandbox/garrigues/fllt/fllt_simple.cc: Start to construct shapes by browsing level lines in interpixels. * sandbox/garrigues/fllt/fllt_simple.svg.1.cc: New, just browse the c4 connected component of an image. * sandbox/garrigues/fllt/fllt_simple.svg.2.cc: New, just browse the c6 connected component of an image. * sandbox/garrigues/fllt/fllt_simple.svg.3.cc: New, build a tree where a connected component is parent of the shapes contained in its holes. It give the same representation than fllt only on simple images. * sandbox/garrigues/fllt/fllt_theo.cc: Old work, a faster version is in sandbox/geraud/fllt.cc --- fllt_simple.cc | 349 ++++++++++++++++++++++++++--- fllt_simple.svg.1.cc | 325 +++++++++++++++++++++++++++ fllt_simple.svg.2.cc | 349 +++++++++++++++++++++++++++++ fllt_simple.svg.3.cc | 612 +++++++++++++++++++++++++++++++++++++++++++++++++++ fllt_theo.cc | 186 +++++++++++++-- 5 files changed, 1764 insertions(+), 57 deletions(-) Index: trunk/milena/sandbox/garrigues/fllt/fllt_simple.svg.1.cc =================================================================== --- trunk/milena/sandbox/garrigues/fllt/fllt_simple.svg.1.cc (revision 0) +++ trunk/milena/sandbox/garrigues/fllt/fllt_simple.svg.1.cc (revision 1877) @@ -0,0 +1,325 @@ +// Copyright (C) 2008 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, 51 Franklin Street, Fifth Floor, +// 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. + +#include <iomanip> +#include <iostream> +#include <sstream> + +#include <mln/core/image2d.hh> +#include <mln/core/sub_image.hh> +#include <mln/core/neighb2d.hh> +#include <mln/core/p_array.hh> +#include <mln/core/clone.hh> + +#include <mln/value/int_u8.hh> + +#include <mln/io/pgm/load.hh> +#include <mln/io/pgm/save.hh> + +#include <mln/level/fill.hh> +#include <mln/debug/println.hh> +#include <mln/labeling/regional_minima.hh> +#include <mln/accu/bbox.hh> +#include <mln/io/pgm/save.hh> + + +#include <mln/core/cast_image.hh> + +namespace mln +{ + // Un autre version recursive de la fllt. + + // Idee : + // Parcourir l'image en pratant d'un coin de preference, + // le parcour des pixels se fait dans un ordre conexe. + // + + /* + + fonction fllt_rec(racine R, domaine D, marques M, conexite C) + { + pour tout les points du domaine non marquees + recuperer la composante conexe A (en conexite C) qui inclut ce point : + Ceci est fait avec la methode de grossissement de region + pour avoir acces a la bordure externe et donc aux trous + de la composante. + + Cette composante sera fille de R dans l'arbre d'inclusion. + + Marquer les points de A (Peut etre fait en meme temps que la + construction de A) + + Pour chaque trous T de A : + appel recursif : fllt_rec(A, T.domaine(), marques, inv(C)) + T.domaine() sera calculer en recuperant la composante connexe + de la bordure de A lui correspondant (On recupere facilement + les segments horizontaux qui le composent -> parcour ok). + + } + inv(c4) = c8 + inv(c8) = c4 + + + Autre version qui Marche sur les images hexagonales (Plus rapide et plus simple) + car il y a plus le probleme du theoreme de jordan non verifie. + FIXME: Est-ce que rendre l'image hexagonale altere vraiment le resultat? + + pour tout les points du domaine non marquees + recuperer la composante conexe A qui inclut ce point : + Ceci est fait avec la methode de grossissement de region + pour avoir acces a la bordure externe et donc aux trous + de la composante. + + Marquer les points de A (Peut etre fait en meme temps que la + construction de A) + + Marquer les extremites des trou de A. + + Si un point de A est l'extremite d'un trou, + alors on a facilement le pere de A (la forme qui inclue A). + Sinon + C'est qu'il y a une composante connexe adjacente qui + a deja ete construite, et qui a donc deja un pere, qui + est aussi celui de A. + + continuer jusqu'a avoir marquer tout les points + + */ + + namespace my + { + + + void save_u(const image2d<value::int_u8>& u, + const image2d<unsigned char>& is, + box2d R_box) + { + static int id = 0; + std::stringstream filename; + filename << "fllt_u_" << std::setw(5) << std::setfill('0') + << std::right << id++ << ".ppm"; + + image2d<value::int_u8> out = clone(u); + const unsigned in_R = 255; + + mln_piter_(box2d) p(R_box); + for_all(p) + if (is(p) == in_R) + out(p) = 255; + + io::pgm::save(out, filename.str()); + } + + void swap_arrays(p_array<point2d>*& A, + p_array<point2d>*& N) + { + p_array<point2d>* tmp = A; + A = N; + N = tmp; + } + + template <typename I, typename Nbh> + void fllt(const Image<I>& input_, const Neighborhood<Nbh>& nbh_) + { + const I& input = exact(input_); + const Nbh& nbh = exact(nbh_); + + // Variables. + I u = mln::clone(input); + mln_point(I) x0; + mln_value(I) g, gN; + image2d<unsigned char> is(input.domain()); + image2d<bool> tagged(input.domain()); + const unsigned in_R = 255, in_N = 2, in_O = 0; + + typedef p_array<mln_point(I)> arr_t; + arr_t* A = new arr_t(); + arr_t* N = new arr_t(); + + accu::bbox<mln_point(I)> R_box, N_box; + + unsigned n_step_1 = 0, n_step_3 = 0; + + level::fill(tagged, false); + mln_piter(I) min(input.domain()); + min.start(); + // Step 1. + step_1: + { +#ifdef FLLTDEBUG + std::cout << "Step 1" << std::endl; +#endif + ++n_step_1; + for(; min.is_valid(); min.next()) + if (!tagged(min)) + break; + + if (!min.is_valid()) + goto end; + + x0 = min; + g = input(x0); + } + + // Step 2. + step_2: + { +#ifdef FLLTDEBUG + std::cout << "Step 2" << std::endl; +#endif + if (N_box.is_valid()) + level::fill(inplace(is | N_box.to_result()), in_O); + + N_box.init(); + R_box.init(); + A->clear(); + A->append(x0); + N->clear(); + } + + // Step 3. + step_3: + { + ++n_step_3; +#ifdef FLLTDEBUG + std::cout << "Step 3" << std::endl; +#endif + mln_piter(arr_t) a(*A); + mln_niter(Nbh) x(nbh, a); + + // Stop. + if (A->npoints() == 0) + goto end; + + // R <- R U A +#ifdef FLLTDEBUG + std::cout << "Add To R : "; +#endif + for_all(a) + { + tagged(a) = true; + is(a) = in_R; +#ifdef FLLTDEBUG + std::cout << a; +#endif + } +#ifdef FLLTDEBUG + std::cout << std::endl; +#endif + + +#ifdef FLLTDEBUG + std::cout << "points of A : " << A->npoints() << std::endl; +#endif + mln_assertion(A->npoints() > 0); + R_box.take(A->bbox()); + mln_assertion(R_box.is_valid()); + +#ifdef FLLTTRACE + save_u(u, is, R_box); +#endif + // N <- N U { x in nbh of A and not in R / input(x) == g} +#ifdef FLLTDEBUG + std::cout << "Add To N : "; +#endif + for_all(a) + for_all(x) + if (u.has(x) && is(x) == in_O && input(x) == g) + { + mln_assertion(!tagged(x)); + N_box.take(x); + is(x) = in_N; + N->append(x); +#ifdef FLLTDEBUG + std::cout << x; +#endif + } +#ifdef FLLTDEBUG + std::cout << std::endl; +#endif + +#ifdef FLLTDEBUG + std::cout << "g = " << g << std::endl; +#endif + + // Stop if N is empty. + if (N->npoints() == 0) + goto step_1; + else + { + swap_arrays(A, N); + N->clear(); + goto step_3; + } + } + + step_4: + { + // Follow N, find the holes, and browse it. + } + + end: + { + std::cout << n_step_1 << ' ' << n_step_3 << std::endl; + } + } + + } // end of namespace mln::my + +} // end of namespace mln + + +int main() +{ + using namespace mln; + using value::int_u8; + + image2d<int_u8> lena; + + io::pgm::load(lena, "../../../img/lena.pgm"); + + + // int_u8 vs[9][9] = { + + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + + // }; + + //image2d<int_u8> lena = make::image2d(vs); + + my::fllt(lena, c4()); + io::pgm::save(lena, "./out.pgm"); + +} Index: trunk/milena/sandbox/garrigues/fllt/fllt_simple.svg.3.cc =================================================================== --- trunk/milena/sandbox/garrigues/fllt/fllt_simple.svg.3.cc (revision 0) +++ trunk/milena/sandbox/garrigues/fllt/fllt_simple.svg.3.cc (revision 1877) @@ -0,0 +1,612 @@ +// Copyright (C) 2008 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, 51 Franklin Street, Fifth Floor, +// 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. + +#include <iomanip> +#include <iostream> +#include <sstream> + +#include <mln/core/image2d.hh> +#include <mln/core/sub_image.hh> +#include <mln/core/neighb2d.hh> +#include <mln/core/p_array.hh> +#include <mln/core/clone.hh> + +#include <mln/value/int_u8.hh> + +#include <mln/io/pgm/load.hh> +#include <mln/io/pgm/save.hh> + +#include <mln/level/fill.hh> +#include <mln/level/compare.hh> +#include <mln/debug/println.hh> +#include <mln/labeling/regional_minima.hh> +#include <mln/accu/bbox.hh> +#include <mln/io/pgm/save.hh> + +#include <mln/util/tree.hh> +#include <mln/util/tree_to_image.hh> +#include <mln/util/branch_iter_ind.hh> + +#include <mln/core/cast_image.hh> +#include <mln/core/p_queue_fast.hh> + +namespace mln +{ + // Un autre version recursive de la fllt. + + // Idee : + // Parcourir l'image en pratant d'un coin de preference, + // le parcour des pixels se fait dans un ordre conexe. + // + + /* + + fonction fllt_rec(racine R, domaine D, marques M, conexite C) + { + pour tout les points du domaine non marquees + recuperer la composante conexe A (en conexite C) qui inclut ce point : + Ceci est fait avec la methode de grossissement de region + pour avoir acces a la bordure externe et donc aux trous + de la composante. + + Cette composante sera fille de R dans l'arbre d'inclusion. + + Marquer les points de A (Peut etre fait en meme temps que la + construction de A) + + Pour chaque trous T de A : + appel recursif : fllt_rec(A, T.domaine(), marques, inv(C)) + T.domaine() sera calculer en recuperant la composante connexe + de la bordure de A lui correspondant (On recupere facilement + les segments horizontaux qui le composent -> parcour ok). + + } + inv(c4) = c8 + inv(c8) = c4 + + + Autre version qui Marche sur les images hexagonales (Plus rapide et plus simple) + car il y a plus le probleme du theoreme de jordan non verifie. + FIXME: Est-ce que rendre l'image hexagonale altere vraiment le resultat? + + pour tout les points du domaine non marquees + recuperer la composante conexe A qui inclut ce point : + Ceci est fait avec la methode de grossissement de region + pour avoir acces a la bordure externe et donc aux trous + de la composante. + + Marquer les points de A (Peut etre fait en meme temps que la + construction de A) + + Marquer les extremites des trou de A. + + Si un point de A est l'extremite d'un trou, + alors on a facilement le pere de A (la forme qui inclue A). + Sinon + C'est qu'il y a une composante connexe adjacente qui + a deja ete construite, et qui a donc deja un pere, qui + est aussi celui de A. + + continuer jusqu'a avoir marquer tout les points + + Cette methode me marche que dans le cas ou les courbes de niveau corespondent + au formes car on creer les formes en parcourant les pixels. + + Le probleme peut etre resolu en grossissant la forme en passant sur les courbes + de niveaux qui se sitent entre les pixels. + */ + + namespace my + { + +# define fllt_tree(P, V) mln::util::tree< fllt_node_elt<P, V> > +# define fllt_node(P, V) mln::util::tree_node< fllt_node_elt<P, V> > +# define fllt_branch(P, V) mln::util::branch< fllt_node_elt<P, V> > +# define fllt_branch_iter_ind(P, V) mln::util::branch_iter_ind< fllt_node_elt<P, V> > + + + template <typename P, typename V> + struct fllt_node_elt + { + V value; + p_array<P> points; + p_array<P> holes; + /// Tell if his parent if brighter or not. Nb : if the parent + /// if brighter, the node come from the lower level set + bool brighter; + unsigned npoints; + + }; + + template <typename P, typename V> + void add_npoints_to(fllt_node(P, V)* node, unsigned npoints) + { + mln_assertion(node); + + node->elt().npoints += npoints; + if (node->parent()) + add_npoints_to(node->parent(), npoints); + } + + + template <typename R> + struct map_cell + { + R* border_of_hole_of; + R* old_border_of_hole_of; + R* belongs_to; + + map_cell() : border_of_hole_of(0), belongs_to(0) {} + + void restore_border() + { border_of_hole_of = old_border_of_hole_of; } + + void set_border_of_hole_of(R* b) + { + old_border_of_hole_of = border_of_hole_of; + border_of_hole_of = b; + } + }; + + + + template <typename P, typename V> + void + draw_tree(const image2d<V>& ima, + fllt_tree(P, V)& tree) + { + fllt_branch_iter_ind(P, V) p(tree.main_branch()); + for_all(p) + { + std::cout << "region mere : " << (*p).parent() << std::endl; + std::cout << " ^" << std::endl; + std::cout << " |" << std::endl; + std::cout << "region : " << &*p + << " value = " << (*p).elt().value << std::endl + << " npoints = " << (*p).elt().npoints << std::endl + << std::endl; + + if ((*p).elt().points.npoints() > 0) + debug::println(ima | (*p).elt().points); + std::cout << std::endl; + } + } + + + template <typename P, typename V> + void + visualize_bounds(image2d<value::int_u8>& output, + fllt_tree(P, V)& tree, + unsigned limit) + { + fllt_branch_iter_ind(P, V) p(tree.main_branch()); + level::fill(output, 255); + for_all(p) + { + if ((*p).elt().npoints > limit) + { + mln_piter(p_array<point2d>) q((*p).elt().points); + for_all(q) + { + output(q) = 0; + } + } + } + } + + void save_u(const image2d<value::int_u8>& u, + const image2d<unsigned char>& is, + box2d R_box) + { + static int id = 0; + std::stringstream filename; + filename << "fllt_u_" << std::setw(5) << std::setfill('0') + << std::right << id++ << ".ppm"; + + image2d<value::int_u8> out = clone(u); + const unsigned in_R = 255; + + mln_piter_(box2d) p(R_box); + for_all(p) + if (is(p) == in_R) + out(p) = 255; + + io::pgm::save(out, filename.str()); + } + + void swap_arrays(p_array<point2d>*& A, + p_array<point2d>*& N) + { + p_array<point2d>* tmp = A; + A = N; + N = tmp; + } + + + template <typename N_t> + void clear_N(N_t& N) + { + for (unsigned i = 0; i < 256; ++i) + N[i]->clear(); + } + + template <typename I, typename CC> + void erase_exterior_border(I& map, const box2d& bbox, const CC& current_cc, const std::vector<dpoint2d> nbh[]) + { + typedef const std::vector<dpoint2d> arr_dp_t; + typedef std::vector<dpoint2d>::const_iterator arr_dp_t_it; + mln_piter(I) p(bbox); + for_all(p) + if (map(p).border_of_hole_of == current_cc) + { + //mln_assertion(map(p).belongs_to != current_cc); + break; + } + mln_assertion(map(p).belongs_to != current_cc); + p_queue_fast<mln_point(I)> qu; + map(p).restore_border(); + qu.push(p); +// std::cout << std::endl; + + while(!qu.is_empty()) + { + mln_point(I) a = qu.pop_front(); + //map(a).border_of_hole_of = 0; + arr_dp_t* n_dp = &nbh[abs(a[1] % 2 > 0)]; + +// unsigned i = 0; + for(arr_dp_t_it x = n_dp->begin(); x != n_dp->end(); x++) + { + mln_point(I) n = mln_point(I)(a) + mln_dpoint(I)(*x); + + if(!map.has(n)) + continue; + if (map(n).border_of_hole_of == current_cc && + map(n).belongs_to != current_cc) + { +// i++; +// std::cout << i << std::endl; +// mln_assertion(i <= 2); + map(n).restore_border(); + qu.push(n); + break; + } + } + } + } + + template <typename I> + fllt_tree(mln_point(I), mln_value(I))& + fllt(const Image<I>& input_) + { + const I& input = exact(input_); + + typedef std::vector<dpoint2d> arr_dp_t; + typedef std::vector<dpoint2d>::const_iterator arr_dp_t_it; + typedef fllt_node(mln_point(I), mln_value(I)) node_type; + typedef fllt_tree(mln_point(I), mln_value(I)) tree_type; + + // C6 neigboohood. + arr_dp_t neighb_c6[2]; + neighb_c6[0].push_back(make::dpoint2d(-1,-1)); + neighb_c6[0].push_back(make::dpoint2d(-1,0)); + neighb_c6[0].push_back(make::dpoint2d(-1,1)); + neighb_c6[0].push_back(make::dpoint2d(0,1)); + neighb_c6[0].push_back(make::dpoint2d(1,0)); + neighb_c6[0].push_back(make::dpoint2d(0,-1)); + + neighb_c6[1].push_back(make::dpoint2d(-1,0)); + neighb_c6[1].push_back(make::dpoint2d(0,1)); + neighb_c6[1].push_back(make::dpoint2d(1,1)); + neighb_c6[1].push_back(make::dpoint2d(1,0)); + neighb_c6[1].push_back(make::dpoint2d(1,-1)); + neighb_c6[1].push_back(make::dpoint2d(0,-1)); + + // Variables. + image2d<map_cell<node_type> > map(input.domain().to_larger(1)); + I u = mln::clone(input); + mln_point(I) x0; + mln_value(I) g, gN; + image2d<unsigned char> is(input.domain().to_larger(1)); + image2d<bool> tagged(input.domain().to_larger(1)); + const unsigned in_R = 255, in_N = 2, in_O = 0; + node_type* root = new node_type(); + node_type* current_cc; + node_type* current_parent = root; + + typedef p_array<mln_point(I)> arr_t; + arr_t* A = new arr_t(); + arr_t* N[256]; + for (unsigned i = 0; i < 256; ++i) + N[i] = new arr_t(); + + accu::bbox<mln_point(I)> R_box, N_box; + + unsigned n_step_1 = 0, n_step_3 = 0; + unsigned cc_cpt = 0; + bool parent_found = false; + + level::fill(tagged, false); + mln_piter(I) min(input.domain()); + min.start(); + // Step 1. + step_1: + { +#ifdef FLLTDEBUG + std::cout << "Step 1" << std::endl; +#endif + ++n_step_1; + for(;min.is_valid(); min.next()) + if (!tagged(min)) + break; + + if (!min.is_valid()) + goto end; + + x0 = min; + g = input(x0); + current_cc = new node_type(); + ++cc_cpt; + current_cc->elt().value = g; + current_cc->elt().npoints = 0; + if (cc_cpt > 1) + current_parent = 0; +#ifdef FLLTDEBUG + std::cout << "current_cc: " << current_cc << std::endl; +#endif + } + + // Step 2. + step_2: + { +#ifdef FLLTDEBUG + std::cout << "Step 2" << std::endl; +#endif + if (N_box.is_valid()) + level::fill(inplace(is | N_box.to_result()), in_O); + + N_box.init(); + R_box.init(); + A->clear(); + A->append(x0); + clear_N(N); + + mln_assertion(map(x0).belongs_to == 0); + if (map(x0).border_of_hole_of != 0) + { + mln_assertion(map(x0).border_of_hole_of != current_cc); + current_parent = map(x0).border_of_hole_of; +// std::cout << "propagation : " << x0 << std::endl; + } + } + + // Step 3. + step_3: + { + ++n_step_3; +#ifdef FLLTDEBUG + std::cout << "Step 3" << std::endl; +#endif + mln_piter(arr_t) a(*A); + + // Stop. + if (A->npoints() == 0) + goto end; + + // R <- R U A +#ifdef FLLTDEBUG + std::cout << "Add To R : "; +#endif + for_all(a) + { + mln_assertion(map(a).belongs_to == 0); + map(a).belongs_to = current_cc; + current_cc->elt().points.append(a); + current_cc->elt().npoints++; + tagged(a) = true; + is(a) = in_R; +#ifdef FLLTDEBUG + std::cout << a; +#endif + } +#ifdef FLLTDEBUG + std::cout << std::endl; +#endif + + +#ifdef FLLTDEBUG + std::cout << "points of A : " << A->npoints() << std::endl; +#endif + mln_assertion(A->npoints() > 0); + R_box.take(A->bbox()); + mln_assertion(R_box.is_valid()); + +#ifdef FLLTTRACE + save_u(u, is, R_box); +#endif + // N <- N U { x in nbh of A and not in R / input(x) == g} +#ifdef FLLTDEBUG + std::cout << "Add To N : "; +#endif + for_all(a) + { + arr_dp_t* nbh = &neighb_c6[a[1] % 2]; + for(arr_dp_t_it x = nbh->begin(); x != nbh->end(); x++) + { + mln_point(I) n = mln_point(I)(a) + mln_dpoint(I)(*x); + if (is(n) == in_O) + { + if (!current_parent) + { + if (map(n).border_of_hole_of != 0 && + map(n).border_of_hole_of != map(n).belongs_to) + { + mln_assertion(map(n).border_of_hole_of != current_cc); + current_parent = map(n).border_of_hole_of; +// std::cout << "propagation : " << n << std::endl; + } + else if (map(n).belongs_to) + { + current_parent = map(n).belongs_to->parent(); + mln_assertion(current_parent != current_cc); + } + } + map(n).set_border_of_hole_of(current_cc); + N_box.take(n); + is(n) = in_N; + if (u.has(n)) + N[u(n)]->append(n); +#ifdef FLLTDEBUG + std::cout << n; +#endif + } + } + } +#ifdef FLLTDEBUG + std::cout << std::endl; +#endif + +#ifdef FLLTDEBUG + std::cout << "g = " << g << std::endl; +#endif + + // Stop if N[g] is empty. + if (N[g]->npoints() == 0) + { + add_npoints_to(current_parent, current_cc->elt().npoints); + // Was : current_parent->elt().npoints += current_cc->elt().npoints; + current_cc->set_parent(current_parent); + erase_exterior_border(map, N_box, current_cc, neighb_c6); + goto step_1; + } + else + { + // CC is growing. + swap_arrays(A, N[g]); + N[g]->clear(); + goto step_3; + } + } + + end: + { + std::cout << "n_step_1 : " << n_step_1 + << " n_step_3 : " << n_step_3 + << " number of cc : " << cc_cpt << std::endl; + } + + return *new tree_type(root); + } + + } // end of namespace mln::my + +} // end of namespace mln + + +int main() +{ + using namespace mln; + using namespace mln::my; + using value::int_u8; + + typedef image2d<int_u8> I; + typedef fllt_node(mln_point_(I), mln_value_(I)) node_type; + typedef fllt_tree(mln_point_(I), mln_value_(I)) tree_type; + +// image2d<int_u8> ima; +// //io::pgm::load(ima, "../../../img/lena.pgm"); +// io::pgm::load(ima, "../tapis.pgm"); + + + // int_u8 vs[9][9] = { + + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + + // }; + + //image2d<int_u8> lena = make::image2d(vs); + +// int vs[3][6] = { {0, 0, 0, 1, 1, 1}, +// {0, 1, 0, 1, 0, 1}, +// {0, 0, 0, 1, 1, 1} }; + +// int vs[5][5] = { {100, 100, 100, 100, 100}, +// {100, 200, 255, 200, 100}, +// {100, 200, 200, 200, 100}, +// {100, 200, 255, 200, 100}, +// {100, 100, 100, 100, 100} }; + + int vs[9][9] = { {2,2,2,2,2,2,2,2,2}, + {2,2,2,2,2,2,2,2,2}, + {2,1,1,1,1,1,1,1,2}, + {2,1,2,2,1,0,0,1,2}, + {2,1,2,2,1,0,0,1,2}, + {2,1,2,2,1,0,0,1,2}, + {2,1,1,1,1,1,1,1,2}, + {2,1,1,1,1,1,1,1,2}, + {2,2,2,2,2,2,2,2,2} }; + +// int vs[7[7] = { {101, 101, 101, 191, 204, 255, 191}, +// {101, 101, 191, 204, 204, 204, 204}, +// {101, 191, 191, 204, 255, 204, 191}, +// {204, 204, 204, 191, 191, 191, 76}, +// {191, 191, 204, 191, 101, 101, 76}, +// {204, 204, 191, 204, 101, 76, 76}, +// {191, 191, 191, 101, 76, 101, 0}}; + + +// int vs[2][1] = { {121}, {101} }; + + image2d<int> ima_(make::image2d(vs)); + image2d<int_u8> ima(ima_.domain()); + level::fill(ima, ima_); + + tree_type tree = my::fllt(ima); + + + draw_tree(ima, tree); + + + + image2d<value::int_u8> output (ima.domain ()); + util::tree_to_image (tree, output); + mln_assertion(output == ima); + io::pgm::save(output, "out.pgm"); + + image2d<value::int_u8> bounds (ima.domain ()); + visualize_bounds(bounds, tree, 2); + io::pgm::save(bounds, "bounds.pgm"); + +} Index: trunk/milena/sandbox/garrigues/fllt/fllt_simple.cc =================================================================== --- trunk/milena/sandbox/garrigues/fllt/fllt_simple.cc (revision 1876) +++ trunk/milena/sandbox/garrigues/fllt/fllt_simple.cc (revision 1877) @@ -41,13 +41,18 @@ #include <mln/io/pgm/save.hh> #include <mln/level/fill.hh> +#include <mln/level/compare.hh> #include <mln/debug/println.hh> #include <mln/labeling/regional_minima.hh> #include <mln/accu/bbox.hh> #include <mln/io/pgm/save.hh> +#include <mln/util/tree.hh> +#include <mln/util/tree_to_image.hh> +#include <mln/util/branch_iter_ind.hh> #include <mln/core/cast_image.hh> +#include <mln/core/p_queue_fast.hh> namespace mln { @@ -108,11 +113,110 @@ continuer jusqu'a avoir marquer tout les points + Cette methode me marche que dans le cas ou les courbes de niveau corespondent + au formes car on creer les formes en parcourant les pixels. + + Le probleme peut etre resolu en grossissant la forme en passant sur les courbes + de niveaux qui se sitent entre les pixels. */ namespace my { +# define fllt_tree(P, V) mln::util::tree< fllt_node_elt<P, V> > +# define fllt_node(P, V) mln::util::tree_node< fllt_node_elt<P, V> > +# define fllt_branch(P, V) mln::util::branch< fllt_node_elt<P, V> > +# define fllt_branch_iter_ind(P, V) mln::util::branch_iter_ind< fllt_node_elt<P, V> > + + + template <typename P, typename V> + struct fllt_node_elt + { + V value; + p_array<P> points; + p_array<P> holes; + /// Tell if his parent if brighter or not. Nb : if the parent + /// if brighter, the node come from the lower level set + bool brighter; + unsigned npoints; + + }; + + template <typename P, typename V> + void add_npoints_to(fllt_node(P, V)* node, unsigned npoints) + { + mln_assertion(node); + + node->elt().npoints += npoints; + if (node->parent()) + add_npoints_to(node->parent(), npoints); + } + + + template <typename R> + struct map_cell + { + R* border_of_hole_of; + R* old_border_of_hole_of; + R* belongs_to; + + map_cell() : border_of_hole_of(0), belongs_to(0) {} + + void restore_border() + { border_of_hole_of = old_border_of_hole_of; } + + void set_border_of_hole_of(R* b) + { + old_border_of_hole_of = border_of_hole_of; + border_of_hole_of = b; + } + }; + + + + template <typename P, typename V> + void + draw_tree(const image2d<V>& ima, + fllt_tree(P, V)& tree) + { + fllt_branch_iter_ind(P, V) p(tree.main_branch()); + for_all(p) + { + std::cout << "region mere : " << (*p).parent() << std::endl; + std::cout << " ^" << std::endl; + std::cout << " |" << std::endl; + std::cout << "region : " << &*p + << " value = " << (*p).elt().value << std::endl + << " npoints = " << (*p).elt().npoints << std::endl + << std::endl; + + if ((*p).elt().points.npoints() > 0) + debug::println(ima | (*p).elt().points); + std::cout << std::endl; + } + } + + + template <typename P, typename V> + void + visualize_bounds(image2d<value::int_u8>& output, + fllt_tree(P, V)& tree, + unsigned limit) + { + fllt_branch_iter_ind(P, V) p(tree.main_branch()); + level::fill(output, 255); + for_all(p) + { + if ((*p).elt().npoints > limit) + { + mln_piter(p_array<point2d>) q((*p).elt().points); + for_all(q) + { + output(q) = 0; + } + } + } + } void save_u(const image2d<value::int_u8>& u, const image2d<unsigned char>& is, @@ -142,27 +246,109 @@ N = tmp; } - template <typename I, typename Nbh> - void fllt(const Image<I>& input_, const Neighborhood<Nbh>& nbh_) + + template <typename N_t> + void clear_N(N_t& N) + { + for (unsigned i = 0; i < 256; ++i) + N[i]->clear(); + } + + template <typename I, typename CC> + void erase_exterior_border(I& map, const box2d& bbox, const CC& current_cc, const std::vector<dpoint2d> nbh[]) + { + typedef const std::vector<dpoint2d> arr_dp_t; + typedef std::vector<dpoint2d>::const_iterator arr_dp_t_it; + mln_piter(I) p(bbox); + for_all(p) + if (map(p).border_of_hole_of == current_cc) + { + //mln_assertion(map(p).belongs_to != current_cc); + break; + } + mln_assertion(map(p).belongs_to != current_cc); + p_queue_fast<mln_point(I)> qu; + map(p).restore_border(); + qu.push(p); +// std::cout << std::endl; + + while(!qu.is_empty()) + { + mln_point(I) a = qu.pop_front(); + //map(a).border_of_hole_of = 0; + arr_dp_t* n_dp = &nbh[abs(a[1] % 2 > 0)]; + +// unsigned i = 0; + for(arr_dp_t_it x = n_dp->begin(); x != n_dp->end(); x++) + { + mln_point(I) n = mln_point(I)(a) + mln_dpoint(I)(*x); + + if(!map.has(n)) + continue; + if (map(n).border_of_hole_of == current_cc && + map(n).belongs_to != current_cc) + { +// i++; +// std::cout << i << std::endl; +// mln_assertion(i <= 2); + map(n).restore_border(); + qu.push(n); + break; + } + } + } + } + + template <typename I> + fllt_tree(mln_point(I), mln_value(I))& + fllt(const Image<I>& input_) { const I& input = exact(input_); - const Nbh& nbh = exact(nbh_); + + typedef std::vector<dpoint2d> arr_dp_t; + typedef std::vector<dpoint2d>::const_iterator arr_dp_t_it; + typedef fllt_node(mln_point(I), mln_value(I)) node_type; + typedef fllt_tree(mln_point(I), mln_value(I)) tree_type; + + // C6 neigboohood. + arr_dp_t neighb_c6[2]; + neighb_c6[0].push_back(make::dpoint2d(-1,-1)); + neighb_c6[0].push_back(make::dpoint2d(-1,0)); + neighb_c6[0].push_back(make::dpoint2d(-1,1)); + neighb_c6[0].push_back(make::dpoint2d(0,1)); + neighb_c6[0].push_back(make::dpoint2d(1,0)); + neighb_c6[0].push_back(make::dpoint2d(0,-1)); + + neighb_c6[1].push_back(make::dpoint2d(-1,0)); + neighb_c6[1].push_back(make::dpoint2d(0,1)); + neighb_c6[1].push_back(make::dpoint2d(1,1)); + neighb_c6[1].push_back(make::dpoint2d(1,0)); + neighb_c6[1].push_back(make::dpoint2d(1,-1)); + neighb_c6[1].push_back(make::dpoint2d(0,-1)); // Variables. + image2d<map_cell<node_type> > map(input.domain().to_larger(1)); I u = mln::clone(input); mln_point(I) x0; mln_value(I) g, gN; - image2d<unsigned char> is(input.domain()); - image2d<bool> tagged(input.domain()); + image2d<unsigned char> is(input.domain().to_larger(1)); + image2d<bool> tagged(input.domain().to_larger(1)); const unsigned in_R = 255, in_N = 2, in_O = 0; + node_type* root = new node_type(); + node_type* current_cc; + node_type* current_parent = root; typedef p_array<mln_point(I)> arr_t; arr_t* A = new arr_t(); - arr_t* N = new arr_t(); + arr_t* N[256]; + for (unsigned i = 0; i < 256; ++i) + N[i] = new arr_t(); accu::bbox<mln_point(I)> R_box, N_box; unsigned n_step_1 = 0, n_step_3 = 0; + unsigned cc_cpt = 0; + bool parent_found = false; level::fill(tagged, false); mln_piter(I) min(input.domain()); @@ -174,7 +360,7 @@ std::cout << "Step 1" << std::endl; #endif ++n_step_1; - for(min.next(); min.is_valid(); min.next()) + for(;min.is_valid(); min.next()) if (!tagged(min)) break; @@ -183,6 +369,15 @@ x0 = min; g = input(x0); + current_cc = new node_type(); + ++cc_cpt; + current_cc->elt().value = g; + current_cc->elt().npoints = 0; + if (cc_cpt > 1) + current_parent = 0; +#ifdef FLLTDEBUG + std::cout << "current_cc: " << current_cc << std::endl; +#endif } // Step 2. @@ -198,7 +393,15 @@ R_box.init(); A->clear(); A->append(x0); - N->clear(); + clear_N(N); + + mln_assertion(map(x0).belongs_to == 0); + if (map(x0).border_of_hole_of != 0) + { + mln_assertion(map(x0).border_of_hole_of != current_cc); + current_parent = map(x0).border_of_hole_of; +// std::cout << "propagation : " << x0 << std::endl; + } } // Step 3. @@ -209,7 +412,6 @@ std::cout << "Step 3" << std::endl; #endif mln_piter(arr_t) a(*A); - mln_niter(Nbh) x(nbh, a); // Stop. if (A->npoints() == 0) @@ -221,6 +423,10 @@ #endif for_all(a) { + mln_assertion(map(a).belongs_to == 0); + map(a).belongs_to = current_cc; + current_cc->elt().points.append(a); + current_cc->elt().npoints++; tagged(a) = true; is(a) = in_R; #ifdef FLLTDEBUG @@ -247,17 +453,39 @@ std::cout << "Add To N : "; #endif for_all(a) - for_all(x) - if (u.has(x) && is(x) == in_O && input(x) == g) { - mln_assertion(!tagged(x)); - N_box.take(x); - is(x) = in_N; - N->append(x); + arr_dp_t* nbh = &neighb_c6[a[1] % 2]; + for(arr_dp_t_it x = nbh->begin(); x != nbh->end(); x++) + { + mln_point(I) n = mln_point(I)(a) + mln_dpoint(I)(*x); + if (is(n) == in_O) + { + if (!current_parent) + { + if (map(n).border_of_hole_of != 0 && + map(n).border_of_hole_of != map(n).belongs_to) + { + mln_assertion(map(n).border_of_hole_of != current_cc); + current_parent = map(n).border_of_hole_of; +// std::cout << "propagation : " << n << std::endl; + } + else if (map(n).belongs_to) + { + current_parent = map(n).belongs_to->parent(); + mln_assertion(current_parent != current_cc); + } + } + map(n).set_border_of_hole_of(current_cc); + N_box.take(n); + is(n) = in_N; + if (u.has(n)) + N[u(n)]->append(n); #ifdef FLLTDEBUG - std::cout << x; + std::cout << n; #endif } + } + } #ifdef FLLTDEBUG std::cout << std::endl; #endif @@ -266,26 +494,32 @@ std::cout << "g = " << g << std::endl; #endif - // Stop if N is empty. - if (N->npoints() == 0) + // Stop if N[g] is empty. + if (N[g]->npoints() == 0) + { + add_npoints_to(current_parent, current_cc->elt().npoints); + // Was : current_parent->elt().npoints += current_cc->elt().npoints; + current_cc->set_parent(current_parent); + erase_exterior_border(map, N_box, current_cc, neighb_c6); goto step_1; + } else { - swap_arrays(A, N); - N->clear(); + // CC is growing. + swap_arrays(A, N[g]); + N[g]->clear(); goto step_3; } } - step_4: - { - // Follow N, find the holes, and browse it. - } - end: { - std::cout << n_step_1 << ' ' << n_step_3 << std::endl; + std::cout << "n_step_1 : " << n_step_1 + << " n_step_3 : " << n_step_3 + << " number of cc : " << cc_cpt << std::endl; } + + return *new tree_type(root); } } // end of namespace mln::my @@ -296,11 +530,16 @@ int main() { using namespace mln; + using namespace mln::my; using value::int_u8; - image2d<int_u8> lena; - - io::pgm::load(lena, "../../../img/lena.pgm"); + typedef image2d<int_u8> I; + typedef fllt_node(mln_point_(I), mln_value_(I)) node_type; + typedef fllt_tree(mln_point_(I), mln_value_(I)) tree_type; + +// image2d<int_u8> ima; +// //io::pgm::load(ima, "../../../img/lena.pgm"); +// io::pgm::load(ima, "../tapis.pgm"); // int_u8 vs[9][9] = { @@ -319,7 +558,55 @@ //image2d<int_u8> lena = make::image2d(vs); - my::fllt(lena, c4()); - io::pgm::save(lena, "./out.pgm"); +// int vs[3][6] = { {0, 0, 0, 1, 1, 1}, +// {0, 1, 0, 1, 0, 1}, +// {0, 0, 0, 1, 1, 1} }; + +// int vs[5][5] = { {100, 100, 100, 100, 100}, +// {100, 200, 255, 200, 100}, +// {100, 200, 200, 200, 100}, +// {100, 200, 255, 200, 100}, +// {100, 100, 100, 100, 100} }; + + int vs[9][9] = { {2,2,2,2,2,2,2,2,2}, + {2,2,2,2,2,2,2,2,2}, + {2,1,1,1,1,1,1,1,2}, + {2,1,2,2,1,0,0,1,2}, + {2,1,2,2,1,0,0,1,2}, + {2,1,2,2,1,0,0,1,2}, + {2,1,1,1,1,1,1,1,2}, + {2,1,1,1,1,1,1,1,2}, + {2,2,2,2,2,2,2,2,2} }; + +// int vs[7[7] = { {101, 101, 101, 191, 204, 255, 191}, +// {101, 101, 191, 204, 204, 204, 204}, +// {101, 191, 191, 204, 255, 204, 191}, +// {204, 204, 204, 191, 191, 191, 76}, +// {191, 191, 204, 191, 101, 101, 76}, +// {204, 204, 191, 204, 101, 76, 76}, +// {191, 191, 191, 101, 76, 101, 0}}; + + +// int vs[2][1] = { {121}, {101} }; + + image2d<int> ima_(make::image2d(vs)); + image2d<int_u8> ima(ima_.domain()); + level::fill(ima, ima_); + + tree_type tree = my::fllt(ima); + + + draw_tree(ima, tree); + + + + image2d<value::int_u8> output (ima.domain ()); + util::tree_to_image (tree, output); + mln_assertion(output == ima); + io::pgm::save(output, "out.pgm"); + + image2d<value::int_u8> bounds (ima.domain ()); + visualize_bounds(bounds, tree, 2); + io::pgm::save(bounds, "bounds.pgm"); } Index: trunk/milena/sandbox/garrigues/fllt/fllt_theo.cc =================================================================== --- trunk/milena/sandbox/garrigues/fllt/fllt_theo.cc (revision 1876) +++ trunk/milena/sandbox/garrigues/fllt/fllt_theo.cc (revision 1877) @@ -25,6 +25,10 @@ // reasons why the executable file might be covered by the GNU General // Public License. +#include <iomanip> +#include <iostream> +#include <sstream> + #include <mln/core/image2d.hh> #include <mln/core/neighb2d.hh> #include <mln/core/p_array.hh> @@ -39,7 +43,10 @@ #include <mln/debug/println.hh> #include <mln/labeling/regional_minima.hh> #include <mln/accu/bbox.hh> +#include <mln/io/pgm/save.hh> + +#include <mln/core/cast_image.hh> namespace mln { @@ -47,16 +54,39 @@ namespace my { - template <typename N_t> - unsigned compute_gN(const N_t& N) + + void save_state(const image2d<unsigned char>& out) { - for (unsigned i = 0; i < 256; ++i) - if (N[i].npoints() != 0) - return i; - mln_invariant(0); - return 0; +// static int id = 0; +// std::stringstream filename; +// filename << "fllt_trace_" << std::setw(5) << std::setfill('0') +// << std::right << id++ << ".ppm"; + +// io::pgm::save(cast_image<value::int_u8>(out), filename.str()); + //io::pgm::save(out, filename.str()); } + void save_u(const image2d<value::int_u8>& u, + const image2d<unsigned char>& is, + box2d R_box) + { + static int id = 0; + std::stringstream filename; + filename << "fllt_u_" << std::setw(5) << std::setfill('0') + << std::right << id++ << ".ppm"; + + image2d<value::int_u8> out = clone(u); + const unsigned in_R = 255; + + mln_assertion(R_box.is_valid()); + mln_piter_(box2d) p(R_box); + for_all(p) + if (is(p) == in_R) + out(p) = 255; + + io::pgm::save(out, filename.str()); + //io::pgm::save(out, filename.str()); + } template <typename I, typename Nbh> void fllt(const Image<I>& input_, const Neighborhood<Nbh>& nbh_) @@ -65,14 +95,16 @@ const Nbh& nbh = exact(nbh_); unsigned l = 0, l_max; - mln_ch_value(I, unsigned) reg_min = labeling::regional_minima(input, nbh, l_max); + mln_ch_value(I, unsigned) reg_min = + labeling::regional_minima(input, nbh, l_max); // Variables. I u = mln::clone(input); mln_point(I) x0; mln_value(I) g, gN; image2d<unsigned char> is(input.domain()); - const unsigned in_R = 1, in_N = 2, in_O = 0; + image2d<bool> tagged(input.domain()); + const unsigned in_R = 255, in_N = 2, in_O = 0; typedef p_array<mln_point(I)> arr_t; arr_t A; @@ -80,54 +112,124 @@ accu::bbox<mln_point(I)> R_box; - int cpt = 0; - + level::fill(tagged, false); + mln_piter(I) min(input.domain()); + min.start(); // Step 1. step_1: { +#ifdef FLLTDEBUG + std::cout << "Step 1" << std::endl; +#endif if (l == l_max) return; l += 1; - mln_piter(I) p(input.domain()); - for_all(p) - if (reg_min(p) == l) + for(min.next(); min.is_valid(); min.next()) + if (reg_min(min) !=0 && !tagged(min)) break; - x0 = p; + +#ifdef FLLTDEBUG + std::cout << "min local : " << min << std::endl; +#endif + + if (!min.is_valid()) + goto end; + + x0 = min; g = input(x0); } // Step 2. step_2: { +#ifdef FLLTDEBUG + std::cout << "Step 2" << std::endl; +#endif R_box.init(); level::fill(is, in_O); + A.clear(); A.append(x0); + for (unsigned i = 0; i < 256; ++i) + N[i].clear(); } // Step 3. step_3: { +#ifdef FLLTDEBUG + std::cout << "Step 3" << std::endl; +#endif mln_piter(arr_t) a(A); mln_niter(Nbh) x(nbh, a); // Stop. - if (A.npoints() > 0) + if (A.npoints() == 0) goto end; // R <- R U A +#ifdef FLLTDEBUG + std::cout << "Add To R : "; +#endif for_all(a) + { + tagged(a) = true; is(a) = in_R; +#ifdef FLLTDEBUG + std::cout << a; +#endif + } +#ifdef FLLTDEBUG + std::cout << std::endl; +#endif + + +#ifdef FLLTDEBUG + std::cout << "points of A : " << A.npoints() << std::endl; +#endif mln_assertion(A.npoints() > 0); R_box.take(A.bbox()); + mln_assertion(R_box.is_valid()); +#ifdef FLLTTRACE + save_state(is); + save_u(u, is, R_box); +#endif // N <- N U { x in nbh of A and not in R } +#ifdef FLLTDEBUG + std::cout << "Add To N : "; +#endif for_all(a) for_all(x) - if (u.has(x) && is(x) != in_R) + if (u.has(x) && (is(x) == in_O)) + { + is(x) = in_N; N[u(x)].append(x); - +#ifdef FLLTDEBUG + std::cout << x; +#endif + } +#ifdef FLLTDEBUG + std::cout << std::endl; +#endif // gN = min u(x) for all x in N - gN = compute_gN(N); + unsigned i; + for (i = 0; i < 256; ++i) + if (N[i].npoints() != 0) + { + gN = i; + break; + } +#ifdef FLLTDEBUG + std::cout << "gN = " << gN << ", g = " << g << std::endl; +#endif + + // Stop if N is empty. +#ifdef FLLTDEBUG + std::cout << "i = " << i << std::endl; +#endif + if (i == 256) + goto step_4c; + mln_assertion(N[gN].npoints() > 0); // FIXME: update the number of CC of the border of R } @@ -138,25 +240,39 @@ // a) if (g < gN) { +#ifdef FLLTDEBUG + std::cout << "Step 4a" << std::endl; +#endif // FIXME: DO the hole thing. - A = N[g]; - N[g].clear(); + g = gN; - gN = compute_gN(N); + + A = N[gN]; + N[gN].clear(); + mln_assertion(A.npoints() > 0); + mln_assertion(N[gN].npoints() == 0); goto step_3; } // b) else if (g == gN) { - A = N[g]; - N[g].clear(); - g = gN; - gN = compute_gN(N); +#ifdef FLLTDEBUG + std::cout << "Step 4b" << std::endl; +#endif + A = N[gN]; + N[gN].clear(); + mln_assertion(A.npoints() > 0); + mln_assertion(N[gN].npoints() == 0); goto step_3; } // c) else { + step_4c: +#ifdef FLLTDEBUG + std::cout << "Step 4c" << std::endl; +#endif + mln_assertion(R_box.is_valid()); mln_piter(box_<mln_point(I)>) p(R_box); for_all(p) if (is(p) == in_R) @@ -180,8 +296,26 @@ using value::int_u8; image2d<int_u8> lena; + io::pgm::load(lena, "small.pgm"); + +// int_u8 vs[9][9] = { + +// { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, +// { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, +// { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, +// { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, +// { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, +// { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, +// { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, +// { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, +// { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + +// }; + + //image2d<int_u8> lena = make::image2d(vs); + my::fllt(lena, c4()); io::pgm::save(lena, "./out.pgm"); Index: trunk/milena/sandbox/garrigues/fllt/fllt_simple.svg.2.cc =================================================================== --- trunk/milena/sandbox/garrigues/fllt/fllt_simple.svg.2.cc (revision 0) +++ trunk/milena/sandbox/garrigues/fllt/fllt_simple.svg.2.cc (revision 1877) @@ -0,0 +1,349 @@ +// Copyright (C) 2008 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, 51 Franklin Street, Fifth Floor, +// 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. + +#include <iomanip> +#include <iostream> +#include <sstream> + +#include <mln/core/image2d.hh> +#include <mln/core/sub_image.hh> +#include <mln/core/neighb2d.hh> +#include <mln/core/p_array.hh> +#include <mln/core/clone.hh> + +#include <mln/value/int_u8.hh> + +#include <mln/io/pgm/load.hh> +#include <mln/io/pgm/save.hh> + +#include <mln/level/fill.hh> +#include <mln/debug/println.hh> +#include <mln/labeling/regional_minima.hh> +#include <mln/accu/bbox.hh> +#include <mln/io/pgm/save.hh> + + +#include <mln/core/cast_image.hh> + +namespace mln +{ + // Un autre version recursive de la fllt. + + // Idee : + // Parcourir l'image en pratant d'un coin de preference, + // le parcour des pixels se fait dans un ordre conexe. + // + + /* + + fonction fllt_rec(racine R, domaine D, marques M, conexite C) + { + pour tout les points du domaine non marquees + recuperer la composante conexe A (en conexite C) qui inclut ce point : + Ceci est fait avec la methode de grossissement de region + pour avoir acces a la bordure externe et donc aux trous + de la composante. + + Cette composante sera fille de R dans l'arbre d'inclusion. + + Marquer les points de A (Peut etre fait en meme temps que la + construction de A) + + Pour chaque trous T de A : + appel recursif : fllt_rec(A, T.domaine(), marques, inv(C)) + T.domaine() sera calculer en recuperant la composante connexe + de la bordure de A lui correspondant (On recupere facilement + les segments horizontaux qui le composent -> parcour ok). + + } + inv(c4) = c8 + inv(c8) = c4 + + + Autre version qui Marche sur les images hexagonales (Plus rapide et plus simple) + car il y a plus le probleme du theoreme de jordan non verifie. + FIXME: Est-ce que rendre l'image hexagonale altere vraiment le resultat? + + pour tout les points du domaine non marquees + recuperer la composante conexe A qui inclut ce point : + Ceci est fait avec la methode de grossissement de region + pour avoir acces a la bordure externe et donc aux trous + de la composante. + + Marquer les points de A (Peut etre fait en meme temps que la + construction de A) + + Marquer les extremites des trou de A. + + Si un point de A est l'extremite d'un trou, + alors on a facilement le pere de A (la forme qui inclue A). + Sinon + C'est qu'il y a une composante connexe adjacente qui + a deja ete construite, et qui a donc deja un pere, qui + est aussi celui de A. + + continuer jusqu'a avoir marquer tout les points + + */ + + namespace my + { + + void save_u(const image2d<value::int_u8>& u, + const image2d<unsigned char>& is, + box2d R_box) + { + static int id = 0; + std::stringstream filename; + filename << "fllt_u_" << std::setw(5) << std::setfill('0') + << std::right << id++ << ".ppm"; + + image2d<value::int_u8> out = clone(u); + const unsigned in_R = 255; + + mln_piter_(box2d) p(R_box); + for_all(p) + if (is(p) == in_R) + out(p) = 255; + + io::pgm::save(out, filename.str()); + } + + void swap_arrays(p_array<point2d>*& A, + p_array<point2d>*& N) + { + p_array<point2d>* tmp = A; + A = N; + N = tmp; + } + + template <typename I> + void fllt(const Image<I>& input_) + { + const I& input = exact(input_); + + typedef std::vector<dpoint2d> arr_dp_t; + typedef std::vector<dpoint2d>::const_iterator arr_dp_t_it; + + // C6 neigboohood. + arr_dp_t neighb_c6[2]; + neighb_c6[0].push_back(make::dpoint2d(-1,-1)); + neighb_c6[0].push_back(make::dpoint2d(-1,0)); + neighb_c6[0].push_back(make::dpoint2d(-1,1)); + neighb_c6[0].push_back(make::dpoint2d(0,-1)); + neighb_c6[0].push_back(make::dpoint2d(0,1)); + neighb_c6[0].push_back(make::dpoint2d(1,0)); + + neighb_c6[1].push_back(make::dpoint2d(1,-1)); + neighb_c6[1].push_back(make::dpoint2d(1,0)); + neighb_c6[1].push_back(make::dpoint2d(1,1)); + neighb_c6[1].push_back(make::dpoint2d(0,-1)); + neighb_c6[1].push_back(make::dpoint2d(0,1)); + neighb_c6[1].push_back(make::dpoint2d(-1,0)); + + // Variables. + I u = mln::clone(input); + mln_point(I) x0; + mln_value(I) g, gN; + image2d<unsigned char> is(input.domain()); + image2d<bool> tagged(input.domain()); + const unsigned in_R = 255, in_N = 2, in_O = 0; + + typedef p_array<mln_point(I)> arr_t; + arr_t* A = new arr_t(); + arr_t* N = new arr_t(); + + accu::bbox<mln_point(I)> R_box, N_box; + + unsigned n_step_1 = 0, n_step_3 = 0; + + level::fill(tagged, false); + mln_piter(I) min(input.domain()); + min.start(); + // Step 1. + step_1: + { +#ifdef FLLTDEBUG + std::cout << "Step 1" << std::endl; +#endif + ++n_step_1; + for(; min.is_valid(); min.next()) + if (!tagged(min)) + break; + + if (!min.is_valid()) + goto end; + + x0 = min; + g = input(x0); + } + + // Step 2. + step_2: + { +#ifdef FLLTDEBUG + std::cout << "Step 2" << std::endl; +#endif + if (N_box.is_valid()) + level::fill(inplace(is | N_box.to_result()), in_O); + + N_box.init(); + R_box.init(); + A->clear(); + A->append(x0); + N->clear(); + } + + // Step 3. + step_3: + { + ++n_step_3; +#ifdef FLLTDEBUG + std::cout << "Step 3" << std::endl; +#endif + mln_piter(arr_t) a(*A); + + // Stop. + if (A->npoints() == 0) + goto end; + + // R <- R U A +#ifdef FLLTDEBUG + std::cout << "Add To R : "; +#endif + for_all(a) + { + tagged(a) = true; + is(a) = in_R; +#ifdef FLLTDEBUG + std::cout << a; +#endif + } +#ifdef FLLTDEBUG + std::cout << std::endl; +#endif + + +#ifdef FLLTDEBUG + std::cout << "points of A : " << A->npoints() << std::endl; +#endif + mln_assertion(A->npoints() > 0); + R_box.take(A->bbox()); + mln_assertion(R_box.is_valid()); + +#ifdef FLLTTRACE + save_u(u, is, R_box); +#endif + // N <- N U { x in nbh of A and not in R / input(x) == g} +#ifdef FLLTDEBUG + std::cout << "Add To N : "; +#endif + for_all(a) + { + arr_dp_t* nbh = &neighb_c6[a[1] % 2]; +// if (a[1] % 2) +// x = &x2; + for(arr_dp_t_it x = nbh->begin(); x != nbh->end(); x++) + { + mln_point(I) n = mln_point(I)(a) + mln_dpoint(I)(*x); + if (u.has(n) && is(n) == in_O && input(n) == g) + { + mln_assertion(!tagged(n)); + N_box.take(n); + is(n) = in_N; + N->append(n); +#ifdef FLLTDEBUG + std::cout << n; +#endif + } + } + } +#ifdef FLLTDEBUG + std::cout << std::endl; +#endif + +#ifdef FLLTDEBUG + std::cout << "g = " << g << std::endl; +#endif + + // Stop if N is empty. + if (N->npoints() == 0) + goto step_1; + else + { + swap_arrays(A, N); + N->clear(); + goto step_3; + } + } + + step_4: + { + // Follow N, find the holes, and browse it. + } + + end: + { + std::cout << n_step_1 << ' ' << n_step_3 << std::endl; + } + } + + } // end of namespace mln::my + +} // end of namespace mln + + +int main() +{ + using namespace mln; + using value::int_u8; + + image2d<int_u8> lena; + + io::pgm::load(lena, "../../../img/lena.pgm"); + + + // int_u8 vs[9][9] = { + + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + // { 2, 2, 2, 2, 2, 2, 2, 2, 2 }, + + // }; + + //image2d<int_u8> lena = make::image2d(vs); + + my::fllt(lena); + io::pgm::save(lena, "./out.pgm"); + +}
participants (1)
-
Matthieu Garrigues