Olena-patches
  Threads by month 
                
            - ----- 2025 -----
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2024 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2023 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2022 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2021 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2020 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2019 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2018 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2017 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2016 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2015 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2014 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2013 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2012 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2011 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2010 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2009 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2008 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2007 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2006 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2005 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 - February
 - January
 - ----- 2004 -----
 - December
 - November
 - October
 - September
 - August
 - July
 - June
 - May
 - April
 - March
 
March 2009
- 9 participants
 - 202 discussions
 
                    
                          URL: https://svn.lrde.epita.fr/svn/oln/trunk/milena
ChangeLog:
2009-03-20  Etienne FOLIO  <folio(a)lrde.epita.fr>
	Debug int_u_sat.
	* mln/value/int_u_sat.hh: Debugged a tiny silly error.
---
 int_u_sat.hh |    2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
Index: trunk/milena/mln/value/int_u_sat.hh
===================================================================
--- trunk/milena/mln/value/int_u_sat.hh	(revision 3554)
+++ trunk/milena/mln/value/int_u_sat.hh	(revision 3555)
@@ -61,7 +61,7 @@
       enum {
 	dim = 1,
 	card = metal::math::pow_int<2, n>::value,
-	nbits = n;
+	nbits = n
       };
 
       // FIXME: Overhaul these traits (see other value traits).
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                    
                        https://svn.lrde.epita.fr/svn/oln/trunk/milena
Index: ChangeLog
from  Thierry Geraud  <thierry.geraud(a)lrde.epita.fr>
	Some cleanups in classical filters.
	* mln/data/memcpy_.hh: Deactivate trace.
	This internal routine floods the trace file because it can
	be called in a loop.
	* mln/linear/gaussian.hh (class): Replace by...
	(typename): ...this.
	See sandbox/theo/exec/ for a fastest implementation.
	* mln/accu/transform_line.hh (transform_line_fastest): New.
	* mln/morpho/rank_filter.hh (rank_filter_line): New.
	(rank_filter_dispatch): New overload for rectangle2d.
	* mln/morpho/includes.hh: Update.
	* img/BUG_lean_ascii.pgm.gz: New.
	This file makes io::pgm::load bug.
 mln/accu/transform_line.hh |  149 ++++++++++++++++++++++++++++++++++++++++++++-
 mln/data/memcpy_.hh        |   12 +--
 mln/linear/gaussian.hh     |   22 ++++--
 mln/morpho/includes.hh     |    5 -
 mln/morpho/rank_filter.hh  |   62 ++++++++++++++++--
 5 files changed, 226 insertions(+), 24 deletions(-)
Index: mln/data/memcpy_.hh
--- mln/data/memcpy_.hh	(revision 3553)
+++ mln/data/memcpy_.hh	(working copy)
@@ -1,5 +1,5 @@
-// Copyright (C) 2007, 2008 EPITA Research and Development Laboratory
-// (LRDE)
+// Copyright (C) 2007, 2008, 2009 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
@@ -78,7 +78,7 @@
       inline
       void memcpy__(Pd& dest, const Ps& src, std::size_t n)
       {
-	trace::entering("data::impl::memcpy__");
+	// trace::entering("data::impl::memcpy__");
 
 	typedef mln_image(Pd) Id;
 	typedef mln_image(Ps) Is;
@@ -105,7 +105,7 @@
 	    *p_d++ = *p_s++;
 	}
 
-	trace::exiting("data::impl::memcpy__");
+	// trace::exiting("data::impl::memcpy__");
       }
 
     }
@@ -116,7 +116,7 @@
 		 const Generalized_Pixel<Ps>& src_,
 		 std::size_t n)
     {
-      trace::entering("data::memcpy_");
+      // trace::entering("data::memcpy_");
 
       typedef mln_image(Pd) Id;
       metal::is_not_const<Id>::check();
@@ -143,7 +143,7 @@
 
       impl::memcpy__(dest, src, n);
 
-      trace::exiting("data::memcpy_");
+      // trace::exiting("data::memcpy_");
     }
 
 # endif // ! MLN_INCLUDE_ONLY
Index: mln/linear/gaussian.hh
--- mln/linear/gaussian.hh	(revision 3553)
+++ mln/linear/gaussian.hh	(working copy)
@@ -1,4 +1,4 @@
-// Copyright (C) 2001, 2002, 2003, 2004, 2008 EPITA Research and
+// Copyright (C) 2001, 2002, 2003, 2004, 2008, 2009 EPITA Research and
 // Laboratory (LRDE)
 //
 // This file is part of the Olena Library.  This library is free
@@ -63,10 +63,16 @@
     ///
     /// \pre output.domain = input.domain
     ///
-    template <class I>
+    template <typename I>
     mln_concrete(I)
     gaussian(const Image<I>& input, float sigma);
 
+
+    template <typename I>
+    mln_concrete(I)
+    gaussian(const Image<I>& input, float sigma, int dir);
+
+
 # ifndef MLN_INCLUDE_ONLY
 
     namespace impl
@@ -637,7 +643,7 @@
      * \pre input.is_valid
      * \pre dir < dimension(input)
      */
-    template <class I>
+    template <typename I>
     inline
     mln_concrete(I)
     gaussian(const Image<I>& input, float sigma, int dir)
@@ -669,7 +675,7 @@
      * \pre input.is_valid
      * \pre dir < dimension(input)
      */
-    template <class I>
+    template <typename I>
     inline
     mln_concrete(I)
     gaussian_1st_derivative(const Image<I>& input, float sigma, int dir)
@@ -702,7 +708,7 @@
      * \pre input.is_valid
      * \pre dir < dimension(input)
      */
-    template <class I>
+    template <typename I>
     inline
     mln_concrete(I)
     gaussian_2nd_derivative(const Image<I>& input, float sigma, int dir)
@@ -734,7 +740,7 @@
      *
      * \pre input.is_valid
      */
-    template <class I>
+    template <typename I>
     inline
     mln_concrete(I)
     gaussian(const Image<I>& input, float sigma)
@@ -763,7 +769,7 @@
      *
      * \pre input.is_valid
      */
-    template <class I>
+    template <typename I>
     inline
     mln_concrete(I)
     gaussian_1st_derivative(const Image<I>& input, float sigma)
@@ -791,7 +797,7 @@
      *
      * \pre input.is_valid
      */
-    template <class I>
+    template <typename I>
     inline
     mln_concrete(I)
     gaussian_2nd_derivative(const Image<I>& input, float sigma)
Index: mln/accu/transform_line.hh
--- mln/accu/transform_line.hh	(revision 3553)
+++ mln/accu/transform_line.hh	(working copy)
@@ -66,8 +66,10 @@
 
 # ifndef MLN_INCLUDE_ONLY
 
+
     // Tests.
 
+
     namespace internal
     {
 
@@ -89,6 +91,10 @@
     } // end of namespace mln::accu::internal
 
 
+
+    // Implementations.
+
+
     namespace impl
     {
 
@@ -188,10 +194,150 @@
 
       } // end of namespace mln::accu::impl::generic
 
+
+
+      template <typename A, typename I>
+      inline
+      mln_ch_value(I, mln_result(A))
+	transform_line_fastest(const Accumulator<A>& a_,
+			       const Image<I>& input_,
+			       unsigned length, unsigned dir)
+      {
+	trace::entering("accu::impl::transform_line_fastest");
+
+	const I& input = exact(input_);
+	A a = exact(a_);
+
+	internal::transform_line_tests(a, input);
+
+	mln_ch_value(I, mln_result(A)) output;
+	initialize(output, input);
+
+	typedef mln_psite(I) P;
+
+	mln_delta(P) dp(literal::zero);
+	dp[dir] = 1;
+	int step = input.delta_index(dp);
+
+	P pmin = input.domain().pmin(),
+	  pmax = input.domain().pmax();
+	const def::coord
+	  pmax_dir = pmax[dir],
+	  pmin_dir = pmin[dir];
+
+	P p = pmin; // Starting point.
+	def::coord& p_dir = p[dir];
+
+	do
+	  {
+	    unsigned o_qu, o_qt;
+	    unsigned o_p = input.index_of_point(p);
+
+	    // Start the line.
+ 	    // ----------------
+
+	    a.take_as_init(input.element(o_p));
+	    o_qu = o_p;
+	    for (unsigned i = 1; i <= length / 2; ++i)
+	      {
+		o_qu -= step;
+		a.take(input.element(o_qu));
+	      }
+	    o_qt = o_p;
+	    for (unsigned i = 1; i <= length / 2; ++i)
+	      {
+		o_qt += step;
+		a.take(input.element(o_qt));
+	      }
+	    output.element(o_p) = a.to_result();
+
+	    // Browse the line.
+	    // ----------------
+
+	    while (p_dir < pmax_dir)
+	      {
+		++p_dir;
+
+		o_p  += step;
+		o_qt += step;
+		o_qu += step;
+
+		a.take(input.element(o_qt));
+		a.untake(input.element(o_qu));
+
+		output.element(o_p) = a.to_result();
+	      }
+	  
+ 	    p_dir = pmin_dir;
+
+	    // Go to the next line.
+	    // --------------------
+
+	    for (int c = P::dim - 1; c >= 0; --c)
+	      {
+		if (c == int(dir))
+		  continue;
+		if (p[c] != pmax[c])
+		  {
+		    ++p[c];
+		    break;
+		  }
+		p[c] = pmin[c];
+	      }
+
+	  } while (p != pmin);
+
+	trace::exiting("accu::impl::transform_line_fastest");
+	return output;
+      }
+
+
     } // end of namespace mln::accu::impl
 
 
 
+
+    // Dispatch.
+
+
+    namespace internal
+    {
+
+      template <typename A, typename I>
+      inline
+      mln_ch_value(I, mln_result(A))
+	transform_line_dispatch(trait::image::speed::any,
+				const Accumulator<A>& a,
+				const Image<I>& input,
+				unsigned length, unsigned dir)
+      {
+	return impl::generic::transform_line(a,
+					     input,
+					     length, dir);
+      }
+
+//       template <typename A, typename I>
+//       inline
+//       mln_ch_value(I, mln_result(A))
+// 	transform_line_dispatch(trait::image::speed::fastest,
+// 				const Accumulator<A>& a,
+// 				const Image<I>& input,
+// 				unsigned length, unsigned dir)
+//       {
+// 	return impl::transform_line_fastest(a,
+// 					    input,
+// 					    length, dir);
+//       }
+
+
+    } // end of namespace mln::accu::internal
+
+
+
+
+    // Facades.
+
+
     template <typename A, typename I>
     inline
     mln_ch_value(I, mln_result(A))
@@ -205,7 +351,8 @@
 
       extension::adjust(input, length / 2);
       mln_ch_value(I, mln_result(A)) output;
-      output = impl::generic::transform_line(a, input, length, dir);
+      output = internal::transform_line_dispatch(mln_trait_image_speed(I)(),
+						 a, input, length, dir);
 
       trace::exiting("accu::transform_line");
       return output;
Index: mln/morpho/rank_filter.hh
--- mln/morpho/rank_filter.hh	(revision 3553)
+++ mln/morpho/rank_filter.hh	(working copy)
@@ -1,5 +1,5 @@
-// Copyright (C) 2007, 2008, 2009 EPITA Research and Development Laboratory
-// (LRDE)
+// Copyright (C) 2007, 2008, 2009 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
@@ -31,11 +31,16 @@
 
 /// \file mln/morpho/rank_filter.hh
 ///
-/// Morphological rank_filter.
+/// Morphological rank filter.
+///
+/// \todo Rely on the same mechanism as erosion/dilation.
 
 # include <mln/morpho/includes.hh>
+# include <mln/accu/transform_line.hh>
 # include <mln/convert/to_p_array.hh>
 
