* edwin/MaxTree/Makefile: New. * edwin/MaxTree/cplx2d.hh: Special edge connectivity. * edwin/MaxTree/salembier_edge.cc, * edwin/MaxTree/salembier_edge.hh: Boundary consideration of salembier algorithm. --- milena/sandbox/ChangeLog | 10 ++ milena/sandbox/edwin/MaxTree/Makefile | 13 ++ milena/sandbox/edwin/MaxTree/cplx2d.hh | 113 ++++++++++++++ milena/sandbox/edwin/MaxTree/salembier_edge.cc | 30 ++++ milena/sandbox/edwin/MaxTree/salembier_edge.hh | 191 ++++++++++++++++++++++++ 5 files changed, 357 insertions(+), 0 deletions(-) create mode 100644 milena/sandbox/edwin/MaxTree/Makefile create mode 100644 milena/sandbox/edwin/MaxTree/cplx2d.hh create mode 100644 milena/sandbox/edwin/MaxTree/salembier_edge.cc create mode 100644 milena/sandbox/edwin/MaxTree/salembier_edge.hh
diff --git a/milena/sandbox/ChangeLog b/milena/sandbox/ChangeLog index 29b629c..f1a971f 100644 --- a/milena/sandbox/ChangeLog +++ b/milena/sandbox/ChangeLog @@ -1,5 +1,15 @@ 2010-09-30 edwin carlinet carlinet@lrde.epita.fr
+ Salembier algorithm working on edges. + + * edwin/MaxTree/Makefile: New. + * edwin/MaxTree/cplx2d.hh: Special edge connectivity. + * edwin/MaxTree/salembier_edge.cc, + * edwin/MaxTree/salembier_edge.hh: Boundary consideration of + salembier algorithm. + +2010-09-30 edwin carlinet carlinet@lrde.epita.fr + Minor fixes.
* edwin/TreeAlgorithmsComp/Makefile: Minor fixes. diff --git a/milena/sandbox/edwin/MaxTree/Makefile b/milena/sandbox/edwin/MaxTree/Makefile new file mode 100644 index 0000000..97d1bff --- /dev/null +++ b/milena/sandbox/edwin/MaxTree/Makefile @@ -0,0 +1,13 @@ +CCFILES := $(shell find -name '*.cc') +CXXFLAGS=-W -Wall -I../../.. +CC=g++ + +all: + +depend: + $(CXX) $(CXXFLAGS) -MM $(CCFILES) > makefile.deps + +clean: + rm *.o + +-include makefile.deps \ No newline at end of file diff --git a/milena/sandbox/edwin/MaxTree/cplx2d.hh b/milena/sandbox/edwin/MaxTree/cplx2d.hh new file mode 100644 index 0000000..bdf038f --- /dev/null +++ b/milena/sandbox/edwin/MaxTree/cplx2d.hh @@ -0,0 +1,113 @@ +// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena 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 Olena. If not, see http://www.gnu.org/licenses/. +// +// As a special exception, you may use this file as part of a free +// software project 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 CPLX2D_HH +# define CPLX2D_HH + +# include <mln/core/var.hh> +# include <mln/data/paste.hh> +# include <mln/morpho/gradient.hh> + +namespace mln +{ + + template <typename I, typename J> + void data__paste_values(const Image<I>& input_, Image<J>& output_) + { + const I& input = exact(input_); + J& output = exact(output_); + + mln_fwd_piter(I) pi(input.domain()); + mln_fwd_piter(J) po(output.domain()); + for_all_2(pi, po) + output(po) = input(pi); + } + + namespace cplx2d + { + + typedef neighb< win::multiple<window2d, bool(*)(const point2d&)> > dbl_neighb2d; + + inline + bool is_row_odd(const point2d& p) + { + return p.row() % 2; + } + + // Pixel to neighboring edges. + const neighb2d& p2e() + { + return c4(); + } + + // Edge to (the couple of) pixels. + const dbl_neighb2d& e2p() + { + static bool e2p_h[] = { 0, 1, 0, + 0, 0, 0, + 0, 1, 0 }; + static bool e2p_v[] = { 0, 0, 0, + 1, 0, 1, + 0, 0, 0 }; + static dbl_neighb2d nbh = make::double_neighb2d(is_row_odd, e2p_h, e2p_v); + return nbh; + } + + + inline + bool is_pixel(const point2d& p) + { + // Original pixels. + return p.row() % 2 == 0 && p.col() % 2 == 0; + } + + inline + bool is_edge(const point2d& p) + { + // Edges between pixels. + return p.row() % 2 + p.col() % 2 == 1; + } + + typedef fun::C<bool (*)(const mln::point2d&)> predicate_t; + + image_if< image2dvalue::int_u8, predicate_t > + f_to_g(const image2dvalue::int_u8& f, value::int_u8 value_on_non_edges = 0) + { + image2dvalue::int_u8 f_(2 * f.nrows() - 1, 2 * f.ncols() - 1); + data::fill(f_, value_on_non_edges); // Useless but for display! + + data__paste_values(f, (f_ | is_pixel).rw()); + + mln_VAR(g, f_ | is_edge); + data::paste(morpho::gradient(extend(g, f_), e2p().win()), g); + + return g; + } + + } + +} + +#endif // !CPLX2D_HH diff --git a/milena/sandbox/edwin/MaxTree/salembier_edge.cc b/milena/sandbox/edwin/MaxTree/salembier_edge.cc new file mode 100644 index 0000000..a9abcea --- /dev/null +++ b/milena/sandbox/edwin/MaxTree/salembier_edge.cc @@ -0,0 +1,30 @@ +#include <mln/io/pgm/load.hh> +#include <mln/debug/println.hh> +#include "salembier_edge.hh" + +void usage(char** argv) +{ + std::cout << "Usage: " << argv[0] << " input.png" << std::endl; + std::cout << "Calcule la longueur des contours des CC avec l'algo de Salembier." + << std::endl; + abort(); +} + +int main(int argc, char** argv) +{ + using namespace mln; + typedef image2d< value::int_u8 > I; + + if (argc < 2) + usage(argv); + + const char* filename = argv[1]; + + I input; + io::pgm::load(input, filename); + + image2d<int> e = salembier(input); + + std::cout << "Attribute Image: " << std::endl; + debug::println(e); +} diff --git a/milena/sandbox/edwin/MaxTree/salembier_edge.hh b/milena/sandbox/edwin/MaxTree/salembier_edge.hh new file mode 100644 index 0000000..5072a2b --- /dev/null +++ b/milena/sandbox/edwin/MaxTree/salembier_edge.hh @@ -0,0 +1,191 @@ +// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE) +// +// This file is part of Olena. +// +// Olena is free software: you can redistribute it and/or modify it under +// the terms of the GNU General Public License as published by the Free +// Software Foundation, version 2 of the License. +// +// Olena 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 Olena. If not, see http://www.gnu.org/licenses/. +// +// As a special exception, you may use this file as part of a free +// software project 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 SALEMBIER_EDGE_HH +# define SALEMBIER_EDGE_HH + +#include <mln/core/image/image2d.hh> +#include <mln/core/alias/neighb2d.hh> +#include <mln/core/image/dmorph/image_if.hh> +#include <mln/core/routine/extend.hh> +#include <mln/core/routine/initialize.hh> + +#include <mln/core/image/attribute_image.hh> +#include <mln/util/hqueues.hh> + +#include "cplx2d.hh" + + +namespace mln +{ + typedef image2dvalue::int_u8 I; + + + template <typename I, typename N> + struct salembier_args + { + typedef mln_psite(I) P; + typedef mln_value(I) V; + + enum { nvalues = mln_card(V) }; + + const I& f; + const N& nbh; + unsigned hmin; + util::hqueues< mln_psite(I), mln_value(I) > hqueue; + P levroot[nvalues]; + bool is_node_at_level[nvalues]; + mln_ch_value(I, P) parent; + mln_ch_value(I, bool) deja_vu; + mln_ch_value(I, bool) active_edges; + mln_ch_value(I, int) count_edges; + }; + + + + template <typename I, typename N> + int flood(salembier_args<I, N>& args, const int h) + { + typedef mln_psite(I) P; + + mln_assertion(args.is_node_at_level[h]); + + P root = args.levroot[h]; + + while (!args.hqueue[h].empty()) + { + P p = args.hqueue[h].pop_front(); + args.parent(p) = root; + + mln_niter(N) n(args.nbh, p); + for_all(n) + if (args.f.domain().has(n) && !args.deja_vu(n)) + { + int n_idx = args.f(n); // en faite vset.index_of(...) + args.hqueue[n_idx].push(n); + args.deja_vu(n) = true; + + if (!args.is_node_at_level[n_idx]) + { + args.levroot[n_idx] = n; + args.is_node_at_level[n_idx] = true; + } + + while (h < n_idx) + n_idx = flood(args, n_idx); + } + + mln_niter(N) e(cplx2d::p2e(), p * 2); + for_all(e) + if (args.active_edges(e)) + { + args.active_edges(e) = false; + args.count_edges(root)--; // attribute.untake(e) + } + else + { + args.active_edges(e) = true; + args.count_edges(root)++; // attribute.take(e) + } + } + + args.is_node_at_level[h] = false; + unsigned c = h; + while (c > args.hmin && !args.is_node_at_level[c]) + --c; + + if (args.is_node_at_level[c]) + { + P q = args.levroot[c]; + args.parent(root) = q; + args.count_edges(q) += args.count_edges(root); // attribute.merge + } + else + args.parent(root) = root; + + return c; + } + + image2d<int> + salembier(const image2dvalue::int_u8& f, + const neighb2d& nbh = c4()) + { + // Init + typedef image2dvalue::int_u8 I; + typedef neighb2d N; + + enum { nv = mln_card(mln_value_(I)) }; + + salembier_args<I, N> args = { f, nbh, }; + { + box2d b(2 * f.nrows() - 1, 2 * f.ncols() - 1); + + initialize(args.parent, f); + initialize(args.deja_vu, f); + initialize(args.count_edges, f); + args.active_edges.init_(b); + + std::fill(args.is_node_at_level, args.is_node_at_level + nv, false); + data::fill(args.deja_vu, false); + data::fill(args.active_edges, false); + data::fill(args.count_edges, 0); + } + + // Get start value + mln_psite_(I) pstart = f.domain().pmin(); + mln_value_(I) hstart = f(pstart); + { + unsigned h[nv] = {0}; + mln_piter_(I) p(f.domain()); + for_all(p) + { + mln_value_(I) v = f(p); + ++h[v]; + if (v < hstart) + { + hstart = v; + pstart = p; + } + } + + for (unsigned i = 0; i < nv; ++i) + args.hqueue[i].reserve(h[i]); + } + + // Start flooding + args.hmin = hstart; + args.deja_vu(pstart) = true; + args.hqueue[hstart].push(pstart); + args.levroot[hstart] = pstart; + args.is_node_at_level[hstart] = true; + + int r = flood(args, hstart); + mln_assertion(r == hstart); + return args.count_edges; + } + +} + +#endif // !SALEMBIER_EDGE_HH