URL:
https://svn.lrde.epita.fr/svn/oln/trunk/milena
ChangeLog:
2009-03-24 Edwin Carlinet <carlinet(a)lrde.epita.fr>
Test geodesic distance with component tree and try to apply.
* mln/morpho/attribute/sharpness.hh: Fix bugs related to
height computation.
* sandbox/edwin/attributes/bbox.hh: Add bbox morpho attribute.
* sandbox/edwin/tree/run.hh: Correct bugs and delete
run_while_treshold which can be computed throught pointwise.
* sandbox/edwin/tree/test.cc: Test file.
---
mln/morpho/attribute/sharpness.hh | 5
sandbox/edwin/attributes/bbox.hh | 203 ++++++++++++++++++++++++++++++++++++++
sandbox/edwin/tree/Makefile | 10 -
sandbox/edwin/tree/configure | 14 ++
sandbox/edwin/tree/run.hh | 67 ------------
sandbox/edwin/tree/test.cc | 143 ++++++++++++++++++++++++--
6 files changed, 362 insertions(+), 80 deletions(-)
Index: trunk/milena/mln/morpho/attribute/sharpness.hh
===================================================================
--- trunk/milena/mln/morpho/attribute/sharpness.hh (revision 3571)
+++ trunk/milena/mln/morpho/attribute/sharpness.hh (revision 3572)
@@ -177,7 +177,10 @@
double
sharpness<I>::to_result() const
{
- return (double)volume_.to_result() / (double)(volume_.area() * height_.to_result());
+ double d = (double) volume_.to_result() /
+ (double)(volume_.area() * (height_.to_result() + 1));
+ mln_postcondition(d >= 0 && d <= 1);
+ return d;
}
template <typename I>
Index: trunk/milena/sandbox/edwin/tree/configure
===================================================================
--- trunk/milena/sandbox/edwin/tree/configure (revision 0)
+++ trunk/milena/sandbox/edwin/tree/configure (revision 3572)
@@ -0,0 +1,14 @@
+#! /bin/bash
+
+
+for arg in "$@"; do
+ if [ "$arg" == "--debug" ]; then
+ debug=1;
+ fi
+done
+
+rm -f makefile.rules
+touch makefile.rules
+if [ "$debug" ]; then
+ echo 'DEBUG=1' > makefile.rules
+fi
\ No newline at end of file
Property changes on: trunk/milena/sandbox/edwin/tree/configure
___________________________________________________________________
Name: svn:executable
+ *
Index: trunk/milena/sandbox/edwin/tree/run.hh
===================================================================
--- trunk/milena/sandbox/edwin/tree/run.hh (revision 3571)
+++ trunk/milena/sandbox/edwin/tree/run.hh (revision 3572)
@@ -91,7 +91,7 @@
**
** @param tree Component tree used for propagation.
** @param a Attributed image where values are propagated.
- ** @param accu_ Accumulator to apply on tree.
+ ** @param acc Accumulator to apply on tree.
** @param n The repetition number.
**
** @return Array of propagated nodes.
@@ -104,28 +104,6 @@
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
@@ -143,16 +121,16 @@
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;
+ while (pred(p) && a(p) != 0)
+ {
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()));
+ p = morpho::tree::run(tree, a, accu);
+ }
for (unsigned i = 0; i < arr_sites.nsites(); i++)
a(arr_sites[i]) = arr_values[i];
return arr_sites;
@@ -178,28 +156,6 @@
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
@@ -231,19 +187,6 @@
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,
Index: trunk/milena/sandbox/edwin/tree/test.cc
===================================================================
--- trunk/milena/sandbox/edwin/tree/test.cc (revision 3571)
+++ trunk/milena/sandbox/edwin/tree/test.cc (revision 3572)
@@ -1,6 +1,8 @@
/* mln core */
#include <mln/core/image/image2d.hh>
+#include <mln/core/image/image_if.hh>
#include <mln/core/alias/neighb2d.hh>
+#include <mln/core/routine/duplicate.hh>
#include <mln/core/var.hh>
/* Site set */
@@ -15,15 +17,34 @@
#include "accumulator/arg_max.hh"
/* Attributes */
-#include <mln/morpho/attribute/sharpness.hh>
+#include <mln/transform/distance_geodesic.hh>
+#include <mln/morpho/attribute/card.hh>
+#include "../attributes/bbox.hh"
/* io */
-#include <mln/io/pgm/load.hh>
+#include <mln/io/pbm/load.hh>
+#include <mln/io/pgm/save.hh>
+#include <mln/io/ppm/save.hh>
#include <../../theo/color/change_attributes.hh>
-#include <iostream>
+
+/* data & pw */
+#include <mln/core/concept/function.hh>
+#include <mln/fun/p2v/ternary.hh>
+#include <mln/data/fill.hh>
+#include <mln/data/paste.hh>
+#include <mln/pw/all.hh>
+
+/* labeling */
+#include <mln/value/label.hh>
+#include <mln/labeling/blobs.hh>
+#include <mln/debug/colorize.hh>
+
+/* Draw debug */
+#include <mln/draw/box.hh>
/* std */
#include <string>
+#include <iostream>
bool mydebug = false;
@@ -42,6 +63,35 @@
<< "*********************" << std::endl;
}
+template <typename P2V>
+struct ratio_ : public mln::Function_p2v< ratio_<P2V> >
+{
+ typedef double result;
+
+ ratio_(const P2V& f) :
+ f_ (f)
+ {
+ }
+
+ template <typename P>
+ double operator() (const P& p) const
+ {
+ return (double) (f_(p).len(1)) / (double)(f_(p).len(0));
+ }
+
+protected:
+ const P2V& f_;
+};
+
+template <typename P2V>
+ratio_<P2V> ratio(const mln::Function_p2v<P2V>& f)
+{
+ return ratio_<P2V>(exact(f));
+}
+
+
+
+
int main(int argc, char* argv[])
{
using namespace mln;
@@ -56,8 +106,16 @@
/* Image loadin' */
typedef image2d<int_u8> I;
- I input;
- io::pgm::load(input, argv[1]);
+ image2d<bool> input_;
+ io::pbm::load(input_, argv[1]);
+
+ /* Work on geodesic distance image */
+ I input = transform::distance_geodesic(input_, c8(), mln_max(int_u8));
+
+ if (mydebug)
+ dsp("Distance geodesic");
+
+ io::pgm::save(input, "distance.pgm");
/* Component tree creation */
typedef p_array< mln_site_(I) > S;
@@ -67,20 +125,44 @@
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;
+ typedef morpho::attribute::bbox<I> bbox_t;
+ typedef mln_ch_value_(I, double) A;
- A a = morpho::tree::compute_attribute_image(accu_t (), tree);
+ mln_VAR(attr_image, morpho::tree::compute_attribute_image(bbox_t (), tree));
+ A a = duplicate(ratio(pw::value(attr_image)) | attr_image.domain());
morpho::tree::propagate_representant(tree, a);
if (mydebug) {
- dsp("Image attribute"); display_tree_attributes(tree, a);
+ dsp("Image sharp attribute"); display_tree_attributes(tree, a);
}
- /* Run max accumulator, looking for 5 objects */
+ /* We don't want little components */
+
+ // So we compute card attribute and we filter big components
+ // FIXME: some attributes are compositions of attributes, here
+ // sharpness can give area so, it would be fine if we could give an
+ // optional extra argument to compute_attribute where the
+ // accumulators image will be stored.
+
+// typedef morpho::attribute::card<I> card_t;
+// typedef mln_ch_value_(tree_t::function, mln_result_(card_t)) B;
+
+// B b = morpho::tree::compute_attribute_image(card_t (), tree);
+// morpho::tree::propagate_representant(tree, b);
+
+// if (mydebug) {
+// dsp("Image card attribute"); display_tree_attributes(tree, b);
+// }
+
+// a = duplicate((fun::p2v::ternary(pw::value(b) > pw::cst(2), pw::value(a),
pw::cst(0.0))) | a.domain());
+
+
+ /* Run max accumulator */
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);
+
+ mln_VAR(predicate, pw::value(a) > pw::cst(0.5));
+ obj_array = morpho::tree::run_while(tree, a, argmax, predicate);
if (mydebug) {
dsp("Run max accumulator, lk 4 5 objs"); display_tree_attributes(tree, a);
@@ -94,5 +176,44 @@
std::cout << c;
}
+ /* Now Back Propagate to component */
+ typedef mln_ch_value_(I, bool) M;
+ M mask;
+ initialize(mask, a);
+ data::fill(mask, false);
+
+ mln_fwd_piter_(p_array< mln_psite_(I) >) c(obj_array);
+ for_all(c)
+ {
+ mask(c) = true;
+ propagate_node_to_descendants(c, tree, mask);
+ }
+ morpho::tree::propagate_representant(tree, mask);
+
+ // mask now contains all nodes related to objects
+
+ if (mydebug) {
+ dsp("Create mask and propagate"); display_tree_attributes(tree, mask);
+ }
+
+ /* Labeling */
+ typedef mln_ch_value_(I, value::label<8>) L;
+ value::label<8> nlabel;
+ L label = labeling::blobs(mask, c4(), nlabel);
+ io::ppm::save(debug::colorize(value::rgb8(), label, nlabel), "label.pgm");
+
+ /* Now store output image image */
+ I out;
+ initialize(out, input);
+ data::fill(out, 0);
+ data::paste(input | pw::value(mask), out);
+
+ if (mydebug) {
+ mln_fwd_piter_(p_array< mln_psite_(I) >) c(obj_array);
+ for_all(c)
+ draw::box(out, attr_image(c), mln_max(int_u8));
+ dsp("Mask input"); display_tree_attributes(tree, out);
+ }
+ io::pgm::save(out, "output.pgm");
}
Index: trunk/milena/sandbox/edwin/tree/Makefile
===================================================================
--- trunk/milena/sandbox/edwin/tree/Makefile (revision 3571)
+++ trunk/milena/sandbox/edwin/tree/Makefile (revision 3572)
@@ -1,3 +1,4 @@
+include makefile.rules
TARGET=test
SRC=test.cc
OBJS=${SRC:.cc=.o}
@@ -7,16 +8,15 @@
CXXFLAGS=-I$(MILENADIR) -I./ -W -Wall
-CXXFLAGS += -g -ggdb
-#CXXFLAGS += -DNDEBUG -O1
+
+CXXFLAGS += $(if $(DEBUG), -g -ggdb, -DNDEBUG -O1)
CXX=g++
LD=g++
LDFLAGS=
all: clean $(TARGET)
- #chmod +x exo2.sh
- #./exo2.sh
+
$(TARGET): $(OBJS) $(SRC)
$(LD) $(LDFLAGS) -o $@ $(OBJS)
@@ -29,5 +29,5 @@
clean:
rm -f *.o $(TARGET)
- rm -f *.pbm
- find -name "*.pgm" \! -regex ".*/affiche2?.pgm" -delete
\ No newline at end of file
+ #rm -f *.pbm
+ #find -name "*.pgm" \! -regex ".*/affiche2?.pgm" -delete
Index: trunk/milena/sandbox/edwin/attributes/bbox.hh
===================================================================
--- trunk/milena/sandbox/edwin/attributes/bbox.hh (revision 0)
+++ trunk/milena/sandbox/edwin/attributes/bbox.hh (revision 3572)
@@ -0,0 +1,203 @@
+// 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_ATTRIBUTE_BBOX_HH_
+# define MLN_MORPHO_ATTRIBUTE_BBOX_HH_
+
+/// \file mln/morpho/attribute/bbox.hh
+///
+/// Define an accumulator that computes bounding box of a
+/// component.
+
+# include <mln/core/concept/box.hh>
+
+
+namespace mln
+{
+
+ // Forward declaration.
+
+ namespace morpho {
+ namespace attribute {
+ template <typename I> class bbox;
+ }
+ }
+
+ // Traits.
+
+ namespace trait
+ {
+
+ template <typename I>
+ struct accumulator_< morpho::attribute::bbox<I> >
+ {
+ typedef accumulator::has_untake::no has_untake;
+ typedef accumulator::has_set_value::no has_set_value;
+ typedef accumulator::has_stop::no has_stop;
+ typedef accumulator::when_pix::use_p when_pix;
+ };
+
+ } // end of namespace mln::trait
+
+ namespace morpho {
+ namespace attribute {
+
+ template <typename I>
+ struct bbox : public mln::accu::internal::base<const
box<mln_psite(I)>&, bbox<I> >
+ {
+ typedef mln::accu::internal::base<const box<mln_psite(I)>&, bbox<I>
> super_;
+
+ public:
+ typedef mln_psite(I) P;
+ typedef mln_psite(I) argument;
+
+ bbox();
+
+ /// Manipulators.
+ /// \{
+ void init();
+ void take(const argument& p);
+ void take(const bbox<I>& other);
+ void take_as_init(const argument& p);
+
+ /// \}
+
+ /// Get the value of the accumulator.
+ const box<P>& to_result() const;
+
+
+ /// Check whether this accu is able to return a result.
+ /// Always true here.
+ bool is_valid() const;
+
+ protected:
+
+ bool is_valid_;
+ box<mln_psite(I)> b_;
+ };
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <typename I>
+ inline
+ bbox<I>::bbox()
+ {
+ init();
+ }
+
+ template <typename I>
+ inline
+ void
+ bbox<I>::init()
+ {
+ is_valid_ = false;
+ }
+
+ template <typename I>
+ inline
+ void
+ bbox<I>::take_as_init(const mln_psite(I)& p)
+ {
+ b_.pmin() = p;
+ b_.pmax() = p;
+ is_valid_ = true;
+ }
+
+ template <typename I>
+ inline
+ void
+ bbox<I>::take(const mln_psite(I)& p)
+ {
+ if (!is_valid_)
+ {
+ b_.pmin() = p;
+ b_.pmax() = p;
+ is_valid_ = true;
+ return;
+ }
+ for (unsigned i = 0; i < mln_psite_(I)::dim; ++i)
+ if (p[i] < b_.pmin()[i])
+ b_.pmin()[i] = p[i];
+ else if (p[i] > b_.pmax()[i])
+ b_.pmax()[i] = p[i];
+ }
+
+ template <typename I>
+ inline
+ void
+ bbox<I>::take(const bbox<I>& other)
+ {
+ if (! other.is_valid_)
+ {
+ // no-op
+ return;
+ }
+ if (! this->is_valid_)
+ {
+ // 'other' makes '*this' valid
+ *this = other;
+ is_valid_ = true;
+ return;
+ }
+ // both are valids so:
+ const box<mln_psite(I)>& o_b = other.b_;
+ for (unsigned i = 0; i < mln_psite_(I)::dim; ++i)
+ {
+ if (o_b.pmin()[i] < b_.pmin()[i])
+ b_.pmin()[i] = o_b.pmin()[i];
+ if (o_b.pmax()[i] > b_.pmax()[i])
+ b_.pmax()[i] = o_b.pmax()[i];
+ }
+ }
+
+ template <typename I>
+ inline
+ const box<mln_psite(I)>&
+ bbox<I>::to_result() const
+ {
+ mln_precondition(is_valid_);
+ return b_;
+ }
+
+ template <typename I>
+ inline
+ bool
+ bbox<I>::is_valid() const
+ {
+ return is_valid_;
+ }
+
+
+# endif /* !MLN_INCLUDE_ONLY */
+ } // end of namespace mln::morpho::attribute
+ } // end of namespace mln::morpho
+} // end of namespace mln
+
+
+
+#endif /* !MLN_MORPHO_ATTRIBUTE_BBOX_HH_ */