+
+
 namespace mln
 {
 
@@ -51,6 +56,8 @@
 # ifndef MLN_INCLUDE_ONLY
 
 
+    // Tests.
+
 
     namespace internal
     {
@@ -73,6 +80,10 @@
     } // end of namespace mln::morpho::internal
 
 
+
+    // Implementations.
+
+
     namespace impl
     {
 
@@ -119,9 +130,27 @@
       template <typename I, typename W>
       inline
       mln_concrete(I)
+      rank_filter_line(const Image<I>& input, const Window<W>& win, unsigned k, unsigned dir)
+      {
+	trace::entering("morpho::impl::rank_filter_line");
+
+	internal::rank_filter_tests(input, win, k);
+
+	accu::rank<mln_value(I)> accu(k);
+	extension::adjust_fill(input, geom::delta(win) + 1, accu);
+	mln_concrete(I) output = accu::transform_line(accu, input, exact(win).length(), dir);
+
+	trace::exiting("morpho::impl::rank_filter_line");
+	return output;
+      }
+
+
+      template <typename I, typename W>
+      inline
+      mln_concrete(I)
       rank_filter_directional(const Image<I>& input, const Window<W>& win, unsigned k, unsigned dir)
       {
-	trace::entering("morpho::impl::generic::rank_filter_directional");
+	trace::entering("morpho::impl::rank_filter_directional");
 
 	internal::rank_filter_tests(input, win, k);
 
@@ -129,13 +158,18 @@
 	extension::adjust_fill(input, geom::delta(win) + 1, accu);
 	mln_concrete(I) output = accu::transform_directional(accu, input, win, dir);
 
-	trace::exiting("morpho::impl::generic::rank_filter_directional");
+	trace::exiting("morpho::impl::rank_filter_directional");
 	return output;
       }
 
+
     } // end of namespace mln::morpho::impl
 
 
+
+    // Dispatch.
+
+
     namespace internal
     {
 
@@ -144,10 +178,22 @@
       mln_concrete(I)
       rank_filter_dispatch(const Image<I>& input, const win::line<M, i, C> & win, unsigned k)
       {
-	return impl::rank_filter_directional(input, win, k, i);
+	return impl::rank_filter_line(input, win, k, i);
       }
 
-
+      template <typename I>
+      inline
+      mln_concrete(I)
+      rank_filter_dispatch(const Image<I>& input, const win::rectangle2d& win, unsigned k)
+      {
+	if (win.height() <= 3 && win.width() <= 3)
+	  return impl::generic::rank_filter(input, win, k);
+	else
+	  if (win.height() < win.width())
+	    return impl::rank_filter_directional(input, win, k, 1);
+	  else
+	    return impl::rank_filter_directional(input, win, k, 0);
+      }
 
       template <typename I, typename W>
       inline
@@ -163,12 +209,14 @@
 
     // Facades.
 
+
     template <typename I, typename W>
     inline
     mln_concrete(I)
     rank_filter(const Image<I>& input, const Window<W>& win, unsigned k)
     {
       trace::entering("morpho::rank_filter");
+
       mln_precondition(exact(input).is_valid());
       mln_precondition(! exact(win).is_empty());
 
Index: mln/morpho/includes.hh
--- mln/morpho/includes.hh	(revision 3553)
+++ mln/morpho/includes.hh	(working copy)
@@ -1,5 +1,5 @@
-// Copyright (C) 2007, 2008 EPITA Research and Development Laboratory
-// (LRDE)
+// Copyright (C) 2007, 2008, 2009 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
@@ -49,6 +49,7 @@
 
 # include <mln/accu/transform_directional.hh>
 # include <mln/accu/transform_diagonal.hh>
+# include <mln/accu/transform_line.hh>
 # include <mln/accu/transform_snake.hh>
 
 # include <mln/fun/v2v/saturate.hh>
Index: img/BUG_lean_ascii.pgm.gz
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: img/BUG_lean_ascii.pgm.gz
___________________________________________________________________
Added: svn:mime-type
   + application/octet-stream
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                    
                        https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox
Index: ChangeLog
from  Thierry Geraud  <thierry.geraud(a)lrde.epita.fr>
	Add some useful executable source.
	* theo/exec/gaussian_directional_2d.cc: New.
	* theo/exec/rank_rectangle.cc: New.
	* theo/exec/closing_rectangle.cc: New.
	* theo/exec/gaussian_directional_2d.hh: New.
 closing_rectangle.cc       |   42 +++
 gaussian_directional_2d.cc |   99 +++++++++
 gaussian_directional_2d.hh |  475 +++++++++++++++++++++++++++++++++++++++++++++
 rank_rectangle.cc          |   52 ++++
 4 files changed, 668 insertions(+)
Index: theo/exec/gaussian_directional_2d.cc
--- theo/exec/gaussian_directional_2d.cc	(revision 0)
+++ theo/exec/gaussian_directional_2d.cc	(revision 0)
@@ -0,0 +1,99 @@
+
+# define MLN_FLOAT double
+
+#include "filetype.hh"
+#include "./gaussian_directional_2d.hh"
+
+#include <mln/io/pgm/load.hh>
+#include <mln/io/pgm/save.hh>
+
+#include <mln/pw/all.hh>
+
+#include <mln/data/fill.hh>
+#include <mln/level/saturate.hh>
+
+
+
+
+
+void usage(char* argv[])
+{
+  std::cerr << "usage: " << argv[0] << " input.xxx bdr dir sigma output.pgm" << std::endl
+	    << "  xxx is pbm or pgm" << std::endl
+	    << "  bdr is the outer border value" << std::endl
+	    << "  dir = 0 (vertical blur) or 1 (horizontal blur)" << std::endl
+	    << "  sigma > 0" << std::endl
+	    << "  Directional gaussian blur." << std::endl;
+  std::abort();
+}
+
+
+
+int main(int argc, char* argv[])
+{
+
+  using namespace mln;
+  using value::int_u8;
+
+  trace::entering("main");
+
+  if (argc != 6)
+    usage(argv);
+
+
+  int dir = atoi(argv[3]);
+  if (dir != 0 && dir != 1)
+    usage(argv);
+
+  MLN_FLOAT sigma = atof(argv[4]);
+  if (sigma <= 0.f)
+    usage(argv);
+
+
+  switch (get_filetype(argv[1]))
+    {
+    case filetype::pbm:
+      {
+	int bdr = atoi(argv[2]);
+	if (bdr != 0 && bdr != 1)
+	  usage(argv);
+
+	image2d<bool> ima;
+	io::pbm::load(ima, argv[1]);
+
+	image2d<MLN_FLOAT> temp(ima.domain()), out;
+	data::fill(temp, ima);
+
+	out = linear::gaussian_directional_2d(temp, dir, sigma, bdr);
+
+	io::pgm::save(level::saturate(int_u8(),
+				      (pw::value(out) * pw::cst(255.f)) | out.domain()),
+		      argv[5]);
+      }
+      break;
+
+    case filetype::pgm:
+      {
+	int bdr = atoi(argv[2]);
+	if (bdr < 0 || bdr > 255)
+	  usage(argv);
+
+	image2d<int_u8> ima;
+	io::pgm::load(ima, argv[1]);
+    
+	image2d<MLN_FLOAT> temp(ima.domain()), out;
+	data::fill(temp, ima);
+
+	out = linear::gaussian_directional_2d(temp, dir, sigma, bdr);
+
+	io::pgm::save(level::saturate(int_u8(), out), argv[5]);
+      }
+      break;
+
+    default:
+      std::cerr << "file type not handled!" << std::endl;
+      usage(argv);
+    }
+
+  trace::exiting("main");
+}
Index: theo/exec/rank_rectangle.cc
--- theo/exec/rank_rectangle.cc	(revision 0)
+++ theo/exec/rank_rectangle.cc	(revision 0)
@@ -0,0 +1,52 @@
+#include <mln/core/image/image2d.hh>
+#include <mln/io/pbm/load.hh>
+#include <mln/io/pbm/save.hh>
+
+#include <mln/win/hline2d.hh>
+#include <mln/win/rectangle2d.hh>
+
+#include <mln/morpho/rank_filter.hh>
+
+
+
+void usage(char* argv[])
+{
+  std::cerr << "usage: " << argv[0] << " input.pbm height width k output.pbm" << std::endl
+	    << "  Rank filter with a 2D rectangle." << std::endl;
+  std::abort();
+}
+
+
+
+int main(int argc, char* argv[])
+{
+  using namespace mln;
+  using value::int_u8;
+
+  if (argc != 6)
+    usage(argv);
+
+  trace::entering("main");
+
+  image2d<bool> ima, out;
+  io::pbm::load(ima, argv[1]);
+
+  int height = atoi(argv[2]);
+  if (height < 0)
+    usage(argv);
+
+  int width  = atoi(argv[3]);
+  if (width < 0)
+    usage(argv);
+
+  int k = atoi(argv[4]);
+  if (k < 1 || k > height * width)
+    usage(argv);
+
+  out = morpho::rank_filter(ima,
+			    win::rectangle2d(height, width),
+			    k);
+  io::pbm::save(out, argv[5]);
+
+  trace::exiting("main");
+}
Index: theo/exec/closing_rectangle.cc
--- theo/exec/closing_rectangle.cc	(revision 0)
+++ theo/exec/closing_rectangle.cc	(revision 0)
@@ -0,0 +1,42 @@
+#include "filetype.hh"
+
+#include <mln/morpho/closing/structural.hh>
+
+
+
+void usage(char* argv[])
+{
+  std::cerr << "usage: " << argv[0] << " input.pgm height width output.pgm" << std::endl
+	    << "  Height and width are odd positive integers." << std::endl
+	    << "  Rectangle closing." << std::endl;
+  std::abort();
+}
+
+
+
+int main(int argc, char* argv[])
+{
+  using namespace mln;
+  using value::int_u8;
+
+  trace::entering("main");
+
+  if (argc != 5)
+    usage(argv);
+
+  int height = atoi(argv[2]);
+  if (height < 0 || height % 2 == 0)
+    usage(argv);
+
+  int width  = atoi(argv[3]);
+  if (width < 0 || width % 2 == 0)
+    usage(argv);
+
+  image2d<int_u8> ima, clo;
+  io::pgm::load(ima, argv[1]);
+
+  clo = morpho::closing::structural(ima, win::rectangle2d(height, width));
+  io::pgm::save(clo, argv[4]);
+
+  trace::exiting("main");
+}
Index: theo/exec/gaussian_directional_2d.hh
--- theo/exec/gaussian_directional_2d.hh	(revision 0)
+++ theo/exec/gaussian_directional_2d.hh	(revision 0)
@@ -0,0 +1,475 @@
+
+#include <mln/core/image/image2d.hh>
+#include <mln/extension/adjust_fill.hh>
+#include <mln/extension/adjust_duplicate.hh>
+
+
+
+namespace mln
+{
+
+  namespace linear
+  {
+
+    namespace my
+    {
+
+      struct recursivefilter_coef_
+      {
+	enum FilterType { DericheGaussian,
+			  DericheGaussianFirstDerivative,
+			  DericheGaussianSecondDerivative };
+
+	std::vector<MLN_FLOAT> n, d, nm, dm;
+	MLN_FLOAT sumA, sumC;
+
+	recursivefilter_coef_(MLN_FLOAT a0, MLN_FLOAT a1,
+			      MLN_FLOAT b0, MLN_FLOAT b1,
+			      MLN_FLOAT c0, MLN_FLOAT c1,
+			      MLN_FLOAT w0, MLN_FLOAT w1,
+			      MLN_FLOAT s, FilterType filter_type)
+	{
+	  n.reserve(5);
+	  d.reserve(5);
+	  nm.reserve(5);
+	  dm.reserve(5);
+
+	  b0 /= s;
+	  b1 /= s;
+	  w0 /= s;
+	  w1 /= s;
+
+	  MLN_FLOAT sin0	= sin(w0);
+	  MLN_FLOAT sin1	= sin(w1);
+	  MLN_FLOAT cos0	= cos(w0);
+	  MLN_FLOAT cos1	= cos(w1);
+
+	  switch (filter_type) {
+
+	  case DericheGaussian :
+	    {
+	      sumA  =
+		(2.0 * a1 * exp( b0 ) * cos0 * cos0 - a0 * sin0 * exp( 2.0 * b0 )
+		 + a0 * sin0 - 2.0 * a1 * exp( b0 )) /
+		(( 2.0 * cos0 * exp( b0 ) - exp( 2.0 * b0 ) - 1 ) * sin0);
+
+	      sumC  =
+		(2.0 * c1 * exp( b1 ) * cos1 * cos1 - c0 * sin1 * exp( 2.0 * b1 )
+		 + c0 * sin1 - 2.0 * c1 * exp( b1 ))
+		/ (( 2.0 * cos1 * exp( b1 ) - exp( 2.0 * b1 ) - 1 ) * sin1);
+	      break;
+	    }
+
+	  case DericheGaussianFirstDerivative :
+	    {
+	      sumA  = -2.f *
+		(a0 * cos0 - a1 * sin0 + a1 * sin0 * exp( 2.0 * b0 )
+		 + a0 * cos0 * exp( 2.0 * b0 ) - 2.0 * a0 * exp( b0 ))
+		* exp( b0 )
+		/ (exp( 4.0 * b0 ) - 4.0 * cos0 * exp( 3.0 * b0 )
+		   + 2.0 * exp( 2.0 * b0 ) + 4.0 * cos0 * cos0 * exp( 2.0 * b0 )
+		   + 1.0 - 4.0 * cos0 * exp( b0 ));
+	      sumC  = - 2.f *
+		(c0 * cos1 - c1 * sin1 + c1 * sin1 * exp( 2.0 * b1 )
+		 + c0 * cos1 * exp( 2.0 * b1 ) - 2.0 * c0 * exp( b1 ))
+		* exp( b1 ) /
+		(exp( 4.0 * b1 ) - 4.0 * cos1 * exp( 3.0 * b1 )
+		 + 2.0 * exp( 2.0 * b1 ) + 4.0 * cos1 * cos1 * exp( 2.0 * b1 )
+		 + 1.0 - 4.0 * cos1 * exp( b1 ));
+	      break;
+	    }
+
+	  case DericheGaussianSecondDerivative :
+	    {
+	      MLN_FLOAT aux;
+	      aux   =
+		12.0 * cos0 * exp( 3.0 * b0 ) - 3.0 * exp( 2.0 * b0 )
+		+ 8.0 * cos0 * cos0 * cos0 * exp( 3.0 * b0 ) - 12.0 * cos0 * cos0 *
+		exp( 4.0 * b0 )
+		- (3.0 * exp( 4.0 * b0 ))
+		+ 6.0 * cos0 * exp( 5.0 * b0 ) -  exp( 6.0 * b0 ) + 6.0 * cos0 * exp
+		( b0 )
+		- ( 1.0 + 12.0 * cos0 * cos0 * exp( 2.0 * b0 ) );
+	      sumA  =
+		4.0 * a0 * sin0 * exp( 3.0 * b0 ) + a1 * cos0 * cos0 * exp( 4.0 * b0 )
+		- ( 4.0 * a0 * sin0 * exp( b0 ) + 6.0 * a1 * cos0 * cos0 * exp( 2.0 * b0 ) )
+		+ 2.0 * a1 * cos0 * cos0 * cos0 * exp( b0 ) - 2.0 * a1 * cos0 * exp(b0)
+		+ 2.0 * a1 * cos0 * cos0 * cos0 * exp( 3.0 * b0 ) - 2.0 * a1 * cos0
+		* exp( 3.0 * b0 )
+		+ a1 * cos0 * cos0 - a1 * exp( 4.0 * b0 )
+		+ 2.0 * a0 * sin0 * cos0 * cos0 * exp( b0 ) - 2.0 * a0 * sin0 * cos0
+		* cos0 * exp( 3.0 * b0 )
+		- ( a0 * sin0 * cos0 * exp( 4.0 * b0 ) + a1 )
+		+ 6.0 * a1 * exp( 2.0 * b0 ) + a0 * cos0 * sin0
+		* 2.0 * exp( b0 ) / ( aux * sin0 );
+	      aux   =
+		12.0 * cos1 * exp( 3.0 * b1 ) - 3.0 * exp( 2.0 * b1 )
+		+ 8.0 * cos1 * cos1 * cos1 * exp( 3.0 * b1 ) - 12.0 * cos1 * cos1 *
+		exp( 4.0 * b1 )
+		- 3.0 * exp( 4.0 * b1 )
+		+ 6.0 * cos1 * exp( 5.0 * b1 ) -  exp( 6.0 * b1 ) + 6.0 * cos1 * exp
+		( b1 )
+		- ( 1.0 + 12.0 * cos1 * cos1 * exp( 2.0 * b1 ) );
+	      sumC  = 4.0 * c0 * sin1 * exp( 3.0 * b1 ) + c1 * cos1 * cos1 * exp( 4.0 * b1 )
+		- ( 4.0 * c0 * sin1 * exp( b1 ) + 6.0 * c1 * cos1 * cos1 * exp( 2.0 * b1 ) )
+		+ 2.0 * c1 * cos1 * cos1 * cos1 * exp( b1 ) - 2.0 * c1 * cos1 * exp( b1 )
+		+ 2.0 * c1 * cos1 * cos1 * cos1 * exp( 3.0 * b1 ) - 2.0 * c1 * cos1
+		* exp( 3.0 * b1 )
+		+ c1 * cos1 * cos1 - c1 * exp( 4.0 * b1 )
+		+ 2.0 * c0 * sin1 * cos1 * cos1 * exp( b1 ) - 2.0 * c0 * sin1 * cos1
+		* cos1 * exp( 3.0 * b1 )
+		- ( c0 * sin1 * cos1 * exp( 4.0 * b1 ) + c1 )
+		+ 6.0 * c1 * exp( 2.0 * b1 ) + c0 * cos1 * sin1
+		* 2.0 * exp( b1 ) / ( aux * sin1 );
+	      sumA /= 2;
+	      sumC /= 2;
+	      break;
+	    }
+	  }
+
+	  a0 /= (sumA + sumC);
+	  a1 /= (sumA + sumC);
+	  c0 /= (sumA + sumC);
+	  c1 /= (sumA + sumC);
+
+	  n[3] =
+	    exp( -b1 - 2*b0 ) * (c1 * sin1 - cos1 * c0) +
+	    exp( -b0 - 2*b1 ) * (a1 * sin0 - cos0 * a0);
+	  n[2] =
+	    2 * exp(-b0 - b1) * ((a0 + c0) * cos1 * cos0 -
+				 cos1 * a1 * sin0 -
+				 cos0 * c1 * sin1) +
+	    c0 * exp(-2 * b0) + a0 * exp(-2 * b1);
+	  n[1] =
+	    exp(-b1) * (c1 * sin1 - (c0 + 2*a0) * cos1) +
+	    exp(-b0) * (a1 * sin0 - (2*c0 + a0) * cos0);
+	  n[0] =
+	    a0 + c0;
+
+	  d[4] = exp(-2 * b0 - 2 * b1);
+	  d[3] =
+	    -2 * cos0 * exp(-b0 - 2*b1) -
+	    2 * cos1 * exp(-b1 - 2*b0);
+	  d[2] =
+	    4 * cos1 * cos0 * exp(-b0 - b1) +
+	    exp(-2*b1) + exp(-2*b0);
+	  d[1] =
+	    -2*exp(-b1) * cos1 - 2 * exp(-b0) * cos0;
+
+	  switch (filter_type) {
+	  case DericheGaussian :
+	  case DericheGaussianSecondDerivative :
+	    {
+	      for (unsigned i = 1; i <= 3; ++i)
+		{
+		  dm[i] = d[i];
+		  nm[i] = n[i] - d[i] * n[0];
+		}
+	      dm[4] = d[4];
+	      nm[4] = -d[4] * n[0];
+	      break;
+	    }
+	  case DericheGaussianFirstDerivative :
+	    {
+	      for (unsigned i = 1; i <= 3; ++i)
+		{
+		  dm[i] = d[i];
+		  nm[i] = - (n[i] - d[i] * n[0]);
+		}
+	      dm[4] = d[4];
+	      nm[4] = d[4] * n[0];
+	      break;
+	    }
+	  }
+	}
+      };
+
+
+    } // end of namespace mln::linear::my
+
+
+
+
+    // FIXME: in the "generic" code below there is no test that we
+    // actually stay in the image domain...
+
+
+    template <typename I, typename C>
+    inline
+    void
+    recursivefilter_directional_2d_generic(I& ima,
+					   const C& c,
+					   const mln_psite(I)& start,
+					   const mln_psite(I)& finish,
+					   int len,
+					   const mln_deduce(I, psite, delta)& d)
+    {
+      std::vector<MLN_FLOAT> tmp1(len);
+      std::vector<MLN_FLOAT> tmp2(len);
+
+      tmp1[0] =
+	c.n[0]*ima(start);
+
+      tmp1[1] =
+	c.n[0]*ima(start + d)
+	+ c.n[1]*ima(start)
+	- c.d[1]*tmp1[0];
+
+      tmp1[2] =
+	c.n[0]*ima(start + d + d)
+	+ c.n[1]*ima(start + d)
+	+ c.n[2]*ima(start)
+	- c.d[1]*tmp1[1]
+	- c.d[2]*tmp1[0];
+
+      tmp1[3] =
+	c.n[0]*ima(start + d + d + d)
+	+ c.n[1]*ima(start + d + d)
+	+ c.n[2]*ima(start + d)
+	+ c.n[3]*ima(start)
+	- c.d[1]*tmp1[2] - c.d[2]*tmp1[1]
+	- c.d[3]*tmp1[0];
+
+      mln_site(I) current = start + d + d + d + d;
+      for (int i = 4; i < len; ++i)
+	{
+	  tmp1[i] =
+	    c.n[0]*ima(current)
+	    + c.n[1]*ima(current - d)
+	    + c.n[2]*ima(current - d - d)
+	    + c.n[3]*ima(current - d - d - d)
+	    - c.d[1]*tmp1[i - 1] - c.d[2]*tmp1[i - 2]
+	    - c.d[3]*tmp1[i - 3] - c.d[4]*tmp1[i - 4];
+	  current += d;
+	}
+
+      // Non causal part
+
+      tmp2[len - 1] = 0;
+
+      tmp2[len - 2] =
+	c.nm[1]*ima(finish);
+
+      tmp2[len - 3] =
+	c.nm[1]*ima(finish - d)
+	+ c.nm[2]*ima(finish)
+	- c.dm[1]*tmp2[len-2];
+
+      tmp2[len - 4] =
+	c.nm[1]*ima(finish - d - d)
+	+ c.nm[2]*ima(finish - d)
+	+ c.nm[3]*ima(finish)
+	- c.dm[1]*tmp2[len-3]
+	- c.dm[2]*tmp2[len-2];
+
+      current = finish - d - d - d ;
+
+      for (int i = len - 5; i >= 0; --i)
+	{
+	  tmp2[i] =
+	    c.nm[1]*ima(current)
+	    + c.nm[2]*ima(current + d)
+	    + c.nm[3]*ima(current + d + d)
+	    + c.nm[4]*ima(current + d + d + d)
+	    - c.dm[1]*tmp2[i+1] - c.dm[2]*tmp2[i+2]
+	    - c.dm[3]*tmp2[i+3] - c.dm[4]*tmp2[i+4];
+	  current -= d;
+	}
+
+      // Combine results from causal and non-causal parts.
+
+      current = start;
+      for (int i = 0; i < len; ++i)
+	{
+	  ima(current) = (tmp1[i] + tmp2[i]);
+	  current += d;
+	}
+    }
+
+
+
+
+    template <typename I, typename C>
+    inline
+    void
+    recursivefilter_directional_2d_fastest(I& ima,
+					   const C& c,
+					   const mln_psite(I)& start,
+					   const mln_psite(I)& finish,
+					   int len,
+					   const mln_deduce(I, psite, delta)& d,
+					   const mln_value(I)& bdr)
+    {
+//       extension::adjust_fill(ima, 5 * int(151 + .50001) + 1, bdr);
+      // extension::fill(ima, bdr);
+
+      std::vector<MLN_FLOAT> tmp1(len);
+      std::vector<MLN_FLOAT> tmp2(len);
+
+      unsigned delta_offset = ima.delta_index(d);
+      unsigned
+	o_start = ima.index_of_point(start),
+	o_start_d   = o_start +     delta_offset,
+	o_start_dd  = o_start + 2 * delta_offset,
+	o_start_ddd = o_start + 3 * delta_offset;
+
+      tmp1[0] =
+	c.n[0] * ima.element(o_start);
+
+      tmp1[1] = 0
+	+ c.n[0] * ima.element(o_start_d)
+	+ c.n[1] * ima.element(o_start)
+	- c.d[1] * tmp1[0];
+
+      tmp1[2] = 0
+	+ c.n[0] * ima.element(o_start_dd)
+	+ c.n[1] * ima.element(o_start_d)
+	+ c.n[2] * ima.element(o_start)
+	- c.d[1] * tmp1[1]
+	- c.d[2] * tmp1[0];
+
+      tmp1[3] = 0
+	+ c.n[0] * ima.element(o_start_ddd)
+	+ c.n[1] * ima.element(o_start_dd)
+	+ c.n[2] * ima.element(o_start_d)
+	+ c.n[3] * ima.element(o_start)
+	- c.d[1] * tmp1[2] - c.d[2] * tmp1[1]
+	- c.d[3] * tmp1[0];
+
+      unsigned
+	o_current = o_start + 4 * delta_offset,
+	o_current_d   = o_current -     delta_offset,
+	o_current_dd  = o_current - 2 * delta_offset,
+	o_current_ddd = o_current - 3 * delta_offset;
+
+      for (int i = 4; i < len; ++i)
+	{
+	  tmp1[i] = 0
+	    + c.n[0] * ima.element(o_current)
+	    + c.n[1] * ima.element(o_current_d)
+	    + c.n[2] * ima.element(o_current_dd)
+	    + c.n[3] * ima.element(o_current_ddd)
+	    - c.d[1] * tmp1[i - 1] - c.d[2] * tmp1[i - 2]
+	    - c.d[3] * tmp1[i - 3] - c.d[4] * tmp1[i - 4];
+	  o_current     += delta_offset;
+	  o_current_d   += delta_offset;
+	  o_current_dd  += delta_offset;
+	  o_current_ddd += delta_offset;
+	}
+
+      // Non causal part
+
+      // extension::fill(ima, bdr);
+
+      unsigned
+	o_finish   = ima.index_of_point(finish),
+	o_finish_d  = o_finish -     delta_offset,
+	o_finish_dd = o_finish - 2 * delta_offset;
+
+      tmp2[len - 1] = 0;
+
+      tmp2[len - 2] =
+	c.nm[1] * ima.element(o_finish);
+
+      tmp2[len - 3] = 0
+	+ c.nm[1] * ima.element(o_finish_d)
+	+ c.nm[2] * ima.element(o_finish)
+	- c.dm[1] * tmp2[len-2];
+
+      tmp2[len - 4] = 0
+	+ c.nm[1] * ima.element(o_finish_dd)
+	+ c.nm[2] * ima.element(o_finish_d)
+	+ c.nm[3] * ima.element(o_finish)
+	- c.dm[1] * tmp2[len-3]
+	- c.dm[2] * tmp2[len-2];
+
+      o_current = o_finish - 3 * delta_offset;
+      o_current_d   = o_current +     delta_offset;
+      o_current_dd  = o_current + 2 * delta_offset;
+      o_current_ddd = o_current + 3 * delta_offset;
+
+      for (int i = len - 5; i >= 0; --i)
+	{
+	  tmp2[i] = 0
+	    + c.nm[1] * ima.element(o_current)
+	    + c.nm[2] * ima.element(o_current_d)
+	    + c.nm[3] * ima.element(o_current_dd)
+	    + c.nm[4] * ima.element(o_current_ddd)
+	    - c.dm[1] * tmp2[i+1] - c.dm[2] * tmp2[i+2]
+	    - c.dm[3] * tmp2[i+3] - c.dm[4] * tmp2[i+4];
+	  o_current     -= delta_offset;
+	  o_current_d   -= delta_offset;
+	  o_current_dd  -= delta_offset;
+	  o_current_ddd -= delta_offset;
+	}
+
+      // Combine results from causal and non-causal parts.
+
+      o_current = o_start;
+      for (int i = 0; i < len; ++i)
+	{
+	  ima.element(o_current) = (tmp1[i] + tmp2[i]);
+	  o_current += delta_offset;
+	}
+    }
+
+
+    template <typename I>
+    inline
+    mln_concrete(I)
+    gaussian_directional_2d(const Image<I>& input_,
+			    unsigned dir, MLN_FLOAT sigma,
+			    const mln_value(I)& bdr)
+    {
+      const I& input = exact(input_);
+
+      mln_precondition(dir == 0 || dir == 1);
+      mln_precondition(input.is_valid());
+
+      my::recursivefilter_coef_ coef(1.68f, 3.735f,
+				     1.783f, 1.723f,
+				     -0.6803f, -0.2598f,
+				     0.6318f, 1.997f,
+				     sigma,
+				     my::recursivefilter_coef_::DericheGaussian);
+
+      extension::adjust_fill(input, 5 * int(sigma + .50001) + 1, bdr);
+      mln_concrete(I) output = duplicate(input);
+
+      if (sigma < 0.006)
+	return output;
+
+      int
+	nrows = geom::nrows(input),
+	ncols = geom::ncols(input),
+	b     = input.border();
+
+      if (dir == 0)
+	{
+	  for (int j = 0; j < ncols; ++j)
+	    recursivefilter_directional_2d_fastest(output, coef,
+						   point2d(- b, j),
+						   point2d(nrows - 1 + b, j),
+						   nrows + 2 * b,
+						   dpoint2d(1, 0),
+						   bdr);
+	}
+
+      if (dir == 1)
+	{
+	  for (int i = 0; i < nrows; ++i)
+	    recursivefilter_directional_2d_fastest(output, coef,
+						   point2d(i, - b),
+						   point2d(i, ncols - 1 + b),
+						   ncols + 2 * b,
+						   dpoint2d(0, 1),
+						   bdr);
+	}
+
+      return output;
+    }
+
+
+  } // end of namespace mln::linear
+
+} // end of namespace mln
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                        
                            
                                
                            
                            milena r3552: Optimize propagations and add	component processing functions
                        
                        
by Edwin Carlinet 19 Mar '09
                    by Edwin Carlinet 19 Mar '09
19 Mar '09
                    
                          URL: https://svn.lrde.epita.fr/svn/oln/trunk/milena
ChangeLog:
2009-03-19  Edwin Carlinet  <carlinet(a)lrde.epita.fr>
	Optimize propagations and add component processing functions.
	* mln/morpho/tree/data.hh: Add optimization about preorder
	iterator.
	* tests/morpho/tree/data.cc: Update test file.
	* sandbox/edwin/tree/accumulator/arg_max.hh: New accumulator
	that returns site having the max value.
	* sandbox/edwin/tree/accumulator/max.hh: Remove.
	* sandbox/edwin/tree/propagate.hh: Make clean.
	* sandbox/edwin/tree/propagate_if.hh: Functions performing
	different propagations on nodes matching a predicate.
	* sandbox/edwin/tree/propagate_node.hh: Basic ascendant and
	descendant propagations computation.
	* sandbox/edwin/tree/propagation.cc: Test file for propagations.
	* sandbox/edwin/tree/routines.hh: Remove.
	* sandbox/edwin/tree/run.hh: Methods to apply accumulator on
	tree nodes, and to perform object component research with a
	criteria (treshold...).
	* sandbox/edwin/tree/test.cc: New.
---
 mln/morpho/tree/data.hh                   |  134 ++++++++++--
 sandbox/edwin/tree/Makefile               |    6 
 sandbox/edwin/tree/accumulator/arg_max.hh |  160 +++++++++++++++
 sandbox/edwin/tree/propagate.hh           |  102 ---------
 sandbox/edwin/tree/propagate_if.hh        |  320 ++++++++++++++++++++++++++++++
 sandbox/edwin/tree/propagate_node.hh      |   46 ++--
 sandbox/edwin/tree/propagation.cc         |   82 ++++---
 sandbox/edwin/tree/run.hh                 |  272 +++++++++++++++++++++++++
 sandbox/edwin/tree/test.cc                |   98 +++++++++
 tests/morpho/tree/data.cc                 |   14 +
 10 files changed, 1052 insertions(+), 182 deletions(-)
Index: trunk/milena/tests/morpho/tree/data.cc
===================================================================
--- trunk/milena/tests/morpho/tree/data.cc	(revision 3551)
+++ trunk/milena/tests/morpho/tree/data.cc	(revision 3552)
@@ -65,11 +65,18 @@
     /* Check site and node up order */
     tree_t::up_node_piter n(t);
     tree_t::up_site_piter s(t);
+    tree_t::up_leaf_piter l(t);
     n.start();
+    l.start();
     for_all(s)
       if (t.is_a_node(s))
 	{
 	  mln_assertion(s == n);
+	  if (t.is_a_leaf(n))
+	    {
+	      mln_assertion(l == n);
+	      l.next();
+	    }
 	  n.next();
 	}
     mln_assertion(!n.is_valid());
@@ -79,11 +86,18 @@
     /* Check site and node up order */
     tree_t::dn_node_piter n(t);
     tree_t::dn_site_piter s(t);
+    tree_t::dn_leaf_piter l(t);
     n.start();
+    l.start();
     for_all(s)
       if (t.is_a_node(s))
 	{
 	  mln_assertion(s == n);
+	  if (t.is_a_leaf(n))
+	    {
+	      mln_assertion(l == n);
+	      l.next();
+	    }
 	  n.next();
 	}
     mln_assertion(!n.is_valid());
Index: trunk/milena/mln/morpho/tree/data.hh
===================================================================
--- trunk/milena/mln/morpho/tree/data.hh	(revision 3551)
+++ trunk/milena/mln/morpho/tree/data.hh	(revision 3552)
@@ -47,12 +47,16 @@
 # define mln_dn_site_piter(T)	typename T::dn_site_piter
 # define mln_up_node_piter(T)	typename T::up_node_piter
 # define mln_dn_node_piter(T)	typename T::dn_node_piter
+# define mln_up_leaf_piter(T)	typename T::up_leaf_piter
+# define mln_dn_leaf_piter(T)	typename T::dn_leaf_piter
 # define mln_preorder_piter(T)	typename T::preorder_piter
 
 # define mln_up_site_piter_(T)	T::up_site_piter
 # define mln_dn_site_piter_(T)  T::dn_site_piter
 # define mln_up_node_piter_(T)  T::up_node_piter
 # define mln_dn_node_piter_(T)  T::dn_node_piter
+# define mln_up_leaf_piter_(T)	T::up_leaf_piter
+# define mln_dn_leaf_piter_(T)	T::dn_leaf_piter
 # define mln_preorder_piter_(T) T::preorder_piter
 
 namespace mln
@@ -78,6 +82,12 @@
       /// Iterate on tree's nodes (component representants) from leaves to roots.
       template <typename T> struct dn_node_piter;
 
+      /// Iterate on tree's leaves in the same way of up_node_piter.
+      template <typename T> struct up_leaf_piter;
+
+      /// Iterate on tree's leaves in the same way of dn_node_piter.
+      template <typename T> struct dn_leaf_piter;
+
       /// Preorder tree traversal iterator.
       template <typename T> struct preorder_piter;
 
@@ -101,8 +111,10 @@
 	typedef mln_site(I) site;
 	/// Site set associated type.
 	typedef S sites_t;
-	/// Node list associated type.
+	/// Node set associated type.
 	typedef p_array<mln_psite(I)> nodes_t;
+	/// Leaf set associated type.
+	typedef p_array<mln_psite(I)> leaves_t;
 
 	/// Parent image associated type.
 	typedef mln_ch_value(I, mln_psite(I)) parent_t;
@@ -115,6 +127,10 @@
 	typedef mln::morpho::tree::up_node_piter<self_> up_node_piter;
 	typedef mln::morpho::tree::dn_node_piter<self_> dn_node_piter;
 
+	// Iterate on leaves only.
+	typedef mln::morpho::tree::up_leaf_piter<self_> up_leaf_piter;
+	typedef mln::morpho::tree::dn_leaf_piter<self_> dn_leaf_piter;
+
 	typedef mln::morpho::tree::preorder_piter<self_> preorder_piter;
 
 // 	typedef mln_bkd_piter(S) piter;
@@ -123,7 +139,7 @@
 
 	/// Constructor.
 	template <typename N>
-	explicit data(const Image<I>& f, const Site_Set<S>& s, const Neighborhood<N>& nbh);
+	data(const Image<I>& f, const Site_Set<S>& s, const Neighborhood<N>& nbh);
 
 
 
@@ -134,32 +150,46 @@
 
 	/// \}
 
+	/// \{ Child-related materials.
+
 	const p_array<mln_psite(I)>& children(const mln_psite(I)& p) const;
 	const mln_ch_value(I, nodes_t)& children_image() const;
 
-	/// \{ Tests.
+	/// \}
 
-	bool is_valid() const;
-	bool is_root(const mln_psite(I)& p) const;
-	bool is_a_node(const mln_psite(I)& p) const;
-	bool is_a_non_root_node(const mln_psite(I)& p) const;
-	bool is_a_leaf(const mln_psite(I)& p) const;
+	/// \{ Nodes materials.
 
-	/// \}
+	const p_array<mln_psite(I)>& nodes() const;
 
+	/// \}
 
-	/// \{ Nodes-related materials.
+	/// \{ Leaves materials.
 
-	const p_array<mln_psite(I)>& nodes() const;
+	const p_array<mln_psite(I)>& leaves() const;
 
 	/// \}
 
-	/// \{ Sites-related materials.
+	/// \{ Sites materials.
 
 	const S& domain() const;
 
 	/// \}
 
+
+
+	/// \{ Tests.
+
+	bool is_valid() const;
+	bool is_root(const mln_psite(I)& p) const;
+	bool is_a_node(const mln_psite(I)& p) const;
+	bool is_a_non_root_node(const mln_psite(I)& p) const;
+	bool is_a_leaf(const mln_psite(I)& p) const;
+
+	/// \}
+
+
+
+
 	unsigned nroots() const;
 
 
@@ -175,10 +205,13 @@
 	mln_ch_value(I, mln_psite(I)) parent_;	// Parent image.
 	mln_ch_value(I, nodes_t) children_;	// Children image.
 	nodes_t nodes_;
+	leaves_t leaves_;
 	unsigned nroots_;
       };
 
 
+      /* Iterators */
+
       template <typename T>
       struct up_site_piter
 	: public mln::internal::piter_identity_< typename T::sites_t::bkd_piter,	// Adaptee.
@@ -227,7 +260,7 @@
 						 up_node_piter<T> >			// Exact.
       {
       private:
-	typedef typename T::sites_t::fwd_piter Pi_;
+	typedef typename T::nodes_t::fwd_piter Pi_;
 	typedef mln::internal::piter_identity_< Pi_, up_node_piter<T> > super_;
 
       public:
@@ -248,7 +281,7 @@
 						 dn_node_piter<T> >			// Exact.
       {
       private:
-	typedef typename T::sites_t::bkd_piter Pi_;
+	typedef typename T::nodes_t::bkd_piter Pi_;
 	typedef mln::internal::piter_identity_< Pi_, dn_node_piter<T> > super_;
 
       public:
@@ -264,6 +297,48 @@
       };
 
       template <typename T>
+      struct up_leaf_piter
+	: public mln::internal::piter_identity_< typename T::leaves_t::fwd_piter,	// Adaptee.
+						 up_leaf_piter<T> >			// Exact.
+      {
+      private:
+	typedef typename T::leaves_t::fwd_piter Pi_;
+	typedef mln::internal::piter_identity_< Pi_, up_leaf_piter<T> > super_;
+
+      public:
+	up_leaf_piter(const T& t)
+	{
+	  this->change_target(t.leaves());
+	}
+
+	up_leaf_piter(const Pi_& pi)
+	  : super_(pi)
+	{
+	}
+      };
+
+      template <typename T>
+      struct dn_leaf_piter
+	: public mln::internal::piter_identity_< typename T::leaves_t::bkd_piter,	// Adaptee.
+						 dn_leaf_piter<T> >			// Exact.
+      {
+      private:
+	typedef typename T::leaves_t::bkd_piter Pi_;
+	typedef mln::internal::piter_identity_< Pi_, dn_leaf_piter<T> > super_;
+
+      public:
+	dn_leaf_piter(const T& t)
+	{
+	  this->change_target(t.leaves());
+	}
+
+	dn_leaf_piter(const Pi_& pi)
+	  : super_(pi)
+	{
+	}
+      };
+
+      template <typename T>
       class preorder_piter
 	: public mln::internal::site_set_iterator_base< T, preorder_piter<T> >
       {
@@ -294,6 +369,9 @@
 	/// Go to the next point.
 	void next_();
 
+	/// Skip current point children. Next call to next() goes to the brother point.
+	void skip_children();
+
       protected:
 	using super_::p_;
 	using super_::s_;
@@ -328,11 +406,14 @@
 	    {
 	      nodes_.insert(p);
 	      children_(parent_(p)).insert(p);
+	      if (is_a_leaf(p))
+		leaves_.insert(p);
 	    }
-	  else
-	    if (parent_(p) == p)
+	  else if (parent_(p) == p) //it's a root.
 	      {
 		nodes_.insert(p);
+	      if (is_a_leaf(p)) // One pixel image...
+		leaves_.insert(p);
 		++nroots_;
 	      }
 	}
@@ -418,6 +499,15 @@
 
       template <typename I, typename S>
       inline
+      const p_array<mln_psite(I)>&
+      data<I,S>::leaves() const
+      {
+	mln_precondition(is_valid());
+	return leaves_;
+      }
+
+      template <typename I, typename S>
+      inline
       const S&
       data<I,S>::domain() const
       {
@@ -490,6 +580,7 @@
 					const mln_psite(T::function)& p)
 	: root_ (&p)
       {
+	mln_assertion(t.is_a_node(p));
 	this->change_target(t);
       }
 
@@ -522,7 +613,7 @@
 	else
 	  {
 	    mln_dn_node_piter(T) n(*s_);
-	    int roots = 0;
+	    unsigned roots = 0;
 	    for (n.start(); n.is_valid() && roots < s_->nroots(); n.next())
 	      if (s_->is_root(n))
 		{
@@ -548,6 +639,15 @@
 	  stack_.push_back(child);
       }
 
+      template <typename T>
+      inline
+      void
+      preorder_piter<T>::skip_children()
+      {
+	while (stack_.size() != 1 && s_->parent(stack_.back()) == p_)
+	  stack_.pop_back();
+      }
+
 
 # endif // ! MLN_INCLUDE_ONLY
 
Index: trunk/milena/sandbox/edwin/tree/routines.hh (deleted)
===================================================================
Index: trunk/milena/sandbox/edwin/tree/accumulator/max.hh (deleted)
===================================================================
Index: trunk/milena/sandbox/edwin/tree/accumulator/arg_max.hh
===================================================================
--- trunk/milena/sandbox/edwin/tree/accumulator/arg_max.hh	(revision 0)
+++ trunk/milena/sandbox/edwin/tree/accumulator/arg_max.hh	(revision 3552)
@@ -0,0 +1,160 @@
+// Copyright (C) 2007, 2008, 2009 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_MORPHO_TREE_ACCUMULATOR_ARG_MAX_HH_
+# define MLN_MORPHO_TREE_ACCUMULATOR_ARG_MAX_HH_
+
+/// \file mln/morpho/tree/accumulator/arg_max.hh
+///
+/// Define an accumulator that performs arg max.
+
+
+# include <mln/core/concept/image.hh>
+# include <mln/accu/internal/base.hh>
+# include <mln/util/pix.hh>
+
+namespace mln {
+  namespace accumulator {
+
+	template <typename I>
+	class arg_max : public mln::accu::internal::base<const mln_psite(I)&, arg_max<I> >
+	{
+	  typedef mln::accu::internal::base<const mln_psite(I)&, arg_max<I> > super_;
+
+	public:
+	  typedef typename util::pix<I> argument;
+
+	  /// Constructor
+	  arg_max(const Image<I>& ima);
+	  /// Destructor
+	  ~arg_max();
+
+	  /// Manipulators.
+	  /// \{
+	  void init();
+
+	  void take(const argument& pix);
+	  void take(const arg_max<I>& other);
+
+	  void take_as_init(const argument& pix);
+	  /// \}
+
+	  /// Get the value of the accumulator.
+	  const mln_psite(I)& to_result() const;
+
+	  /// Check whether the accumulator is able to give a result.
+	  bool is_valid() const;
+
+	private:
+	  const I& ima_;
+	  mln_psite(I)* p_;
+	};
+
+# ifndef MLN_INCLUDE_ONLY
+
+	template <typename I>
+	inline
+	arg_max<I>::arg_max(const Image<I>& ima) :
+	  ima_ (exact(ima)),
+	  p_ (0)
+	{
+	}
+
+	template <typename I>
+	inline
+	arg_max<I>::~arg_max()
+	{
+	  delete p_;
+	}
+
+
+	template <typename I>
+	inline
+	void
+	arg_max<I>::init()
+	{
+	}
+
+	template <typename I>
+	inline
+	void
+	arg_max<I>::take(const argument& pix)
+	{
+	  if (!is_valid())
+	    {
+	      take_as_init(pix);
+	      return;
+	    }
+
+	  if (pix.v() > ima_(*p_))
+	    *p_ = pix.p();
+	}
+
+ 	template <typename I>
+	inline
+	void
+	arg_max<I>::take(const arg_max<I>& other)
+	{
+	  mln_invariant(other.is_valid());
+
+	  if (other.ima_(*other.p_) > ima_(*p_))
+	    *p_ = *other.p_;
+	}
+
+    	template <typename I>
+	inline
+	void
+	arg_max<I>::take_as_init(const argument& pix)
+	{
+	  p_ = new mln_psite(I)(pix.p());
+	}
+
+	template <typename I>
+	inline
+	const mln_psite(I)&
+	arg_max<I>::to_result() const
+	{
+	  mln_invariant(p_ != 0);
+	  return *p_;
+	}
+
+	template <typename I>
+	inline
+	bool
+	arg_max<I>::is_valid() const
+	{
+	  return p_ != 0;
+	}
+
+
+# endif // ! MLN_INCLUDE_ONLY
+
+      }  // end of namespace mln::accumulator
+    }  // end of namespace mln
+
+#endif /* ! MLN_MORPHO_TREE_ACCUMULATOR_ARG_MAX_HH_ */
Index: trunk/milena/sandbox/edwin/tree/propagate.hh
===================================================================
--- trunk/milena/sandbox/edwin/tree/propagate.hh	(revision 3551)
+++ trunk/milena/sandbox/edwin/tree/propagate.hh	(revision 3552)
@@ -46,7 +46,7 @@
       propagate_representant(const T& t, Image<A>& a_)
       {
 	A a = exact(a_);
-	mln_fwd_piter(T) p(t.domain());
+	mln_up_site_piter(T) p(t);
 	for_all(p)
 	  if (! t.is_a_node(p))
 	    {
@@ -55,106 +55,6 @@
 	    }
       }
 
-
-
-
-
-      /// Dans le cas des images binaires...
-      /// Propagate a tagged node's value to its subbranches.
-	template <typename T, typename A>
-	void
-	propagate_to_childhood(const T& t, A& a)
-	{
-	  mln_bkd_piter(T::nodes_t) n(t.nodes());
-	  for_all(n)
-	  {
-	    if (a(t.parent(n)))
-	      {
-		mln_assertion(t.is_a_node(t.parent(n)));
-		a(n) = a(t.parent(n));
-	    }
-	  }
-	}
-
-
-      /// Propagate a tagged node's value to its direct children.
-      template <typename T, typename A>
-      void
-      propagate_to_children(const T& t, A& a)
-      {
-	mln_fwd_piter(T::nodes_t) n(t.nodes());
-	for_all(n)
-	{
-	  if (a(t.parent(n)))
-	    {
-	      mln_assertion(t.is_a_node(t.parent(n)));
-	      a(n) = a(t.parent(n));
-	    }
-	}
-      }
-
-      /// Propagate a tagged node's value to its ancestors.
-      template <typename T, typename A>
-      void
-      propagate_to_ancestors(const T& t, A& a)
-      {
-	mln_fwd_piter(T::nodes_t) n(t.nodes());
-	for_all(n)
-	{
-	  if (a(n))
-	    {
-	      mln_assertion(t.is_a_node(t.parent(n)));
-	      a(t.parent(n)) = a(n);
-	    }
-	}
-      }
-
-      /// Propagate a tagged node's value to its direct parents.
-      template <typename T, typename A>
-      void
-      propagate_to_parent(const T& t, A& a)
-      {
-	mln_bkd_piter(T::nodes_t) n(t.nodes());
-	for_all(n)
-	{
-	  mln_assertion(t.is_a_node(n));
-	  if (a(n))
-	    {
-	      mln_assertion(t.is_a_node(t.parent(n)));
-	      a(t.parent(n)) = a(n);
-	    }
-	}
-      }
-
-      /// Propagate a tagged leaf's value to its ancestors.
-      /// In others words, tag the branch which the tagged leaf belongs to.
-      /// At the end, the tree should get this property:
-      /// for all n
-      ///   a(n) is true iff there exits an l in tree's leaves such that
-      ///       n <== l and a(l) is true.
-      /// TODO: post-condition which checks this property.
-
-
-      template <typename T, typename A>
-      void
-      propagate_leaf_to_ancestors(const T& t, A& a)
-      {
-
-	mln_fwd_piter(T::leaves_t) l(t.leaves());
-	for_all(l)
-	  a(t.parent(l)) = 0;
-
-
-	mln_fwd_piter(T::nodes_t) n(t.nodes());
-	for_all(n)
-	{
-	  mln_assertion(t.is_a_node(t.parent(n)));
-	  a(t.parent(n)) = a(t.parent(n)) || a(n);
-	}
-      }
-
-
-
     } // end of namespace mln::morpho::tree
   } // end of namespace mln::morpho
 } // end of namespace mln
Index: trunk/milena/sandbox/edwin/tree/run.hh
===================================================================
--- trunk/milena/sandbox/edwin/tree/run.hh	(revision 0)
+++ trunk/milena/sandbox/edwin/tree/run.hh	(revision 3552)
@@ -0,0 +1,272 @@
+// Copyright (C) 2007, 2008, 2009 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_MORPHO_TREE_PROPAGATE_RUN_HH_
+# define MLN_MORPHO_TREE_PROPAGATE_RUN_HH_
+
+# include <mln/core/concept/accumulator.hh>
+# include <mln/core/concept/image.hh>
+# include <mln/core/concept/function.hh>
+
+# include <mln/core/site_set/p_array.hh>
+# include <mln/util/pix.hh>
+
+# include "propagate_node.hh"
+
+namespace mln {
+  namespace morpho {
+    namespace tree {
+
+
+      /**
+      ** Traverse component tree \p tree and provide tree nodes values
+      ** to accumulator \p accu_. (Alias to "map")
+      **
+      ** @param tree Component tree used to perform accumulation.
+      ** @param a_ Attributed image.
+      ** @accu_ Accumulator that will be applied on tree nodes.
+      **
+      ** @return The result of accumulation.
+      */
+      template <typename T, typename A, typename I>
+      mln_result(A)
+      run(const T& tree,
+	  const Image<I>& a_,
+	  Accumulator<A>& accu_);
+
+      /**
+      ** Apply accumulator \accu on tree nodes. If the resulting node of
+      ** accumulation checks predicate \p pred, the node is inserted
+      ** into resulting array, then ascendant and descendant zero-fill
+      ** propagations are performed from the node. These operations
+      ** are repeated until the node won't check predicate.
+      **
+      ** @param tree Component tree used for propagation.
+      ** @param a Attributed image where values are propagated.
+      ** @param accu_ Accumulator to apply on tree.
+      ** @param pred Predicate that must check the result of
+      ** accumulator to propagate the node.
+      **
+      ** @return Array of propagated nodes.
+      */
+      template <typename T, typename A, typename ACC, typename P2B>
+      p_array< mln_psite(A) >
+      run_while(const T& tree,
+		Image<A>& a,
+		Accumulator<ACC>& accu_,
+		Function_p2b<P2B>& pred);
+
+
+      /**
+      ** Apply accumulator \accu on tree nodes values n times.
+      ** Each time, the result of accumulator is inserted
+      ** into the returned array, then ascendant and descendant zero-fill
+      ** propagations are performed from the node.
+      ** (This function is a shorcut of run_while with a cardinality predicate).
+      **
+      ** @param tree Component tree used for propagation.
+      ** @param a Attributed image where values are propagated.
+      ** @param accu_ Accumulator to apply on tree.
+      ** @param n The repetition number.
+      **
+      ** @return Array of propagated nodes.
+      */
+      template <typename T, typename A, typename ACC>
+      inline
+      p_array< mln_psite(A) >
+      run_ntimes(const T& tree,
+		 Image<A>& a,
+		 Accumulator<ACC>& acc,
+		 unsigned n);
+
+      /**
+      ** Apply accumulator \accu on tree nodes value until the value
+      ** accumulated by \p acc get lesser than the treshold \p n.
+      ** Each time, the result of accumulator is inserted
+      ** into the returned array, then ascendant and descendant zero-fill
+      ** propagations are performed from the node.
+      ** (This function is a shorcut of run_while with a treshold predicate).
+      **
+      ** @param tree Component tree used for propagation.
+      ** @param a Attributed image where values are propagated.
+      ** @param accu_ Accumulator to apply on tree.
+      ** @param n Treshold.
+      **
+      ** @return Array of propagated nodes.
+      */
+      template <typename T, typename A, typename ACC>
+      inline
+      p_array< mln_psite(A) >
+      run_while_treshold(const T& tree,
+			 Image<A>& a,
+			 Accumulator<ACC>& acc,
+			 mln_value(A) n);
+
+# ifndef MLN_INCLUDE_ONLY
+
+      namespace internal
+      {
+
+	template <typename T, typename A, typename ACC, typename P2B>
+	p_array< mln_psite(A) >
+	run_while(const T& tree,
+		  A& a,
+		  ACC& accu,
+		  P2B& pred)
+	{
+	  mln_psite(A) p;
+	  p_array< mln_psite(A) > arr_sites;
+	  util::array< mln_value(A) > arr_values;
+
+	  do  {
+	      p = morpho::tree::run(tree, a, accu);
+	      if (a(p) == 0) //there's no more objects.
+		break;
+	      arr_sites.insert(p);
+	      arr_values.append(a(p));
+	      morpho::tree::propagate_node_to_descendants(p, tree, a, 0);
+	      morpho::tree::propagate_node_to_ancestors(p, tree, a, 0);
+	      a(p) = 0;
+	  } while (pred(accu.to_result()));
+	  for (unsigned i = 0; i < arr_sites.nsites(); i++)
+	    a(arr_sites[i]) = arr_values[i];
+	  return arr_sites;
+	}
+
+	struct ncard : Function_p2b< ncard >
+	{
+	  typedef bool result;
+
+	  ncard(unsigned n)
+	    : n_ (n)
+	  {
+	  }
+
+	  template <typename P>
+	  bool operator()(const P& p)
+	  {
+	    (void)p;
+	    return (n_-- > 0);
+	  }
+
+	private:
+	  unsigned n_;
+	};
+
+	template <typename I>
+	struct treshold : Function_p2b< treshold<I> >
+	{
+	  typedef bool result;
+
+	  treshold(const Image<I>& ima,
+		   const mln_value(I)& treshold)
+	    : ima_ (exact(ima)),
+	      treshold_ (treshold)
+	  {
+	  }
+
+	  bool operator()(const mln_psite(I)& p) const
+	  {
+	    return (ima_(p) > treshold_);
+	  }
+
+	private:
+	  const I& ima_;
+	  const mln_value(I) treshold_;
+	};
+
+
+      } // end of namespace mln::morpho::tree::internal
+
+      template <typename T, typename A, typename ACC, typename P2B>
+      inline
+      p_array< mln_psite(A) >
+      run_while(const T& tree,
+		Image<A>& a_,
+		Accumulator<ACC>& acc,
+		Function_p2b<P2B>& pred)
+      {
+	A& a = exact(a_);
+
+	mln_precondition(tree.f().domain() == a.domain());
+	mln_precondition(a.is_valid());
+
+	return internal::run_while(tree, a, exact(acc), exact(pred));
+      }
+
+      template <typename T, typename A, typename ACC>
+      inline
+      p_array< mln_psite(A) >
+      run_ntimes(const T& tree,
+		 Image<A>& a,
+		 Accumulator<ACC>& acc,
+		 unsigned n)
+      {
+	internal::ncard predicate(n - 1);
+	return run_while(tree, a, acc, predicate);
+      }
+
+
+      template <typename T, typename A, typename ACC>
+      inline
+      p_array< mln_psite(A) >
+      run_while_treshold(const T& tree,
+			 Image<A>& a,
+			 Accumulator<ACC>& acc,
+			 mln_value(A) n)
+      {
+	internal::treshold<A> predicate(a, n);
+	return run_while(tree, a, acc, predicate);
+      }
+
+      template <typename T, typename A, typename I>
+      mln_result(A)
+      run(const T& tree,
+	  const Image<I>& a_,
+	  Accumulator<A>& accu_)
+      {
+	A& accu = exact(accu_);
+	const I& a = exact(a_);
+
+	mln_precondition(tree.f().domain() == a.domain());
+	mln_precondition(a.is_valid());
+
+	mln_up_node_piter(T) n(tree);
+	for_all(n)
+	  accu.take(make::pix(a, n));
+	return (accu.to_result());
+      }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+
+    } // end of namespace mln::morpho::tree
+  } // end of namespace mln::morpho
+} // end of namespace mln
+
+#endif /* !MLN_MORPHO_TREE_PROPAGATE_RUN_HH_ */
Index: trunk/milena/sandbox/edwin/tree/test.cc
===================================================================
--- trunk/milena/sandbox/edwin/tree/test.cc	(revision 0)
+++ trunk/milena/sandbox/edwin/tree/test.cc	(revision 3552)
@@ -0,0 +1,98 @@
+/* mln core */
+#include <mln/core/image/image2d.hh>
+#include <mln/core/alias/neighb2d.hh>
+#include <mln/core/var.hh>
+
+/* Site set */
+#include <mln/core/site_set/p_array.hh>
+#include <mln/level/sort_psites.hh>
+
+/* Component trees */
+#include <mln/morpho/tree/data.hh>
+#include <mln/morpho/tree/compute_attribute_image.hh>
+#include "propagate.hh"
+#include "run.hh"
+#include "accumulator/arg_max.hh"
+
+/* Attributes */
+#include <mln/morpho/attribute/sharpness.hh>
+
+/* io */
+#include <mln/io/pgm/load.hh>
+#include <../../theo/color/change_attributes.hh>
+#include <iostream>
+
+/* std */
+#include <string>
+
+bool mydebug = false;
+
+
+void usage(char** argv)
+{
+  std::cerr << "usage: " << argv[0] << " input [--debug]" << std::endl;
+  abort();
+}
+
+void dsp(const char* str)
+{
+  std::cout << std::endl
+	    << "*********************" << std::endl
+	    << "** " << str << std::endl
+	    << "*********************" << std::endl;
+}
+
+int main(int argc, char* argv[])
+{
+  using namespace mln;
+  using value::int_u8;
+
+  if (argc < 2)
+    usage(argv);
+
+  mydebug = (argc >= 3 && std::string(argv[2]) == "--debug");
+
+
+  /* Image loadin' */
+  typedef image2d<int_u8> I;
+
+  I input;
+  io::pgm::load(input, argv[1]);
+
+  /* Component tree creation */
+  typedef p_array< mln_site_(I) > S;
+  typedef morpho::tree::data<I,S> tree_t;
+
+  S sorted_sites = level::sort_psites_decreasing(input);
+  tree_t tree(input, sorted_sites, c4());
+
+  /* Compute Attribute On Image */
+  typedef morpho::attribute::sharpness<I> accu_t;
+  typedef mln_ch_value_(tree_t::function, mln_result_(accu_t)) A;
+
+  A a = morpho::tree::compute_attribute_image(accu_t (), tree);
+  morpho::tree::propagate_representant(tree, a);
+
+  if (mydebug) {
+    dsp("Image attribute"); display_tree_attributes(tree, a);
+  }
+
+  /* Run max accumulator, looking for 5 objects */
+  accumulator::arg_max<A> argmax(a);
+  p_array< mln_psite_(A) > obj_array; // Array of object components.
+  obj_array = morpho::tree::run_ntimes(tree, a, argmax, 5);
+
+  if (mydebug) {
+    dsp("Run max accumulator, lk 4 5 objs"); display_tree_attributes(tree, a);
+  }
+
+  /* Print them */
+  if (mydebug) {
+    dsp("Image Filtered Components");
+    mln_fwd_piter_(p_array< mln_psite_(I) >) c(obj_array);
+    for_all(c)
+      std::cout << c;
+  }
+
+
+}
Index: trunk/milena/sandbox/edwin/tree/propagate_node.hh
===================================================================
--- trunk/milena/sandbox/edwin/tree/propagate_node.hh	(revision 3551)
+++ trunk/milena/sandbox/edwin/tree/propagate_node.hh	(revision 3552)
@@ -41,41 +41,42 @@
   namespace morpho {
     namespace tree {
 
-
       /**
-      ** Propagate a value to a node and its descendants.
+      ** Propagate a value \v from a node \n to its descendants.
       **
-      ** @param n The root of subtree which value propagates in.
-      ** @param t The reference to components tree.
-      ** @param a_ The reference to image.
-      ** @param v The value to propagate. Default is a_(n).
+      ** @param n Node to propagate.
+      ** @param t Component tree used for propagation.
+      ** @param a_ Attributed image where values are propagated.
+      ** @param v Value to propagate.
       */
       template <typename T, typename A>
       void
       propagate_node_to_descendants(mln_psite(A) n,
 				    const T& t,
 				    Image<A>& a_,
-				    mln_value(A) v);
+				    const mln_value(A)& v);
 
       /**
       ** Propagate the node's value to its descendants.
       **
-      ** @param n The root of subtree which value propagates in.
-      ** @param t The reference to components tree.
-      ** @param a_ The reference to image.
+      ** @param n Node to propagate.
+      ** @param t Component tree used for propagation.
+      ** @param a_ Attributed image where values are propagated.
       */
       template <typename T, typename A>
+      inline
       void
       propagate_node_to_descendants(mln_psite(A)& n,
 				    const T& t,
 				    Image<A>& a_);
 
+
       /**
-      ** Propagate a value from a node to its ancestors.
+      ** Propagate a value \v from a node \n to its ancestors.
       **
-      ** @param n Forward iterator related to the node.
-      ** @param t Reference to components tree.
-      ** @param a_ Reference to image.
+      ** @param n Node to propagate.
+      ** @param t Component tree used for propagation.
+      ** @param a_ Attributed image where values are propagated.
       ** @param v Value to propagate.
       */
       template <typename T, typename A>
@@ -83,23 +84,24 @@
       propagate_node_to_ancestors(mln_psite(A) n,
 				  const T& t,
 				  Image<A>& a_,
-				  mln_value(A) v);
+				  const mln_value(A)& v);
 
       /**
       ** Propagate the node's value to its ancestors.
       **
-      ** @param n Forward iterator related to the node.
-      ** @param t Reference to components tree.
-      ** @param a_ Reference to image.
+      ** @param n Node to propagate.
+      ** @param t Component tree used for propagation.
+      ** @param a_ Attributed image where values are propagated.
       */
       template <typename T, typename A>
+      inline
       void
       propagate_node_to_ancestors(mln_psite(A) n,
 				  const T& t,
 				  Image<A>& a_);
 
 
-# ifndef MLN_INCLUDE_ONLY
+      //# ifndef MLN_INCLUDE_ONLY
 
       /* Descendants propagation */
 
@@ -109,7 +111,7 @@
       propagate_node_to_descendants(mln_psite(A) n,
 				    const T& t,
 				    Image<A>& a_,
-				    mln_value(A) v)
+				    const mln_value(A)& v)
       {
 	A& a = exact(a_);
 	mln_precondition(a.is_valid());
@@ -148,7 +150,7 @@
       propagate_node_to_ancestors(mln_psite(A) n,
 				  const T& t,
 				  Image<A>& a_,
-				  mln_value(A) v)
+				  const mln_value(A)& v)
       {
 	A& a = exact(a_);
 	mln_precondition(a.is_valid());
@@ -180,7 +182,7 @@
 	propagate_node_to_ancestors(n, t, a, a(n));
       }
 
