https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)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