
https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox Index: ChangeLog from Thierry Geraud <thierry.geraud@lrde.epita.fr> Augment color segmentation algorithm. * geraud/tufa_2008/filter_n.cc: Simplify a test. * geraud/color/sum_pix.hh: New. * geraud/color/blen_pix.hh: New. * geraud/color/segment.cc: Augment. color/blen_pix.hh | 174 +++++++++++++++ color/segment.cc | 561 ++++++++++++++++++++++++++++++++++++++++++-------- color/sum_pix.hh | 162 ++++++++++++++ tufa_2008/filter_n.cc | 2 4 files changed, 810 insertions(+), 89 deletions(-) Index: geraud/tufa_2008/filter_n.cc --- geraud/tufa_2008/filter_n.cc (revision 3148) +++ geraud/tufa_2008/filter_n.cc (working copy) @@ -164,7 +164,7 @@ if (! t.is_root(p)) { acc(t.parent(p)).take(acc(p)); - if (t.f()(t.parent(p)) != t.f()(p)) // not within a flat zone + if (t.is_a_node(p)) ++nchildren(t.parent(p)); // so parent(p) is a node } // Back-propagate attribute from a node to sites of its Index: geraud/color/sum_pix.hh --- geraud/color/sum_pix.hh (revision 0) +++ geraud/color/sum_pix.hh (revision 0) @@ -0,0 +1,162 @@ +// Copyright (C) 2007, 2008 EPITA Research and Development Laboratory +// (LRDE) +// +// 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. + +#ifndef MLN_ACCU_SUM_PIX_HH +# define MLN_ACCU_SUM_PIX_HH + +/// \file mln/accu/sum_pix.hh +/// +/// Define an accumulator that computes a sum. + +# include <mln/core/concept/meta_accumulator.hh> +# include <mln/accu/internal/base.hh> + +# include <mln/util/pix.hh> // To prevent accu::sum_pix to work on pixels (ambiguous). + +# include <mln/trait/value_.hh> // For mln_sum_pix. +# include <mln/value/builtin/all.hh> // In the case of summing builtin values. +# include <mln/literal/zero.hh> // For initialization. + + +namespace mln +{ + + namespace accu + { + + + /// Generic sum_pix accumulator class. + /*! + * Parameter \c T is the type of values that we sum. Parameter \c + * S is the type to store the value sum; the default type of + * \c S is the summation type (property) of \c T. + */ + template <typename P, typename S = mln_sum(mln_value(P))> + struct sum_pix : public mln::accu::internal::base< const S&, sum_pix<P,S> > + { + typedef P argument; + + sum_pix(); + + /// Manipulators. + /// \{ + void init(); + void take(const argument& t); + void take(const sum_pix<P,S>& other); + /// \} + + void set_value(S v) + { + s_ = v; + } + + /// Get the value of the accumulator. + const S& to_result() const; + + /// Check whether this accu is able to return a result. + /// Always true here. + bool is_valid() const; + + protected: + + S s_; + }; + + + namespace meta + { + + /// Meta accumulator for sum_pix. + struct sum_pix : public Meta_Accumulator< sum_pix > + { + template <typename P, typename S = mln_sum(mln_value(P))> + struct with + { + typedef accu::sum_pix<P, S> ret; + }; + }; + + } // end of namespace mln::accu::meta + + +# ifndef MLN_INCLUDE_ONLY + + template <typename P, typename S> + inline + sum_pix<P,S>::sum_pix() + { + init(); + } + + template <typename P, typename S> + inline + void + sum_pix<P,S>::init() + { + s_ = literal::zero; + } + + template <typename P, typename S> + inline + void sum_pix<P,S>::take(const argument& p) + { + s_ += 1 + p.v(); + } + + template <typename P, typename S> + inline + void + sum_pix<P,S>::take(const sum_pix<P,S>& other) + { + s_ += other.s_; + } + + template <typename P, typename S> + inline + const S& + sum_pix<P,S>::to_result() const + { + return s_; + } + + template <typename P, typename S> + inline + bool + sum_pix<P,S>::is_valid() const + { + return true; + } + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::accu + +} // end of namespace mln + + +#endif // ! MLN_ACCU_SUM_PIX_HH Index: geraud/color/segment.cc --- geraud/color/segment.cc (revision 3148) +++ geraud/color/segment.cc (working copy) @@ -1,25 +1,78 @@ +#include <cstdlib> + # include <mln/core/var.hh> # include <mln/core/image/image2d.hh> +#include <mln/core/alias/box3d.hh> + # include <mln/core/alias/neighb2d.hh> +#include <mln/make/double_neighb2d.hh> # include <mln/core/image/image_if.hh> -# include <mln/core/routine/extend.hh> # include <mln/pw/all.hh> +#include <mln/core/routine/extend.hh> +#include <mln/core/routine/duplicate.hh> +#include <mln/data/paste.hh> -# include <mln/io/ppm/load.hh> +#include <mln/io/pgm/load.hh> # include <mln/io/pgm/save.hh> +#include <mln/io/ppm/load.hh> # include <mln/io/ppm/save.hh> + # include <mln/math/diff_abs.hh> -# include <mln/make/double_neighb2d.hh> -# include <mln/data/paste.hh> -# include <mln/morpho/closing_volume.hh> -# include <mln/morpho/meyer_wst.hh> +#include <mln/debug/println.hh> + # include <mln/morpho/dilation.hh> # include <mln/morpho/erosion.hh> +#include <mln/morpho/tree/data.hh> +#include <mln/morpho/meyer_wst.hh> +#include <mln/morpho/closing_attribute.hh> + +#include <mln/core/site_set/p_array.hh> +#include <mln/level/sort_psites.hh> +#include <mln/labeling/regional_minima.hh> + + +#include <mln/accu/count.hh> +#include <mln/accu/volume.hh> + +#include "sum_pix.hh" + + +namespace mln +{ + + point3d color2point(const value::rgb8& c) + { + point3d p(c.red(), c.green(), c.blue()); + return p; + } + + + image2d<value::rgb8> blen_image; + + + template <typename B> + void accu_blen_take(B& b, const point2d& e) + { + if (e.row() % 2) + { + b.take(color2point(blen_image(e + up))); + b.take(color2point(blen_image(e + down))); + } + else + { + b.take(color2point(blen_image(e + left))); + b.take(color2point(blen_image(e + right))); + } + } + +} + +#include "blen_pix.hh" + -# include <mln/debug/println.hh> namespace mln @@ -52,8 +105,69 @@ } + // Neighborhoods. + + typedef neighb< win::multiple<window2d, bool(*)(const point2d&)> > dbl_neighb2d; + + const dbl_neighb2d& e2c() + { + static bool e2c_h[] = { 0, 1, 0, + 0, 0, 0, + 0, 1, 0 }; + static bool e2c_v[] = { 0, 0, 0, + 1, 0, 1, + 0, 0, 0 }; + static dbl_neighb2d nbh = make::double_neighb2d(is_row_odd, e2c_h, e2c_v); + return nbh; + } + + const dbl_neighb2d& e2e() + { + static bool e2e_h[] = { 0, 0, 1, 0, 0, + 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, + 0, 0, 1, 0, 0 }; + static bool e2e_v[] = { 0, 0, 0, 0, 0, + 0, 1, 0, 1, 0, + 1, 0, 0, 0, 1, + 0, 1, 0, 1, 0, + 0, 0, 0, 0, 0 }; + static dbl_neighb2d nbh = make::double_neighb2d(is_row_odd, e2e_h, e2e_v); + return nbh; + } + + // Transforms. + template <typename T> + image2d<T> + image2full(const image2d<T>& input) + { + image2d<T> output(2 * input.nrows() - 1, + 2 * input.ncols() - 1); + for (int row = 0; row < input.nrows(); ++row) + for (int col = 0; col < input.ncols(); ++col) + opt::at(output, 2 * row, 2 * col) = opt::at(input, row, col); + return output; + } + + template <typename T> + image2d<T> + full2image(const image2d<T>& input) + { + image2d<T> output((input.nrows() + 1) / 2, + (input.ncols() + 1) / 2); + for (int row = 0; row < input.nrows(); row += 2) + for (int col = 0; col < input.ncols(); col += 2) + opt::at(output, row / 2, col / 2) = + opt::at(input, row, col); + return output; + } + + + // Display. + template <typename I> I display_edge(const I& ima, mln_value(I) bg, unsigned zoom) { @@ -82,31 +196,6 @@ return output; } - template <typename T> - image2d<T> - image2squares(const image2d<T>& input) - { - image2d<T> output(2 * input.nrows() - 1, - 2 * input.ncols() - 1); - for (int row = 0; row < input.nrows(); ++row) - for (int col = 0; col < input.ncols(); ++col) - opt::at(output, 2 * row, 2 * col) = opt::at(input, row, col); - return output; - } - - template <typename T> - image2d<T> - squares2image(const image2d<T>& input) - { - image2d<T> output((input.nrows() + 1) / 2, - (input.ncols() + 1) / 2); - for (int row = 0; row < input.nrows(); row += 2) - for (int col = 0; col < input.ncols(); col += 2) - opt::at(output, row / 2, col / 2) = - opt::at(input, row, col); - return output; - } - // Distance. @@ -145,6 +234,285 @@ } + // Sorting. + + + template <typename I> + struct my_less_ + { + const I& ima_; + + inline + my_less_(const I& ima) + : ima_(ima) + { + } + + inline + bool operator()(const mln_site(I)& lhs, + const mln_site(I)& rhs) const + { + return util::ord_strict(ima_(lhs), ima_(rhs)) + || (ima_(lhs) == ima_(rhs) + && + util::ord_strict(lhs, rhs)); + } + }; + + + template <typename I, typename S> + p_array<mln_site(I)> my_sort_increasing(const I& ima, const S& s) + { + p_array<mln_site(I)> v; + convert::from_to(s, v); + std::sort(v.hook_std_vector_().begin(), v.hook_std_vector_().end(), + my_less_<I>(ima)); + return v; + } + + + + + // Tree -> attributes (on nodes only). + // ----------------------------------- + + + + template <typename A, typename T> + inline + mln_ch_value(typename T::function, mln_result(A)) + compute_attribute_on_nodes(const A& a, const T& t) + { + typedef typename T::function I; + + mln_ch_value(I, A) acc; + mln_ch_value(I, mln_result(A)) attr; + + // Initialization of 'acc'. + { + initialize(acc, t.f()); + data::fill(acc, a); // Transfer "dynamic data" (state) of 'a'. + } + + // Initialize every attribute with the corresponding pixel. + { + mln_piter(I) p(t.f().domain()); + for_all(p) + acc(p).take_as_init(make::pix(t.f(), p)); + } + + // Propagate attribute from a site to its parent. + { + mln_fwd_piter(T) p(t.domain()); + for_all(p) + if (! t.is_root(p)) + acc(t.parent(p)).take(acc(p)); + // No back-propagation to non-node sites. + } + + + // Change accumulator into its result. + { + initialize(attr, acc); + typedef typename T::nodes_t N; + mln_piter(N) p(t.nodes()); + for_all(p) + { + mln_invariant(t.is_a_node(p)); + attr(p) = acc(p).to_result(); + } + } + + return attr; + } + + + template <typename A, typename T> + inline + mln_ch_value(typename T::function, mln_result(A)) + compute_rand_attribute_on_nodes(const A& a, const T& t) + { + typedef typename T::function I; + + mln_ch_value(I, mln_result(A)) attr; + initialize(attr, t.f()); + + // Initialize every attribute with the corresponding pixel. + { + mln_piter(I) p(t.f().domain()); + for_all(p) + attr(p) = float(std::rand() % 10000) / 1000.f; + } + + // Propagate attribute from a site to its parent. + { + mln_fwd_piter(T) p(t.domain()); + for_all(p) + if (! t.is_root(p)) + attr(t.parent(p)) += attr(p); + } + + return attr; + } + + + + // Tree -> nchildren (on nodes). + // ----------------------------- + + + template <typename T> + inline + mln_ch_value(typename T::function, unsigned) + compute_nchildren(const T& t) + { + typedef typename T::function I; + mln_ch_value(I, unsigned) nchildren; + initialize(nchildren, t.f()); + data::fill(nchildren, 0); + + { + mln_fwd_piter(T) p(t.domain()); + // Propagate attribute from a site to its parent. + for_all(p) + if (t.is_a_non_root_node(p)) + { + mln_invariant(t.is_a_node(t.parent(p))); + ++nchildren(t.parent(p)); // so parent(p) is a node + } + } + + return nchildren; + } + + + + + template <typename A, typename T, typename N> + inline + mln_concrete(typename T::function) + filter(const A& a, const T& t, const N& nbh, + unsigned n_objects, + mln_value(A)& lambda, + bool echo = false) + { + typedef typename T::function I; + + unsigned n_regmins_f; // This value can be obtained while computing the attributes! + mln_ch_value(I, unsigned) regmins_f = labeling::regional_minima(t.f(), nbh, n_regmins_f); + if (echo) + { + debug::println("f =", t.f()); + debug::println("regmins(f) =", regmins_f); + // debug::println("par on nodes = ", t.parent_image() | t.nodes()); + std::cout << "n regmins(f) = " << n_regmins_f << std::endl + << std::endl; + } + if (n_objects >= n_regmins_f) + { + std::cout << "warning: number of expected objects is greater than number of regmins!" << std::endl; + std::cout << "aborting..." << std::endl; + return duplicate(t.f()); + } + + lambda = mln_max(mln_value(A)); + + mln_ch_value(typename T::function, unsigned) nchildren = compute_nchildren(t); + + typedef p_array<mln_site(I)> S; + S s = my_sort_increasing(a, t.nodes()); + + const typename T::parent_t& par = t.parent_image(); + + unsigned + count = n_regmins_f, + less = 0; + mln_fwd_piter(S) p(s); + for_all(p) + { + if (a(p) < lambda && par(p) != p) + { + mln_assertion(nchildren(par(p)) > 0); + --nchildren(par(p)); + if (nchildren(par(p)) != 0) + { + if (count <= n_objects) + { + ++less; // minus 1 object wrt the expected number! + } + --count; + if (count == n_objects) + { + lambda = a(p) + 1; + std::cout << "lambda = " << lambda << std::endl + << std::endl; + // break; // Stop iterations. + } + } + } + } + + if (less != 0) + std::cerr << "WARNING: less objects (" << less << ") than expected..." << std::endl + << std::endl; + + if (echo) + debug::println("nchildren =", nchildren | t.nodes()); + + + // Filtering. + mln_concrete(I) g; + { + initialize(g, t.f()); + mln_bkd_piter(T) p(t.domain()); + for_all(p) + if (t.is_a_node(p) && a(p) >= lambda) + g(p) = t.f(p); + else + g(p) = g(par(p)); + + if (echo) + debug::println("g =", g); + } + + if (echo) + { + unsigned n_regmins_g; + debug::println( "regmin(g)", labeling::regional_minima(g, nbh, n_regmins_g) ); + } + + return g; + } + + + template <typename A, typename I, typename N> + void + test_filter(A a, mln_result(A) lambda, + const I& f, const I& g, const N& nbh, + bool echo = false) + { + mln_concrete(I) g_ref = morpho::closing_attribute<A>(f, nbh, lambda); + if (echo) + debug::println("g_ref =", g_ref); + + unsigned n_regmins_g_ref; + mln_ch_value(I, unsigned) regmin_g = labeling::regional_minima(g_ref, nbh, n_regmins_g_ref); + if (echo) + std::cout << "n_regmins(g_ref) = " << n_regmins_g_ref << std::endl + << std::endl; + + if (g != g_ref) + std::cerr << "OOPS: g DIFFERS FROM ref!" << std::endl + << std::endl; + +// bool consistency = (n_regmins_g_ref + less == n_objects); +// if (consistency == false) +// std::cerr << "OOPS: INCONSISTENCY (BUG...)!" << std::endl +// << std::endl; + } + + + } // mln @@ -167,88 +535,105 @@ if (argc != 4) usage(argv); - image2d<rgb8> raw_input, input; - - io::ppm::load(raw_input, argv[1]); - input = image2squares(raw_input); - // e2c - - bool e2c_h[] = { 0, 1, 0, - 0, 0, 0, - 0, 1, 0 }; + { - bool e2c_v[] = { 0, 0, 0, - 1, 0, 1, - 0, 0, 0 }; + // Color version. + // -------------- - mln_VAR( e2c, make::double_neighb2d(is_row_odd, e2c_h, e2c_v) ); + image2d<rgb8> input; + io::ppm::load(input, argv[1]); + unsigned n_objects = atoi(argv[2]); - image2d<int_u8> G = dist(extend(input | is_edge, pw::value(input)), - e2c); - mln_VAR(G_edges, G | is_edge); + // Changing input into 'f on edges'. - /* + image2d<int_u8> f_; + image2d<rgb8> input_ = image2full(input); { - io::pgm::save(display_edge(G, 0, 3), - "temp_G.pgm"); + f_ = dist(extend(input_ | is_edge, pw::value(input_)), + e2c()); } - */ + mln_VAR(f, f_ | is_edge); + typedef f_t I; - // e2e - bool e2e_h[] = { 0, 0, 1, 0, 0, - 0, 1, 0, 1, 0, - 0, 0, 0, 0, 0, - 0, 1, 0, 1, 0, - 0, 0, 1, 0, 0 }; + // Filtering f -> g. - bool e2e_v[] = { 0, 0, 0, 0, 0, - 0, 1, 0, 1, 0, - 1, 0, 0, 0, 1, - 0, 1, 0, 1, 0, - 0, 0, 0, 0, 0 }; + typedef p_array<point2d> S; + S s = level::sort_psites_decreasing(f); - mln_VAR( e2e, make::double_neighb2d(is_row_odd, e2e_h, e2e_v) ); + typedef morpho::tree::data<I,S> tree_t; + tree_t t(f, s, e2e()); - data::paste( morpho::closing_volume(G_edges, e2e, 50), G_edges ); +// accu::count< util::pix<I> > a_; +// accu::volume<I> a_; + accu::sum_pix< util::pix<I> > a_; - /* - { - io::pgm::save(display_edge(G_edges.unmorph_(), 0, 3), - "temp_G_closed.pgm"); - } - */ +// blen_image = input_; +// accu::blen_pix<I> a_; + + mln_VAR(a, compute_attribute_on_nodes(a_, t)); + + mln_value_(a_t) lambda; + f_t g = filter(a, t, e2e(), n_objects, lambda); + + test_filter(a_, lambda, f, g, e2e()); + + + // Watershed transform. int_u8 nbasins; - mln_VAR(W_edges, morpho::meyer_wst(G_edges, e2e, nbasins)); + mln_ch_value_(f_t, int_u8) w_edges = morpho::meyer_wst(g, e2e(), nbasins); + + // io::pgm::save(display_edge(w_edges.unmorph_(), 0, 3), "temp_w_edges.pgm"); - /* + image2d<int_u8> w_all = w_edges.unmorph_(); { - io::pgm::save(display_edge(W_edges.unmorph_(), 0, 3), - "temp_W_edges.pgm"); + // edges -> squares + mln_VAR(w_squares, w_all | is_square); + data::paste(morpho::dilation(extend(w_squares, pw::value(w_all)), + c4().win()), + w_all); + // edges -> points + mln_VAR(w_points, w_all | is_point); + data::paste(morpho::erosion(extend(w_points, pw::value(w_all)), + c4().win()), + w_all); } - */ - mln_VAR(W_all, W_edges.unmorph_()); + io::pgm::save(w_all, "temp_w_all.pgm"); + } - mln_VAR(W_squares, W_all | is_square); - data::paste(morpho::dilation(extend(W_squares, pw::value(W_all)), - c4().win()), - W_all); - mln_VAR(W_points, W_all | is_point); - data::paste(morpho::erosion(extend(W_points, pw::value(W_all)), - c4().win()), - W_all); +// { +// // Gray-level version. +// image2d<int_u8> f_; +// io::pgm::load(f_, argv[1]); + +// unsigned n_objects = atoi(argv[2]); + +// mln_VAR(f, f_ | is_edge); +// typedef f_t I; + +// typedef p_array<point2d> S; +// S s = level::sort_psites_decreasing(f); + +// typedef morpho::tree::data<I,S> tree_t; +// tree_t t(f, s, e2e()); + +// accu::count< util::pix<I> > a_; +// mln_VAR(a, compute_attribute_on_nodes(a_, t)); + +// f_t g = filter(a, t, e2e(), n_objects); + +// unsigned nbasins; +// debug::println("wst =", morpho::meyer_wst(g, e2e(), nbasins)); +// } - { - io::pgm::save(W_all, "temp_W_all.pgm"); - } } Index: geraud/color/blen_pix.hh --- geraud/color/blen_pix.hh (revision 0) +++ geraud/color/blen_pix.hh (revision 0) @@ -0,0 +1,174 @@ +// Copyright (C) 2007, 2008 EPITA Research and Development Laboratory +// (LRDE) +// +// 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. + +#ifndef MLN_ACCU_BLEN_PIX_HH +# define MLN_ACCU_BLEN_PIX_HH + +/// \file mln/accu/blen_pix.hh +/// +/// Define an accumulator that computes a sum. + +# include <mln/core/concept/meta_accumulator.hh> +# include <mln/accu/bbox.hh> +# include <mln/accu/internal/base.hh> + +# include <mln/util/pix.hh> // To prevent accu::blen_pix to work on pixels (ambiguous). + +# include <mln/trait/value_.hh> // For mln_blen_pix. +# include <mln/value/builtin/all.hh> // In the case of summing builtin values. +# include <mln/literal/zero.hh> // For initialization. + +# include <mln/core/alias/point3d.hh> + + +namespace mln +{ + + + namespace accu + { + + + /// Generic blen_pix accumulator class. + template <typename I> + struct blen_pix : public mln::accu::internal::base< unsigned, blen_pix<I> > + { + typedef util::pix<I> argument; + + blen_pix(); + + /// Manipulators. + /// \{ + void init(); + void take(const argument& t); + void take(const blen_pix<I>& other); + /// \} + + void set_value(unsigned v) + { + len_ = v; + } + + /// Get the value of the accumulator. + unsigned to_result() const; + + /// Check whether this accu is able to return a result. + /// Always true here. + bool is_valid() const; + + const accu::bbox<point3d>& b() const + { + return b_; + } + + accu::bbox<point3d>& b() + { + return b_; + } + + protected: + + accu::bbox<point3d> b_; + unsigned len_; + }; + + + template <typename B> + unsigned max_len(const Box<B>& b_) + { + const B& b = exact(b_); + typedef mln_site(B) P; + enum { n = P::dim }; + unsigned len = b.len(0); + for (unsigned i = 1; i < n; ++i) + if (b.len(i) > len) + len = b.len(i); + return len; + } + + +# ifndef MLN_INCLUDE_ONLY + + template <typename I> + inline + blen_pix<I>::blen_pix() + { + init(); + } + + template <typename I> + inline + void + blen_pix<I>::init() + { + b_.init(); + len_ = 0; + } + + template <typename I> + inline + void blen_pix<I>::take(const argument& pxl) + { + const mln_site(I)& p = pxl.p(); + accu_blen_take(b_, p); + len_ = max_len(b_.to_result()); + } + + template <typename I> + inline + void + blen_pix<I>::take(const blen_pix<I>& other) + { + b_.take(other.b()); + len_ = max_len(b_.to_result()); + } + + template <typename I> + inline + unsigned + blen_pix<I>::to_result() const + { + return len_; + } + + template <typename I> + inline + bool + blen_pix<I>::is_valid() const + { + return true; + } + +# endif // ! MLN_INCLUDE_ONLY + + } // end of namespace mln::accu + +} // end of namespace mln + + +#endif // ! MLN_ACCU_BLEN_PIX_HH