-# endif // ! MLN_INCLUDE_ONLY
+      //# endif // ! MLN_INCLUDE_ONLY
 
     } // end of namespace mln::morpho::tree
   } // end of namespace mln::morpho
Index: trunk/milena/sandbox/edwin/tree/propagation.cc
===================================================================
--- trunk/milena/sandbox/edwin/tree/propagation.cc	(revision 3551)
+++ trunk/milena/sandbox/edwin/tree/propagation.cc	(revision 3552)
@@ -1,9 +1,15 @@
 #include <iostream>
 
+
+#include <mln/accu/max.hh>
+#include <mln/util/pix.hh>
+
 #include <mln/core/image/image2d.hh>
 #include <mln/core/alias/neighb2d.hh>
 #include <mln/core/alias/point2d.hh>
 #include <mln/core/routine/duplicate.hh>
+#include <mln/core/concept/function.hh>
+
 
 #include <mln/value/int_u8.hh>
 #include <mln/io/pgm/load.hh>
@@ -12,12 +18,14 @@
 #include <mln/level/sort_psites.hh>
 #include <mln/morpho/tree/data.hh>
 
-
 #include <../../theo/color/change_attributes.hh>
+
+
+
 #include "propagate_node.hh"
-#include "propagate_value.hh"
+#include "propagate_if.hh"
+#include "accumulator/arg_max.hh"
 #include "run.hh"
-#include "accumulator/max.hh"
 
 void usage(char** argv)
 {
@@ -46,6 +54,9 @@
     print(img, it);
 }
 
+using namespace mln;
+
+
 int main(int argc, char* argv[])
 {
   using namespace mln;
@@ -90,53 +101,46 @@
   dsp("Propagate node to descendants  : (point2d(0, 2), tree, dup)");
   display_tree_attributes(tree, dup);
 
- //  dup = duplicate(input);
-//   morpho::tree::propagate_value_to_ancestors(117, tree, dup, 0);
-//   dsp("Propagate value to ancestors  : (117, tree, dup, 0)");
-//   display_tree_attributes(tree, dup);
 
-//   dup = duplicate(input);
-//   morpho::tree::propagate_value_to_ancestors(117, tree, dup);
-//   dsp("Propagate value to ancestors  : (117, tree, dup)");
-//   display_tree_attributes(tree, dup);
-
-//   dup = duplicate(input);
-//   morpho::tree::propagate_value_to_descendants(117, tree, dup, 0);
-//   dsp("Propagate value to descendants  : (117, tree, dup, 0)");
-//   display_tree_attributes(tree, dup);
-
-//   dup = duplicate(input);
-//   morpho::tree::propagate_value_to_descendants(117, tree, dup);
-//   dsp("Propagate value to descendants  : (117, tree, dup)");
-//   display_tree_attributes(tree, dup);
+  dup = duplicate(input);
+  morpho::tree::propagate_if_value(tree, dup, morpho::tree::asc_propagation (), 117, 0);
+  dsp("Propagate value to ancestors  : (117, tree, dup, 0)");
+  display_tree_attributes(tree, dup);
 
+  dup = duplicate(input);
+  morpho::tree::propagate_if_value(tree, dup, morpho::tree::asc_propagation (), 117);
+  dsp("Propagate value to ancestors  : (117, tree, dup)");
+  display_tree_attributes(tree, dup);
 
+  dup = duplicate(input);
+  morpho::tree::propagate_if_value(tree, dup, morpho::tree::desc_propagation (), 117, 0);
+  dsp("Propagate value to descendants  : (117, tree, dup, 0)");
+  display_tree_attributes(tree, dup);
 
   dup = duplicate(input);
+  morpho::tree::propagate_if_value(tree, dup, morpho::tree::desc_propagation (), 117);
+  dsp("Propagate value to descendants  : (117, tree, dup)");
+  display_tree_attributes(tree, dup);
+
 
-  typedef morpho::tree::accumulator::max<tree_t, I> A;
-  A accu(dup);
-  morpho::tree::run_bkd(tree, accu);
+  accumulator::arg_max<I> mmax;
+  p_array< mln_psite_(I) > tabmax;
+  mln_fwd_piter_(p_array< mln_psite_(I) >) pit(tabmax);
 
-  mln_bkd_piter_(tree_t::nodes_t) it_max = accu.to_result();
-  morpho::tree::propagate_node_to_descendants(it_max, tree, dup, 69);
-  dsp("Propagate value to descendants  : (it_max, tree, dup, 69)");
+  dup = duplicate(input);
+  tabmax = morpho::tree::run_ntimes(tree, dup, mmax, 5);
+  for_all(pit)
+    std::cout << pit << std::endl;
+  dsp("Run ntimes  : (tree, dup, max, 5)");
   display_tree_attributes(tree, dup);
 
-//    mln_dn_node_piter_(tree_t) n(tree);
-//    n.start();
-//    print(tree.children_image(), n);
 
-  std::cout << "\n";
-  mln_preorder_piter_(tree_t) pit(tree);
-  mln_psite_(I) parent;
+  dup = duplicate(input);
+  tabmax = morpho::tree::run_while_treshold(tree, dup, mmax, 20);
   for_all(pit)
-  {
-    if (parent != tree.parent(pit))
-      std::cout << std::endl;
-    std::cout << pit << " -> ";
-    parent = pit;
-  }
+    std::cout << pit << std::endl;
+  dsp("Run with treshold  : (tree, dup, max, 20)");
+  display_tree_attributes(tree, dup);
 }
 
 
Index: trunk/milena/sandbox/edwin/tree/Makefile
===================================================================
--- trunk/milena/sandbox/edwin/tree/Makefile	(revision 3551)
+++ trunk/milena/sandbox/edwin/tree/Makefile	(revision 3552)
@@ -1,11 +1,11 @@
-TARGET=propagation
-SRC=propagation.cc
+TARGET=test
+SRC=test.cc
 OBJS=${SRC:.cc=.o}
 
 OLENADIR=$(MLN_DIR)/..
 MILENADIR=$(OLENADIR)/milena
 
-CXXFLAGS=-I$(MILENADIR) -I./
+CXXFLAGS=-I$(MILENADIR) -I./ -W -Wall
 
 CXXFLAGS += -g -ggdb
 #CXXFLAGS += -DNDEBUG -O1
Index: trunk/milena/sandbox/edwin/tree/propagate_if.hh
===================================================================
--- trunk/milena/sandbox/edwin/tree/propagate_if.hh	(revision 0)
+++ trunk/milena/sandbox/edwin/tree/propagate_if.hh	(revision 3552)
@@ -0,0 +1,320 @@
+// Copyright (C) 2007, 2008, 2009 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_MORPHO_TREE_PROPAGATE_IF_HH_
+# define MLN_MORPHO_TREE_PROPAGATE_IF_HH_
+
+/**
+** @file   mln/morpho/tree/propagate_if.hh
+**
+** @brief Methods to handle propagation startegies
+** in component trees.
+**
+*/
+
+# include <mln/morpho/tree/data.hh>
+# include "propagate_node.hh"
+
+namespace mln {
+  namespace morpho {
+    namespace tree {
+
+      template <typename WP>
+      struct way_of_propagation : Object< WP > { protected: way_of_propagation() {}; };
+      struct desc_propagation : way_of_propagation <desc_propagation> {};
+      struct asc_propagation : way_of_propagation <asc_propagation> {};
+
+      /**
+      ** Propagate nodes checking the predicate \p pred in the way
+      ** defined by \p way_of_propagation.
+      **
+      ** @param tree Component tree used for propagation.
+      ** @param a_ Attributed image where values are propagated.
+      ** @param way_of_propagation Propagate node in acsendant or
+      ** descendant way.
+      ** @param pred Predicate that node must check to be propagated.
+      ** @param v Value to be propagated. (By default \v is the value
+      ** at the node being propagated).
+      */
+      template <typename T, typename A, class P, typename WP>
+      inline
+      void
+      propagate_if(const T& tree,
+		   Image<A>& a_,
+		   const way_of_propagation<WP>&,
+		   const P& pred,
+		   const mln_value(A)& v);
+
+      template <typename T, typename A, class P, typename WP>
+      inline
+      void
+      propagate_if(const T& tree,
+		   Image<A>& a_,
+		   const way_of_propagation<WP>&,
+		   const P& pred);
+
+      /**
+      ** Propagate nodes having the value v in the way
+      ** defined by \p way_of_propagation.
+      **
+      ** @param tree Component tree used for propagation.
+      ** @param a_ Attributed image where values are propagated.
+      ** @param way_of_propagation Propagate node in acsendant or
+      ** descendant way.
+      ** @param v Value that node must have to be propagated.
+      ** @param v_prop Value to propagate (By default it is the value
+      ** at the node being propagated).
+      */
+      template <typename T, typename A, class P, typename WP>
+      inline
+      void
+      propagate_if_value(const T& tree,
+			 Image<A>& a_,
+			 const way_of_propagation<WP>&,
+			 const mln_value(A)& v,
+			 const mln_value(A)& v_prop);
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+      namespace internal
+      {
+
+	template <typename I>
+	struct pred_value_eq : public mln::Function_p2b< pred_value_eq<I> >
+	{
+	  typedef bool result;
+
+	  pred_value_eq(const I& a, const mln_value(I)& v)
+	    : a_ (a),
+	      v_ (v)
+	  {
+	    mln_invariant(a_.is_valid());
+	  }
+
+	  bool operator() (const mln_psite(I)& p) const
+	  {
+	    mln_invariant(a_.domain().has(p));
+	    return (v_ == a_(p));
+	  }
+
+	private:
+	  const I& a_;
+	  const mln_value(I) v_;
+	};
+
+
+	template <typename T, typename A>
+	bool check_propagate_value(const T& t,
+				   const A& a,
+				   const asc_propagation& prop,
+				   const mln_value(A)& v)
+	{
+	  (void) prop;
+	  mln_up_node_piter(T) n(t);
+	  for_all(n)
+	    if (a(n) == v && a(t.parent(n)) != v)
+	      return false;
+	  return true;
+	}
+
+	template <typename T, typename A>
+	bool check_propagate_value(const T& t,
+				   const A& a,
+				   const desc_propagation& prop,
+				   const mln_value(A)& v)
+	{
+	  (void) prop;
+	  mln_up_node_piter(T) n(t);
+	  for_all(n)
+	    if (a(n) != v && a(t.parent(n)) == v)
+	      return false;
+	  return true;
+	}
+
+
+	template <typename T, typename A, class P>
+	inline
+	void
+	propagate_if(const T& tree,
+		     Image<A>& a_,
+		     const desc_propagation& prop,
+		     const P& pred,
+		     const mln_value(A)& v)
+	{
+	  const A& a = exact(a_);
+	  (void) prop;
+
+	  mln_precondition(a.is_valid());
+	  mln_precondition(tree.f().domain() == a.domain());
+
+	  mln_preorder_piter(T) n(tree);
+	  for_all(n)
+	    if (pred(n))
+	      {
+		propagate_node_to_descendants(n, tree, a_, v);
+		n.skip_children();
+	      }
+	}
+
+	template <typename T, typename A, class P>
+	inline
+	void
+	propagate_if(const T& tree,
+		     Image<A>& a_,
+		     const desc_propagation& prop,
+		     const P& pred)
+	{
+	  const A& a = exact(a_);
+	  (void) prop;
+
+	  mln_precondition(a.is_valid());
+	  mln_precondition(tree.f().domain() == a.domain());
+
+	  mln_preorder_piter(T) n(tree);
+	  for_all(n)
+	    if (pred(n))
+	      {
+		propagate_node_to_descendants(n, tree, a_);
+		n.skip_children();
+	      }
+	}
+
+	template <typename T, typename A, class P>
+	inline
+	void
+	propagate_if(const T& tree,
+		     Image<A>& a_,
+		     const asc_propagation& prop,
+		     const P& pred,
+		     const mln_value(A)& v)
+	{
+	  const A& a = exact(a_);
+	  (void) prop;
+
+	  mln_precondition(a.is_valid());
+	  mln_precondition(tree.f().domain() == a.domain());
+
+	  mln_up_node_piter(T) n(tree);
+	  for_all(n)
+	    if (pred(n))
+	      propagate_node_to_ancestors(n, tree, a_, v);
+	}
+
+	template <typename T, typename A, class P>
+	inline
+	void
+	propagate_if(const T& tree,
+		     Image<A>& a_,
+		     const asc_propagation& prop,
+		     const P& pred)
+	{
+	  const A& a = exact(a_);
+	  (void) prop;
+
+	  mln_precondition(a.is_valid());
+	  mln_precondition(tree.f().domain() == a.domain());
+
+	  mln_up_node_piter(T) n(tree);
+	  for_all(n)
+	    if (pred(n))
+	      propagate_node_to_ancestors(n, tree, a_, a(n));
+	}
+
+      } // end of namespace mln::morpho::tree::internal
+
+
+      /* Facades */
+
+      template <typename T, typename A, typename WP>
+      inline
+      void
+      propagate_if_value(const T& tree,
+			 Image<A>& a_,
+			 const way_of_propagation<WP>& prop_,
+			 const mln_value(A)& v,
+			 const mln_value(A)& v_prop)
+      {
+	A& a = exact(a_);
+	const WP& prop = exact(prop_);
+	internal::pred_value_eq<A> pred(a, v);
+
+	internal::propagate_if(tree, a_, prop, pred, v_prop);
+      }
+
+
+      template <typename T, typename A, typename WP>
+      inline
+      void
+      propagate_if_value(const T& tree,
+			 Image<A>& a_,
+			 const way_of_propagation<WP>& prop_,
+			 const mln_value(A)& v)
+      {
+	const A& a = exact(a_);
+	const WP& prop = exact(prop_);
+	internal::pred_value_eq<A> pred(a, v);
+
+	internal::propagate_if(tree, a_, prop, pred);
+	mln_postcondition(internal::check_propagate_value(tree, a, prop, v));
+      }
+
+      template <typename T, typename A, class P, typename WP>
+      inline
+      void
+      propagate_if(const T& tree,
+		   Image<A>& a_,
+		   const way_of_propagation<WP>& prop_,
+		   const P& pred,
+		   const mln_value(A)& v)
+      {
+	const WP& prop = exact(prop_);
+	internal::propagate_if(tree, a_, prop, pred, v);
+      }
+
+      template <typename T, typename A, class P, typename WP>
+      inline
+      void
+      propagate_if(const T& tree,
+		   Image<A>& a_,
+		   const way_of_propagation<WP>& prop_,
+		   const P& pred)
+      {
+	const WP& prop = exact(prop_);
+	internal::propagate_if(tree, a_, prop, pred);
+      }
+
+#endif /* !MLN_INCLUDE_ONLY */
+
+
+    } // end of namespace mln::morpho::tree
+  } // end of namespace mln::morpho
+} // end of namespace mln
+
+#endif /* !MLN_MORPHO_TREE_PROPAGATE_IF_HH_ */
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                    
                        	* scribo/Makefile: add new targets.
	* scribo/core/central_sites.hh,
	* scribo/core/component_bboxes.hh: add more assertions.
	* scribo/text/recognition.hh,
	* scribo/text/grouping/internal/find_root.hh,
	* scribo/text/grouping/internal/init_link_array.hh,
	* scribo/text/grouping/group_from_double_link.hh,
	* scribo/text/grouping/group_from_multiple_links.hh,
	* scribo/text/grouping/group_from_single_link.hh,
	* scribo/text/grouping/group_with_multiple_links.hh,
	* scribo/text/grouping/group_with_single_left_link.hh,
	* scribo/text/grouping/group_with_single_right_link.hh,
	* scribo/text/extract_bboxes.hh,
	* scribo/src/extract_text_double_link.cc,
	* scribo/src/extract_text_multiple_links.cc,
	* scribo/src/extract_text_single_link.cc,
	* scribo/debug/save_linked_textbboxes_image.hh,
	* scribo/debug/save_table_image.hh,
	* scribo/debug/save_textbboxes_image.hh,
	* scribo/draw/bounding_box_links.hh,
	* scribo/draw/bounding_boxes.hh: make use of util::text.
	* scribo/filter/large_components.hh,
	* scribo/filter/small_components.hh,
	* scribo/filter/thin_bboxes.hh: new filters.
	* scribo/make/debug_filename.hh: improve.
	* scribo/make/text.hh: Construct a text class.
	* scribo/src/dmap.cc,
	* scribo/src/morpho.cc,
	* scribo/src/table_extract.cc,
	* scribo/src/table_rebuild.cc,
	* scribo/src/thin_bboxes.cc: new sample code.
	* scribo/src/table.cc: fix include.
	* scribo/table/internal/align_lines.hh,
	* scribo/table/align_lines_horizontaly.hh,
	* scribo/table/align_lines_verticaly.hh,
	* scribo/table/connect_horizontal_lines.hh,
	* scribo/table/connect_vertical_lines.hh: add more parameters.
	* scribo/table/extract.hh: new routine to extract document tables.
	* scribo/table/extract_lines_with_opening.hh: new routine to extract
	document tables.
	* scribo/table/extract_lines_with_rank.hh: fix missing bbox.enlarge.
	* scribo/table/internal/connect_lines.hh: make it compile.
	* scribo/table/internal/repair_lines.hh: make it work.
	* scribo/table/rebuild.hh: new routine to rebuild document tables.
	* scribo/core/erase_bboxes.hh,
	* scribo/table/repair_horizontal_lines.hh: revamp.
	* scribo/tests/filter/small_and_large_bboxes.cc,
	* scribo/tests/table/extract_lines_with_rank.cc,
	* scribo/tests/table/repair_lines.cc: new tests.
	* scribo/text/extract_lines.hh: new routine to extract text
	automatically.
	* scribo/text/grouping/internal/update_link_array.hh,
	* scribo/text/grouping/internal/update_link_graph.hh: fix conditions.
	* scribo/util/text.hh: new object to represent text components.
---
 milena/sandbox/ChangeLog                           |   80 ++++++++-
 milena/sandbox/scribo/Makefile                     |   27 ++-
 milena/sandbox/scribo/core/central_sites.hh        |    2 +-
 milena/sandbox/scribo/core/component_bboxes.hh     |   19 ++-
 milena/sandbox/scribo/core/erase_bboxes.hh         |    4 +-
 .../scribo/debug/save_linked_textbboxes_image.hh   |   49 +++---
 milena/sandbox/scribo/debug/save_table_image.hh    |   65 +++++--
 .../sandbox/scribo/debug/save_textbboxes_image.hh  |    7 +-
 milena/sandbox/scribo/draw/bounding_box_links.hh   |   26 ++--
 milena/sandbox/scribo/draw/bounding_boxes.hh       |    4 +-
 milena/sandbox/scribo/filter/large_components.hh   |  196 ++++++++++++++++++
 milena/sandbox/scribo/filter/small_components.hh   |  207 ++++++++++++++++++++
 milena/sandbox/scribo/filter/thin_bboxes.hh        |  165 ++++++++++++++++
 milena/sandbox/scribo/make/debug_filename.hh       |   33 +++-
 .../{text/extract_bboxes.hh => make/text.hh}       |   81 +++++---
 milena/sandbox/scribo/src/dmap.cc                  |   26 +++
 .../sandbox/scribo/src/extract_text_double_link.cc |   69 ++++----
 .../scribo/src/extract_text_multiple_links.cc      |   34 ++--
 .../sandbox/scribo/src/extract_text_single_link.cc |   72 ++++---
 milena/sandbox/scribo/src/morpho.cc                |   64 ++++++
 milena/sandbox/scribo/src/table.cc                 |    2 +-
 ...act_text_multiple_links.cc => table_extract.cc} |   37 ++---
 ...act_text_multiple_links.cc => table_rebuild.cc} |   45 +++--
 milena/sandbox/scribo/src/thin_bboxes.cc           |   32 +++
 .../scribo/table/align_lines_horizontaly.hh        |   18 ++-
 .../sandbox/scribo/table/align_lines_verticaly.hh  |   15 +-
 .../scribo/table/connect_horizontal_lines.hh       |   14 +-
 .../sandbox/scribo/table/connect_vertical_lines.hh |   14 +-
 .../{text/extract_bboxes.hh => table/extract.hh}   |   73 ++++----
 ..._with_rank.hh => extract_lines_with_opening.hh} |   67 ++++---
 .../scribo/table/extract_lines_with_rank.hh        |   27 ++-
 .../sandbox/scribo/table/internal/align_lines.hh   |    9 +-
 .../sandbox/scribo/table/internal/connect_lines.hh |   17 ++-
 .../sandbox/scribo/table/internal/repair_lines.hh  |   67 +++++--
 milena/sandbox/scribo/table/rebuild.hh             |  147 ++++++++++++++
 .../scribo/table/repair_horizontal_lines.hh        |    6 +-
 .../filter/small_and_large_bboxes.cc}              |   13 ++-
 .../scribo/tests/table/extract_lines_with_rank.cc  |   36 ++++
 milena/sandbox/scribo/tests/table/repair_lines.cc  |   45 +++++
 milena/sandbox/scribo/text/extract_bboxes.hh       |   15 +-
 milena/sandbox/scribo/text/extract_lines.hh        |  133 +++++++++++++
 .../scribo/text/grouping/group_from_double_link.hh |   65 +++++--
 .../text/grouping/group_from_multiple_links.hh     |   63 ++++---
 .../scribo/text/grouping/group_from_single_link.hh |   43 +++--
 .../text/grouping/group_with_multiple_links.hh     |   37 ++---
 .../text/grouping/group_with_single_left_link.hh   |   47 ++---
 .../text/grouping/group_with_single_right_link.hh  |   49 ++---
 .../scribo/text/grouping/internal/find_root.hh     |    4 +-
 .../text/grouping/internal/init_link_array.hh      |    7 +-
 .../text/grouping/internal/update_link_array.hh    |    7 +-
 .../text/grouping/internal/update_link_graph.hh    |    6 +-
 milena/sandbox/scribo/text/recognition.hh          |   19 +-
 milena/sandbox/scribo/util/text.hh                 |  189 ++++++++++++++++++
 53 files changed, 2087 insertions(+), 511 deletions(-)
 create mode 100644 milena/sandbox/scribo/filter/large_components.hh
 create mode 100644 milena/sandbox/scribo/filter/small_components.hh
 create mode 100644 milena/sandbox/scribo/filter/thin_bboxes.hh
 copy milena/sandbox/scribo/{text/extract_bboxes.hh => make/text.hh} (56%)
 create mode 100644 milena/sandbox/scribo/src/dmap.cc
 create mode 100644 milena/sandbox/scribo/src/morpho.cc
 copy milena/sandbox/scribo/src/{extract_text_multiple_links.cc => table_extract.cc} (61%)
 copy milena/sandbox/scribo/src/{extract_text_multiple_links.cc => table_rebuild.cc} (61%)
 create mode 100644 milena/sandbox/scribo/src/thin_bboxes.cc
 copy milena/sandbox/scribo/{text/extract_bboxes.hh => table/extract.hh} (55%)
 copy milena/sandbox/scribo/table/{extract_lines_with_rank.hh => extract_lines_with_opening.hh} (67%)
 create mode 100644 milena/sandbox/scribo/table/rebuild.hh
 copy milena/sandbox/scribo/{src/extract_text_multiple_links.cc => tests/filter/small_and_large_bboxes.cc} (87%)
 create mode 100644 milena/sandbox/scribo/tests/table/extract_lines_with_rank.cc
 create mode 100644 milena/sandbox/scribo/tests/table/repair_lines.cc
 create mode 100644 milena/sandbox/scribo/text/extract_lines.hh
 create mode 100644 milena/sandbox/scribo/util/text.hh
diff --git a/milena/sandbox/ChangeLog b/milena/sandbox/ChangeLog
index 8c7681f..7137a4d 100644
--- a/milena/sandbox/ChangeLog
+++ b/milena/sandbox/ChangeLog
@@ -1,4 +1,82 @@
-2009-03-16  Guillaume Lazzara  <z(a)lrde.epita.fr>
+2009-03-19  Guillaume Lazzara  <z(a)lrde.epita.fr>
+
+	Update Scribo's code.
+
+	* scribo/Makefile: add new targets.
+
+	* scribo/core/central_sites.hh,
+	* scribo/core/component_bboxes.hh: add more assertions.
+
+	* scribo/text/recognition.hh,
+	* scribo/text/grouping/internal/find_root.hh,
+	* scribo/text/grouping/internal/init_link_array.hh,
+	* scribo/text/grouping/group_from_double_link.hh,
+	* scribo/text/grouping/group_from_multiple_links.hh,
+	* scribo/text/grouping/group_from_single_link.hh,
+	* scribo/text/grouping/group_with_multiple_links.hh,
+	* scribo/text/grouping/group_with_single_left_link.hh,
+	* scribo/text/grouping/group_with_single_right_link.hh,
+	* scribo/text/extract_bboxes.hh,
+	* scribo/src/extract_text_double_link.cc,
+	* scribo/src/extract_text_multiple_links.cc,
+	* scribo/src/extract_text_single_link.cc,
+	* scribo/debug/save_linked_textbboxes_image.hh,
+	* scribo/debug/save_table_image.hh,
+	* scribo/debug/save_textbboxes_image.hh,
+	* scribo/draw/bounding_box_links.hh,
+	* scribo/draw/bounding_boxes.hh: make use of util::text.
+
+	* scribo/filter/large_components.hh,
+	* scribo/filter/small_components.hh,
+	* scribo/filter/thin_bboxes.hh: new filters.
+
+	* scribo/make/debug_filename.hh: improve.
+
+	* scribo/make/text.hh: Construct a text class.
+
+	* scribo/src/dmap.cc,
+	* scribo/src/morpho.cc,
+	* scribo/src/table_extract.cc,
+	* scribo/src/table_rebuild.cc,
+	* scribo/src/thin_bboxes.cc: new sample code.
+
+	* scribo/src/table.cc: fix include.
+
+	* scribo/table/internal/align_lines.hh,
+	* scribo/table/align_lines_horizontaly.hh,
+	* scribo/table/align_lines_verticaly.hh,
+	* scribo/table/connect_horizontal_lines.hh,
+	* scribo/table/connect_vertical_lines.hh: add more parameters.
+	
+	* scribo/table/extract.hh: new routine to extract document tables.
+
+	* scribo/table/extract_lines_with_opening.hh: new routine to extract
+	document tables.
+
+	* scribo/table/extract_lines_with_rank.hh: fix missing bbox.enlarge.
+
+	* scribo/table/internal/connect_lines.hh: make it compile.
+
+	* scribo/table/internal/repair_lines.hh: make it work.
+
+	* scribo/table/rebuild.hh: new routine to rebuild document tables.
+
+	* scribo/core/erase_bboxes.hh,
+	* scribo/table/repair_horizontal_lines.hh: revamp.
+
+	* scribo/tests/filter/small_and_large_bboxes.cc,
+	* scribo/tests/table/extract_lines_with_rank.cc,
+	* scribo/tests/table/repair_lines.cc: new tests.
+
+	* scribo/text/extract_lines.hh: new routine to extract text
+	automatically.
+
+	* scribo/text/grouping/internal/update_link_array.hh,
+	* scribo/text/grouping/internal/update_link_graph.hh: fix conditions.
+
+	* scribo/util/text.hh: new object to represent text components.
+
+2009-03-19  Guillaume Lazzara  <z(a)lrde.epita.fr>
 
 	Add a buggy sample case.
 
diff --git a/milena/sandbox/scribo/Makefile b/milena/sandbox/scribo/Makefile
index cbb462b..09a3a2d 100644
--- a/milena/sandbox/scribo/Makefile
+++ b/milena/sandbox/scribo/Makefile
@@ -1,28 +1,41 @@
+CXX_FLAGS = -Wextra -Wall -I../.. -I../ -I$(HOME)/local/include -O1 -DNDEBUG # -ggdb #-O1 -DNDEBUG 
+
 all: table photo
 
 tabledbg: demat.hh
-	g++ -Wextra -Wall -I../.. -I../ -I$(HOME)/local/include -O1 -g src/table.cc $(HOME)/local/lib/libtesseract_full.a -lpthread -o bin/table.out
+	g++ -Wextra -Wall -I../.. -I../ -I. -I$(HOME)/local/include -O1 -g src/table.cc $(HOME)/local/lib/libtesseract_full.a -lpthread -o bin/table.out
 
 table: demat.hh
-	g++ -Wextra -Wall -I../.. -I. -I.. -I$(HOME)/local/include -O1 -DNDEBUG src/table.cc $(HOME)/local/lib/libtesseract_full.a -lpthread -o bin/table.out
+	g++ $(CXX_FLAGS) src/table.cc $(HOME)/local/lib/libtesseract_full.a -lpthread -o bin/table.out
 
 oldtable: demat.old.hh
-	g++ -Wextra -Wall -I../.. -I../ -I$(HOME)/local/include -O1 -DNDEBUG src/table_old.cc $(HOME)/local/lib/libtesseract_full.a -lpthread -o bin/table_old.out
+	g++ $(CXX_FLAGS) src/table_old.cc $(HOME)/local/lib/libtesseract_full.a -lpthread -o bin/table_old.out
 
 photo: demat.hh
-	g++ -Wextra -Wall -I../.. -I. -I.. -I$(HOME)/local/include -O1 -DNDEBUG src/photo.cc $(HOME)/local/lib/libtesseract_full.a -lpthread -o bin/photo.out
+	g++ $(CXX_FLAGS) src/photo.cc $(HOME)/local/lib/libtesseract_full.a -lpthread -o bin/photo.out
+
 
+dmap:
+	g++ $(CXX_FLAGS) src/dmap.cc -o bin/dmap.out
 
 
 extract_text_single_link:
-	g++ -Wextra -Wall -I../.. -I../ -I$(HOME)/local/include -O1 -DNDEBUG src/extract_text_single_link.cc -o bin/extract_text_single_link.out
+	g++ $(CXX_FLAGS) src/extract_text_single_link.cc -o bin/extract_text_single_link.out
 
 extract_text_double_link:
-	g++ -Wextra -Wall -I../.. -I../ -I$(HOME)/local/include -O1 -DNDEBUG src/extract_text_double_link.cc -o bin/extract_text_double_link.out
+	g++ $(CXX_FLAGS) src/extract_text_double_link.cc -o bin/extract_text_double_link.out
 
 extract_text_multiple_links:
