https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox
Index: ChangeLog
from Thierry Geraud <thierry.geraud(a)lrde.epita.fr>
Add a color segmentation on pixels (not on edges).
* theo/color/segment.hh: Update.
* theo/color/segment_rgb_pixels.cc: New.
* theo/color/segment_rgb_edges.cc: Update.
* theo/color/mean_rgb_pix.hh: New.
* theo/color/change_attributes.hh: Update.
change_attributes.hh | 55 +++++++++++++++--
mean_rgb_pix.hh | 105 ++++++++++++++------------------
segment.hh | 88 ++++++++++++++++++++++++++-
segment_rgb_edges.cc | 24 +------
segment_rgb_pixels.cc | 160 ++++++++++++++++++++++++++++++++++++--------------
5 files changed, 305 insertions(+), 127 deletions(-)
Index: theo/color/segment.hh
--- theo/color/segment.hh (revision 3313)
+++ theo/color/segment.hh (working copy)
@@ -8,6 +8,9 @@
#include <mln/make/pix.hh>
#include <mln/debug/println.hh>
+#include <mln/value/rgb8.hh>
+#include <mln/math/diff_abs.hh>
+
#include <mln/level/sort_psites.hh>
#include <mln/labeling/regional_minima.hh>
#include <mln/pw/all.hh>
@@ -23,6 +26,31 @@
{
+ // Distance between 2 rgb8 colors.
+
+ value::int_u8 dist(const value::rgb8& c1, const value::rgb8& c2)
+ {
+ unsigned d = 0;
+ d += (math::diff_abs(c1.red(), c2.red()) + 2) / 3;
+ d += (math::diff_abs(c1.green(), c2.green()) + 2) / 3;
+ d += (math::diff_abs(c1.blue(), c2.blue()) + 2) / 3;
+ if (d > 255)
+ d = 255;
+ return d;
+ }
+
+ value::int_u8 dist_(const value::rgb8& c1, const value::rgb8& c2)
+ {
+ unsigned d = 0;
+ d += math::diff_abs(c1.red(), c2.red());
+ d += math::diff_abs(c1.green(), c2.green());
+ d += math::diff_abs(c1.blue(), c2.blue());
+ if (d > 255)
+ d = 255;
+ return d;
+ }
+
+
// Sorting.
@@ -118,6 +146,58 @@
+
+
+ // Tree -> attributes on every pixel.
+ // Warning : it is not an attribute per flat zone!
+ // -----------------------------------------------
+
+ template <typename A, typename T>
+ inline
+ mln_ch_value(typename T::function, mln_result(A))
+ compute_attribute_on_pixels__not_on_flat_zones(const A& a, const T& t)
+ {
+ typedef typename T::function I;
+
+ mln_ch_value(I, A) acc;
+ mln_ch_value(I, mln_result(A)) attr;
+
+ // Initialization of 'acc'.
+ {
+ initialize(acc, t.f());
+ data::fill(acc, a); // Transfer "dynamic data" (state) of 'a'.
+ }
+
+ // Initialize every attribute with the corresponding pixel.
+ {
+ mln_piter(I) p(t.f().domain());
+ for_all(p)
+ acc(p).take_as_init(make::pix(t.f(), p));
+ }
+
+ // Propagate attribute from a site to its parent.
+ {
+ mln_fwd_piter(T) p(t.domain());
+ for_all(p)
+ if (! t.is_root(p))
+ acc(t.parent(p)).take(acc(p));
+ }
+
+
+ // Change accumulator into its result.
+ {
+ initialize(attr, acc);
+ mln_piter(I) p(t.f().domain()); // The main difference is here!
+ for_all(p)
+ attr(p) = acc(p).to_result();
+ }
+
+ return attr;
+ }
+
+
+
+
// Tree -> nchildren (on nodes).
// -----------------------------
@@ -228,7 +308,7 @@
if (echo)
{
- back_propagate(filtered, t);
+ back_propagate(t, filtered);
debug::println("filtered =", filtered);
debug::println("a < lambda = ", (pw::value(a) < pw::cst(lambda)) |
a.domain());
}
@@ -344,7 +424,7 @@
tree_t t(f, s, nbh);
mln_VAR(a, compute_attribute_on_nodes(a_, t));
- back_propagate(a, t);
+ back_propagate(t, a);
if (echo)
{
@@ -363,7 +443,7 @@
break;
case 2:
std::cout << "fuse up attributes" << std::endl;
- fuse_down_attributes(t, a, echo);
+ fuse_up_attributes(t, a, echo);
break;
}
@@ -409,7 +489,7 @@
T t(f, s, nbh);
mln_VAR(a, compute_attribute_on_nodes(a_, t));
- back_propagate(a, t);
+ back_propagate(t, a);
unsigned n_regmins_f; // This value can be obtained while computing the attributes!
Index: theo/color/segment_rgb_pixels.cc
--- theo/color/segment_rgb_pixels.cc (revision 3313)
+++ theo/color/segment_rgb_pixels.cc (working copy)
@@ -4,34 +4,101 @@
#include <mln/core/alias/neighb2d.hh>
#include <mln/value/int_u8.hh>
-#include <mln/value/label_8.hh>
+#include <mln/value/label_16.hh>
#include <mln/value/rgb8.hh>
#include <mln/literal/colors.hh>
-#include <mln/io/pgm/load.hh>
+#include <mln/io/ppm/load.hh>
#include <mln/io/ppm/save.hh>
#include <mln/io/pgm/save.hh>
-
+#include <mln/io/pbm/save.hh>
#include <mln/level/convert.hh>
-#include <mln/morpho/elementary/gradient.hh>
#include <mln/morpho/meyer_wst.hh>
-#include <mln/accu/height.hh>
-
+#include "mean_rgb_pix.hh"
#include "segment.hh"
+namespace mln
+{
+
+
+ // Distance, stored on pixels, of neighboring colors.
+
+ template <typename N>
+ image2d<value::int_u8>
+ dist_on_pixels(const image2d<value::rgb8>& input, const N& nbh)
+ {
+ using value::int_u8;
+ image2d<int_u8> output(input.domain());
+
+ mln_piter(box2d) p(input.domain());
+ mln_niter(N) n(nbh, p);
+ for_all(p)
+ {
+ int_u8 d = 0u;
+ for_all(n) if (input.domain().has(n))
+ {
+ int_u8 d_ = dist(input(p), input(n));
+ if (d_ > d)
+ d = d_;
+ }
+ output(p) = d;
+ }
+
+ io::pgm::save(output, "temp_dist.pgm");
+
+ return output;
+ }
+
+
+
+
+
+ // From 'mean color' attributes to 'mean difference p/par(p)'.
+ // -----------------------------------------------------------
+
+
+ template <typename T, typename A>
+ inline
+ mln_ch_value(A, value::int_u8)
+ dists_from_means(const T& t, const A& a, bool echo = false)
+ {
+ if (echo)
+ {
+ std::cout << "means:" << std::endl;
+ display_tree_attributes(t, a);
+ }
+
+ mln_ch_value(A, value::int_u8) d;
+ initialize(d, a);
+
+ typedef typename T::nodes_t N;
+ mln_fwd_piter(N) n(t.nodes());
+ for_all(n)
+ d(n) = dist(a(n), a(t.parent(n)));
+
+ if (echo)
+ {
+ std::cout << "dists:" << std::endl;
+ display_tree_attributes(t, d);
+ }
+
+ return d;
+ }
+
+
+} // mln
+
void usage(char* argv[])
{
- std::cerr << "usage: " << argv[0] << " input.pgm n
change extinction echo output.ppm" << std::endl;
- std::cerr << "gray-level version on pixels (without edges)" <<
std::endl;
+ std::cerr << "usage: " << argv[0] << " input.ppm n
echo output.ppm" << std::endl;
+ std::cerr << "color version on pixels (without edges)" <<
std::endl;
std::cerr << " n >= 2" << std::endl;
- std::cerr << " change = 0 (none), 1 (move-down), or 2 (fuse)" <<
std::endl;
- std::cerr << " extinction = 0 (none) or 1 (effective)" <<
std::endl;
std::cerr << " echo = 0 (mute) or 1 (verbose)" << std::endl;
abort();
}
@@ -46,30 +113,22 @@
using value::rgb8;
- if (argc != 7)
+ if (argc != 5)
usage(argv);
- // Gray-level debase version.
- // --------------------------
+ // Color debase (on pixels, not edges) version.
+ // --------------------------------------------
- typedef image2d<int_u8> I;
+ typedef image2d<rgb8> I;
I input;
- io::pgm::load(input, argv[1]);
+ io::ppm::load(input, argv[1]);
unsigned n_objects = atoi(argv[2]);
- int change_kind = atoi(argv[3]);
- if (change_kind < 0 || change_kind > 2)
- usage(argv);
-
- int do_extinction = atoi(argv[4]);
- if (do_extinction != 0 && do_extinction != 1)
- usage(argv);
-
- bool echo = atoi(argv[5]);
+ bool echo = atoi(argv[3]);
// Neighborhood.
@@ -78,40 +137,55 @@
// Changing input into 'f'.
- I f = morpho::elementary::gradient(input, c4());
+ typedef image2d<int_u8> F;
+ F f = dist_on_pixels(input, c4());
+
+
+ typedef p_array<mln_psite_(F)> S;
+ S s = level::sort_psites_decreasing(f);
+ typedef morpho::tree::data<F,S> tree_t;
+ tree_t t(f, s, c4());
- // // granulometry:
- // gran_filter(f, c4(), a_);
+ accu::rgb_image_ = input;
+ accu::mean_rgb_pix< util::pix<F> > a_;
+ mln_VAR(a, compute_attribute_on_nodes(a_, t));
+ mln_VAR(d, dists_from_means(t, a, echo));
+ make_attribute_grow(t, d);
+ if (echo)
+ {
+ std::cout << "dists growing:" << std::endl;
+ display_tree_attributes(t, d);
+ }
- // accu::count< util::pix<I> > a_;
- // accu::sum_pix< util::pix<I> > a_;
- // accu::volume<I> a_;
- accu::height<I> a_;
- // It seems that both extinction and changing attributes only
- // properly works for the 'height' attribute.
+ // BAD: extinct_attributes(t, d, echo);
- I g = filter(f, c4(),
- a_,
- change_kind, do_extinction,
- n_objects,
+
+ int_u8 lambda;
+ unsigned less;
+ image2d<int_u8> g = run_filter(d, t, c4(), n_objects, // input
+ less, lambda, // output
echo);
- if (echo)
- debug::println("activity (g != f) = ", (pw::value(g) != pw::value(f)) |
f.domain());
+ io::pbm::save( (pw::value(g) != pw::value(f)) | f.domain(),
+ "temp_activity.pbm" );
+
+// if (echo)
+// debug::println("activity (g != f) = ", (pw::value(g) != pw::value(f)) |
f.domain());
// Watershed transform.
- typedef value::label_8 L;
+ typedef value::label_16 L;
L nbasins;
mln_ch_value_(I, L) w = morpho::meyer_wst(g, c4(), nbasins);
+ std::cout << "n basins = " << nbasins << std::endl;
- image2d<rgb8> output = level::convert(rgb8(), input);
- data::fill((output | (pw::value(w) == 0)).rw(), literal::red);
+ image2d<rgb8> output = duplicate(input);
+ data::fill((output | (pw::value(w) == 0)).rw(), literal::black);
- io::ppm::save(output, argv[6]);
+ io::ppm::save(output, argv[4]);
}
Index: theo/color/segment_rgb_edges.cc
--- theo/color/segment_rgb_edges.cc (revision 3313)
+++ theo/color/segment_rgb_edges.cc (working copy)
@@ -17,8 +17,6 @@
#include <mln/io/ppm/load.hh>
#include <mln/io/ppm/save.hh>
-#include <mln/math/diff_abs.hh>
-
#include <mln/morpho/dilation.hh>
#include <mln/morpho/erosion.hh>
#include <mln/morpho/meyer_wst.hh>
@@ -29,11 +27,10 @@
#include <mln/accu/mean.hh>
#include "sum_pix.hh"
-
-
#include "segment.hh"
+
namespace mln
{
@@ -192,22 +189,11 @@
- // Distance.
-
- value::int_u8 dist(const value::rgb8& c1, const value::rgb8& c2)
- {
- unsigned d = 0;
- d += (math::diff_abs(c1.red(), c2.red()) + 2) / 3;
- d += (math::diff_abs(c1.green(), c2.green()) + 2) / 3;
- d += (math::diff_abs(c1.blue(), c2.blue()) + 2) / 3;
- if (d > 255)
- d = 255;
- return d;
- }
+ // Distance, stored on edges, of a couple of colors.
template <typename I, typename N>
image2d<value::int_u8>
- dist(const I& input, const N& nbh)
+ dist_on_edges(const I& input, const N& nbh)
{
image2d<value::int_u8> output;
initialize(output, input);
@@ -224,6 +210,8 @@
output(p) = dist(c1, c2);
}
+ io::pgm::save(output, "temp_dist.pgm");
+
return output;
}
@@ -288,7 +276,7 @@
image2d<int_u8> f_;
image2d<rgb8> input_ = image2full(input);
{
- f_ = dist(extend(input_ | is_edge, pw::value(input_)),
+ f_ = dist_on_edges(extend(input_ | is_edge, pw::value(input_)),
e2c());
}
mln_VAR(f, f_ | is_edge);
Index: theo/color/mean_rgb_pix.hh
--- theo/color/mean_rgb_pix.hh (revision 3313)
+++ theo/color/mean_rgb_pix.hh (working copy)
@@ -26,57 +26,57 @@
// reasons why the executable file might be covered by the GNU General
// Public License.
-#ifndef MLN_ACCU_SUM_PIX_HH
-# define MLN_ACCU_SUM_PIX_HH
+#ifndef MLN_ACCU_MEAN_RGB_PIX_HH
+# define MLN_ACCU_MEAN_RGB_PIX_HH
-/// \file mln/accu/sum_pix.hh
+/// \file mln/accu/mean_rgb_pix.hh
///
-/// Define an accumulator that computes a sum.
+/// Define an accumulator that computes an rgb8 mean.
# include <mln/core/concept/meta_accumulator.hh>
# include <mln/accu/internal/base.hh>
-# include <mln/util/pix.hh> // To prevent accu::sum_pix to work on pixels
(ambiguous).
+# include <mln/value/rgb8.hh>
+# include <mln/algebra/vec.hh>
-# include <mln/trait/value_.hh> // For mln_sum_pix.
-# include <mln/value/builtin/all.hh> // In the case of summing builtin values.
-# include <mln/literal/zero.hh> // For initialization.
+# include <mln/util/pix.hh>
+# include <mln/core/image/image2d.hh>
namespace mln
{
+
namespace accu
{
- /// Generic sum_pix accumulator class.
- /*!
- * Parameter \c T is the type of values that we sum. Parameter \c
- * S is the type to store the value sum; the default type of
- * \c S is the summation type (property) of \c T.
- */
- template <typename P, typename S = mln_sum(mln_value(P))>
- struct sum_pix : public mln::accu::internal::base< const S&,
sum_pix<P,S> >
+ image2d<value::rgb8> rgb_image_;
+
+
+ /// Generic mean_rgb_pix accumulator class.
+ ///
+ template <typename Pix>
+ struct mean_rgb_pix : public mln::accu::internal::base< value::rgb8,
mean_rgb_pix<Pix> >
{
- typedef P argument;
+ typedef Pix argument;
- sum_pix();
+ mean_rgb_pix();
/// Manipulators.
/// \{
void init();
void take(const argument& t);
- void take(const sum_pix<P,S>& other);
+ void take(const mean_rgb_pix<Pix>& other);
/// \}
- void set_value(S v)
- {
- s_ = v;
- }
+// void set_value(S v)
+// {
+// s_ = v;
+// }
/// Get the value of the accumulator.
- const S& to_result() const;
+ value::rgb8 to_result() const;
/// Check whether this accu is able to return a result.
/// Always true here.
@@ -84,70 +84,59 @@
protected:
- S s_;
+ typedef algebra::vec<3,float> vec_t;
+ vec_t s_;
+ unsigned n_;
};
- namespace meta
- {
-
- /// Meta accumulator for sum_pix.
- struct sum_pix : public Meta_Accumulator< sum_pix >
- {
- template <typename P, typename S = mln_sum(mln_value(P))>
- struct with
- {
- typedef accu::sum_pix<P, S> ret;
- };
- };
-
- } // end of namespace mln::accu::meta
-
-
# ifndef MLN_INCLUDE_ONLY
- template <typename P, typename S>
+ template <typename Pix>
inline
- sum_pix<P,S>::sum_pix()
+ mean_rgb_pix<Pix>::mean_rgb_pix()
{
init();
}
- template <typename P, typename S>
+ template <typename Pix>
inline
void
- sum_pix<P,S>::init()
+ mean_rgb_pix<Pix>::init()
{
- s_ = literal::zero;
+ s_ = vec_t::zero;
+ n_ = 0;
}
- template <typename P, typename S>
+ template <typename Pix>
inline
- void sum_pix<P,S>::take(const argument& p)
+ void mean_rgb_pix<Pix>::take(const argument& px)
{
- s_ += /* 1 + */ p.v();
+ s_ += vec_t(rgb_image_(px.p()));
+ ++n_;
}
- template <typename P, typename S>
+ template <typename Pix>
inline
void
- sum_pix<P,S>::take(const sum_pix<P,S>& other)
+ mean_rgb_pix<Pix>::take(const mean_rgb_pix<Pix>& other)
{
s_ += other.s_;
+ n_ += other.n_;
}
- template <typename P, typename S>
+ template <typename Pix>
inline
- const S&
- sum_pix<P,S>::to_result() const
+ value::rgb8
+ mean_rgb_pix<Pix>::to_result() const
{
- return s_;
+ return algebra::vec<3, unsigned>(s_ / n_);
}
- template <typename P, typename S>
+ template <typename Pix>
inline
bool
- sum_pix<P,S>::is_valid() const
+ mean_rgb_pix<Pix>::is_valid() const
{
return true;
}
@@ -159,4 +148,4 @@
} // end of namespace mln
-#endif // ! MLN_ACCU_SUM_PIX_HH
+#endif // ! MLN_ACCU_MEAN_RGB_PIX_HH
Index: theo/color/change_attributes.hh
--- theo/color/change_attributes.hh (revision 3313)
+++ theo/color/change_attributes.hh (working copy)
@@ -38,12 +38,58 @@
+ // Test attribute growing property.
+ // --------------------------------
+
+ template <typename T, typename A>
+ inline
+ bool
+ test_attribute_growing_property(const T& t, const A& a)
+ {
+ typedef typename T::nodes_t N;
+ mln_fwd_piter(N) n(t.nodes());
+ for_all(n)
+ if (a(t.parent(n)) < a(n))
+ return false;
+ return true;
+ }
+
+ template <typename T, typename A>
+ inline
+ void
+ invariant__attribute_growing_property(const T& t, const A& a)
+ {
+ mln_invariant(test_attribute_growing_property(t, a));
+ }
+
+
+
+
+ // Make attributes grow.
+ // --------------------------------
+
+ template <typename T, typename A>
+ inline
+ void
+ make_attribute_grow(const T& t, A& a)
+ {
+ typedef typename T::nodes_t N;
+ mln_fwd_piter(N) n(t.nodes());
+ for_all(n)
+ if (a(t.parent(n)) < a(n))
+ a(t.parent(n)) = a(n);
+
+ mln_postcondition(test_attribute_growing_property(t, a));
+ }
+
+
+
// Back-propagate values from nodes to component sites.
// ----------------------------------------------------
- template <typename A, typename T>
+ template <typename T, typename A>
void
- back_propagate(A& a, const T& t)
+ back_propagate(const T& t, A& a)
{
mln_fwd_piter(T) p(t.domain());
for_all(p)
@@ -243,13 +289,13 @@
- // Fuse down.
+ // Fuse up.
// ----------
template <typename T, typename A>
inline
void
- fuse_down_attributes(const T& t, A& a, bool echo = false)
+ fuse_up_attributes(const T& t, A& a, bool echo = false)
{
if (echo)
{
@@ -273,6 +319,7 @@
+
// Rand.
// -----