-	g++ -Wextra -Wall -I../.. -I../ -I$(HOME)/local/include -O1 -DNDEBUG src/extract_text_multiple_links.cc -o bin/extract_text_multiple_links.out
+	g++ $(CXX_FLAGS) src/extract_text_multiple_links.cc -o bin/extract_text_multiple_links.out
+
+table_rebuild:
+	g++ $(CXX_FLAGS) src/table_rebuild.cc -o bin/table_rebuild.out
+
+table_extract:
+	g++ $(CXX_FLAGS) src/table_extract.cc -o bin/table_extract.out
 
+thin_bboxes:
+	g++ $(CXX_FLAGS) src/thin_bboxes.cc -o bin/thin_bboxes.out
 
 clean:
 	rm *.ppm *.pgm *.pbm
diff --git a/milena/sandbox/scribo/core/central_sites.hh b/milena/sandbox/scribo/core/central_sites.hh
index fe47625..80686f8 100644
--- a/milena/sandbox/scribo/core/central_sites.hh
+++ b/milena/sandbox/scribo/core/central_sites.hh
@@ -86,7 +86,7 @@ namespace scribo
     p2[dim] += n / 2;
 
     trace::exiting("scribo::central_sites");
-    return make::couple(p1, p2);
+    return mln::make::couple(p1, p2);
   }
 
 # endif // ! MLN_INCLUDE_ONLY
diff --git a/milena/sandbox/scribo/core/component_bboxes.hh b/milena/sandbox/scribo/core/component_bboxes.hh
index 5af99fc..16b6fa0 100644
--- a/milena/sandbox/scribo/core/component_bboxes.hh
+++ b/milena/sandbox/scribo/core/component_bboxes.hh
@@ -43,23 +43,28 @@
 
 # include <mln/util/array.hh>
 
+# include <mln/debug/println.hh>
 
 namespace scribo
 {
 
+  using namespace mln;
+
   /// Extract the components bboxes.
   template <typename I, typename N, typename V>
-  util::array< box<mln_site(I)> >
+  util::couple<util::array< box<mln_site(I)> >, mln_ch_value(I,V)>
   component_bboxes(const Image<I>& input,
-		   const Neighborhood<N>& nbh, const V& label_type);
+		   const Neighborhood<N>& nbh,
+		   V& nbboxes);
 
 # ifndef MLN_INCLUDE_ONLY
 
   template <typename I, typename N, typename V>
   inline
-  util::array< box<mln_site(I)> >
+  util::couple<util::array< box<mln_site(I)> >, mln_ch_value(I,V)>
   component_bboxes(const Image<I>& input,
-		   const Neighborhood<N>& nbh, const V&)
+		   const Neighborhood<N>& nbh,
+		   V& nbboxes)
   {
     trace::entering("scribo::component_bboxes");
 
@@ -68,13 +73,15 @@ namespace scribo
     mln_precondition(exact(input).is_valid());
     mln_precondition(exact(nbh).is_valid());
 
-    V nbboxes;
     mln_ch_value(I,V) lbl = labeling::blobs(input, nbh, nbboxes);
+    mln_assertion(exact(lbl).is_valid());
+
     typedef util::array< box<mln_site(I)> > bboxes_t;
     bboxes_t bboxes = labeling::compute(accu::meta::bbox(), lbl, nbboxes);
+    mln_postcondition(bboxes.nelements() == nbboxes.next());
 
     trace::exiting("scribo::component_bboxes");
-    return bboxes;
+    return mln::make::couple(bboxes, lbl);
   }
 
 # endif // ! MLN_INCLUDE_ONLY
diff --git a/milena/sandbox/scribo/core/erase_bboxes.hh b/milena/sandbox/scribo/core/erase_bboxes.hh
index cea998b..f4b2392 100644
--- a/milena/sandbox/scribo/core/erase_bboxes.hh
+++ b/milena/sandbox/scribo/core/erase_bboxes.hh
@@ -44,6 +44,8 @@
 namespace scribo
 {
 
+  using namespace mln;
+
   /// Remove the content of bounding boxes from an image.
   template <typename I>
   void
@@ -68,7 +70,7 @@ namespace scribo
 
     for_all_components(i, bboxes)
       data::paste((pw::cst(false) | bboxes[i] |
-	    (pw::value(input) == true)), input);
+		  (pw::value(input) == true)), input);
 
     trace::exiting("scribo::erase_bboxes");
   }
diff --git a/milena/sandbox/scribo/debug/save_linked_textbboxes_image.hh b/milena/sandbox/scribo/debug/save_linked_textbboxes_image.hh
index a7f8927..4012c05 100644
--- a/milena/sandbox/scribo/debug/save_linked_textbboxes_image.hh
+++ b/milena/sandbox/scribo/debug/save_linked_textbboxes_image.hh
@@ -42,6 +42,7 @@
 
 # include <scribo/draw/bounding_boxes.hh>
 # include <scribo/draw/bounding_box_links.hh>
+# include <scribo/util/text.hh>
 
 
 namespace scribo
@@ -54,32 +55,32 @@ namespace scribo
 
 
     /// Save the bounding box links image.
-    template <typename I>
+    template <typename I, typename L>
     void
     save_linked_textbboxes_image(const Image<I>& input,
-				 const util::array< box<mln_site(I)> >& textbboxes,
-				 const util::array<unsigned>& link_array,
+				 const scribo::util::text<L>& text,
+				 const mln::util::array<unsigned>& link_array,
 				 const value::rgb8& box_value,
 				 const value::rgb8& link_value,
 				 const std::string& filename);
 
 
-    template <typename I>
+    template <typename I, typename L>
     void
     save_linked_textbboxes_image(const Image<I>& input,
-				 const util::array< box<mln_site(I)> >& textbboxes,
-				 const util::array<unsigned>& left_link,
-				 const util::array<unsigned>& right_array,
+				 const scribo::util::text<L>& text,
+				 const mln::util::array<unsigned>& left_link,
+				 const mln::util::array<unsigned>& right_array,
 				 const value::rgb8& box_value,
 				 const value::rgb8& left_link_value,
 				 const value::rgb8& right_link_value,
 				 const std::string& filename);
 
 
-    template <typename I, typename G>
+    template <typename I, typename L, typename G>
     void
     save_linked_textbboxes_image(const Image<I>& input,
-				 const util::array< box<mln_site(I)> >& textbboxes,
+				 const scribo::util::text<L>& text,
 				 const Graph<G>& g,
 				 const value::rgb8& box_value,
 				 const value::rgb8& link_value,
@@ -89,12 +90,12 @@ namespace scribo
 # ifndef MLN_INCLUDE_ONLY
 
 
-    template <typename I>
+    template <typename I, typename L>
     inline
     void
     save_linked_textbboxes_image(const Image<I>& input,
-				 const util::array< box<mln_site(I)> >& textbboxes,
-				 const util::array<unsigned>& link_array,
+				 const scribo::util::text<L>& text,
+				 const mln::util::array<unsigned>& link_array,
 				 const value::rgb8& box_value,
 				 const value::rgb8& link_value,
 				 const std::string& filename)
@@ -103,21 +104,21 @@ namespace scribo
       mln_precondition(exact(input).is_valid());
 
       mln_ch_value(I,value::rgb8) tmp = level::convert(value::rgb8(), input);
-      draw::bounding_boxes(tmp, textbboxes, box_value);
-      draw::bounding_box_links(tmp, textbboxes, link_array, link_value);
+      draw::bounding_boxes(tmp, text.bboxes(), box_value);
+      draw::bounding_box_links(tmp, text.bboxes(), link_array, link_value);
       io::ppm::save(tmp, filename);
 
       trace::exiting("scribo::debug::save_linked_textbboxes_image");
     }
 
 
-    template <typename I>
+    template <typename I, typename L>
     inline
     void
     save_linked_textbboxes_image(const Image<I>& input,
-				 const util::array< box<mln_site(I)> >& textbboxes,
-				 const util::array<unsigned>& left_link,
-				 const util::array<unsigned>& right_link,
+				 const scribo::util::text<L>& text,
+				 const mln::util::array<unsigned>& left_link,
+				 const mln::util::array<unsigned>& right_link,
 				 const value::rgb8& box_value,
 				 const value::rgb8& left_value,
 				 const value::rgb8& right_value,
@@ -127,8 +128,8 @@ namespace scribo
       mln_precondition(exact(input).is_valid());
 
       mln_ch_value(I,value::rgb8) tmp = level::convert(value::rgb8(), input);
-      draw::bounding_boxes(tmp, textbboxes, box_value);
-      draw::bounding_box_links(tmp, textbboxes,
+      draw::bounding_boxes(tmp, text.bboxes(), box_value);
+      draw::bounding_box_links(tmp, text.bboxes(),
 			       left_link, right_link,
 			       left_value, right_value);
       io::ppm::save(tmp, filename);
@@ -137,11 +138,11 @@ namespace scribo
     }
 
 
-    template <typename I, typename G>
+    template <typename I, typename L, typename G>
     inline
     void
     save_linked_textbboxes_image(const Image<I>& input,
-				 const util::array< box<mln_site(I)> >& textbboxes,
+				 const scribo::util::text<L>& text,
 				 const Graph<G>& g,
 				 const value::rgb8& box_value,
 				 const value::rgb8& link_value,
@@ -152,8 +153,8 @@ namespace scribo
       mln_precondition(exact(input).is_valid());
 
       mln_ch_value(I,value::rgb8) tmp = level::convert(value::rgb8(), input);
-      draw::bounding_boxes(tmp, textbboxes, box_value);
-      draw::bounding_box_links(tmp, textbboxes, g, link_value);
+      draw::bounding_boxes(tmp, text.bboxes(), box_value);
+      draw::bounding_box_links(tmp, text.bboxes(), g, link_value);
       io::ppm::save(tmp, filename);
 
       trace::exiting("scribo::debug::save_linked_textbboxes_image");
diff --git a/milena/sandbox/scribo/debug/save_table_image.hh b/milena/sandbox/scribo/debug/save_table_image.hh
index b170420..4ed0a68 100644
--- a/milena/sandbox/scribo/debug/save_table_image.hh
+++ b/milena/sandbox/scribo/debug/save_table_image.hh
@@ -36,7 +36,9 @@
 # include <string>
 
 # include <mln/core/concept/image.hh>
+# include <mln/core/image/image2d.hh>
 # include <mln/data/fill.hh>
+# include <mln/level/convert.hh>
 # include <mln/util/array.hh>
 # include <mln/util/couple.hh>
 # include <mln/value/rgb8.hh>
@@ -50,16 +52,29 @@ namespace scribo
   namespace debug
   {
 
-    /// Save lines bounding boxes in an image filled with \p bg_color.
+    using namespace mln;
+
+    /// Save lines bounding boxes in a copy of \p input_.
     /// Bounding boxes are displayed with \p bbox_color.
     template <typename I>
     void
-    save_table(const Image<I>& input_,
-	       util::couple<util::array<box<mln_site(I)> >,
-			    util::array<box<mln_site(I)> > > tableboxes,
-	       const value::rgb8& bg_color,
-	       const value::rgb8& bbox_color,
-	       const std::string& filename);
+    save_table_image(const Image<I>& input_,
+		     util::couple<util::array<box<mln_site(I)> >,
+				  util::array<box<mln_site(I)> > > tableboxes,
+		     const value::rgb8& bbox_color,
+		     const std::string& filename);
+
+    /// Save lines bounding boxes in an image defined on \p input_domain
+    /// filled with \p bg_color.
+    /// Bounding boxes are displayed with \p bbox_color.
+    template <typename S>
+    void
+    save_table_image(const Site_Set<S>& input_domain,
+		     util::couple<util::array<box<mln_site(S)> >,
+				  util::array<box<mln_site(S)> > > tableboxes,
+		     const value::rgb8& bg_color,
+		     const value::rgb8& bbox_color,
+		     const std::string& filename);
 
 
 # ifndef MLN_INCLUDE_ONLY
@@ -67,18 +82,40 @@ namespace scribo
 
     template <typename I>
     void
-    save_table(const Image<I>& input_,
-	       util::couple<util::array<box<mln_site(I)> >,
-			    util::array<box<mln_site(I)> > > tableboxes,
-	       const value::rgb8& bg_color,
-	       const value::rgb8& bbox_color,
-	       const std::string& filename)
+    save_table_image(const Image<I>& input_,
+		     util::couple<util::array<box<mln_site(I)> >,
+				  util::array<box<mln_site(I)> > > tableboxes,
+		     const value::rgb8& bbox_color,
+		     const std::string& filename)
     {
       trace::entering("scribo::debug::save_table_image");
+//      mlc_converts_to(mln_value(I), value::rgb8)::check();
       const I& input = exact(input_);
       mln_precondition(input.is_valid());
 
-      mln_ch_value(I,value::rgb8) out2(exact(input).domain());
+      mln_ch_value(I,value::rgb8) out2 = level::convert(value::rgb8(), input);
+      draw::bounding_boxes(out2, tableboxes.first(), bbox_color);
+      draw::bounding_boxes(out2, tableboxes.second(), bbox_color);
+      io::ppm::save(out2, filename);
+
+      trace::exiting("scribo::internal::save_table");
+    }
+
+
+    template <typename S>
+    void
+    save_table_image(const Site_Set<S>& input_domain_,
+		     util::couple<util::array<box<mln_site(S)> >,
+				  util::array<box<mln_site(S)> > > tableboxes,
+		     const value::rgb8& bg_color,
+		     const value::rgb8& bbox_color,
+		     const std::string& filename)
+    {
+      trace::entering("scribo::debug::save_table_image");
+      const S& input_domain = exact(input_domain_);
+      mln_precondition(input_domain.is_valid());
+
+      image2d<value::rgb8> out2(input_domain);
       data::fill(out2, bg_color);
       draw::bounding_boxes(out2, tableboxes.first(), bbox_color);
       draw::bounding_boxes(out2, tableboxes.second(), bbox_color);
diff --git a/milena/sandbox/scribo/debug/save_textbboxes_image.hh b/milena/sandbox/scribo/debug/save_textbboxes_image.hh
index b210b39..86a8b3f 100644
--- a/milena/sandbox/scribo/debug/save_textbboxes_image.hh
+++ b/milena/sandbox/scribo/debug/save_textbboxes_image.hh
@@ -40,6 +40,7 @@
 # include <mln/io/ppm/save.hh>
 
 # include <scribo/draw/bounding_boxes.hh>
+# include <scribo/make/debug_filename.hh>
 
 
 namespace scribo
@@ -55,7 +56,7 @@ namespace scribo
     template <typename I>
     void
     save_textbboxes_image(const Image<I>& input,
-			  const util::array< box<mln_site(I)> >& textbboxes,
+			  const mln::util::array< box<mln_site(I)> >& textbboxes,
 			  const value::rgb8& value,
 			  const std::string& filename);
 
@@ -66,7 +67,7 @@ namespace scribo
     inline
     void
     save_textbboxes_image(const Image<I>& input,
-			  const util::array< box<mln_site(I)> >& textbboxes,
+			  const mln::util::array< box<mln_site(I)> >& textbboxes,
 			  const value::rgb8& value,
 			  const std::string& filename)
     {
@@ -75,7 +76,7 @@ namespace scribo
 
       mln_ch_value(I,value::rgb8) tmp = level::convert(value::rgb8(), input);
       draw::bounding_boxes(tmp, textbboxes, value);
-      io::ppm::save(tmp, filename);
+      io::ppm::save(tmp, scribo::make::debug_filename(filename));
 
       trace::exiting("scribo::debug::save_textbboxes_image");
     }
diff --git a/milena/sandbox/scribo/draw/bounding_box_links.hh b/milena/sandbox/scribo/draw/bounding_box_links.hh
index 7cf57ac..e33da38 100644
--- a/milena/sandbox/scribo/draw/bounding_box_links.hh
+++ b/milena/sandbox/scribo/draw/bounding_box_links.hh
@@ -52,17 +52,17 @@ namespace scribo
     template <typename I>
     void
     bounding_box_links(Image<I>& input_,
-		       const util::array< box<mln_site(I)> >& bboxes,
-		       const util::array<unsigned>& link_array,
+		       const mln::util::array< box<mln_site(I)> >& bboxes,
+		       const mln::util::array<unsigned>& link_array,
 		       const mln_value(I)& value);
 
 
     template <typename I>
     void
     bounding_box_links(Image<I>& input,
-		       const util::array< box<mln_site(I)> >& bboxes,
-		       const util::array<unsigned>& left_link,
-		       const util::array<unsigned>& right_link,
+		       const mln::util::array< box<mln_site(I)> >& bboxes,
+		       const mln::util::array<unsigned>& left_link,
+		       const mln::util::array<unsigned>& right_link,
 		       const mln_value(I)& left_link_value,
 		       const mln_value(I)& right_link_value);
 
@@ -78,7 +78,7 @@ namespace scribo
       {
 
 	draw_graph_edges_functor(I& ima,
-				 const util::array<box<mln_site(I)> >& textbboxes,
+				 const mln::util::array<box<mln_site(I)> >& textbboxes,
 				 const mln_value(I)& value)
 	  : ima_(ima), textbboxes_(textbboxes), value_(value)
 	{}
@@ -114,7 +114,7 @@ namespace scribo
 	{ return to_be_treated(id); }
 
 	I& ima_;
-	const util::array<box<mln_site(I)> >& textbboxes_;
+	const mln::util::array<box<mln_site(I)> >& textbboxes_;
 	mln_value(I) value_;
 	unsigned current_vertex;
 	std::vector<bool> deja_vu;
@@ -127,8 +127,8 @@ namespace scribo
     inline
     void
     bounding_box_links(Image<I>& input_,
-		       const util::array< box<mln_site(I)> >& bboxes,
-		       const util::array<unsigned>& link_array,
+		       const mln::util::array< box<mln_site(I)> >& bboxes,
+		       const mln::util::array<unsigned>& link_array,
 		       const mln_value(I)& value)
     {
       trace::entering("scribo::draw::bounding_box_links");
@@ -152,9 +152,9 @@ namespace scribo
     inline
     void
     bounding_box_links(Image<I>& input,
-		       const util::array< box<mln_site(I)> >& bboxes,
-		       const util::array<unsigned>& left_link,
-		       const util::array<unsigned>& right_link,
+		       const mln::util::array< box<mln_site(I)> >& bboxes,
+		       const mln::util::array<unsigned>& left_link,
+		       const mln::util::array<unsigned>& right_link,
 		       const mln_value(I)& left_link_value,
 		       const mln_value(I)& right_link_value)
     {
@@ -172,7 +172,7 @@ namespace scribo
     inline
     void
     bounding_box_links(Image<I>& input,
-		       const util::array< box<mln_site(I)> >& bboxes,
+		       const mln::util::array< box<mln_site(I)> >& bboxes,
 		       const Graph<G>& g,
 		       const mln_value(I)& link_value)
     {
diff --git a/milena/sandbox/scribo/draw/bounding_boxes.hh b/milena/sandbox/scribo/draw/bounding_boxes.hh
index 0db60a4..bfebaf3 100644
--- a/milena/sandbox/scribo/draw/bounding_boxes.hh
+++ b/milena/sandbox/scribo/draw/bounding_boxes.hh
@@ -51,7 +51,7 @@ namespace scribo
     template <typename I>
     void
     bounding_boxes(Image<I>& input_,
-		   const util::array< box<mln_site(I)> >& boxes,
+		   const mln::util::array< box<mln_site(I)> >& boxes,
 		   const mln_value(I)& value);
 
 
@@ -63,7 +63,7 @@ namespace scribo
     inline
     void
     bounding_boxes(Image<I>& input_,
-		   const util::array< box<mln_site(I)> >& boxes,
+		   const mln::util::array< box<mln_site(I)> >& boxes,
 		   const mln_value(I)& value)
     {
       trace::entering("scribo::draw::bounding_boxes");
diff --git a/milena/sandbox/scribo/filter/large_components.hh b/milena/sandbox/scribo/filter/large_components.hh
new file mode 100644
index 0000000..9ea4e02
--- /dev/null
+++ b/milena/sandbox/scribo/filter/large_components.hh
@@ -0,0 +1,196 @@
+// Copyright (C) 2009 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.
+
+#ifndef SCRIBO_FILTER_LARGE_COMPONENTS_HH
+# define SCRIBO_FILTER_LARGE_COMPONENTS_HH
+
+/// \file scribo/filter/large_components.hh
+///
+/// Remove large components in a binary image.
+
+
+# include <mln/core/concept/image.hh>
+# include <mln/core/concept/neighborhood.hh>
+# include <mln/core/concept/function.hh>
+
+# include <mln/labeling/blobs.hh>
+# include <mln/labeling/relabel.hh>
+
+# include <mln/util/array.hh>
+# include <mln/value/label_16.hh>
+
+# include <mln/pw/all.hh>
+
+namespace scribo
+{
+
+  namespace filter
+  {
+
+    using namespace mln;
+
+
+    /// Remove large components in a binary image.
+    /// Set to 'false' all the removed components.
+    ///
+    /// \param[in] input_     A binary image.
+    /// \param[in] nbh_	      A neighborhood used for labeling \p input_.
+    /// \param[in] label_type The label type used for labeling.
+    /// \param[in] max_size   The minimum cardinality of a component.
+    ///
+    /// \return A binary image without large components.
+    template <typename I, typename N, typename V>
+    mln_concrete(I)
+    large_components(const Image<I>& input_,
+			       const Neighborhood<N>& nbh_,
+			       const V& label_type,
+			       unsigned max_size);
+
+
+    /// Remove large bboxes in a binary image.
+    /// Set to 'false' all the removed bboxes.
+    ///
+    /// \param[in] input_     A binary image.
+    /// \param[in] bboxes     Bounding boxes of components extracted from \p
+    ///			      input_.
+    /// \param[in] max_size   The minimum cardinality of a component.
+    ///
+    /// \return A binary image without large bboxes.
+    template <typename P>
+    util::array< box<P> >
+    large_components(const util::array< box<P> >& bboxes,
+		     unsigned max_size);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+    namespace internal
+    {
+
+
+      /// Filter Functor. Return false for all components which are too
+      /// large.
+      template <typename R>
+      struct filter_large_components_functor
+	: Function_l2b< filter_large_and_large_functor<R> >
+      {
+	filter_large_components_functor(const util::array<R>& nsitecomp,
+					unsigned max_size)
+	  : nsitecomp_(nsitecomp), max_size_(max_size)
+	{
+	}
+
+
+	/// Return false if the components area is strictly inferior to
+	/// \p max_size_.
+	bool operator()(const value::label_16& l) const
+	{
+	  return nsitecomp_[l] <= max_size_;
+	}
+
+
+	const util::array<R>& nsitecomp_;
+	unsigned max_size_;
+      };
+
+
+    } //  end of namespace scribo::filter::internal
+
+
+
+    template <typename I, typename N, typename V>
+    inline
+    mln_concrete(I)
+    large_components(const Image<I>& input_,
+		     const Neighborhood<N>& nbh_,
+		     const V& label_type,
+		     unsigned max_size)
+    {
+      trace::entering("scribo::filter::large_components");
+
+      const I& input = exact(input_);
+      const N& nbh = exact(nbh_);
+
+      mln_precondition(input.is_valid());
+      mln_precondition(nbh.is_valid());
+
+      V nlabels;
+      mln_ch_value(I,V) lbl = labeling::blobs(input, nbh, nlabels);
+
+      typedef accu::count<mln_psite(I)> accu_count_t;
+      typedef mln_result(accu_count_t) accu_count_res_t;
+      typedef util::array<accu_count_res_t> nsitecomp_t;
+      nsitecomp_t nsitecomp = labeling::compute(accu_count_t(), lbl, nlabels);
+
+      typedef internal::filter_large_and_large_functor<accu_count_res_t> func_t;
+      func_t fl2b(nsitecomp, max_size);
+      labeling::relabel_inplace(lbl, nlabels, fl2b);
+
+      mln_concrete(I) output = duplicate(input);
+      data::fill((output | pw::value(lbl) == literal::zero).rw(), false);
+
+      trace::exiting("scribo::filter::large_components");
+      return output;
+    }
+
+
+    template <typename P>
+    inline
+    util::array< box<P> >
+    large_components(const util::array< box<P> >& bboxes,
+		     unsigned max_size)
+    {
+      trace::entering("scribo::filter::large_components");
+
+      mln_precondition(input.is_valid());
+
+      typedef accu::count<P> accu_count_t;
+      typedef mln_result(accu_count_t) accu_count_res_t;
+      typedef util::array<accu_count_res_t> nsitecomp_t;
+
+      util::array<box<P> > result;
+      result.append(box<P>());
+      for_all_components(i, bboxes)
+      {
+	accu_count_res_t count = set::compute(accu_count_t(), bboxes[i]);
+	if (count <= max_size)
+	  result.append(bboxes[i]);
+      }
+
+      trace::exiting("scribo::filter::large_components");
+      return result;
+    }
+
+
+# endif // ! MLN_INCLUDE_ONLY
+
+  } // end of namespace scribo::filter
+
+} // end of namespace scribo
+
+#endif // ! SCRIBO_FILTER_LARGE_COMPONENTS_HH
diff --git a/milena/sandbox/scribo/filter/small_components.hh b/milena/sandbox/scribo/filter/small_components.hh
new file mode 100644
index 0000000..8cb6858
--- /dev/null
+++ b/milena/sandbox/scribo/filter/small_components.hh
@@ -0,0 +1,207 @@
+// Copyright (C) 2009 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.
+
+#ifndef SCRIBO_FILTER_SMALL_COMPONENTS_HH
+# define SCRIBO_FILTER_SMALL_COMPONENTS_HH
+
+/// \file scribo/filter/small_components.hh
+///
+/// Remove small components in a binary image.
+
+
+# include <mln/core/concept/image.hh>
+# include <mln/core/concept/neighborhood.hh>
+# include <mln/core/concept/function.hh>
+
+# include <mln/labeling/blobs.hh>
+# include <mln/labeling/relabel.hh>
+
+# include <mln/util/array.hh>
+# include <mln/value/label_16.hh>
+
+# include <mln/pw/all.hh>
+
+# include <scribo/util/text.hh>
+# include <scribo/make/text.hh>
+
+
+namespace scribo
+{
+
+  namespace filter
+  {
+
+    using namespace mln;
+
+
+    /// Remove small components in a binary image.
+    /// Set to 'false' all the removed components.
+    ///
+    /// \param[in] input_     A binary image.
+    /// \param[in] nbh_	      A neighborhood used for labeling \p input_.
+    /// \param[in] label_type The label type used for labeling.
+    /// \param[in] min_size   The minimum cardinality of a component.
+    ///
+    /// \return A binary image without small components.
+    template <typename I, typename N, typename V>
+    mln_concrete(I)
+    small_components(const Image<I>& input_,
+		     const Neighborhood<N>& nbh_,
+		     const V& label_type,
+		     unsigned min_size);
+
+
+    /// Remove too small text components.
+    ///
+    /// \param[in] text	      Text data.
+    /// \param[in] min_size   The minimum cardinality of a component.
+    ///
+    /// \return updated text data.
+    template <typename I>
+    scribo::util::text<I>
+    small_components(const scribo::util::text<I>& text,
+		     unsigned min_size);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+    namespace internal
+    {
+
+
+      /// Filter Functor. Return false for all components which are too
+      /// small.
+      template <typename R>
+      struct filter_small_components_functor
+	: Function_l2b< filter_small_components_functor<R> >
+      {
+	filter_small_components_functor(const mln::util::array<R>& nsitecomp,
+					unsigned min_size)
+	  : nsitecomp_(nsitecomp), min_size_(min_size)
+	{
+	}
+
+
+	/// Return false if the components area is strictly inferior to
+	/// \p min_size_.
+	bool operator()(const value::label_16& l) const
+	{
+	  return nsitecomp_[l] >= min_size_;
+	}
+
+
+	const mln::util::array<R>& nsitecomp_;
+	unsigned min_size_;
+      };
+
+
+    } //  end of namespace scribo::filter::internal
+
+
+
+    template <typename I, typename N, typename V>
+    inline
+    mln_concrete(I)
+    small_components(const Image<I>& input_,
+		     const Neighborhood<N>& nbh_,
+		     const V& label_type,
+		     unsigned min_size)
+    {
+      trace::entering("scribo::filter::small_components");
+
+      const I& input = exact(input_);
+      const N& nbh = exact(nbh_);
+
+      mln_precondition(input.is_valid());
+      mln_precondition(nbh.is_valid());
+
+      V nlabels;
+      mln_ch_value(I,V) lbl = labeling::blobs(input, nbh, nlabels);
+
+      typedef accu::count<mln_psite(I)> accu_count_t;
+      typedef mln_result(accu_count_t) accu_count_res_t;
+      typedef mln::util::array<accu_count_res_t> nsitecomp_t;
+      nsitecomp_t nsitecomp = labeling::compute(accu_count_t(), lbl, nlabels);
+
+      typedef internal::filter_small_components_functor<accu_count_res_t> func_t;
+      func_t fl2b(nsitecomp, min_size);
+      labeling::relabel_inplace(lbl, nlabels, fl2b);
+
+      mln_concrete(I) output = duplicate(input);
+      data::fill((output | pw::value(lbl) == literal::zero).rw(), false);
+
+      trace::exiting("scribo::filter::small_components");
+      return output;
+    }
+
+
+    template <typename I>
+    inline
+    scribo::util::text<I>
+    small_components(const scribo::util::text<I>& text,
+		     unsigned min_size)
+    {
+      trace::entering("scribo::filter::small_components");
+
+      mln_precondition(text.is_valid());
+
+      typedef mln_site(I) P;
+      typedef accu::count<P> accu_count_t;
+      typedef mln_result(accu_count_t) accu_count_res_t;
+      typedef mln::util::array<accu_count_res_t> nsitecomp_t;
+
+      fun::i2v::array<bool> f(text.nbboxes().next(), false);
+      f(0) = true;
+      mln::util::array<box<P> > bresult;
+      bresult.append(box<P>());
+      for_all_components(i, text.bboxes())
+      {
+	accu_count_res_t count = set::compute(accu_count_t(), text.bbox(i));
+	if (count >= min_size)
+	{
+	  bresult.append(text.bbox(i));
+	  f(i) = true;
+	}
+      }
+
+      mln_value(I) new_nbboxes;
+      I new_lbl = labeling::relabel(text.label_image(), text.nbboxes(),
+				    new_nbboxes, f);
+
+      trace::exiting("scribo::filter::small_components");
+      return scribo::make::text(bresult, new_lbl, new_nbboxes);
+    }
+
+
+# endif // ! MLN_INCLUDE_ONLY
+
+  } // end of namespace scribo::filter
+
+} // end of namespace scribo
+
+#endif // ! SCRIBO_FILTER_SMALL_COMPONENTS_HH
diff --git a/milena/sandbox/scribo/filter/thin_bboxes.hh b/milena/sandbox/scribo/filter/thin_bboxes.hh
new file mode 100644
index 0000000..de99242
--- /dev/null
+++ b/milena/sandbox/scribo/filter/thin_bboxes.hh
@@ -0,0 +1,165 @@
+// Copyright (C) 2009 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.
+
+#ifndef SCRIBO_FILTER_THIN_BBOXES_HH
+# define SCRIBO_FILTER_THIN_BBOXES_HH
+
+/// \file scribo/filter/thin_bboxes.hh
+///
+/// Remove too thin bboxes.
+
+# include <mln/labeling/blobs.hh>
+# include <mln/labeling/compute.hh>
+# include <mln/util/array.hh>
+
+# include <scribo/util/text.hh>
+
+namespace scribo
+{
+
+  namespace filter
+  {
+
+# ifndef MLN_INCLUDE_ONLY
+
+    namespace internal
+    {
+
+
+      /// Filter Functor. Return false for all components which are too
+      /// large.
+      template <typename R>
+      struct filter_too_thin_component_functor
+	: Function_l2b< filter_too_thin_component_functor<R> >
+      {
+	filter_too_thin_component_functor(const mln::util::array<R>& compbboxes,
+					  unsigned min_thickness)
+	  : compbboxes_(compbboxes), min_thickness_(min_thickness)
+	{
+	}
+
+
+	/// Return false if the components is thinner than
+	/// \p min_thickness_.
+	bool operator()(const value::label_16& l) const
+	{
+	  return compbboxes_[l].nrows() > min_thickness_
+		&& compbboxes_[l].ncols() > min_thickness_;
+	}
+
+
+	const mln::util::array<R>& compbboxes_;
+	unsigned min_thickness_;
+      };
+
+
+    } //  end of namespace scribo::filter::internal
+
+
+    template <typename I, typename N, typename V>
+    inline
+    mln_concrete(I)
+    thin_bboxes(const Image<I>& input_,
+		const Neighborhood<N>& nbh_,
+		const V& label_type,
+		unsigned min_thickness)
+    {
+      trace::entering("scribo::filter::thin_bboxes");
+
+      const I& input = exact(input_);
+      const N& nbh = exact(nbh_);
+
+      mln_precondition(input.is_valid());
+      mln_precondition(nbh.is_valid());
+
+      V nlabels;
+      mln_ch_value(I,V) lbl = labeling::blobs(input, nbh, nlabels);
+
+      typedef accu::bbox<mln_psite(I)> accu_bbox_t;
+      typedef mln_result(accu_bbox_t) accu_bbox_res_t;
+      typedef mln::util::array<accu_bbox_res_t> compbboxes_t;
+      compbboxes_t compbboxes = labeling::compute(accu_bbox_t(), lbl, nlabels);
+
+      typedef internal::filter_too_thin_component_functor<accu_bbox_res_t> func_t;
+      func_t fl2b(compbboxes, min_thickness);
+      labeling::relabel_inplace(lbl, nlabels, fl2b);
+
+      mln_concrete(I) output = duplicate(input);
+      data::fill((output | pw::value(lbl) == literal::zero).rw(), false);
+
+      trace::exiting("scribo::filter::thin_bboxes");
+      return output;
+    }
+
+
+    template <typename L>
+    inline
+    scribo::util::text<L>
+    thin_bboxes(const scribo::util::text<L>& text,
+		unsigned min_thickness)
+    {
+      trace::entering("scribo::filter::thin_bboxes");
+
+      mln_precondition(text.is_valid());
+
+      typedef mln_site(L) P;
+      typedef accu::bbox<P> accu_bbox_t;
+      typedef mln_result(accu_bbox_t) accu_bbox_res_t;
+      typedef mln::util::array<accu_bbox_res_t> nsitecomp_t;
+
+      typedef internal::filter_too_thin_component_functor<accu_bbox_res_t> func_t;
+      func_t is_not_too_thin(text.bboxes(), min_thickness);
+
+      fun::i2v::array<bool> f(text.nbboxes().next(), false);
+      f(0) = true;
+      mln::util::array<box<P> > bresult;
+      bresult.append(box<P>());
+      for_all_components(i, text.bboxes())
+	if (is_not_too_thin(i))
+	{
+	  bresult.append(text.bbox(i));
+	  f(i) = true;
+	}
+
+      mln_value(L) new_nbboxes;
+      L new_lbl = labeling::relabel(text.label_image(), text.nbboxes(),
+				    mln::make::relabelfun(f, text.nbboxes(), new_nbboxes));
+
+      mln_assertion(new_nbboxes.next() == bresult.nelements());
+
+      trace::exiting("scribo::filter::thin_bboxes");
+      return scribo::make::text(bresult, new_lbl, new_nbboxes);
+    }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+  } // end of namespace scribo::filter
+
+} // end of namespace scribo
+
+
+#endif // ! SCRIBO_FILTER_THIN_BBOXES_HH
diff --git a/milena/sandbox/scribo/make/debug_filename.hh b/milena/sandbox/scribo/make/debug_filename.hh
index b159328..5a9728c 100644
--- a/milena/sandbox/scribo/make/debug_filename.hh
+++ b/milena/sandbox/scribo/make/debug_filename.hh
@@ -35,6 +35,7 @@
 /// Construct and returns a formated output file name.
 
 # include <sstream>
+# include <mln/trace/all.hh>
 
 
 namespace scribo
@@ -46,25 +47,43 @@ namespace scribo
     /// Construct and returns a formated output file name:
     ///
     ///	    `input_filename`_`id`_`name`
+    /// \sa scribo::make::internal::debug_filename_prefix
     std::string
-    debug_filename(const char *input_filename,
-		   const char *name);
+    debug_filename(const std::string& name);
 
 
+    namespace internal
+    {
+
+      /// Set the default debug filename prefix.
+      extern char *debug_filename_prefix;
+
+    } // end of namespace scribo::make::internal
+
 # ifndef MLN_INCLUDE_ONLY
 
 
+
+    namespace internal
+    {
+
+      char *debug_filename_prefix = 0;
+
+    } // end of namespace scribo::make::internal
+
+
     inline
     std::string
-    debug_filename(const char *input_filename,
-		   const char *name)
+    debug_filename(const std::string& name)
     {
       static int file_id = 1;
 
       std::ostringstream os;
-      os << "./"
-	 << input_filename
-	 << "_";
+
+      if (internal::debug_filename_prefix != 0)
+	os << internal::debug_filename_prefix << "_";
+      else
+	mln::trace::warning("You may like to set a default filename prefix.");
 
       if (file_id < 10)
 	os << "0";
diff --git a/milena/sandbox/scribo/text/extract_bboxes.hh b/milena/sandbox/scribo/make/text.hh
similarity index 56%
copy from milena/sandbox/scribo/text/extract_bboxes.hh
copy to milena/sandbox/scribo/make/text.hh
index 0c88880..3c32ad0 100644
--- a/milena/sandbox/scribo/text/extract_bboxes.hh
+++ b/milena/sandbox/scribo/make/text.hh
@@ -1,5 +1,4 @@
 // Copyright (C) 2009 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
@@ -26,13 +25,12 @@
 // reasons why the executable file might be covered by the GNU General
 // Public License.
 
+#ifndef SCRIBO_MAKE_TEXT_HH
+# define SCRIBO_MAKE_TEXT_HH
 
-#ifndef SCRIBO_TEXT_GROUPING_EXTRACT_BBOXES_HH
-# define SCRIBO_TEXT_GROUPING_EXTRACT_BBOXES_HH
-
-/// \file scribo/text/grouping/group_with_single_link.hh
+/// \file scribo/make/text.hh
 ///
-/// Extract text bounding boxes from a binary image.
+/// Construct a util::text.
 
 # include <mln/core/concept/image.hh>
 # include <mln/core/concept/neighborhood.hh>
@@ -40,56 +38,77 @@
 # include <mln/labeling/blobs.hh>
 # include <mln/labeling/compute.hh>
 # include <mln/util/array.hh>
+# include <scribo/util/text.hh>
 
-# include <scribo/core/component_bboxes.hh>
 
 namespace scribo
 {
 
-  namespace text
+  namespace make
   {
 
-    using namespace mln;
 
-    /// Extract text bounding boxes from a binary image.
-    ///
-    /// \param[in] input_ A binary image.
-    ///
-    /// \return an array of bounding boxes. The first bounding box is
-    /// the background's.
+    template <typename L>
+    scribo::util::text<L>
+    text(const mln::util::array<box<mln_site(L)> >& bboxes,
+	 const Image<L>& lbl,
+	 mln_value(L)& nbboxes);
+
+
     template <typename I, typename N, typename V>
-    inline
-    util::array< box<mln_site(I)> >
-    extract_bboxes(const Image<I>& input_,
-		   const Neighborhood<N>& nbh, V& nbboxes);
+    scribo::util::text<mln_ch_value(I,V)>
+    text(const Image<I>& input_, const Neighborhood<N>& nbh_,
+	 V& nbboxes);
+
 
 # ifndef MLN_INCLUDE_ONLY
 
+    template <typename L>
+    scribo::util::text<L>
+    text(const mln::util::array<box<mln_site(L)> >& bboxes,
+	 const Image<L>& lbl,
+	 mln_value(L)& nbboxes)
+    {
+      trace::entering("scribo::make::text");
+
+      mln_precondition(exact(lbl).is_valid());
+
+      scribo::util::text<L> result = scribo::util::text<L>(bboxes, lbl,
+							   nbboxes);
+
+      trace::exiting("scribo::make::text");
+      return result;
+    }
+
+
 
     template <typename I, typename N, typename V>
-    inline
-    util::array< box<mln_site(I)> >
-    extract_bboxes(const Image<I>& input_,
-		   const Neighborhood<N>& nbh, V& nbboxes)
+    scribo::util::text<mln_ch_value(I,V)>
+    text(const Image<I>& input_, const Neighborhood<N>& nbh_,
+	 V& nbboxes)
     {
-      trace::entering("scribo::text::extract_bboxes");
+      trace::entering("scribo::make::text");
 
       const I& input = exact(input_);
+      const N& nbh = exact(nbh_);
 
-      mlc_equal(mln_value(I), bool)::check();
       mln_precondition(input.is_valid());
+      mln_precondition(nbh.is_valid());
+
+      typedef mln::util::array< box<mln_site(I)> > boxes_t;
+
+      mln_ch_value(I,V) lbl = labeling::blobs(input, nbh, nbboxes);
 
-      typedef util::array< box<mln_site(I)> > bboxes_t;
-      bboxes_t bboxes = component_bboxes(input, nbh, nbboxes);
+      boxes_t cboxes = labeling::compute(accu::meta::bbox(), lbl, nbboxes);
 
-      trace::exiting("scribo::text::extract_bboxes");
-      return bboxes;
+      trace::exiting("scribo::make::text");
+      return make::text(cboxes, lbl, nbboxes);
     }
 
 # endif // ! MLN_INCLUDE_ONLY
 
-  } // end of namespace scribo::text
+  } // end of namespace scribo::make
 
 } // end of namespace scribo
 
-#endif // ! SCRIBO_TEXT_GROUPING_EXTRACT_BBOXES_HH
+#endif // ! SCRIBO_MAKE_TEXT_HH
diff --git a/milena/sandbox/scribo/src/dmap.cc b/milena/sandbox/scribo/src/dmap.cc
new file mode 100644
index 0000000..dac40ba
--- /dev/null
+++ b/milena/sandbox/scribo/src/dmap.cc
@@ -0,0 +1,26 @@
+#include <mln/essential/2d.hh>
+#include <mln/core/var.hh>
+#include <mln/fun/l2l/wrap.hh>
+#include <mln/transform/distance_and_influence_zone_geodesic.hh>
+
+int main(int, char *argv[])
+{
+  using namespace mln;
+
+  using value::int_u16;
+  using value::label_16;
+  using value::label_8;
+  using value::rgb8;
+
+  image2d<bool> ima;
+  io::pbm::load(ima, argv[1]);
+
+  label_16 nlabels;
+  image2d<label_16> lbl = labeling::blobs(ima, c8(), nlabels);
+
+  mln_VAR(res, transform::distance_and_influence_zone_geodesic(lbl, c8(), mln_max(unsigned)));
+
+  io::pgm::save(level::transform(res.first(), fun::l2l::wrap<label_8>()), "dmap.pgm");
+  io::ppm::save(debug::colorize(value::rgb8(), res.second(), nlabels), "iz.ppm");
+
+}
diff --git a/milena/sandbox/scribo/src/extract_text_double_link.cc b/milena/sandbox/scribo/src/extract_text_double_link.cc
index 26fccff..ea4b2b8 100644
--- a/milena/sandbox/scribo/src/extract_text_double_link.cc
+++ b/milena/sandbox/scribo/src/extract_text_double_link.cc
@@ -28,6 +28,7 @@
 #include <iostream>
 
 #include <mln/essential/2d.hh>
+#include <mln/debug/colorize.hh>
 
 #include <scribo/text/extract_bboxes.hh>
 #include <scribo/text/grouping/group_with_single_left_link.hh>
@@ -44,17 +45,6 @@ int usage(const char *name)
 }
 
 
-namespace scribo { namespace text { namespace grouping
-{
-  using namespace mln;
-
-  template <typename I>
-      util::array< box<mln_site(I)> >
-      group_from_double_link(const util::array< box<mln_site(I)> >& textbboxes,
-			     util::array<unsigned>& left_link,
-			     util::array<unsigned>& right_link);
-}}}
-
 int main(int argc, char* argv[])
 {
   using namespace scribo;
@@ -63,47 +53,56 @@ int main(int argc, char* argv[])
   if (argc < 1)
     return usage(argv[0]);
 
+  scribo::make::internal::debug_filename_prefix = "extract_text_double_link";
+
   image2d<bool> input;
   io::pbm::load(input, argv[1]);
 
   value::label_16 nbboxes;
-  util::array<box2d> textbboxes = text::extract_bboxes(input, c8(), nbboxes);
+  scribo::util::text<image2d<value::label_16> > text
+      = text::extract_bboxes(input, c8(), nbboxes);
 
-  util::array<unsigned> left_link
-	= text::grouping::group_with_single_left_link(input,
-						      c8(), nbboxes,
-						      textbboxes, 30);
-  util::array<unsigned> right_link
-	= text::grouping::group_with_single_right_link(input,
-						       c8(), nbboxes,
-						       textbboxes, 30);
+  mln::util::array<unsigned> left_link
+	= text::grouping::group_with_single_left_link(text, 30);
+  mln::util::array<unsigned> right_link
+	= text::grouping::group_with_single_right_link(text, 30);
 
   std::cout << "BEFORE - nbboxes = " << nbboxes << std::endl;
 
-  scribo::debug::save_linked_textbboxes_image(input,
-					      textbboxes, left_link,
-					      literal::red, literal::cyan,
-					      "test_double_link_left_linked.ppm");
-  scribo::debug::save_linked_textbboxes_image(input,
-					      textbboxes, right_link,
-					      literal::red, literal::cyan,
-					      "test_double_link_right_linked.ppm");
+//  scribo::debug::save_linked_textbboxes_image(input,
+//					      text, left_link,
+//					      literal::red, literal::cyan,
+//					      scribo::make::debug_filename("left_linked.ppm"));
+//  scribo::debug::save_linked_textbboxes_image(input,
+//					      text, right_link,
+//					      literal::red, literal::cyan,
+//					      scribo::make::debug_filename("right_linked.ppm"));
 
   scribo::debug::save_linked_textbboxes_image(input,
-					      textbboxes, left_link, right_link,
+					      text, left_link, right_link,
 					      literal::red, literal::cyan,
 					      literal::yellow,
-					      "test_double_link_double_linked.ppm");
+					      scribo::make::debug_filename("links.ppm"));
+
+//  io::ppm::save(mln::debug::colorize(value::rgb8(),
+//				     text.label_image(),
+//				     text.nbboxes()),
+//		scribo::make::debug_filename("lbl_before.ppm"));
 
   // With validation.
-  util::array< box<point2d> > grouped_textbboxes
-	= text::grouping::group_from_double_link(textbboxes, left_link, right_link);
+  scribo::util::text<image2d<value::label_16> > grouped_text
+	= text::grouping::group_from_double_link(text, left_link, right_link);
+
+  io::ppm::save(mln::debug::colorize(value::rgb8(),
+				     grouped_text.label_image(),
+				     grouped_text.nbboxes()),
+		scribo::make::debug_filename("label_color.ppm"));
 
-  std::cout << "AFTER double grouping - nbboxes = " << grouped_textbboxes.nelements() << std::endl;
+  std::cout << "AFTER double grouping - nbboxes = " << grouped_text.bboxes().nelements() << std::endl;
 
-  scribo::debug::save_textbboxes_image(input, grouped_textbboxes,
+  scribo::debug::save_textbboxes_image(input, grouped_text.bboxes(),
 				       literal::red,
-				       "test_double_link_grouped_text.ppm");
+				       scribo::make::debug_filename("bboxes.ppm"));
 
 }
 
diff --git a/milena/sandbox/scribo/src/extract_text_multiple_links.cc b/milena/sandbox/scribo/src/extract_text_multiple_links.cc
index 9b181e6..0c8c624 100644
--- a/milena/sandbox/scribo/src/extract_text_multiple_links.cc
+++ b/milena/sandbox/scribo/src/extract_text_multiple_links.cc
@@ -50,29 +50,39 @@ int main(int argc, char* argv[])
   if (argc < 1)
     return usage(argv[0]);
 
+  scribo::make::internal::debug_filename_prefix = "extract_text_multiple_links";
+
   image2d<bool> input;
   io::pbm::load(input, argv[1]);
 
   value::label_16 nbboxes;
-  util::array<box2d> textbboxes = text::extract_bboxes(input, c8(), nbboxes);
+  scribo::util::text<image2d<value::label_16> > text
+       = text::extract_bboxes(input, c8(), nbboxes);
 
-  util::graph g = text::grouping::group_with_multiple_links(input,
-							    c8(), nbboxes,
-							    textbboxes, 30);
+  mln::util::graph g = text::grouping::group_with_multiple_links(text, 30);
 
-  std::cout << "BEFORE - nbboxes = " << nbboxes << std::endl;
+  std::cout << "BEFORE - nbboxes = " << nbboxes.next() << std::endl;
   scribo::debug::save_linked_textbboxes_image(input,
-					      textbboxes, g,
+					      text, g,
 					      literal::red, literal::cyan,
-					      "test_multiple_links_left_linked.ppm");
+					      scribo::make::debug_filename("left_linked.ppm"));
+//  io::ppm::save(mln::debug::colorize(value::rgb8(),
+//				     text.label_image(),
+//				     text.nbboxes()),
+//		scribo::make::debug_filename("lbl_before.ppm"));
 
-  util::array< box<point2d> > grouped_textbboxes
-    = text::grouping::group_from_multiple_links(textbboxes, g);
+  scribo::util::text<image2d<value::label_16> > grouped_text
+      = text::grouping::group_from_multiple_links(text, g);
 
-  std::cout << "AFTER - nbboxes = " << grouped_textbboxes.nelements() << std::endl;
+  std::cout << "AFTER - nbboxes = " << grouped_text.bboxes().nelements() << std::endl;
 
-  scribo::debug::save_textbboxes_image(input, grouped_textbboxes,
+  scribo::debug::save_textbboxes_image(input, grouped_text.bboxes(),
 				       literal::red,
-				       "test_multiple_links_grouped_text.ppm");
+				       scribo::make::debug_filename("grouped_text.ppm"));
+  io::ppm::save(mln::debug::colorize(value::rgb8(),
+				     grouped_text.label_image(),
+				     grouped_text.nbboxes()),
+		scribo::make::debug_filename("label_color.ppm"));
+
 }
 
diff --git a/milena/sandbox/scribo/src/extract_text_single_link.cc b/milena/sandbox/scribo/src/extract_text_single_link.cc
index 5b4e248..1dee956 100644
--- a/milena/sandbox/scribo/src/extract_text_single_link.cc
+++ b/milena/sandbox/scribo/src/extract_text_single_link.cc
@@ -51,56 +51,70 @@ int main(int argc, char* argv[])
   if (argc < 1)
     return usage(argv[0]);
 
+  scribo::make::internal::debug_filename_prefix = "extract_text_single_link";
+
   image2d<bool> input;
   io::pbm::load(input, argv[1]);
 
   value::label_16 nbboxes;
-  util::array<box2d> textbboxes = text::extract_bboxes(input, c8(), nbboxes);
+  scribo::util::text<image2d<value::label_16> > text
+    = text::extract_bboxes(input, c8(), nbboxes);
 
   {
     std::cout << "* Left grouping" << std::endl;
-    util::array<unsigned> left_link
-	= text::grouping::group_with_single_left_link(input,
-						      c8(), nbboxes,
-						      textbboxes, 30);
+    mln::util::array<unsigned> left_link
+	= text::grouping::group_with_single_left_link(text, 30);
 
     std::cout << "BEFORE - nbboxes = " << nbboxes << std::endl;
     scribo::debug::save_linked_textbboxes_image(input,
-						textbboxes, left_link,
+						text, left_link,
 						literal::red, literal::cyan,
-						"test_single_left_link_linked.ppm");
-
-    util::array< box<point2d> > grouped_textbboxes
-	  = text::grouping::group_from_single_link(textbboxes, left_link);
-
-    std::cout << "AFTER - nbboxes = " << grouped_textbboxes.nelements() << std::endl;
-
-    scribo::debug::save_textbboxes_image(input, grouped_textbboxes,
+						scribo::make::debug_filename("left_links.ppm"));
+//    io::ppm::save(mln::debug::colorize(value::rgb8(),
+//				       text.label_image(),
+//				       text.nbboxes()),
+//				       scribo::make::debug_filename("lbl_before.ppm"));
+
+    scribo::util::text<image2d<value::label_16> > grouped_text
+	  = text::grouping::group_from_single_link(text, left_link);
+
+    std::cout << "AFTER - nbboxes = " << grouped_text.bboxes().nelements() << std::endl;
+    io::ppm::save(mln::debug::colorize(value::rgb8(),
+				       grouped_text.label_image(),
+				       grouped_text.nbboxes()),
+				       scribo::make::debug_filename("left_label_color.ppm"));
+    scribo::debug::save_textbboxes_image(input, grouped_text.bboxes(),
 					 literal::red,
-					 "test_single_left_link_grouped_text.ppm");
+					 scribo::make::debug_filename("left_bboxes.ppm"));
   }
 
   {
     std::cout << "* Left grouping" << std::endl;
-    util::array<unsigned> right_link
-	= text::grouping::group_with_single_right_link(input,
-						      c8(), nbboxes,
-						      textbboxes, 30);
+    mln::util::array<unsigned> right_link
+	= text::grouping::group_with_single_right_link(text, 30);
 
     std::cout << "BEFORE - nbboxes = " << nbboxes << std::endl;
     scribo::debug::save_linked_textbboxes_image(input,
-						textbboxes, right_link,
+						text, right_link,
 						literal::red, literal::cyan,
-						"test_single_right_link_linked.ppm");
-
-    util::array< box<point2d> > grouped_textbboxes
-	  = text::grouping::group_from_single_link(textbboxes, right_link);
-
-    std::cout << "AFTER - nbboxes = " << grouped_textbboxes.nelements() << std::endl;
-
-    scribo::debug::save_textbboxes_image(input, grouped_textbboxes,
+						scribo::make::debug_filename("right_links.ppm"));
+//    io::ppm::save(mln::debug::colorize(value::rgb8(),
+//				       text.label_image(),
+//				       text.nbboxes()),
+//				       scribo::make::debug_filename("lbl_before.ppm"));
+
+    scribo::util::text<image2d<value::label_16> > grouped_text
+	  = text::grouping::group_from_single_link(text, right_link);
+
+    io::ppm::save(mln::debug::colorize(value::rgb8(),
+				       grouped_text.label_image(),
+				       grouped_text.nbboxes()),
+				       scribo::make::debug_filename("right_label_color.ppm"));
+    std::cout << "AFTER - nbboxes = " << grouped_text.bboxes().nelements() << std::endl;
+
+    scribo::debug::save_textbboxes_image(input, grouped_text.bboxes(),
 					 literal::red,
-					 "test_single_right_link_grouped_text.ppm");
+					 scribo::make::debug_filename("right_bboxes.ppm"));
   }
 
 
diff --git a/milena/sandbox/scribo/src/morpho.cc b/milena/sandbox/scribo/src/morpho.cc
new file mode 100644
index 0000000..a527a3d
--- /dev/null
+++ b/milena/sandbox/scribo/src/morpho.cc
@@ -0,0 +1,64 @@
+#include <mln/essential/2d.hh>
+#include <mln/transform/distance_and_influence_zone_geodesic.hh>
+#include <mln/core/var.hh>
+#include <mln/fun/l2l/wrap.hh>
+#include <mln/win/hline2d.hh>
+#include <mln/morpho/watershed/flooding.hh>
+#include <mln/morpho/watershed/superpose.hh>
+
+#include <scribo/make/debug_filename.hh>
+
+int main(int argc, char *argv[])
+{
+  using namespace mln;
+
+  using value::int_u16;
+  using value::label_16;
+  using value::label_8;
+  using value::rgb8;
+
+  image2d<bool> input;
+  io::pbm::load(input, argv[1]);
+
+  scribo::make::internal::debug_filename_prefix = "morpho";
+
+  label_16 nlabels;
+  image2d<label_16> lbl = labeling::blobs(input, c8(), nlabels);
+
+  mln_VAR(res, transform::distance_and_influence_zone_geodesic(lbl, c8(), mln_max(unsigned)));
+
+  io::pgm::save(level::transform(res.first(), fun::l2l::wrap<label_8>()), "dmap.pgm");
+  io::ppm::save(debug::colorize(rgb8(), res.second(), nlabels), "iz.ppm");
+
+  image2d<unsigned>& dmap = res.first();
+  {
+    image2d<unsigned> clo = morpho::closing::structural(dmap, win::hline2d(51));
+    io::pgm::save(clo, scribo::make::debug_filename("clo_line_51.pgm"));
+    label_16 nlabels;
+    image2d<label_16> wsd = morpho::watershed::flooding(clo, c8(), nlabels);
+
+    io::ppm::save(morpho::watershed::superpose(input, wsd),
+		  scribo::make::debug_filename("wsd_line_51.ppm"));
+  }
+
+  {
+    image2d<unsigned> clo = morpho::closing::structural(dmap, win::rectangle2d(11, 101));
+    io::pgm::save(clo, scribo::make::debug_filename("clo_rectangle_11_101.pgm"));
+    label_16 nlabels;
+    image2d<label_16> wsd = morpho::watershed::flooding(clo, c8(), nlabels);
+
+    io::ppm::save(morpho::watershed::superpose(input, wsd),
+		  scribo::make::debug_filename("wsd_rectangle_11_101.ppm"));
+  }
+
+  {
+    image2d<unsigned> clo = morpho::closing::structural(dmap, win::disk2d(51));
+    io::pgm::save(clo, scribo::make::debug_filename("clo_disk_51.pgm"));
+    label_16 nlabels;
+    image2d<label_16> wsd = morpho::watershed::flooding(clo, c8(), nlabels);
+
+    io::ppm::save(morpho::watershed::superpose(input, wsd),
+		  scribo::make::debug_filename("wsd_disk_51.ppm"));
+  }
+
+???
diff --git a/milena/sandbox/scribo/src/table.cc b/milena/sandbox/scribo/src/table.cc
index 3472599..3a12c57 100644
--- a/milena/sandbox/scribo/src/table.cc
+++ b/milena/sandbox/scribo/src/table.cc
@@ -26,7 +26,7 @@
 // Public License.
 
 
-#include "demat.hh"
+#include <demat.hh>
 
 int main(int argc, char*argv[])
 {
diff --git a/milena/sandbox/scribo/src/extract_text_multiple_links.cc b/milena/sandbox/scribo/src/table_extract.cc
similarity index 61%
copy from milena/sandbox/scribo/src/extract_text_multiple_links.cc
copy to milena/sandbox/scribo/src/table_extract.cc
index 9b181e6..36142a2 100644
--- a/milena/sandbox/scribo/src/extract_text_multiple_links.cc
+++ b/milena/sandbox/scribo/src/table_extract.cc
@@ -28,13 +28,10 @@
 #include <iostream>
 
 #include <mln/essential/2d.hh>
+#include <mln/io/dump/save.hh>
 
-#include <scribo/text/extract_bboxes.hh>
-#include <scribo/text/grouping/group_with_multiple_links.hh>
-#include <scribo/text/grouping/group_from_multiple_links.hh>
+#include <scribo/table/extract.hh>
 
-#include <scribo/debug/save_textbboxes_image.hh>
-#include <scribo/debug/save_linked_textbboxes_image.hh>
 
 int usage(const char *name)
 {
@@ -42,6 +39,7 @@ int usage(const char *name)
   return 1;
 }
 
+
 int main(int argc, char* argv[])
 {
   using namespace scribo;
@@ -50,29 +48,20 @@ int main(int argc, char* argv[])
   if (argc < 1)
     return usage(argv[0]);
 
+  scribo::make::internal::debug_filename_prefix = argv[0];
+
   image2d<bool> input;
   io::pbm::load(input, argv[1]);
+  logical::not_inplace(input);
 
-  value::label_16 nbboxes;
-  util::array<box2d> textbboxes = text::extract_bboxes(input, c8(), nbboxes);
-
-  util::graph g = text::grouping::group_with_multiple_links(input,
-							    c8(), nbboxes,
-							    textbboxes, 30);
+  trace::quiet = false;
 
-  std::cout << "BEFORE - nbboxes = " << nbboxes << std::endl;
-  scribo::debug::save_linked_textbboxes_image(input,
-					      textbboxes, g,
-					      literal::red, literal::cyan,
-					      "test_multiple_links_left_linked.ppm");
+  value::label_16 ncells;
+  image2d<value::label_16> tables = scribo::table::extract(input, ncells);
 
-  util::array< box<point2d> > grouped_textbboxes
-    = text::grouping::group_from_multiple_links(textbboxes, g);
+  std::cout << "ncells (including background) = " << ncells << std::endl;
+  io::ppm::save(mln::debug::colorize(value::rgb8(), tables, ncells),
+		scribo::make::debug_filename("table_cells.ppm"));
 
-  std::cout << "AFTER - nbboxes = " << grouped_textbboxes.nelements() << std::endl;
-
-  scribo::debug::save_textbboxes_image(input, grouped_textbboxes,
-				       literal::red,
-				       "test_multiple_links_grouped_text.ppm");
+  io::dump::save(tables, scribo::make::debug_filename("table_cells.dump"));
 }
-
diff --git a/milena/sandbox/scribo/src/extract_text_multiple_links.cc b/milena/sandbox/scribo/src/table_rebuild.cc
similarity index 61%
copy from milena/sandbox/scribo/src/extract_text_multiple_links.cc
copy to milena/sandbox/scribo/src/table_rebuild.cc
index 9b181e6..d195b5b 100644
--- a/milena/sandbox/scribo/src/extract_text_multiple_links.cc
+++ b/milena/sandbox/scribo/src/table_rebuild.cc
@@ -29,12 +29,11 @@
 
 #include <mln/essential/2d.hh>
 
-#include <scribo/text/extract_bboxes.hh>
-#include <scribo/text/grouping/group_with_multiple_links.hh>
-#include <scribo/text/grouping/group_from_multiple_links.hh>
+#include <scribo/table/rebuild.hh>
+#include <scribo/table/erase.hh>
+#include <scribo/table/extract_lines_with_rank.hh>
+#include <scribo/make/debug_filename.hh>
 
-#include <scribo/debug/save_textbboxes_image.hh>
-#include <scribo/debug/save_linked_textbboxes_image.hh>
 
 int usage(const char *name)
 {
@@ -42,6 +41,7 @@ int usage(const char *name)
   return 1;
 }
 
+
 int main(int argc, char* argv[])
 {
   using namespace scribo;
@@ -50,29 +50,30 @@ int main(int argc, char* argv[])
   if (argc < 1)
     return usage(argv[0]);
 
+  scribo::make::internal::debug_filename_prefix = argv[0];
+
   image2d<bool> input;
   io::pbm::load(input, argv[1]);
+  logical::not_inplace(input);
 
-  value::label_16 nbboxes;
-  util::array<box2d> textbboxes = text::extract_bboxes(input, c8(), nbboxes);
+  typedef util::couple<util::array<box2d>,util::array<box2d> > tblboxes_t;
 
-  util::graph g = text::grouping::group_with_multiple_links(input,
-							    c8(), nbboxes,
-							    textbboxes, 30);
+  win::vline2d vline(51);
+  win::hline2d hline(51);
+  tblboxes_t lineboxes
+	= table::extract_lines_with_rank(input, c8(), value::label_16(),
+					 vline, hline, 6, 6);
 
-  std::cout << "BEFORE - nbboxes = " << nbboxes << std::endl;
-  scribo::debug::save_linked_textbboxes_image(input,
-					      textbboxes, g,
-					      literal::red, literal::cyan,
-					      "test_multiple_links_left_linked.ppm");
+  value::label_8 ncells;
+  image2d<value::label_8> tables = scribo::table::rebuild(input, lineboxes, 30, ncells);
 
-  util::array< box<point2d> > grouped_textbboxes
-    = text::grouping::group_from_multiple_links(textbboxes, g);
 
-  std::cout << "AFTER - nbboxes = " << grouped_textbboxes.nelements() << std::endl;
+  std::cout << "ncells (including background) = " << ncells << std::endl;
+  io::ppm::save(mln::debug::colorize(value::rgb8(), tables, ncells),
+		scribo::make::debug_filename("table_cells.ppm"));
+  io::pgm::save(tables, scribo::make::debug_filename("table_cells.pgm"));
 
-  scribo::debug::save_textbboxes_image(input, grouped_textbboxes,
-				       literal::red,
-				       "test_multiple_links_grouped_text.ppm");
+  image2d<bool> in_wo_tables = table::erase(input, lineboxes);
+  io::pbm::save(in_wo_tables,
+      scribo::make::debug_filename("input_wo_tables.pbm"));
 }
-
diff --git a/milena/sandbox/scribo/src/thin_bboxes.cc b/milena/sandbox/scribo/src/thin_bboxes.cc
new file mode 100644
index 0000000..77b158b
--- /dev/null
+++ b/milena/sandbox/scribo/src/thin_bboxes.cc
@@ -0,0 +1,32 @@
+#include <mln/essential/2d.hh>
+#include <scribo/text/extract_lines.hh>
+#include <scribo/filter/thin_bboxes.hh>
+
+int usage(const char *name)
+{
+  std::cout << "Usage: " << name << " <input.pbm> " << std::endl;
+  return 1;
+}
+
+int main(int argc, char *argv[])
+{
+  using namespace mln;
+
+  if (argc < 1)
+    return usage(argv[0]);
+
+  scribo::make::internal::debug_filename_prefix = "thin_bboxes";
+
+  image2d<bool> input;
+  io::pbm::load(input, argv[1]);
+
+  value::label_16 nlines;
+  typedef scribo::util::text<image2d<value::label_16> > text_t;
+  text_t lines = scribo::text::extract_lines(input, c8(), nlines);
+
+  text_t filtered_lines = scribo::filter::thin_bboxes(lines, 5);
+
+  scribo::debug::save_textbboxes_image(input, filtered_lines.bboxes(),
+				       literal::red,
+				       scribo::make::debug_filename("thickness_filter"));
+}
diff --git a/milena/sandbox/scribo/table/align_lines_horizontaly.hh b/milena/sandbox/scribo/table/align_lines_horizontaly.hh
index e75f2f2..4828cfe 100644
--- a/milena/sandbox/scribo/table/align_lines_horizontaly.hh
+++ b/milena/sandbox/scribo/table/align_lines_horizontaly.hh
@@ -38,8 +38,8 @@
 # include <mln/core/concept/image.hh>
 # include <mln/core/site_set/box.hh>
 # include <mln/geom/nrows.hh>
-# include <mln/geom/min_nrow.hh>
-# include <mln/geom/max_nrow.hh>
+# include <mln/geom/min_row.hh>
+# include <mln/geom/max_row.hh>
 
 # include <mln/util/array.hh>
 
@@ -52,18 +52,24 @@ namespace scribo
   namespace table
   {
 
+    using namespace mln;
+
     /// Align line bounding boxes horizontaly.
     ///
     /// \param[in]	input	     Image from which the line bboxes are
     ///				     extracted from.
     /// \param[in, out] lines_bboxes horizontal lines bounding boxes.
+    /// \param[in]	max_alignment_diff max space between two lines to
+    ///					   consider they are potentialy on the
+    ///					   same line.
     ///
     /// \return A list of the resulting aligned rows. Each integer is actually
     ///		a row number.
     template <typename I>
     util::array<int>
     align_lines_horizontaly(const Image<I>& input,
-			  util::array<box<mln_site(I)> >& lines_bboxes);
+			    util::array<box<mln_site(I)> >& lines_bboxes,
+			    unsigned max_alignment_diff);
 
 
 # ifndef MLN_INCLUDE_ONLY
@@ -72,7 +78,8 @@ namespace scribo
     template <typename I>
     util::array<int>
     align_lines_horizontaly(const Image<I>& input,
-			    util::array<box<mln_site(I)> >& lines_bboxes)
+			    util::array<box<mln_site(I)> >& lines_bboxes,
+			    max_alignment_diff)
     {
       trace::entering("scribo::table::align_lines_horizontaly");
 
@@ -80,7 +87,8 @@ namespace scribo
       util::array<int> res =  internal::align_lines(geom::nrows(input),
 						    geom::min_row(input),
 						    geom::max_row(input),
-						    lines_bboxes, 0);
+						    lines_bboxes, 0,
+						    max_alignment_diff);
 
       trace::exiting("scribo::table::align_lines_horizontaly");
       return res;
diff --git a/milena/sandbox/scribo/table/align_lines_verticaly.hh b/milena/sandbox/scribo/table/align_lines_verticaly.hh
index 7e860d0..e4d04ba 100644
--- a/milena/sandbox/scribo/table/align_lines_verticaly.hh
+++ b/milena/sandbox/scribo/table/align_lines_verticaly.hh
@@ -38,8 +38,8 @@
 # include <mln/core/concept/image.hh>
 # include <mln/core/site_set/box.hh>
 # include <mln/geom/ncols.hh>
-# include <mln/geom/min_ncol.hh>
-# include <mln/geom/max_ncol.hh>
+# include <mln/geom/min_col.hh>
+# include <mln/geom/max_col.hh>
 
 # include <mln/util/array.hh>
 
@@ -53,18 +53,24 @@ namespace scribo
   namespace table
   {
 
+    using namespace mln;
+
     /// Align line bounding boxes verticaly.
     ///
     /// \param[in]	input	     Image from which the line bboxes are
     ///				     extracted from.
     /// \param[in, out] lines_bboxes vertical lines bounding boxes.
+    /// \param[in]	max_alignment_diff max space between two lines to
+    ///					   consider they are potentialy on the
+    ///					   same line.
     ///
     /// \return A list of the resulting aligned cols. Each integer is actually
     ///		a col number.
     template <typename I>
     util::array<int>
     align_lines_verticaly(const Image<I>& input,
-			  util::array<box<mln_site(I)> >& lines_bboxes);
+			  util::array<box<mln_site(I)> >& lines_bboxes,
+			  unsigned max_alignment_diff);
 
 
 # ifndef MLN_INCLUDE_ONLY
@@ -81,7 +87,8 @@ namespace scribo
       util::array<int> res = internal::align_lines(geom::ncols(input),
 						   geom::min_col(input),
 						   geom::max_col(input),
-						   lines_bboxes, 1);
+						   lines_bboxes, 1,
+						   max_alignment_diff);
 
       trace::exiting("scribo::table::align_lines_horizontaly");
       return res;
diff --git a/milena/sandbox/scribo/table/connect_horizontal_lines.hh b/milena/sandbox/scribo/table/connect_horizontal_lines.hh
index 7dcf638..c1d3bd6 100644
--- a/milena/sandbox/scribo/table/connect_horizontal_lines.hh
+++ b/milena/sandbox/scribo/table/connect_horizontal_lines.hh
@@ -55,12 +55,15 @@ namespace scribo
     ///				      bounding boxes.
     /// \param[in]	input	      The image from where the lines are
     ///				      extracted.
+    /// \param[in]	max_distance  max distance allowed between a vertical
+    ///				      and horizontal lines.
     template <typename I>
     void
     connect_vertical_lines(const util::array<int>& aligned_rows,
 			   util::couple<util::array<box<mln_site(I)> >,
-					util::array<box<mln_site(I)> > > tableboxes,
-			   const Image<I>& input)
+					util::array<box<mln_site(I)> > >& tableboxes,
+			   const Image<I>& input,
+			   unsigned max_distance);
 
 
 # ifndef MLN_INCLUDE_ONLY
@@ -70,14 +73,15 @@ namespace scribo
     void
     connect_horizontal_lines(const util::array<int>& aligned_cols,
 			     util::couple<util::array<box<mln_site(I)> >,
-					  util::array<box<mln_site(I)> > > tableboxes,
-			     const Image<I>& input)
+					  util::array<box<mln_site(I)> > >& tableboxes,
+			     const Image<I>& input,
+			     unsigned max_distance)
     {
       trace::entering("scribo::table::connect_horizontal_lines");
       mln_precondition(exact(input).is_valid());
 
       internal::connect_lines(aligned_cols, tableboxes.second(),
-			      1, exact(input).ncols());
+			      1, exact(input).ncols(), max_distance);
 
       trace::exiting("scribo::table::connect_horizontal_lines");
     }
diff --git a/milena/sandbox/scribo/table/connect_vertical_lines.hh b/milena/sandbox/scribo/table/connect_vertical_lines.hh
index 98c39f7..2ab4990 100644
--- a/milena/sandbox/scribo/table/connect_vertical_lines.hh
+++ b/milena/sandbox/scribo/table/connect_vertical_lines.hh
@@ -55,12 +55,15 @@ namespace scribo
     ///				      bounding boxes.
     /// \param[in]	input	      The image from where the lines are
     ///				      extracted.
+    /// \param[in]	max_distance  max distance allowed between a vertical
+    ///				      and horizontal lines.
     template <typename I>
     void
     connect_vertical_lines(const util::array<int>& aligned_rows,
 			   util::couple<util::array<box<mln_site(I)> >,
-					util::array<box<mln_site(I)> > > tableboxes,
-			   const Image<I>& input)
+					util::array<box<mln_site(I)> > >& tableboxes,
+			   const Image<I>& input,
+			   unsigned max_distance);
 
 
 # ifndef MLN_INCLUDE_ONLY
@@ -71,14 +74,15 @@ namespace scribo
     void
     connect_vertical_lines(const util::array<int>& aligned_rows,
 			   util::couple<util::array<box<mln_site(I)> >,
-					util::array<box<mln_site(I)> > > tableboxes,
-			   const Image<I>& input)
+					util::array<box<mln_site(I)> > >& tableboxes,
+			   const Image<I>& input,
+			   unsigned max_distance)
     {
       trace::entering("scribo::table::connect_vertical_lines");
       mln_precondition(exact(input).is_valid());
 
       internal::connect_lines(aligned_rows, tableboxes.first(),
-			      0, exact(input).nrows());
+			      0, exact(input).nrows(), max_distance);
 
       trace::exiting("scribo::table::connect_vertical_lines");
     }
diff --git a/milena/sandbox/scribo/text/extract_bboxes.hh b/milena/sandbox/scribo/table/extract.hh
similarity index 55%
copy from milena/sandbox/scribo/text/extract_bboxes.hh
copy to milena/sandbox/scribo/table/extract.hh
index 0c88880..06520c9 100644
--- a/milena/sandbox/scribo/text/extract_bboxes.hh
+++ b/milena/sandbox/scribo/table/extract.hh
@@ -26,70 +26,69 @@
 // reasons why the executable file might be covered by the GNU General
 // Public License.
 
+#ifndef SCRIBO_TABLE_EXTRACT_HH
+# define SCRIBO_TABLE_EXTRACT_HH
 
-#ifndef SCRIBO_TEXT_GROUPING_EXTRACT_BBOXES_HH
-# define SCRIBO_TEXT_GROUPING_EXTRACT_BBOXES_HH
-
-/// \file scribo/text/grouping/group_with_single_link.hh
+/// \file scribo/table/extract.hh
 ///
-/// Extract text bounding boxes from a binary image.
+/// Extract tables from a binary image.
+/// Use arbitrary criterions.
 
 # include <mln/core/concept/image.hh>
-# include <mln/core/concept/neighborhood.hh>
-# include <mln/core/site_set/box.hh>
-# include <mln/labeling/blobs.hh>
-# include <mln/labeling/compute.hh>
+# include <mln/util/couple.hh>
 # include <mln/util/array.hh>
 
-# include <scribo/core/component_bboxes.hh>
+# include <scribo/table/rebuild.hh>
+# include <scribo/table/erase.hh>
+# include <scribo/table/extract_lines_with_rank.hh>
+
+# include <scribo/make/debug_filename.hh>
+
 
 namespace scribo
 {
 
-  namespace text
+  namespace table
   {
 
-    using namespace mln;
+    template <typename I, typename V>
+    mln_ch_value(I,V)
+    extract(const Image<I>& input_, V& ncells);
 
-    /// Extract text bounding boxes from a binary image.
-    ///
-    /// \param[in] input_ A binary image.
-    ///
-    /// \return an array of bounding boxes. The first bounding box is
-    /// the background's.
-    template <typename I, typename N, typename V>
-    inline
-    util::array< box<mln_site(I)> >
-    extract_bboxes(const Image<I>& input_,
-		   const Neighborhood<N>& nbh, V& nbboxes);
 
 # ifndef MLN_INCLUDE_ONLY
 
-
-    template <typename I, typename N, typename V>
+    template <typename I, typename V>
     inline
-    util::array< box<mln_site(I)> >
-    extract_bboxes(const Image<I>& input_,
-		   const Neighborhood<N>& nbh, V& nbboxes)
+    mln_ch_value(I,V)
+    extract(const Image<I>& input_, V& ncells)
     {
-      trace::entering("scribo::text::extract_bboxes");
+      trace::entering("scribo::table::extract");
 
       const I& input = exact(input_);
-
-      mlc_equal(mln_value(I), bool)::check();
       mln_precondition(input.is_valid());
+      mlc_equal(mln_value(I), bool)::check();
+
+      typedef util::array< box<mln_site(I)> > boxarray_t;
+      typedef util::couple<boxarray_t, boxarray_t> tblboxes_t;
+
+      win::line<mln_grid(I::site), 0, mln_coord(I::site)> vline(51);
+      win::line<mln_grid(I::site), 1, mln_coord(I::site)> hline(51);
+      tblboxes_t lineboxes
+	= table::extract_lines_with_rank(input, c8(), V(),
+					 vline, hline, 6, 6);
 
-      typedef util::array< box<mln_site(I)> > bboxes_t;
-      bboxes_t bboxes = component_bboxes(input, nbh, nbboxes);
+      image2d<V> tables
+	= scribo::table::rebuild(input, lineboxes, 30, ncells);
 
-      trace::exiting("scribo::text::extract_bboxes");
-      return bboxes;
+      trace::exiting("scribo::table::extract");
+      return tables;
     }
 
 # endif // ! MLN_INCLUDE_ONLY
 
-  } // end of namespace scribo::text
+  } // end of namespace scribo::table
 
 } // end of namespace scribo
 
-#endif // ! SCRIBO_TEXT_GROUPING_EXTRACT_BBOXES_HH
+#endif // ! SCRIBO_TABLE_EXTRACT_HH
diff --git a/milena/sandbox/scribo/table/extract_lines_with_rank.hh b/milena/sandbox/scribo/table/extract_lines_with_opening.hh
similarity index 67%
copy from milena/sandbox/scribo/table/extract_lines_with_rank.hh
copy to milena/sandbox/scribo/table/extract_lines_with_opening.hh
index 242dc30..55fd77f 100644
--- a/milena/sandbox/scribo/table/extract_lines_with_rank.hh
+++ b/milena/sandbox/scribo/table/extract_lines_with_opening.hh
@@ -27,12 +27,12 @@
 // Public License.
 
 
-#ifndef SCRIBO_TABLE_EXTRACT_LINES_WITH_RANK_HH
-# define SCRIBO_TABLE_EXTRACT_LINES_WITH_RANK_HH
+#ifndef SCRIBO_TABLE_EXTRACT_LINES_WITH_OPENING_HH
+# define SCRIBO_TABLE_EXTRACT_LINES_WITH_OPENING_HH
 
-/// \file scribo/table/extract_lines_with_rank.hh
+/// \file scribo/table/extract_lines_with_opening.hh
 ///
-/// Extract table lines using a rank filter.
+/// Extract table lines using a morphological opening filter.
 
 
 # include <mln/core/concept/image.hh>
@@ -40,14 +40,14 @@
 # include <mln/core/concept/neighborhood.hh>
 # include <mln/core/site_set/box.hh>
 
-# include <mln/morpho/rank_filter.hh>
+# include <mln/morpho/erosion.hh>
 
 # include <mln/accu/bbox.hh>
 
 # include <mln/util/array.hh>
 # include <mln/util/couple.hh>
 
-
+# include <scribo/core/macros.hh>
 # include <scribo/core/component_bboxes.hh>
 
 namespace scribo
@@ -56,18 +56,18 @@ namespace scribo
   namespace table
   {
 
-    /// Find table bboxes thanks to a rank filter.
+    using namespace mln;
+
+    /// Find table bboxes thanks to a opening filter.
     /*!
      *
      * \param[in] input_ A binary image.
      * \param[in] nbh_ The neighborhood used for labeling image components.
      * \param[in] label_type The type used to store the labels.
-     * \param[in] vwin Window used to extract the vertical lines in the rank
-     *		       filter.
-     * \param[in] hwin Window used to extract the horizontal lines in the rank
-     *		       filter.
-     * \param[in] vrank_k Rank used for vertical lines filtering.
-     * \param[in] hrank_k Rank used for horizontal lines filtering.
+     * \param[in] vwin Window used to extract the vertical lines in a morphological
+     *		       opening
+     * \param[in] hwin Window used to extract the horizontal lines in a morphological
+     *		       opening
      *
      * \return pair of array of bounding boxes. The first array holds the
      *		vertical lines bounding boxes and the second one the
@@ -76,45 +76,58 @@ namespace scribo
     template <typename I, typename N, typename V, typename HW, typename VW>
     util::couple<util::array<box<mln_site(I)> >,
 		 util::array<box<mln_site(I)> > >
-    extract_lines_with_rank(const Image<I>& input_,
-			    const Neighborhood<N>& nbh_, const V& label_type,
-			    const Window<HW>& vwin, const Window<VW>& hwin,
-			    unsigned vrank_k, unsigned hrank_k);
+    extract_lines_with_opening(const Image<I>& input_,
+			       const Neighborhood<N>& nbh_, const V& label_type,
+			       const Window<HW>& vwin, const Window<VW>& hwin);
 
 
 # ifndef MLN_INCLUDE_ONLY
 
-    template <typename I, typename N, typename V, typename HW, typename VW>
+    template <typename I, typename N, typename V, typename VW, typename HW>
     inline
     util::couple<util::array<box<mln_site(I)> >,
 		 util::array<box<mln_site(I)> > >
-    extract_lines_with_rank(const Image<I>& input_,
+    extract_lines_with_opening(const Image<I>& input_,
 			    const Neighborhood<N>& nbh_, const V& label_type,
-			    const Window<HW>& vwin, const Window<VW>& hwin,
-			    unsigned vrank_k, unsigned hrank_k)
+			    const Window<VW>& vwin_, const Window<HW>& hwin_);
     {
-      trace::entering("scribo::table::extract_lines_with_rank");
+      trace::entering("scribo::table::extract_lines_with_opening");
 
       mlc_equal(mln_value(I),bool)::check();
       mlc_is_a(V, mln::value::Symbolic)::check();
+
       const I& input = exact(input_);
       const N& nbh = exact(nbh_);
+      const VW& vwin = exact(vwin_);
+      const HW& hwin = exact(hwin_);
+
       mln_precondition(input.is_valid());
       mln_precondition(nbh.is_valid());
-      mln_precondition(exact(vwin).is_valid());
-      mln_precondition(exact(hwin).is_valid());
+      mln_precondition(vwin.is_valid());
+      mln_precondition(hwin.is_valid());
 
       typedef accu::bbox<mln_psite(I)> A;
       typedef util::array<mln_result(A)> boxes_t;
 
       // Vertical lines
-      mln_ch_value(I,bool) vfilter = morpho::rank_filter(input, vwin, vrank_k);
+      mln_ch_value(I,bool) vfilter = morpho::erosion(input, vwin);
       boxes_t vboxes = component_bboxes(vfilter, nbh, label_type);
+      for_all_components(i, vboxes)
+      {
+	vboxes[i].enlarge(0, vwin.length() / 2);
+	vboxes[i].crop_wrt(input.domain());
+      }
 
       // Horizontal lines.
-      mln_ch_value(I,bool) hfilter = morpho::rank_filter(input, hwin, hrank_k);
+      mln_ch_value(I,bool) hfilter = morpho::erosion(input, hwin);
       boxes_t hboxes = component_bboxes(hfilter, nbh, label_type);
+      for_all_components(i, hboxes)
+      {
+	hboxes[i].enlarge(1, hwin.length() / 2);
+	hboxes[i].crop_wrt(input.domain());
+      }
 
+      trace::exiting("scribo::table::extract_lines_with_opening");
       return mln::make::couple(vboxes, hboxes);
     }
 
@@ -124,4 +137,4 @@ namespace scribo
 
 } // end of namespace scribo
 
-#endif // ! SCRIBO_TABLE_EXTRACT_LINES_WITH_RANK_HH
+#endif // ! SCRIBO_TABLE_EXTRACT_LINES_WITH_OPENING_HH
diff --git a/milena/sandbox/scribo/table/extract_lines_with_rank.hh b/milena/sandbox/scribo/table/extract_lines_with_rank.hh
index 242dc30..63c90b1 100644
--- a/milena/sandbox/scribo/table/extract_lines_with_rank.hh
+++ b/milena/sandbox/scribo/table/extract_lines_with_rank.hh
@@ -47,7 +47,7 @@
 # include <mln/util/array.hh>
 # include <mln/util/couple.hh>
 
-
+# include <scribo/core/macros.hh>
 # include <scribo/core/component_bboxes.hh>
 
 namespace scribo
@@ -56,6 +56,8 @@ namespace scribo
   namespace table
   {
 
+    using namespace mln;
+
     /// Find table bboxes thanks to a rank filter.
     /*!
      *
@@ -84,25 +86,29 @@ namespace scribo
 
 # ifndef MLN_INCLUDE_ONLY
 
-    template <typename I, typename N, typename V, typename HW, typename VW>
+    template <typename I, typename N, typename V, typename VW, typename HW>
     inline
     util::couple<util::array<box<mln_site(I)> >,
 		 util::array<box<mln_site(I)> > >
     extract_lines_with_rank(const Image<I>& input_,
 			    const Neighborhood<N>& nbh_, const V& label_type,
-			    const Window<HW>& vwin, const Window<VW>& hwin,
+			    const Window<VW>& vwin_, const Window<HW>& hwin_,
 			    unsigned vrank_k, unsigned hrank_k)
     {
       trace::entering("scribo::table::extract_lines_with_rank");
 
       mlc_equal(mln_value(I),bool)::check();
       mlc_is_a(V, mln::value::Symbolic)::check();
+
       const I& input = exact(input_);
       const N& nbh = exact(nbh_);
+      const VW& vwin = exact(vwin_);
+      const HW& hwin = exact(hwin_);
+
       mln_precondition(input.is_valid());
       mln_precondition(nbh.is_valid());
-      mln_precondition(exact(vwin).is_valid());
-      mln_precondition(exact(hwin).is_valid());
+      mln_precondition(vwin.is_valid());
+      mln_precondition(hwin.is_valid());
 
       typedef accu::bbox<mln_psite(I)> A;
       typedef util::array<mln_result(A)> boxes_t;
@@ -110,11 +116,22 @@ namespace scribo
       // Vertical lines
       mln_ch_value(I,bool) vfilter = morpho::rank_filter(input, vwin, vrank_k);
       boxes_t vboxes = component_bboxes(vfilter, nbh, label_type);
+      for_all_components(i, vboxes)
+      {
+	vboxes[i].enlarge(0, vwin.length() / 2);
+	vboxes[i].crop_wrt(input.domain());
+      }
 
       // Horizontal lines.
       mln_ch_value(I,bool) hfilter = morpho::rank_filter(input, hwin, hrank_k);
       boxes_t hboxes = component_bboxes(hfilter, nbh, label_type);
+      for_all_components(i, hboxes)
+      {
+	hboxes[i].enlarge(1, hwin.length() / 2);
+	hboxes[i].crop_wrt(input.domain());
+      }
 
+      trace::exiting("scribo::table::extract_lines_with_rank");
       return mln::make::couple(vboxes, hboxes);
     }
 
diff --git a/milena/sandbox/scribo/table/internal/align_lines.hh b/milena/sandbox/scribo/table/internal/align_lines.hh
index aaad9fa..202b2dd 100644
--- a/milena/sandbox/scribo/table/internal/align_lines.hh
+++ b/milena/sandbox/scribo/table/internal/align_lines.hh
@@ -51,6 +51,8 @@ namespace scribo
     namespace internal
     {
 
+      using namespace mln;
+
       /// Align table lines bboxes according to a given dimension.
       ///
       /// \return A list of the resulting aligned cols. Each integer is actually
@@ -102,7 +104,8 @@ namespace scribo
 		  int min_coord,
 		  int max_coord,
 		  util::array<box<P> >& line_boxes,
-		  unsigned dim)
+		  unsigned dim,
+		  unsigned max_alignment_diff)
       {
 	trace::entering("scribo::internal::align_lines");
 
@@ -114,9 +117,9 @@ namespace scribo
 	// Map components with actual lines.
 	for_all_components(i, line_boxes)
 	{
-	  int minline = line_boxes[i].pmin()[dim] - 5;
+	  int minline = line_boxes[i].pmin()[dim] - max_alignment_diff;
 	  minline = (minline < min_coord ? min_coord : minline);
-	  int maxline = line_boxes[i].pmax()[dim] + 5;
+	  int maxline = line_boxes[i].pmax()[dim] + max_alignment_diff;
 	  maxline = (maxline > max_coord ? max_coord : maxline);
 
 	  for (int line = minline;
diff --git a/milena/sandbox/scribo/table/internal/connect_lines.hh b/milena/sandbox/scribo/table/internal/connect_lines.hh
index d510fe2..08f395f 100644
--- a/milena/sandbox/scribo/table/internal/connect_lines.hh
+++ b/milena/sandbox/scribo/table/internal/connect_lines.hh
@@ -35,6 +35,7 @@
 /// Connect vertical lines with aligned rows.
 
 # include <mln/core/image/image1d.hh>
+# include <mln/core/alias/neighb1d.hh>
 
 # include <mln/data/fill.hh>
 
@@ -45,7 +46,7 @@
 # include <mln/opt/at.hh>
 
 # include <scribo/core/macros.hh>
-
+# include <scribo/core/central_sites.hh>
 
 namespace scribo
 {
@@ -56,6 +57,8 @@ namespace scribo
     namespace internal
     {
 
+      using namespace mln;
+
       /// Connect vertical and horizontal lines if they are close to each other.
       ///
       ///  ------                 ------
@@ -70,7 +73,8 @@ namespace scribo
       connect_lines(const util::array<int>& aligned_lines,
 		    util::array< box<P> >& boxes,
 		    unsigned dim,
-		    unsigned dim_size);
+		    unsigned dim_size,
+		    unsigned max_distance);
 
 
 # ifndef MLN_INCLUDE_ONLY
@@ -81,7 +85,8 @@ namespace scribo
       connect_lines(const util::array<int>& aligned_lines,
 		    util::array< box<P> >& boxes,
 		    unsigned dim,
-		    unsigned dim_size)
+		    unsigned dim_size,
+		    unsigned max_distance)
       {
 	trace::entering("scribo::table::internal::connect_lines");
 
@@ -91,12 +96,12 @@ namespace scribo
 	for_all_elements(i, aligned_lines)
 	  opt::at(l, aligned_lines[i]) = i;
 
-	for (unsigned i = 0; i < settings.max_dist_lines; ++i)
+	for (unsigned i = 0; i < max_distance; ++i)
 	  l = morpho::elementary::dilation(l, c2());
 
 	for_all_components(i, boxes)
 	{
-	  util::couple<point2d, point2d> cp = central_sites(boxes[i], dim);
+	  util::couple<P,P> cp = central_sites(boxes[i], dim);
 	  if (opt::at(l, cp.first()[dim]) != -1)
 	    boxes[i].pmin()[dim] = aligned_lines[opt::at(l, cp.first()[dim])];
 	  if (opt::at(l, cp.second()[dim]) != -1)
@@ -110,6 +115,8 @@ namespace scribo
 # endif // ! MLN_INCLUDE_ONLY
 
 
+    } // end of namespace scribo::table::internal
+
   } // end of namespace scribo::table
 
 } // end of namespace scribo
diff --git a/milena/sandbox/scribo/table/internal/repair_lines.hh b/milena/sandbox/scribo/table/internal/repair_lines.hh
index 87f0933..cf21564 100644
--- a/milena/sandbox/scribo/table/internal/repair_lines.hh
+++ b/milena/sandbox/scribo/table/internal/repair_lines.hh
@@ -41,10 +41,17 @@
 # include <mln/data/fill.hh>
 # include <mln/util/couple.hh>
 # include <mln/util/array.hh>
+# include <mln/util/ord.hh>
 # include <mln/win/line.hh>
 # include <mln/pw/all.hh>
 
+# include <mln/debug/colorize.hh>
+# include <mln/value/rgb8.hh>
+# include <mln/value/label_16.hh>
+# include <scribo/make/debug_filename.hh>
+
 # include <scribo/core/central_sites.hh>
+# include <scribo/core/macros.hh>
 # include <scribo/table/internal/repair_lines.hh>
 
 
@@ -57,15 +64,23 @@ namespace scribo
     namespace internal
     {
 
+      /// Repair lines which have small discontinuities.
+      /// FIXME: buggy. Sometimes few lines move or shrink!
+      template <unsigned axis, typename I>
+      void
+      repair_lines(const Image<I>& input_,
+		   util::array<box<mln_site(I)> >& tableboxes,
+		   unsigned max_discontinuity);
+
 
 # ifndef MLN_INCLUDE_ONLY
 
-      /// Repair lines which have small discontinuities.
-      /// FIXME: buggy. Sometimes few lines move or shrink!
+
       template <unsigned axis, typename I>
       void
       repair_lines(const Image<I>& input_,
-		   util::array<box<mln_site(I)> >& tableboxes)
+		   util::array<box<mln_site(I)> >& tableboxes,
+		   unsigned max_discontinuity)
       {
 	trace::entering("scribo::table::internal::repair_lines");
 
@@ -76,7 +91,7 @@ namespace scribo
 	typedef win::line<mln_grid(P), axis, mln_coord(P)> line_t;
 
 	// Initialization
-	mln_ch_value(I,unsigned) l(input.domain());
+	mln_ch_value(I,value::label_16) l(input.domain());
 	data::fill(l, literal::zero);
 	for_all_components(i, tableboxes)
 	{
@@ -86,28 +101,52 @@ namespace scribo
 	}
 
 	// Repair
-	extension_val<mln_ch_value(I,unsigned)> l_ext(l, literal::zero);
+	extension_val<mln_ch_value(I,value::label_16)> l_ext(l, literal::zero);
 
 	util::array<box<P> > result;
 	std::vector<bool> to_keep(tableboxes.nelements(), true);
 
-	mln_VAR(tbb_ima, extend(l | pw::value(l) != literal::zero, l));
+	mln_VAR(tbb_ima, extend(l | pw::value(l) != pw::cst(literal::zero), l));
 	//FIXME: use a half window, just the bottom of the vertical line.
-	line_t vl(settings.repair_max_dist);
+	line_t vl(max_discontinuity);
 	mln_piter(tbb_ima_t) p(tbb_ima.domain());
 	mln_qiter(line_t) q(vl, p);
 	for_all(p)
+	{
+	  util::couple<P,P> cp_p = central_sites(tableboxes[l_ext(p)], axis);
 	  for_all(q)
 	  if (l_ext(q) != literal::zero && l_ext(q) != l_ext(p))
 	  {
-	    to_keep[l_ext(q)] = false;
-
-	    tableboxes[l_ext(p)].pmax() = tableboxes[l_ext(q)].pmax();
-
-	    util::couple<P,P> cp = central_sites(tableboxes[l_ext(q)], axis);
-	    l_ext(cp.first()) = l_ext(p);
-	    l_ext(cp.second()) = l_ext(p);
+	    if (util::ord_strict(tableboxes[l_ext(p)].pmax(),
+				 tableboxes[l_ext(q)].pmax()))
+	    {
+	      tableboxes[l_ext(p)].pmax() = tableboxes[l_ext(q)].pmax();
+	      to_keep[l_ext(q)] = false;
+	    }
+
+	    if (util::ord_strict(tableboxes[l_ext(q)].pmin(),
+				 tableboxes[l_ext(p)].pmin()))
+	    {
+	      tableboxes[l_ext(p)].pmin() = tableboxes[l_ext(q)].pmin();
+	      to_keep[l_ext(q)] = false;
+	    }
+
+	    if (!to_keep[l_ext(q)])
+	    {
+	      util::couple<P,P> cp_q = central_sites(tableboxes[l_ext(q)], axis);
+	      l_ext(cp_q.first()) = literal::zero;
+	      l_ext(cp_q.second()) = literal::zero;
+
+	      unsigned p_i = l_ext(p);
+	      l_ext(cp_p.first()) = literal::zero;
+	      l_ext(cp_p.second()) = literal::zero;
+
+	      util::couple<P,P> new_cp_p = central_sites(tableboxes[p_i], axis);
+	      l_ext(new_cp_p.first()) = p_i;
+	      l_ext(new_cp_p.second()) = p_i;
+	    }
 	  }
+	}
 
 
 	// Remove merged boxes.
diff --git a/milena/sandbox/scribo/table/rebuild.hh b/milena/sandbox/scribo/table/rebuild.hh
new file mode 100644
index 0000000..b78112d
--- /dev/null
+++ b/milena/sandbox/scribo/table/rebuild.hh
@@ -0,0 +1,147 @@
+// Copyright (C) 2009 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 SCRIBO_TABLE_REBUILD_HH
+# define SCRIBO_TABLE_REBUILD_HH
+
+/// \file scribo/table/rebuild.hh
+///
+/// Rebuild a table from its line bounding boxes.
+
+# include <mln/core/concept/image.hh>
+# include <mln/labeling/background.hh>
+# include <mln/util/array.hh>
+# include <mln/util/couple.hh>
+# include <mln/value/label_8.hh>
+
+# include <scribo/table/align_lines_verticaly.hh>
+# include <scribo/table/align_lines_horizontaly.hh>
+# include <scribo/table/connect_vertical_lines.hh>
+# include <scribo/table/connect_horizontal_lines.hh>
+# include <scribo/table/repair_horizontal_lines.hh>
+# include <scribo/table/repair_vertical_lines.hh>
+
+# include <scribo/debug/save_table_image.hh>
+
+
+
+namespace scribo
+{
+
+  namespace table
+  {
+
+    template <typename I, typename V>
+    mln_ch_value(I,V)
+    rebuild(const Image<I>& in_,
+	    const util::couple<util::array<box<mln_site(I)> >,
+			       util::array<box<mln_site(I)> > >& lineboxes,
+	    unsigned max_dist_lines,
+	    V& ncells);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+    template <typename I, typename V>
+    mln_ch_value(I,V)
+    rebuild(const Image<I>& in_,
+	    const util::couple<util::array<box<mln_site(I)> >,
+			       util::array<box<mln_site(I)> > >& lineboxes,
+	    unsigned max_dist_lines,
+	    V& ncells)
+    {
+      trace::entering("scribo::table::rebuild");
+      const I& in = exact(in_);
+
+      mlc_equal(mln_value(I), bool)::check();
+      mln_precondition(in.is_valid());
+
+      util::couple<util::array<box<mln_site(I)> >,
+		   util::array<box<mln_site(I)> > > tblboxes = lineboxes;
+
+//# ifndef SCRIBO_NDEBUG
+//      scribo::debug::save_table_image(in, tblboxes,
+//				      literal::red, "table.ppm");
+//# endif
+      scribo::debug::save_table_image(in, tblboxes,
+				      literal::red, "table-raw.ppm");
+
+      util::array<int> rows = align_lines_horizontaly(in, tblboxes.second(), 5);
+      util::array<int> cols = align_lines_verticaly(in, tblboxes.first(), 5);
+
+# ifndef SCRIBO_NDEBUG
+      scribo::debug::save_table_image(in, tblboxes,
+				      literal::red, "table-aligned.ppm");
+# endif
+
+      repair_vertical_lines(in, tblboxes, 30);
+      repair_horizontal_lines(in, tblboxes, 30);
+
+# ifndef SCRIBO_NDEBUG
+      scribo::debug::save_table_image(in, tblboxes,
+				      literal::red, "table-repaired.ppm");
+# endif
+
+      // Connect vertical lines with horizontal lines.
+      connect_vertical_lines(rows, tblboxes, in, max_dist_lines);
+      connect_horizontal_lines(cols, tblboxes, in, max_dist_lines);
+
+# ifndef SCRIBO_NDEBUG
+      scribo::debug::save_table_image(in, tblboxes,
+				      literal::red, "table-connected.ppm");
+# endif
+
+
+      mln_ch_value(I,bool) res;
+      initialize(res, in);
+      data::fill(res, false);
+      for_all_components(i, tblboxes.first())
+	mln::draw::box(res, tblboxes.first()[i], true);
+      for_all_components(i, tblboxes.second())
+	mln::draw::box(res, tblboxes.second()[i], true);
+
+      mln_ch_value(I,V) lbl = labeling::background(res, c8(), ncells);
+
+//# ifndef SCRIBO_NDEBUG
+//      scribo::debug::save_table_image(in, tblboxes,
+//				      literal::red, "table-connected.ppm");
+//# endif
+
+      trace::exiting("scribo::table::rebuild");
+      return lbl;
+    }
+
+
+# endif // ! MLN_INCLUDE_ONLY
+
+  } // end of namespace scribo::table
+
+} // end of namespace scribo
+
+#endif // ! SCRIBO_TABLE_REBUILD_HH
diff --git a/milena/sandbox/scribo/table/repair_horizontal_lines.hh b/milena/sandbox/scribo/table/repair_horizontal_lines.hh
index 7c1edbd..e871480 100644
--- a/milena/sandbox/scribo/table/repair_horizontal_lines.hh
+++ b/milena/sandbox/scribo/table/repair_horizontal_lines.hh
@@ -59,9 +59,9 @@ namespace scribo
     template <typename I>
     void
     repair_horizontal_lines(const Image<I>& input,
-			  util::couple<util::array<box<mln_site(I)> >,
-				       util::array<box<mln_site(I)> > >& tableboxes,
-			  unsigned max_discontinuity);
+			    util::couple<util::array<box<mln_site(I)> >,
+					 util::array<box<mln_site(I)> > >& tableboxes,
+			    unsigned max_discontinuity);
 
 # ifndef MLN_INCLUDE_ONLY
 
diff --git a/milena/sandbox/scribo/src/extract_text_multiple_links.cc b/milena/sandbox/scribo/tests/filter/small_and_large_bboxes.cc
similarity index 87%
copy from milena/sandbox/scribo/src/extract_text_multiple_links.cc
copy to milena/sandbox/scribo/tests/filter/small_and_large_bboxes.cc
index 9b181e6..2cf7ebc 100644
--- a/milena/sandbox/scribo/src/extract_text_multiple_links.cc
+++ b/milena/sandbox/scribo/tests/filter/small_and_large_bboxes.cc
@@ -32,6 +32,7 @@
 #include <scribo/text/extract_bboxes.hh>
 #include <scribo/text/grouping/group_with_multiple_links.hh>
 #include <scribo/text/grouping/group_from_multiple_links.hh>
+#include <scribo/filter/small_components.hh>
 
 #include <scribo/debug/save_textbboxes_image.hh>
 #include <scribo/debug/save_linked_textbboxes_image.hh>
@@ -50,6 +51,8 @@ int main(int argc, char* argv[])
   if (argc < 1)
     return usage(argv[0]);
 
+  scribo::make::internal::debug_filename_prefix = argv[0];
+
   image2d<bool> input;
   io::pbm::load(input, argv[1]);
 
@@ -66,7 +69,7 @@ int main(int argc, char* argv[])
 					      literal::red, literal::cyan,
 					      "test_multiple_links_left_linked.ppm");
 
-  util::array< box<point2d> > grouped_textbboxes
+  util::array<box2d> grouped_textbboxes
     = text::grouping::group_from_multiple_links(textbboxes, g);
 
   std::cout << "AFTER - nbboxes = " << grouped_textbboxes.nelements() << std::endl;
@@ -74,5 +77,13 @@ int main(int argc, char* argv[])
   scribo::debug::save_textbboxes_image(input, grouped_textbboxes,
 				       literal::red,
 				       "test_multiple_links_grouped_text.ppm");
+
+  util::array<box2d> filtered_textbboxes
+    = scribo::filter::small_components(grouped_textbboxes, 6);
+
+  scribo::debug::save_textbboxes_image(input, filtered_textbboxes,
+				       literal::red,
+				       "test_multiple_links_filtered_text.ppm");
+
 }
 
diff --git a/milena/sandbox/scribo/tests/table/extract_lines_with_rank.cc b/milena/sandbox/scribo/tests/table/extract_lines_with_rank.cc
new file mode 100644
index 0000000..ed5ce3c
--- /dev/null
+++ b/milena/sandbox/scribo/tests/table/extract_lines_with_rank.cc
@@ -0,0 +1,36 @@
+#include <mln/essential/2d.hh>
+#include <scribo/table/extract_lines_with_rank.hh>
+#include <scribo/debug/save_table_image.hh>
+#include <mln/util/couple.hh>
+
+int main(int argc, char *argv[])
+{
+  using namespace mln;
+
+  if (argc < 2)
+  {
+    std::cout << "Usage: " << argv[0] << " <image.pbm>" << std::endl;
+    return 1;
+  }
+
+  image2d<bool> input;
+  io::pbm::load(input, argv[1]);
+
+  typedef util::couple<util::array<box2d>,
+		       util::array<box2d> > tblboxes_t;
+
+  tblboxes_t lineboxes;
+  lineboxes.first().append(make::box2d(0,0, 59,59));
+  lineboxes.first().append(make::box2d(0,28, 27, 32));
+  lineboxes.first().append(make::box2d(31,28, 59,32));
+  lineboxes.second().append(make::box2d(0,0, 59,59));
+  lineboxes.second().append(make::box2d(27,0, 31, 26));
+  lineboxes.second().append(make::box2d(27,34, 31,59));
+
+
+  tblboxes_t lineboxes_test = scribo::table::extract_lines_with_rank(input, c8(),
+				  value::label_16(), win::vline2d(11),
+				  win::hline2d(11), 2, 2);
+
+  mln_assertion(lineboxes == lineboxes_test);
+}
diff --git a/milena/sandbox/scribo/tests/table/repair_lines.cc b/milena/sandbox/scribo/tests/table/repair_lines.cc
new file mode 100644
index 0000000..ff5551c
--- /dev/null
+++ b/milena/sandbox/scribo/tests/table/repair_lines.cc
@@ -0,0 +1,45 @@
+#include <mln/essential/2d.hh>
+#include <scribo/table/repair_vertical_lines.hh>
+#include <scribo/table/repair_horizontal_lines.hh>
+#include <scribo/table/extract_lines_with_rank.hh>
+#include <scribo/debug/save_table_image.hh>
+#include <mln/util/couple.hh>
+
+int main(int argc, char *argv[])
+{
+  using namespace mln;
+
+  if (argc < 2)
+  {
+    std::cout << "Usage: " << argv[0] << " <image.pbm>" << std::endl;
+    return 1;
+  }
+
+  image2d<bool> input;
+  io::pbm::load(input, argv[1]);
+
+  typedef util::couple<util::array<box2d>,
+		       util::array<box2d> > tblboxes_t;
+
+  tblboxes_t lineboxes;
+  lineboxes.first().append(make::box2d(0,0, 1,1)); // Dummy value for component 0.
+  lineboxes.first().append(make::box2d(0,28, 27, 32));
+  lineboxes.first().append(make::box2d(31,28, 59,32));
+  lineboxes.second().append(make::box2d(0,0, 1,1)); // Dummy value for component 0.
+  lineboxes.second().append(make::box2d(27,0, 31, 26));
+  lineboxes.second().append(make::box2d(27,34, 31,59));
+
+
+//  tblboxes_t lineboxes = scribo::table::extract_lines_with_rank(input, c8(), value::label_16(), win::vline2d(11), win::hline2d(11), 2, 2);
+//
+//  std::cout << lineboxes.first() << std::endl;
+//  std::cout << lineboxes.second() << std::endl;
+
+  scribo::table::repair_vertical_lines(input, lineboxes, 31);
+  scribo::table::repair_horizontal_lines(input, lineboxes, 31);
+
+  mln_assertion(lineboxes.first().nelements() == 2);
+  mln_assertion(lineboxes.second().nelements() == 2);
+  mln_assertion(lineboxes.first()[1] == make::box2d(0,28, 59,32));
+  mln_assertion(lineboxes.second()[1] == make::box2d(27,0, 31,59));
+}
diff --git a/milena/sandbox/scribo/text/extract_bboxes.hh b/milena/sandbox/scribo/text/extract_bboxes.hh
index 0c88880..4a936b5 100644
--- a/milena/sandbox/scribo/text/extract_bboxes.hh
+++ b/milena/sandbox/scribo/text/extract_bboxes.hh
@@ -42,6 +42,8 @@
 # include <mln/util/array.hh>
 
 # include <scribo/core/component_bboxes.hh>
+# include <scribo/util/text.hh>
+# include <scribo/make/text.hh>
 
 namespace scribo
 {
@@ -58,8 +60,7 @@ namespace scribo
     /// \return an array of bounding boxes. The first bounding box is
     /// the background's.
     template <typename I, typename N, typename V>
-    inline
-    util::array< box<mln_site(I)> >
+    scribo::util::text<mln_ch_value(I,V)>
     extract_bboxes(const Image<I>& input_,
 		   const Neighborhood<N>& nbh, V& nbboxes);
 
@@ -68,7 +69,7 @@ namespace scribo
 
     template <typename I, typename N, typename V>
     inline
-    util::array< box<mln_site(I)> >
+    scribo::util::text<mln_ch_value(I,V)>
     extract_bboxes(const Image<I>& input_,
 		   const Neighborhood<N>& nbh, V& nbboxes)
     {
@@ -79,11 +80,13 @@ namespace scribo
       mlc_equal(mln_value(I), bool)::check();
       mln_precondition(input.is_valid());
 
-      typedef util::array< box<mln_site(I)> > bboxes_t;
-      bboxes_t bboxes = component_bboxes(input, nbh, nbboxes);
+      typedef mln::util::array< box<mln_site(I)> > bboxes_t;
+      typedef mln::util::couple<bboxes_t, mln_ch_value(I,V)> bboxes_and_lbl_t;
+      bboxes_and_lbl_t bboxes_and_lbl = component_bboxes(input, nbh, nbboxes);
 
       trace::exiting("scribo::text::extract_bboxes");
-      return bboxes;
+      return scribo::make::text(bboxes_and_lbl.first(),
+				bboxes_and_lbl.second(), nbboxes);
     }
 
 # endif // ! MLN_INCLUDE_ONLY
diff --git a/milena/sandbox/scribo/text/extract_lines.hh b/milena/sandbox/scribo/text/extract_lines.hh
new file mode 100644
index 0000000..6be2e37
--- /dev/null
+++ b/milena/sandbox/scribo/text/extract_lines.hh
@@ -0,0 +1,133 @@
+// Copyright (C) 2009 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.
+
+#ifndef SCRIBO_TEXT_EXTRACT_LINES_HH
+# define SCRIBO_TEXT_EXTRACT_LINES_HH
+
+/// \file scribo/text/extract_lines.hh
+///
+/// Extract line of text bounding boxes.
+
+
+# include <mln/core/concept/image.hh>
+# include <mln/core/site_set/box.hh>
+
+# include <mln/data/fill.hh>
+
+# include <mln/accu/bbox.hh>
+
+# include <mln/draw/box.hh>
+
+# include <mln/labeling/blobs.hh>
+# include <mln/labeling/compute.hh>
+
+# include <mln/util/array.hh>
+# include <mln/util/graph.hh>
+# include <mln/value/label_16.hh>
+
+# include <scribo/text/grouping/group_with_multiple_links.hh>
+# include <scribo/text/grouping/group_from_multiple_links.hh>
+# include <scribo/filter/small_components.hh>
+# include <scribo/util/text.hh>
+
+# include <scribo/debug/save_textbboxes_image.hh>
+# include <scribo/debug/save_linked_textbboxes_image.hh>
+
+namespace scribo
+{
+
+  namespace text
+  {
+
+    using namespace mln;
+
+
+    template <typename I, typename N, typename V>
+    scribo::util::text<mln_ch_value(I,V)>
+    extract_lines(const Image<I>& input_,
+		  const Neighborhood<N>& nbh_,
+		  V& nbboxes);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+    template <typename I, typename N, typename V>
+    scribo::util::text<mln_ch_value(I,V)>
+    extract_lines(const Image<I>& input_,
+		  const Neighborhood<N>& nbh_,
+		  V& nbboxes)
+    {
+      trace::entering("scribo::text::extract_lines");
+
+      const I& input = exact(input_);
+      const N& nbh = exact(nbh_);
+
+      mln_precondition(input.is_valid());
+      mln_precondition(nbh.is_valid());
+
+      scribo::util::text<mln_ch_value(I,V)> text
+	    = scribo::make::text(input, nbh, nbboxes);
+
+# ifndef SCRIBO_NDEBUG
+      debug::save_textbboxes_image(input, text.bboxes(), literal::red,
+				   scrib::make::debug_filename("character-bboxes.ppm"));
+# endif // ! SCRIBO_NDEBUG
+
+      //Link character bboxes to their left neighboor if possible.
+      mln::util::graph g
+	= text::grouping::group_with_multiple_links(text, 30);
+# ifndef SCRIBO_NDEBUG
+      debug::save_linked_textbboxes_image(input,
+					  text, g,
+					  literal::red, literal::cyan,
+					  scribo::make::debug_filename("multiple_links_left_linked.ppm"));
+# endif // ! SCRIBO_NDEBUG
+
+      //Merge character bboxes through a graph.
+      scribo::util::text<mln_ch_value(I,V)> grouped_text
+	  = text::grouping::group_from_multiple_links(text, g);
+
+# ifndef SCRIBO_NDEBUG
+      debug::save_textbboxes_image(input, grouped_text.bboxes(),
+				   literal::red,
+				   scribo::make::debug_filename("multiple_links_grouped_text.ppm"));
+# endif // ! SCRIBO_NDEBUG
+
+
+      trace::exiting("scribo::text::extract_lines");
+      return grouped_text;
+    }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+  } // end of namespace scribo::text
+
+} // end of namespace scribo
+
+#endif // ! SCRIBO_TEXT_EXTRACT_LINES_HH
+
diff --git a/milena/sandbox/scribo/text/grouping/group_from_double_link.hh b/milena/sandbox/scribo/text/grouping/group_from_double_link.hh
index d178a80..582abcd 100644
--- a/milena/sandbox/scribo/text/grouping/group_from_double_link.hh
+++ b/milena/sandbox/scribo/text/grouping/group_from_double_link.hh
@@ -41,10 +41,14 @@
 
 # include <mln/util/array.hh>
 
+# include <mln/fun/l2l/relabel.hh>
+
 # include <scribo/text/grouping/internal/find_root.hh>
 
 # include <scribo/core/macros.hh>
 
+# include <scribo/util/text.hh>
+
 
 namespace scribo
 {
@@ -56,42 +60,67 @@ namespace scribo
     {
 
       /// FIXME: Add much more doc!
-      template <typename P>
-      util::array< box<P> >
-      group_from_double_link(const util::array< box<P> >& textbboxes,
-			     util::array<unsigned>& left_link,
-			     util::array<unsigned>& right_link);
+      template <typename I>
+      scribo::util::text<I>
+      group_from_double_link(const scribo::util::text<I>& text,
+			     const mln::util::array<unsigned>& left_link,
+			     const mln::util::array<unsigned>& right_link);
 
 # ifndef MLN_INCLUDE_ONLY
 
-      template <typename P>
+      template <typename I>
       inline
-      util::array< box<P> >
-      group_from_double_link(const util::array< box<P> >& textbboxes,
-			     util::array<unsigned>& left_link,
-			     util::array<unsigned>& right_link)
+      scribo::util::text<I>
+      group_from_double_link(const scribo::util::text<I>& text,
+			     const mln::util::array<unsigned>& left_link,
+			     const mln::util::array<unsigned>& right_link)
       {
 	trace::entering("scribo::text::grouping::group_from_double_link");
 
 	mln_precondition(left_link.nelements() == right_link.nelements());
 
-	util::array< accu::bbox<P> > tboxes;
-	tboxes.resize(textbboxes.nelements());
-	for_all_components(i, textbboxes)
+	mln::util::array< accu::bbox<mln_site(I)> > tboxes;
+	tboxes.resize(text.bboxes().nelements());
+
+	mln::util::array<unsigned> left_parent = left_link;
+	for_all_components(i, left_parent)
+	  left_parent[i] = internal::find_root(left_parent, i);
+
+	fun::i2v::array<mln_value(I)> f(text.bboxes().nelements(),
+					literal::zero);
+	for_all_components(i, text.bboxes())
 	{
 	  unsigned nbh = right_link[left_link[i]];
 	  if (nbh == i)
-	    tboxes[left_link[i]].take(textbboxes[i]);
+	  {
+	    tboxes[left_parent[i]].take(text.bbox(i));
+	    f(i) = left_parent[left_link[i]];
+	  }
 	  else
-	    tboxes[i].take(textbboxes[i]);
+	  {
+	    f(i) = i;
+	    tboxes[i].take(text.bbox(i));
+	  }
 	}
 
-	util::array< box<P> > result;
+	// Update bounding boxes information.
+	mln::util::array< box<mln_site(I)> > bresult;
 	// component 0, the background, has an invalid box.
-	result.append(box<P>());
+	bresult.append(box<mln_site(I)>());
 	for_all_components(i, tboxes)
 	  if (tboxes[i].is_valid())
-	    result.append(tboxes[i]);
+	    bresult.append(tboxes[i]);
+
+	// Update label image.
+	mln_value(I) new_nbboxes;
+	I new_lbl = labeling::relabel(text.label_image(),
+				      text.nbboxes(),
+				      mln::make::relabelfun(f, text.nbboxes(),
+							    new_nbboxes));
+
+	mln_assertion(bresult.nelements() == new_nbboxes.next());
+
+	scribo::util::text<I> result(bresult, new_lbl, new_nbboxes);
 
 	trace::exiting("scribo::text::grouping::group_from_double_link");
 	return result;
diff --git a/milena/sandbox/scribo/text/grouping/group_from_multiple_links.hh b/milena/sandbox/scribo/text/grouping/group_from_multiple_links.hh
index 612fb87..059fa22 100644
--- a/milena/sandbox/scribo/text/grouping/group_from_multiple_links.hh
+++ b/milena/sandbox/scribo/text/grouping/group_from_multiple_links.hh
@@ -47,6 +47,9 @@
 # include <mln/util/array.hh>
 
 # include <scribo/core/macros.hh>
+# include <scribo/util/text.hh>
+# include <scribo/make/text.hh>
+
 
 namespace scribo
 {
@@ -58,9 +61,9 @@ namespace scribo
     {
 
       /// FIXME: Add much more doc!
-      template <typename G, typename P>
-      util::array<box<P> >
-      group_from_multiple_links(util::array<box<P> >& textbboxes,
+      template <typename I, typename G>
+      scribo::util::text<I>
+      group_from_multiple_links(const scribo::util::text<I>& text,
 				const Graph<G>& g_);
 
 # ifndef MLN_INCLUDE_ONLY
@@ -71,14 +74,15 @@ namespace scribo
 
 	/// Functor to be passed to depth_first_search.
 	/// Map each component vertex with its representative vertex id.
+	template <typename V>
 	struct map_vertex_to_component_id_functor
 	{
-	    template <typename G>
-	    void init(const Graph<G>& g)
-	    {
-	      vertextocomp.resize(exact(g).v_nmax(), mln_max(unsigned));
-	      ncomp = 0;
-	    }
+	  template <typename G>
+	  void init(const Graph<G>& g)
+	  {
+	    vertextocomp.resize(exact(g).v_nmax(), mln_max(V));
+	    ncomp = 0;
+	  }
 
 	  void final()
 	  {}
@@ -96,23 +100,23 @@ namespace scribo
 	  {}
 
 	  bool to_be_treated(unsigned id)
-	  { return vertextocomp(id) == mln_max(unsigned); }
+	  { return vertextocomp(id) == mln_max(V); }
 
 	  bool to_be_queued(unsigned id)
 	  { return to_be_treated(id); }
 
 	  unsigned ncomp;
-	  fun::i2v::array<unsigned> vertextocomp;
+	  fun::l2l::relabel<V> vertextocomp;
 	};
 
       } // end of namespace scribo::text::grouping::internal
 
 
 
-      template <typename G, typename P>
+      template <typename I, typename G>
       inline
-      util::array<box<P> >
-      group_from_multiple_links(util::array<box<P> >& textbboxes,
+      scribo::util::text<I>
+      group_from_multiple_links(const scribo::util::text<I>& text,
 				const Graph<G>& g_)
       {
 	trace::entering("scribo::text::grouping::group_from_multiple_links");
@@ -121,25 +125,34 @@ namespace scribo
 
 	mln_assertion(g.is_valid());
 
-	internal::map_vertex_to_component_id_functor f;
+	internal::map_vertex_to_component_id_functor<mln_value(I)> f;
 	canvas::browsing::depth_first_search(g, f);
 
-	util::array< accu::bbox<P> > tboxes;
-	tboxes.resize(textbboxes.nelements());
-	for_all_components(i, textbboxes)
-	  tboxes[f.vertextocomp(i)].take(textbboxes[i]);
+	mln::util::array< accu::bbox<mln_site(I)> > tboxes;
+	tboxes.resize(text.nbboxes().next());
+	for_all_components(i, text.bboxes())
+	  tboxes[f.vertextocomp(i)].take(text.bbox(i));
 
-	util::array< box<P> > result;
+	// Update bounding boxes.
+	mln::util::array<box<mln_site(I)> > bresult;
 	// Component 0 - the background has not valid bboxes.
-	result.append(box<P>());
-	for_all_components(i, textbboxes)
+	bresult.append(box<mln_site(I)>());
+	for_all_components(i, text.bboxes())
 	  if (tboxes[i].is_valid())
-	    result.append(tboxes[i].to_result());
+	    bresult.append(tboxes[i].to_result());
+
+	mln_assertion(bresult.nelements() == f.ncomp);
+
+	// Update label image.
+	mln_value(I) new_nbboxes;
+	I new_lbl = labeling::relabel(text.label_image(),
+				      text.nbboxes(),
+				      f.vertextocomp);
 
-	mln_assertion(result.nelements() == f.ncomp);
+	mln_assertion(new_nbboxes.next() == bresult.nelements());
 
 	trace::exiting("scribo::text::grouping::group_from_multiple_links");
-	return result;
+	return scribo::make::text(bresult, new_lbl, new_nbboxes);
       }
 
 
diff --git a/milena/sandbox/scribo/text/grouping/group_from_single_link.hh b/milena/sandbox/scribo/text/grouping/group_from_single_link.hh
index eccde96..43bb7b1 100644
--- a/milena/sandbox/scribo/text/grouping/group_from_single_link.hh
+++ b/milena/sandbox/scribo/text/grouping/group_from_single_link.hh
@@ -44,6 +44,7 @@
 # include <scribo/text/grouping/internal/find_root.hh>
 
 # include <scribo/core/macros.hh>
+# include <scribo/util/text.hh>
 
 
 namespace scribo
@@ -56,38 +57,46 @@ namespace scribo
     {
 
       /// FIXME: Add much more doc!
-      template <typename P>
-      util::array< box<P> >
-      group_from_single_link(const util::array< box<P> >& textbboxes,
-			     util::array<unsigned>& link_array);
+      template <typename I>
+      scribo::util::text<I>
+      group_from_single_link(const scribo::util::text<I>& text,
+			     const mln::util::array<unsigned>& link_array);
 
 # ifndef MLN_INCLUDE_ONLY
 
-      template <typename P>
+      template <typename I>
       inline
-      util::array< box<P> >
-      group_from_single_link(const util::array< box<P> >& textbboxes,
-			     util::array<unsigned>& link_array)
+      scribo::util::text<I>
+      group_from_single_link(const scribo::util::text<I>& text,
+			     const mln::util::array<unsigned>& link_array)
       {
 	trace::entering("scribo::text::grouping::group_from_single_link");
 
-	for (unsigned i = 0; i < link_array.nelements(); ++i)
-	  link_array[i] = internal::find_root(link_array, i);
+	mln_precondition(text.is_valid());
+	mln_precondition(link_array.nelements() == text.nbboxes().next());
+	mln_precondition(link_array.nelements() == text.bboxes().nelements());
 
-	util::array< accu::bbox<P> > tboxes;
-	tboxes.resize(textbboxes.nelements());
-	for_all_components(i, textbboxes)
-	  tboxes[link_array[i]].take(textbboxes[i]);
+	mln::util::array<unsigned> parent_array = link_array;
+	for_all_components(i, parent_array)
+	  internal::find_root(parent_array, i);
 
-	util::array< box<P> > result;
+	mln::util::array< accu::bbox<mln_site(I)> > tboxes;
+	tboxes.resize(text.nbboxes().next());
+	for_all_components(i, text.bboxes())
+	  tboxes[parent_array[i]].take(text.bbox(i));
+
+	mln::util::array< box<mln_site(I)> > result;
 	// component 0, the background, has an invalid box.
-	result.append(box<P>());
+	result.append(box<mln_site(I)>());
 	for_all_components(i, tboxes)
 	  if (tboxes[i].is_valid())
 	    result.append(tboxes[i]);
 
+	I lbl = labeling::relabel(text.label_image(), text.nbboxes(),
+				  convert::to<fun::l2l::relabel<mln_value(I)> >(parent_array));
+	mln_value(I) new_nbboxes = result.nelements() - 1;
 	trace::exiting("scribo::text::grouping::group_from_single_link");
-	return result;
+	return scribo::make::text(result, lbl, new_nbboxes);
       }
 
 # endif // ! MLN_INCLUDE_ONLY
diff --git a/milena/sandbox/scribo/text/grouping/group_with_multiple_links.hh b/milena/sandbox/scribo/text/grouping/group_with_multiple_links.hh
index 2f769fc..236cf16 100644
--- a/milena/sandbox/scribo/text/grouping/group_with_multiple_links.hh
+++ b/milena/sandbox/scribo/text/grouping/group_with_multiple_links.hh
@@ -43,6 +43,7 @@
 # include <scribo/core/macros.hh>
 # include <scribo/text/grouping/internal/init_link_array.hh>
 # include <scribo/text/grouping/internal/update_link_graph.hh>
+# include <scribo/util/text.hh>
 
 namespace scribo
 {
@@ -55,44 +56,34 @@ namespace scribo
 
       /// Group character bounding boxes with multiple links.
       /// Look up for neighbors on the left of each box.
-      template <typename I, typename N, typename V>
-      util::graph
-      group_with_multiple_links(const Image<I>& input_,
-				const Neighborhood<N>& nbh, V& nbboxes,
-				const util::array<box<mln_site(I)> >& textbboxes,
+      template <typename I>
+      mln::util::graph
+      group_with_multiple_links(const scribo::util::text<I>& text,
 				unsigned neighb_max_distance);
 
 # ifndef MLN_INCLUDE_ONLY
 
-      template <typename I, typename N, typename V>
-      util::graph
-      group_with_multiple_links(const Image<I>& input_,
-				const Neighborhood<N>& nbh, V& nbboxes,
-				const util::array<box<mln_site(I)> >& textbboxes,
+      template <typename I>
+      inline
+      mln::util::graph
+      group_with_multiple_links(const scribo::util::text<I>& text,
 				unsigned neighb_max_distance)
       {
 	trace::entering("scribo::text::grouping::group_with_multiple_links");
 
-	const I& input = exact(input_);
+	mln::util::graph g(text.nbboxes().next());
 
-	mlc_equal(mln_value(I), bool)::check();
-	mln_assertion(input.is_valid());
-
-	typedef mln_ch_value(I,V) lbl_t;
-	lbl_t lbl = labeling::blobs(input, nbh, nbboxes);
-
-	util::graph g(nbboxes.next());
-
-	for_all_ncomponents(i, nbboxes)
+	for_all_ncomponents(i, text.nbboxes())
 	{
-	  unsigned midcol = (textbboxes[i].pmax().col()
-				- textbboxes[i].pmin().col()) / 2;
+	  unsigned midcol = (text.bbox(i).pmax().col()
+				- text.bbox(i).pmin().col()) / 2;
 	  int dmax = midcol + neighb_max_distance;
-	  mln_site(I) c = textbboxes[i].center();
+	  mln_site(I) c = text.bbox(i).center();
 
 	  /// First site on the right of the central site
 	  mln_site(I) p = c + right;
 
+	  const I& lbl = text.label_image();
 	  while (lbl.domain().has(p) && (lbl(p) == literal::zero || lbl(p) == i)
 	      && math::abs(p.col() - c.col()) < dmax)
 	    ++p.col();
diff --git a/milena/sandbox/scribo/text/grouping/group_with_single_left_link.hh b/milena/sandbox/scribo/text/grouping/group_with_single_left_link.hh
index f1a3013..ca1a8da 100644
--- a/milena/sandbox/scribo/text/grouping/group_with_single_left_link.hh
+++ b/milena/sandbox/scribo/text/grouping/group_with_single_left_link.hh
@@ -46,6 +46,8 @@
 # include <scribo/core/macros.hh>
 # include <scribo/text/grouping/internal/init_link_array.hh>
 # include <scribo/text/grouping/internal/update_link_array.hh>
+# include <scribo/text/grouping/internal/find_root.hh>
+# include <scribo/util/text.hh>
 
 //FIXME: not generic.
 # include <mln/core/alias/dpoint2d.hh>
@@ -63,46 +65,34 @@ namespace scribo
       /// if possible.
       /// Iterate to the right but link boxes to the left.
       ///
-      /// \return an util::array. Map a bounding box to its left neighbor.
-      template <typename I, typename N, typename V>
+      /// \return an mln::util::array. Map a bounding box to its left neighbor.
+      template <typename L>
       inline
-      util::array<unsigned>
-      group_with_single_left_link(const Image<I>& input_,
-				  const Neighborhood<N>& nbh, V& nbboxes,
-				  const util::array< box<mln_site(I)> >& textbboxes,
+      mln::util::array<unsigned>
+      group_with_single_left_link(const scribo::util::text<L>& text,
 				  unsigned neighb_max_distance);
 
 # ifndef MLN_INCLUDE_ONLY
 
-      template <typename I, typename N, typename V>
+      template <typename L>
       inline
-      util::array<unsigned>
-      group_with_single_left_link(const Image<I>& input_,
-				  const Neighborhood<N>& nbh_, V& nbboxes,
-				  const util::array< box<mln_site(I)> >& textbboxes,
+      mln::util::array<unsigned>
+      group_with_single_left_link(const scribo::util::text<L>& text,
 				  unsigned neighb_max_distance)
       {
 	trace::entering("scribo::text::grouping::group_with_single_left_link");
 
-	const I& input = exact(input_);
-	const N& nbh = exact(nbh_);
+	mln_precondition(text.is_valid());
 
-        mlc_equal(mln_value(I), bool)::check();
-	mln_assertion(input.is_valid());
-	mln_precondition(nbh.is_valid());
-
-	typedef mln_ch_value(I,V) lbl_t;
-	lbl_t lbl = labeling::blobs(input, nbh, nbboxes);
-
-	util::array<unsigned> left_link(nbboxes.next());
+	mln::util::array<unsigned> left_link(text.nbboxes().next());
 	internal::init_link_array(left_link);
 
-	for_all_ncomponents(i, nbboxes)
+	for_all_ncomponents(i, text.nbboxes())
 	{
-	  unsigned midcol = (textbboxes[i].pmax().col()
-				- textbboxes[i].pmin().col()) / 2;
+	  unsigned midcol = (text.bbox(i).pmax().col()
+				- text.bbox(i).pmin().col()) / 2;
 	  int dmax = midcol + neighb_max_distance;
-	  mln_site(I) c = textbboxes[i].center();
+	  mln_site(L) c = text.bbox(i).center();
 
 	  ///
 	  /// Find a neighbor on the right
@@ -110,14 +100,15 @@ namespace scribo
 
 	  ///FIXME: the following code is not generic...
 	  /// First site on the right of the central site
-	  mln_site(I) p = c + right;
+	  mln_site(L) p = c + right;
 
-	  while (lbl.domain().has(p) && (lbl(p) == literal::zero || lbl(p) == i)
+	  const L& lbl = text.label_image();
+	  while (lbl.domain().has(p) && (lbl(p) == literal::zero || lbl(p) == i ||
+		left_link[i] == lbl(p))
 	      && math::abs(p.col() - c.col()) < dmax)
 	    ++p.col();
 
 	  internal::update_link_array(lbl, left_link, p, c, i, dmax);
-
 	}
 
 	trace::exiting("scribo::text::grouping::group_with_single_left_link");
diff --git a/milena/sandbox/scribo/text/grouping/group_with_single_right_link.hh b/milena/sandbox/scribo/text/grouping/group_with_single_right_link.hh
index 7f1eeac..5740b09 100644
--- a/milena/sandbox/scribo/text/grouping/group_with_single_right_link.hh
+++ b/milena/sandbox/scribo/text/grouping/group_with_single_right_link.hh
@@ -46,6 +46,8 @@
 # include <scribo/core/macros.hh>
 # include <scribo/text/grouping/internal/init_link_array.hh>
 # include <scribo/text/grouping/internal/update_link_array.hh>
+# include <scribo/text/grouping/internal/find_root.hh>
+# include <scribo/util/text.hh>
 
 //FIXME: not generic.
 # include <mln/core/alias/dpoint2d.hh>
@@ -63,46 +65,34 @@ namespace scribo
       /// if possible.
       /// Iterate to the right but link boxes to the right.
       ///
-      /// \return an util::array. Map a bounding box to its right neighbor.
-      template <typename I, typename N, typename V>
+      /// \return an mln::util::array. Map a bounding box to its right neighbor.
+      template <typename L>
       inline
-      util::array<unsigned>
-      group_with_single_right_link(const Image<I>& input_,
-				   const Neighborhood<N>& nbh, V& nbboxes,
-				   const util::array< box<mln_site(I)> >& textbboxes,
+      mln::util::array<unsigned>
+      group_with_single_right_link(const scribo::util::text<L>& text,
 				   unsigned neighb_max_distance);
 
 # ifndef MLN_INCLUDE_ONLY
 
-      template <typename I, typename N, typename V>
+      template <typename L>
       inline
-      util::array<unsigned>
-      group_with_single_right_link(const Image<I>& input_,
-				   const Neighborhood<N>& nbh_, V& nbboxes,
-				   const util::array< box<mln_site(I)> >& textbboxes,
+      mln::util::array<unsigned>
+      group_with_single_right_link(const scribo::util::text<L>& text,
 				   unsigned neighb_max_distance)
       {
 	trace::entering("scribo::text::grouping::group_with_single_right_link");
 
-	const I& input = exact(input_);
-	const N& nbh = exact(nbh_);
+	mln_precondition(text.is_valid());
 
-        mlc_equal(mln_value(I), bool)::check();
-	mln_assertion(input.is_valid());
-	mln_precondition(nbh.is_valid());
-
-	typedef mln_ch_value(I,V) lbl_t;
-	lbl_t lbl = labeling::blobs(input, nbh, nbboxes);
-
-	util::array<unsigned> right_link(nbboxes.next());
+	mln::util::array<unsigned> right_link(text.nbboxes().next());
 	internal::init_link_array(right_link);
 
-	for_all_ncomponents(i, nbboxes)
+	for_all_ncomponents(i, text.nbboxes())
 	{
-	  unsigned midcol = (textbboxes[i].pmax().col()
-				- textbboxes[i].pmin().col()) / 2;
+	  unsigned midcol = (text.bbox(i).pmax().col()
+				- text.bbox(i).pmin().col()) / 2;
 	  int dmax = midcol + neighb_max_distance;
-	  mln_site(I) c = textbboxes[i].center();
+	  mln_site(L) c = text.bbox(i).center();
 
 	  ///
 	  /// Find a neighbor on the left
@@ -110,14 +100,15 @@ namespace scribo
 
 	  ///FIXME: the following code is not generic...
 	  /// First site on the left of the central site
-	  mln_site(I) p = c + left;
+	  mln_site(L) p = c + left;
 
-	  while (lbl.domain().has(p) && (lbl(p) == literal::zero || lbl(p) == i)
-	      && math::abs(p.col() - c.col()) < dmax)
+	  const L& lbl = text.label_image();
+	  while (lbl.domain().has(p) && (lbl(p) == literal::zero
+		    || lbl(p) == i || right_link[i] == lbl(p))
+		 && math::abs(p.col() - c.col()) < dmax)
 	    --p.col();
 
 	  internal::update_link_array(lbl, right_link, p, c, i, dmax);
-
 	}
 
 	trace::exiting("scribo::text::grouping::group_with_single_right_link");
diff --git a/milena/sandbox/scribo/text/grouping/internal/find_root.hh b/milena/sandbox/scribo/text/grouping/internal/find_root.hh
index 0b1e307..9e3eedf 100644
--- a/milena/sandbox/scribo/text/grouping/internal/find_root.hh
+++ b/milena/sandbox/scribo/text/grouping/internal/find_root.hh
@@ -52,13 +52,13 @@ namespace scribo
 
 	/// Find root in a parent array arrays.
 	unsigned
-        find_root(util::array<unsigned>& parent, unsigned x);
+        find_root(mln::util::array<unsigned>& parent, unsigned x);
 
 # ifndef MLN_INCLUDE_ONLY
 
 	inline
 	unsigned
-        find_root(util::array<unsigned>& parent, unsigned x)
+        find_root(mln::util::array<unsigned>& parent, unsigned x)
         {
           if (parent[x] == x)
 	    return x;
diff --git a/milena/sandbox/scribo/text/grouping/internal/init_link_array.hh b/milena/sandbox/scribo/text/grouping/internal/init_link_array.hh
index ba197f9..7e4f751 100644
--- a/milena/sandbox/scribo/text/grouping/internal/init_link_array.hh
+++ b/milena/sandbox/scribo/text/grouping/internal/init_link_array.hh
@@ -41,6 +41,8 @@
 namespace scribo
 {
 
+  using namespace mln;
+
   namespace text
   {
 
@@ -51,13 +53,14 @@ namespace scribo
       {
 
 	/// Initialize a link array.
-	void init_link_array(util::array<unsigned>& link_array);
+	void
+	init_link_array(mln::util::array<unsigned>& link_array);
 
 # ifndef MLN_INCLUDE_ONLY
 
         inline
         void
-	init_link_array(util::array<unsigned>& link_array)
+	init_link_array(mln::util::array<unsigned>& link_array)
 	{
 	  for (unsigned i = 0; i < link_array.nelements(); ++i)
 	    link_array[i] = i;
diff --git a/milena/sandbox/scribo/text/grouping/internal/update_link_array.hh b/milena/sandbox/scribo/text/grouping/internal/update_link_array.hh
index 242d18f..501d6f2 100644
--- a/milena/sandbox/scribo/text/grouping/internal/update_link_array.hh
+++ b/milena/sandbox/scribo/text/grouping/internal/update_link_array.hh
@@ -56,7 +56,7 @@ namespace scribo
 	/// on the right of the current bbox.
 	template <typename I>
 	void
-	update_link_array(const Image<I>& lbl, util::array<unsigned>& link_array,
+	update_link_array(const Image<I>& lbl, mln::util::array<unsigned>& link_array,
 			  const mln_site(I)& p, const mln_site(I)& c,
 			  unsigned i, int dmax);
 
@@ -65,7 +65,7 @@ namespace scribo
 	template <typename I>
 	inline
 	void
-	update_link_array(const Image<I>& lbl_, util::array<unsigned>& link_array,
+	update_link_array(const Image<I>& lbl_, mln::util::array<unsigned>& link_array,
 			  const mln_site(I)& p, const mln_site(I)& c,
 			  unsigned i, int dmax)
 	{
@@ -75,7 +75,8 @@ namespace scribo
 	  mln_assertion(lbl.is_valid());
 
 	  if (lbl.domain().has(p) && lbl(p) != literal::zero && lbl(p) != i
-	      && (math::abs(p.col() - c.col())) < dmax && link_array[lbl(p)] == lbl(p))
+	      && (math::abs(p.col() - c.col())) < dmax && link_array[lbl(p)] == lbl(p)
+	      && link_array[i] != lbl(p))
 	    link_array[lbl(p)] = i;
 	}
 
diff --git a/milena/sandbox/scribo/text/grouping/internal/update_link_graph.hh b/milena/sandbox/scribo/text/grouping/internal/update_link_graph.hh
index e31c5e8..f572a47 100644
--- a/milena/sandbox/scribo/text/grouping/internal/update_link_graph.hh
+++ b/milena/sandbox/scribo/text/grouping/internal/update_link_graph.hh
@@ -52,7 +52,7 @@ namespace scribo
 	/// Update graph edges if a valid neighbor is found.
 	template <typename I>
 	void
-	update_link_graph(Image<I>& lbl_, util::graph& g,
+	update_link_graph(const Image<I>& lbl_, mln::util::graph& g,
 			  const mln_site(I)& p, const mln_site(I)& c,
 			  unsigned i, int dmax);
 
@@ -63,7 +63,7 @@ namespace scribo
 	template <typename I>
 	inline
 	void
-	update_link_graph(Image<I>& lbl_, util::graph& g,
+	update_link_graph(const Image<I>& lbl_, mln::util::graph& g,
 			  const mln_site(I)& p, const mln_site(I)& c,
 			  unsigned i, int dmax)
 	{
@@ -72,7 +72,7 @@ namespace scribo
 	  mlc_is_a(mln_value(I), mln::value::Symbolic)::check();
 	  mln_precondition(exact(lbl).is_valid());
 
-	  if (lbl.domain().has(p) && lbl(p) != 0u && lbl(p) != i
+	  if (lbl.domain().has(p) && lbl(p) != literal::zero && lbl(p) != i
 	      && (math::abs(p.col() - c.col())) < dmax)
 	    g.add_edge(lbl(p), i);
 	}
diff --git a/milena/sandbox/scribo/text/recognition.hh b/milena/sandbox/scribo/text/recognition.hh
index 98c3b67..c11ed54 100644
--- a/milena/sandbox/scribo/text/recognition.hh
+++ b/milena/sandbox/scribo/text/recognition.hh
@@ -54,6 +54,8 @@ namespace scribo
   namespace text
   {
 
+    using namespace mln;
+
     /// Passes the text bboxes to Tesseract (OCR) and store the result in
     /// an image of characters.
     ///
@@ -71,8 +73,8 @@ namespace scribo
     template <typename I, typename N, typename V>
     mln_ch_value(I,char)
     text_recognition(const Image<I>& input_,
-		     const Neighborhood<N>& nbh_, V& nbboxes,
-		     const util::array< box<mln_site(I)> >& textbboxes,
+		     const Neighborhood<N>& nbh_, const V& label_type,
+		     const scribo::util::text_bboxes<mln_ch_value(I,V)>& textbboxes,
 		     const char *language);
 
 
@@ -81,8 +83,8 @@ namespace scribo
     template <typename I, typename N, typename V>
     mln_ch_value(I,char)
     text_recognition(const Image<I>& input_,
-		     const Neighborhood<N>& nbh_, V& nbboxes,
-		     const util::array< box<mln_site(I)> >& textbboxes,
+		     const Neighborhood<N>& nbh_, const V& label_type,
+		     const scribo::util::text_bboxes<mln_ch_value(I,V)>& textbboxes,
 		     const char *language)
     {
       trace::entering("scribo::text::recognition");
@@ -93,6 +95,7 @@ namespace scribo
       mln_precondition(input.is_valid());
       mln_precondition(nbh.is_valid());
 
+      V nbboxes;
       mln_ch_value(I,V) lbl = labeling::blobs(input, nbh, nbboxes);
 
       /// Use text bboxes with Tesseract
@@ -104,7 +107,7 @@ namespace scribo
       {
 	if (textbboxes[i].is_valid())
 	{
-	  mln_ch_value(I,bool) b(textbboxes[i], 0);
+	  mln_ch_value(I,bool) b(textbboxes.bboxes()[i], 0);
 	  data::fill(b, false);
 	  data::fill((b | (pw::value(lbl) == pw::cst(i))).rw(), true);
 
@@ -119,9 +122,9 @@ namespace scribo
 
 
 
-	  mln_site(I) p = textbboxes[i].center();
-	  p.col() -= (textbboxes[i].pmax().col()
-			  - textbboxes[i].pmin().col()) / 2;
+	  mln_site(I) p = textbboxes.bboxes[i].center();
+	  p.col() -= (textbboxes.bboxes()[i].pmax().col()
+			  - textbboxes.bboxes()[i].pmin().col()) / 2;
 	  if (s != 0)
 	    debug::put_word(txt, p, s);
 	  free(s);
diff --git a/milena/sandbox/scribo/util/text.hh b/milena/sandbox/scribo/util/text.hh
new file mode 100644
index 0000000..2619a79
--- /dev/null
+++ b/milena/sandbox/scribo/util/text.hh
@@ -0,0 +1,189 @@
+// Copyright (C) 2009 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.
+
+#ifndef SCRIBO_UTIL_TEXT_HH
+# define SCRIBO_UTIL_TEXT_HH
+
+/// \file scribo/util/text.hh
+///
+/// A class representing text bounding boxes and their associated
+/// labeled image.
+
+# include <mln/core/image/image2d.hh>
+# include <mln/core/concept/proxy.hh>
+# include <mln/core/site_set/box.hh>
+# include <mln/value/label_16.hh>
+# include <mln/util/couple.hh>
+# include <mln/util/array.hh>
+
+namespace scribo
+{
+
+  using namespace mln;
+
+  namespace util
+  {
+
+    /// Store text bounding boxes and their associated labeled image.
+    template <typename L>
+    class text
+    {
+    public:
+      typedef mln_site(L) site;
+      typedef mln::util::array<box<site> > boxes_t;
+
+      text();
+      text(const mln::util::array<box<mln_site(L)> >& bboxes,
+		  const Image<L>& lbl,
+		  const mln_value(L)& nbboxes);
+
+      const L& label_image() const;
+      L& label_image();
+
+      const mln_value(L)& nbboxes() const;
+      mln_value(L)& nbboxes();
+
+      const boxes_t& bboxes() const;
+      boxes_t& bboxes();
+
+      const box<mln_site(L)>& bbox(unsigned i) const;
+      box<mln_site(L)>& bbox(unsigned i);
+
+      bool is_valid() const;
+
+    private:
+      boxes_t bboxes_;
+      L lbl_;
+      mln_value(L) nbboxes_;
+    };
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+
+    template <typename L>
+    inline
+    text<L>::text()
+    {
+    }
+
+    template <typename L>
+    inline
+    text<L>::text(const mln::util::array<box<mln_site(L)> >& bboxes,
+		  const Image<L>& lbl,
+		  const mln_value(L)& nbboxes)
+      : bboxes_(bboxes), lbl_(exact(lbl)), nbboxes_(nbboxes)
+    {
+      mln_assertion(bboxes.nelements() == nbboxes.next());
+    }
+
+    template <typename L>
+    inline
+    const L&
+    text<L>::label_image() const
+    {
+      mln_precondition(lbl_.is_valid());
+      return lbl_;
+    }
+
+    template <typename L>
+    inline
+    L&
+    text<L>::label_image()
+    {
+      return lbl_;
+    }
+
+    template <typename L>
+    inline
+    const mln_value(L)&
+    text<L>::nbboxes() const
+    {
+      return nbboxes_;
+    }
+
+    template <typename L>
+    inline
+    mln_value(L)&
+    text<L>::nbboxes()
+    {
+      return nbboxes_;
+    }
+
+    template <typename L>
+    inline
+    const typename text<L>::boxes_t&
+    text<L>::bboxes() const
+    {
+      mln_precondition(bboxes_.nelements() == nbboxes_.next());
+      return bboxes_;
+    }
+
+    template <typename L>
+    inline
+    typename text<L>::boxes_t&
+    text<L>::bboxes()
+    {
+      return bboxes_;
+    }
+
+    template <typename L>
+    inline
+    const box<mln_site(L)>&
+    text<L>::bbox(unsigned i) const
+    {
+      mln_precondition(bboxes_.nelements() == nbboxes_.next());
+      mln_precondition(i < bboxes_.nelements());
+      return bboxes_[i];
+    }
+
+    template <typename L>
+    inline
+    box<mln_site(L)>&
+    text<L>::bbox(unsigned i)
+    {
+      mln_precondition(bboxes_.nelements() == nbboxes_.next());
+      mln_precondition(i < bboxes_.nelements());
+      return bboxes_[i];
+    }
+
+    template <typename L>
+    inline
+    bool
+    text<L>::is_valid() const
+    {
+      return lbl_.is_valid() && bboxes_.nelements() == nbboxes_.next();
+    }
+
+
+# endif // ! MLN_INCLUDE_ONLY
+
+  } // end of namespace scribo::util
+
+} // end of namespace scribo
+
+#endif // ! SCRIBO_UTIL_TEXT_HH
-- 
1.5.6.5
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                    
                        ---
 ChangeLog    |    4 ++++
 configure.ac |    1 +
 2 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index 58297c6..076c1f3 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2009-03-19  Guillaume Lazzara  <lazzara(a)lrde.epita.fr>
+
+	* configure.ac: configure tests/accu/site_set.
+
 2009-03-18  Guillaume Lazzara  <lazzara(a)lrde.epita.fr>
 
 	* configure.ac: configure tests/accu/image.
diff --git a/configure.ac b/configure.ac
index 118ce2b..3eac78d 100644
--- a/configure.ac
+++ b/configure.ac
@@ -185,6 +185,7 @@ AC_CONFIG_FILES([
   milena/tests/Makefile
     milena/tests/accu/Makefile
     milena/tests/accu/image/Makefile
+    milena/tests/accu/site_set/Makefile
     milena/tests/algebra/Makefile
     milena/tests/arith/Makefile
     milena/tests/binarization/Makefile
-- 
1.5.6.5
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                    
                        	* mln/accu/all.hh,
	* mln/accu/essential.hh,
	* mln/accu/image/essential.hh,
	* mln/accu/site_set/all.hh,
	* mln/accu/site_set/essential.hh: update all and essential includes.
	* mln/accu/site_set/rectangularity.hh: new accumulator.
	* tests/accu/Makefile.am,
	* tests/accu/site_set/Makefile.am,
	* tests/accu/site_set/rectangularity.cc: add associated test.
---
 milena/ChangeLog                                   |   16 +++
 milena/mln/accu/all.hh                             |    1 +
 milena/mln/accu/essential.hh                       |    5 +-
 milena/mln/accu/{ => image}/essential.hh           |   25 +---
 milena/mln/accu/{essential.hh => site_set/all.hh}  |   26 +---
 milena/mln/accu/{ => site_set}/essential.hh        |   25 +---
 milena/mln/accu/site_set/rectangularity.hh         |  132 ++++++++++++++++++++
 milena/tests/accu/Makefile.am                      |    4 +
 milena/tests/accu/site_set/Makefile.am             |   10 ++
 .../accu/site_set/rectangularity.cc}               |   54 +++++----
 10 files changed, 218 insertions(+), 80 deletions(-)
 copy milena/mln/accu/{ => image}/essential.hh (67%)
 copy milena/mln/accu/{essential.hh => site_set/all.hh} (67%)
 copy milena/mln/accu/{ => site_set}/essential.hh (67%)
 create mode 100644 milena/mln/accu/site_set/rectangularity.hh
 create mode 100644 milena/tests/accu/site_set/Makefile.am
 copy milena/{mln/accu/essential.hh => tests/accu/site_set/rectangularity.cc} (63%)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index be240e1..c68b693 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,21 @@
 2009-03-19  Guillaume Lazzara  <lazzara(a)lrde.epita.fr>
 
+	Add accu::site_set::rectangularity.
+
+	* mln/accu/all.hh,
+	* mln/accu/essential.hh,
+	* mln/accu/image/essential.hh,
+	* mln/accu/site_set/all.hh,
+	* mln/accu/site_set/essential.hh: update all and essential includes.
+
+	* mln/accu/site_set/rectangularity.hh: new accumulator.
+
+	* tests/accu/Makefile.am,
+	* tests/accu/site_set/Makefile.am,
+	* tests/accu/site_set/rectangularity.cc: add associated test.
+
+2009-03-19  Guillaume Lazzara  <lazzara(a)lrde.epita.fr>
+
 	Add accu::couple.
 
 	* mln/accu/internal/couple.hh: new class.
diff --git a/milena/mln/accu/all.hh b/milena/mln/accu/all.hh
index 5b4e761..0e4d72d 100644
--- a/milena/mln/accu/all.hh
+++ b/milena/mln/accu/all.hh
@@ -96,6 +96,7 @@ namespace mln
 // Sub-directories
 
 # include <mln/accu/image/all.hh>
+# include <mln/accu/site_set/all.hh>
 
 
 #endif // ! MLN_ACCU_ALL_HH
diff --git a/milena/mln/accu/essential.hh b/milena/mln/accu/essential.hh
index e8c57cc..c69540d 100644
--- a/milena/mln/accu/essential.hh
+++ b/milena/mln/accu/essential.hh
@@ -1,4 +1,4 @@
-// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2008, 2009 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
@@ -46,5 +46,8 @@
 # include <mln/accu/rank.hh>
 # include <mln/accu/sum.hh>
 
+# include <mln/accu/image/essential.hh>
+# include <mln/accu/site_set/essential.hh>
+
 #endif // !MLN_ACCU_ESSENTIAL_HH_
 
diff --git a/milena/mln/accu/essential.hh b/milena/mln/accu/image/essential.hh
similarity index 67%
copy from milena/mln/accu/essential.hh
copy to milena/mln/accu/image/essential.hh
index e8c57cc..9a72225 100644
--- a/milena/mln/accu/essential.hh
+++ b/milena/mln/accu/image/essential.hh
@@ -1,4 +1,4 @@
-// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2009 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
@@ -25,26 +25,13 @@
 // reasons why the executable file might be covered by the GNU General
 // Public License.
 
-#ifndef MLN_ACCU_ESSENTIAL_HH_
-# define MLN_ACCU_ESSENTIAL_HH_
+#ifndef MLN_ACCU_IMAGE_ESSENTIAL_HH_
+# define MLN_ACCU_IMAGE_ESSENTIAL_HH_
 
-/// \file mln/accu/essential.hh
+/// \file mln/accu/image/essential.hh
 ///
-/// File that includes the most useful accumulator types.
+/// File that includes the most useful accumulator types working on images.
 
-# include <mln/accu/bbox.hh>
-# include <mln/accu/center.hh>
-# include <mln/accu/count.hh>
-# include <mln/accu/histo.hh>
-# include <mln/accu/max.hh>
-# include <mln/accu/max_h.hh>
-# include <mln/accu/mean.hh>
-# include <mln/accu/median_h.hh>
-# include <mln/accu/min.hh>
-# include <mln/accu/min_h.hh>
-# include <mln/accu/min_max.hh>
-# include <mln/accu/rank.hh>
-# include <mln/accu/sum.hh>
 
-#endif // !MLN_ACCU_ESSENTIAL_HH_
+#endif // !MLN_ACCU_IMAGE_ESSENTIAL_HH_
 
diff --git a/milena/mln/accu/essential.hh b/milena/mln/accu/site_set/all.hh
similarity index 67%
copy from milena/mln/accu/essential.hh
copy to milena/mln/accu/site_set/all.hh
index e8c57cc..03c8dae 100644
--- a/milena/mln/accu/essential.hh
+++ b/milena/mln/accu/site_set/all.hh
@@ -1,4 +1,4 @@
-// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2009 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
@@ -25,26 +25,14 @@
 // reasons why the executable file might be covered by the GNU General
 // Public License.
 
-#ifndef MLN_ACCU_ESSENTIAL_HH_
-# define MLN_ACCU_ESSENTIAL_HH_
+#ifndef MLN_ACCU_SITE_SET_ALL_HH_
+# define MLN_ACCU_SITE_SET_ALL_HH_
 
-/// \file mln/accu/essential.hh
+/// \file mln/accu/site_set/all.hh
 ///
-/// File that includes the most useful accumulator types.
+/// File that includes all accumulator types working on site sets.
 
-# include <mln/accu/bbox.hh>
-# include <mln/accu/center.hh>
-# include <mln/accu/count.hh>
-# include <mln/accu/histo.hh>
-# include <mln/accu/max.hh>
-# include <mln/accu/max_h.hh>
-# include <mln/accu/mean.hh>
-# include <mln/accu/median_h.hh>
-# include <mln/accu/min.hh>
-# include <mln/accu/min_h.hh>
-# include <mln/accu/min_max.hh>
-# include <mln/accu/rank.hh>
-# include <mln/accu/sum.hh>
+# include <mln/accu/site_set/rectangularity.hh>
 
-#endif // !MLN_ACCU_ESSENTIAL_HH_
+#endif // !MLN_ACCU_SITE_SET_ALL_HH_
 
diff --git a/milena/mln/accu/essential.hh b/milena/mln/accu/site_set/essential.hh
similarity index 67%
copy from milena/mln/accu/essential.hh
copy to milena/mln/accu/site_set/essential.hh
index e8c57cc..feb5a97 100644
--- a/milena/mln/accu/essential.hh
+++ b/milena/mln/accu/site_set/essential.hh
@@ -1,4 +1,4 @@
-// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2009 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
@@ -25,26 +25,13 @@
 // reasons why the executable file might be covered by the GNU General
 // Public License.
 
-#ifndef MLN_ACCU_ESSENTIAL_HH_
-# define MLN_ACCU_ESSENTIAL_HH_
+#ifndef MLN_ACCU_SITE_SET_ESSENTIAL_HH_
+# define MLN_ACCU_SITE_SET_ESSENTIAL_HH_
 
-/// \file mln/accu/essential.hh
+/// \file mln/accu/site_set/essential.hh
 ///
-/// File that includes the most useful accumulator types.
+/// File that includes the most useful accumulator types working on site sets.
 
-# include <mln/accu/bbox.hh>
-# include <mln/accu/center.hh>
-# include <mln/accu/count.hh>
-# include <mln/accu/histo.hh>
-# include <mln/accu/max.hh>
-# include <mln/accu/max_h.hh>
-# include <mln/accu/mean.hh>
-# include <mln/accu/median_h.hh>
-# include <mln/accu/min.hh>
-# include <mln/accu/min_h.hh>
-# include <mln/accu/min_max.hh>
-# include <mln/accu/rank.hh>
-# include <mln/accu/sum.hh>
 
-#endif // !MLN_ACCU_ESSENTIAL_HH_
+#endif // !MLN_ACCU_SITE_SET_ESSENTIAL_HH_
 
diff --git a/milena/mln/accu/site_set/rectangularity.hh b/milena/mln/accu/site_set/rectangularity.hh
new file mode 100644
index 0000000..fef5b21
--- /dev/null
+++ b/milena/mln/accu/site_set/rectangularity.hh
@@ -0,0 +1,132 @@
+// Copyright (C) 2009 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_SITE_SET_RECTANGULARITY_HH
+# define MLN_ACCU_SITE_SET_RECTANGULARITY_HH
+
+/// \file mln/accu/site_set/rectangularity.hh
+///
+/// Compute the rectangularity of a site set.
+
+# include <mln/accu/internal/couple.hh>
+# include <mln/accu/bbox.hh>
+# include <mln/accu/count.hh>
+
+namespace mln
+{
+
+  namespace accu
+  {
+
+    namespace site_set
+    {
+
+      /// Compute the rectangularity of a site set.
+      template <typename P>
+      class rectangularity
+	: public accu::internal::couple<accu::bbox<P>,
+					accu::count<P>,
+					float,
+					rectangularity<P> >
+      {
+
+      public:
+
+	typedef accu::internal::couple<accu::bbox<P>,
+				       accu::count<P>,
+				       float,
+				       rectangularity<P> > super_;
+
+	typedef accu::bbox<P> A1;
+	typedef accu::count<P> A2;
+
+	typedef float result;
+
+	/// Constructor
+	rectangularity();
+
+	/// Return the site set bounding box.
+	mln_result(A1) bbox() const;
+	/// Return the site set area.
+	mln_result(A2) area() const;
+
+	/// Return the rectangularity value.
+	result to_result() const;
+
+      protected:
+	using super_::a1_;
+	using super_::a2_;
+
+      };
+
+# ifndef MLN_INCLUDE_ONLY
+
+      template <typename P>
+      inline
+      rectangularity<P>::rectangularity()
+      {
+      }
+
+      template <typename P>
+      inline
+      mln_result(rectangularity<P>::A1)
+      rectangularity<P>::bbox() const
+      {
+	mln_precondition(a1_.is_valid());
+	return a1_.to_result();
+      }
+
+      template <typename P>
+      inline
+      mln_result(rectangularity<P>::A2)
+      rectangularity<P>::area() const
+      {
+	mln_precondition(a2_.is_valid());
+	return a2_.to_result();
+      }
+
+      template <typename P>
+      inline
+      mln_result(rectangularity<P>)
+      rectangularity<P>::to_result() const
+      {
+	mln_precondition(this->is_valid());
+	// Force division return type.
+	return static_cast<result>(a2_.to_result()) / a1_.to_result().nsites();
+      }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+    } // end of namespace mln::accu::site_set
+
+  } // end of namespace mln::accu
+
+} // end of namespace mln
+
+#endif // ! MLN_ACCU_SITE_SET_RECTANGULARITY_HH
diff --git a/milena/tests/accu/Makefile.am b/milena/tests/accu/Makefile.am
index fafbec1..7aca2bd 100644
--- a/milena/tests/accu/Makefile.am
+++ b/milena/tests/accu/Makefile.am
@@ -2,6 +2,10 @@
 
 include $(top_srcdir)/milena/tests/tests.mk
 
+SUBDIRS =					\
+  image 					\
+  site_set
+
 check_PROGRAMS =				\
   all_accus					\
   bbox						\
diff --git a/milena/tests/accu/site_set/Makefile.am b/milena/tests/accu/site_set/Makefile.am
new file mode 100644
index 0000000..042cf00
--- /dev/null
+++ b/milena/tests/accu/site_set/Makefile.am
@@ -0,0 +1,10 @@
+## Process this file through Automake to create Makefile.in -*- Makefile -*-
+
+include $(top_srcdir)/milena/tests/tests.mk
+
+check_PROGRAMS =				\
+  rectangularity
+
+rectangularity_SOURCES = rectangularity.cc
+
+TESTS = $(check_PROGRAMS)
diff --git a/milena/mln/accu/essential.hh b/milena/tests/accu/site_set/rectangularity.cc
similarity index 63%
copy from milena/mln/accu/essential.hh
copy to milena/tests/accu/site_set/rectangularity.cc
index e8c57cc..22e1e3e 100644
--- a/milena/mln/accu/essential.hh
+++ b/milena/tests/accu/site_set/rectangularity.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2009 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
@@ -25,26 +25,36 @@
 // reasons why the executable file might be covered by the GNU General
 // Public License.
 
-#ifndef MLN_ACCU_ESSENTIAL_HH_
-# define MLN_ACCU_ESSENTIAL_HH_
-
-/// \file mln/accu/essential.hh
+/// \file tests/accu/site_set/rectangularity.hh
 ///
-/// File that includes the most useful accumulator types.
-
-# include <mln/accu/bbox.hh>
-# include <mln/accu/center.hh>
-# include <mln/accu/count.hh>
-# include <mln/accu/histo.hh>
-# include <mln/accu/max.hh>
-# include <mln/accu/max_h.hh>
-# include <mln/accu/mean.hh>
-# include <mln/accu/median_h.hh>
-# include <mln/accu/min.hh>
-# include <mln/accu/min_h.hh>
-# include <mln/accu/min_max.hh>
-# include <mln/accu/rank.hh>
-# include <mln/accu/sum.hh>
-
-#endif // !MLN_ACCU_ESSENTIAL_HH_
+/// Tests on mln::accu::site_set::rectangularity.
+
+
+#include <mln/core/alias/point2d.hh>
+#include <mln/core/alias/box2d.hh>
+
+#include <mln/accu/site_set/rectangularity.hh>
+
+int main()
+{
+  using namespace mln;
+
+  {
+    accu::site_set::rectangularity<point2d> accu;
+    accu.take_as_init(point2d(0,0));
+    accu.take(point2d(0,1));
+    accu.take(point2d(1,0));
+    accu.take(point2d(1,1));
+
+    mln_assertion(accu.to_result() == 1);
+  }
+
+  {
+    accu::site_set::rectangularity<point2d> accu;
+    accu.take(point2d(0,0));
+    accu.take(point2d(1,1));
+    std::cout << accu << std::endl;
+    mln_assertion(accu.to_result() == 0.5f);
+  }
+}
 
-- 
1.5.6.5
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                    
                        	* mln/accu/internal/couple.hh: new class.
---
 milena/ChangeLog                   |    6 +
 milena/mln/accu/internal/couple.hh |  184 ++++++++++++++++++++++++++++++++++++
 2 files changed, 190 insertions(+), 0 deletions(-)
 create mode 100644 milena/mln/accu/internal/couple.hh
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 5944d9b..be240e1 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,3 +1,9 @@
+2009-03-19  Guillaume Lazzara  <lazzara(a)lrde.epita.fr>
+
+	Add accu::couple.
+
+	* mln/accu/internal/couple.hh: new class.
+
 2009-03-18  Guillaume Lazzara  <lazzara(a)lrde.epita.fr>
 
 	Add transform::distance_and_influence_zone_geodesic.
diff --git a/milena/mln/accu/internal/couple.hh b/milena/mln/accu/internal/couple.hh
new file mode 100644
index 0000000..d4678a6
--- /dev/null
+++ b/milena/mln/accu/internal/couple.hh
@@ -0,0 +1,184 @@
+// Copyright (C) 2009 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_INTERNAL_COUPLE_HH
+# define MLN_ACCU_INTERNAL_COUPLE_HH
+
+/// \file mln/accu/couple.hh
+///
+/// Base implementation of a couple of accumulators.
+
+# include <utility>
+
+# include <mln/core/concept/accumulator.hh>
+# include <mln/accu/internal/base.hh>
+
+# include <mln/metal/equal.hh>
+
+
+namespace mln
+{
+
+  namespace accu
+  {
+
+    namespace internal
+    {
+
+      /// Base implementation of a couple of accumulators.
+      ///
+      /// The parameter \c T is the type of values.
+      ///
+      /// \todo Check that, when T is not provided, A1 and A2 have the same value.
+      template <typename A1, typename A2, typename R, typename E>
+      struct couple
+        : base<R,E>,
+	  mlc_equal(mln_argument(A1), mln_argument(A2))::check_t
+      {
+        typedef mln_argument(A1) argument;
+
+	/// Manipulators.
+	/// \{
+	void init();
+	void take_as_init(const argument& t);
+	void take(const argument& t);
+	void take(const E& other);
+	/// \}
+
+	/// Check whether this accu is able to return a result.
+	/// Always true here.
+	bool is_valid() const;
+
+	A1& first();
+	A2& second();
+	const A1& first() const;
+	const A2& second() const;
+
+	protected:
+	couple();
+
+	A1 a1_;
+	A2 a2_;
+      };
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+      template <typename A1, typename A2, typename R, typename E>
+      inline
+      couple<A1,A2,R,E>::couple()
+      {
+	init();
+      }
+
+      template <typename A1, typename A2, typename R, typename E>
+      inline
+      void
+      couple<A1,A2,R,E>::init()
+      {
+	a1_.init();
+	a2_.init();
+      }
+
+      template <typename A1, typename A2, typename R, typename E>
+      inline
+      void
+      couple<A1,A2,R,E>::take_as_init(const argument& t)
+      {
+	a1_.take_as_init(t);
+	a2_.take_as_init(t);
+      }
+
+      template <typename A1, typename A2, typename R, typename E>
+      inline
+      void
+      couple<A1,A2,R,E>::take(const argument& t)
+      {
+	a1_.take(t);
+	a2_.take(t);
+      }
+
+      template <typename A1, typename A2, typename R, typename E>
+      inline
+      void
+      couple<A1,A2,R,E>::take(const E& other)
+      {
+	a1_.take(other.a1_);
+	a2_.take(other.a2_);
+      }
+
+      template <typename A1, typename A2, typename R, typename E>
+      inline
+      bool
+      couple<A1,A2,R,E>::is_valid() const
+      {
+	return a1_.is_valid() && a2_.is_valid();
+      }
+
+      template <typename A1, typename A2, typename R, typename E>
+      inline
+      A1&
+      couple<A1,A2,R,E>::first()
+      {
+	return a1_;
+      }
+
+      template <typename A1, typename A2, typename R, typename E>
+      inline
+      const A1&
+      couple<A1,A2,R,E>::first() const
+      {
+	return a1_;
+      }
+
+      template <typename A1, typename A2, typename R, typename E>
+      inline
+      A2&
+      couple<A1,A2,R,E>::second()
+      {
+	return a2_;
+      }
+
+      template <typename A1, typename A2, typename R, typename E>
+      inline
+      const A2&
+      couple<A1,A2,R,E>::second() const
+      {
+	return a2_;
+      }
+
+# endif // ! MLN_INCLUDE_ONLY
+
+    } // end of namespace mln::accu::internal
+
+  } // end of namespace mln::accu
+
+} // end of namespace mln
+
+
+#endif // ! MLN_ACCU_INTERNAL_COUPLE_HH
-- 
1.5.6.5
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    
                    
                        	* bugs/concept_and_assignment.cc: sample code of what should not
	be done while assigning an image to another.
---
 milena/sandbox/ChangeLog                      |    7 ++
 milena/sandbox/bugs/concept_and_assignment.cc |   84 +++++++++++++++++++++++++
 2 files changed, 91 insertions(+), 0 deletions(-)
 create mode 100644 milena/sandbox/bugs/concept_and_assignment.cc
diff --git a/milena/sandbox/ChangeLog b/milena/sandbox/ChangeLog
index 0512bfc..8c7681f 100644
--- a/milena/sandbox/ChangeLog
+++ b/milena/sandbox/ChangeLog
@@ -1,3 +1,10 @@
+2009-03-16  Guillaume Lazzara  <z(a)lrde.epita.fr>
+
+	Add a buggy sample case.
+
+	* bugs/concept_and_assignment.cc: sample code of what should not
+	be done while assigning an image to another.
+
 2009-03-19  Fabien Freling  <fabien.freling(a)lrde.epita.fr>
 
 	Add a new file translating IGR Matlab code.
diff --git a/milena/sandbox/bugs/concept_and_assignment.cc b/milena/sandbox/bugs/concept_and_assignment.cc
new file mode 100644
index 0000000..379d17d
--- /dev/null
+++ b/milena/sandbox/bugs/concept_and_assignment.cc
@@ -0,0 +1,84 @@
+/*
+** We do NOT want to pass images as reference.
+**
+** Assigning an image to an image concept will compile but
+** will not perform anything. This is ERROR PRONE.
+**
+** Thus, if the image passed as reference is not initialized it will remain
+** uninitialized and an assertion will raised. The problem is if the image is
+** already initialized. It will FAIL SILENTLY and give wrong image values.
+**
+** Always prefer returning images.
+*/
+
+#include <mln/essential/2d.hh>
+
+namespace mln
+{
+
+  template <typename I>
+  mln_ch_value(I,value::label_8)
+  bar(const Image<I>& ima)
+  {
+    value::label_8 n;
+
+    mln_ch_value(I,value::label_8) lbl;
+    initialize(lbl, ima);
+
+    lbl = labeling::blobs(ima, c8(),n);
+    mln_assertion(lbl.is_valid());
+
+    return lbl;
+  }
+
+  // DO NOT WORK!
+  template <typename I>
+  void foo_template_and_concept(Image<I>& lbl)
+  {
+    mln_ch_value(I,bool) ima(3,4);
+
+    /// The difference is here!
+    lbl = bar(ima);
+
+    mln_assertion(exact(lbl).is_valid());
+  }
+
+  // WORK
+  template <typename I>
+  void foo_template_concept_and_exact(Image<I>& lbl)
+  {
+    mln_ch_value(I,bool) ima(3,4);
+
+    /// The difference is here!
+    exact(lbl) = bar(ima);
+
+    mln_assertion(exact(lbl).is_valid());
+  }
+
+}
+
+
+
+int main(int, char*argv[])
+{
+  using namespace mln;
+
+  image2d<bool> ima(3,4);
+
+  // WORK
+  {
+    std::cout << "template with I + concept + exact" << std::endl;
+    image2d<value::label_8> lbl;
+    foo_template_concept_and_exact(lbl);
+    mln_assertion(lbl.is_valid());
+  }
+
+  // DO NOT WORK
+  {
+    std::cout << "template with I + concept" << std::endl;
+    image2d<value::label_8> lbl;
+    foo_template_and_concept(lbl);
+    mln_assertion(lbl.is_valid());
+  }
+
+}
-- 
1.5.6.5
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0
                            
                          
                          
                            
    
                          
                        
                    19 Mar '09
                    
                        	* mln/transform/all.hh: include new file.
	* mln/transform/distance_and_influence_zone_geodesic.hh: new routine.
---
 milena/ChangeLog                                   |    8 ++
 milena/mln/transform/all.hh                        |    4 +-
 .../distance_and_influence_zone_geodesic.hh        |   96 ++++++++++++++++++++
 3 files changed, 107 insertions(+), 1 deletions(-)
 create mode 100644 milena/mln/transform/distance_and_influence_zone_geodesic.hh
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 2d33b38..5944d9b 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,3 +1,11 @@
+2009-03-18  Guillaume Lazzara  <lazzara(a)lrde.epita.fr>
+
+	Add transform::distance_and_influence_zone_geodesic.
+
+	* mln/transform/all.hh: include new file.
+
+	* mln/transform/distance_and_influence_zone_geodesic.hh: new routine.
+
 2009-03-19  Thierry Geraud  <thierry.geraud(a)lrde.epita.fr>
 
 	Add meta-code to access component types of value types.
diff --git a/milena/mln/transform/all.hh b/milena/mln/transform/all.hh
index 4967197..7d6ef27 100644
--- a/milena/mln/transform/all.hh
+++ b/milena/mln/transform/all.hh
@@ -1,4 +1,5 @@
-// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2008, 2009 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
@@ -43,6 +44,7 @@ namespace mln
 
 
 # include <mln/transform/distance_and_closest_point_geodesic.hh>
+# include <mln/transform/distance_and_influence_zone_geodesic.hh>
 # include <mln/transform/distance_front.hh>
 # include <mln/transform/distance_geodesic.hh>
 # include <mln/transform/influence_zone_front.hh>
diff --git a/milena/mln/transform/distance_and_influence_zone_geodesic.hh b/milena/mln/transform/distance_and_influence_zone_geodesic.hh
new file mode 100644
index 0000000..f461d30
--- /dev/null
+++ b/milena/mln/transform/distance_and_influence_zone_geodesic.hh
@@ -0,0 +1,96 @@
+// Copyright (C) 2008, 2009 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_TRANSFORM_DISTANCE_AND_INFLUENCE_ZONE_GEODESIC_HH
+# define MLN_TRANSFORM_DISTANCE_AND_INFLUENCE_ZONE_GEODESIC_HH
+
+/// \file mln/transform/distance_and_influence_zone_geodesic.hh
+///
+/// Distance and geodesic closest point transform.
+
+# include <mln/canvas/distance_geodesic.hh>
+# include <mln/transform/internal/influence_zone_functor.hh>
+
+# include <mln/data/fill.hh>
+# include <mln/util/couple.hh>
+
+
+namespace mln
+{
+
+  namespace transform
+  {
+
+    /// Discrete geodesic distance transform
+    ///
+    /// \param[in] input  Image from which the geodesic distance is computed.
+    /// \param[in] nbh	  Neighborhood
+    /// \param[in] max	  Max distance of propagation.
+    ///
+    /// \return a couple of images. The first one is the distance map and the
+    ///		second one is the closest point image. The closest point image
+    ///		contains sites.
+    ///
+    /// \post The returned images have the same domain as \p input.
+    template <typename I, typename N, typename D>
+    util::couple<mln_ch_value(I,D), I>
+    distance_and_influence_zone_geodesic(const Image<I>& input,
+					 const Neighborhood<N>& nbh,
+					 D max);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+    template <typename I, typename N, typename D>
+    inline
+    util::couple<mln_ch_value(I,D), I>
+    distance_and_influence_zone_geodesic(const Image<I>& input,
+					 const Neighborhood<N>& nbh,
+					 D max)
+    {
+      trace::entering("transform::distance_influence_zone_geodesic");
+
+      mln_precondition(exact(input).is_valid());
+      mln_precondition(exact(nbh).is_valid());
+
+      internal::influence_zone_functor<I> f;
+      mln_ch_value(I,D) dmap = mln::canvas::distance_geodesic(input, nbh,
+							      max, f);
+
+      trace::exiting("transform::distance_and_influence_zone_geodesic");
+      return make::couple(dmap, f.output);
+    }
+
+
+# endif // ! MLN_INCLUDE_ONLY
+
+  } // end of namespace mln::transform
+
+} // end of namespace mln
+
+
+#endif // ! MLN_TRANSFORM_DISTANCE_AND_INFLUENCE_ZONE_GEODESIC_HH
-- 
1.5.6.5
                    
                  
                  
                          
                            
                            1
                            
                          
                          
                            
                            0