Comments from Theo or me on your work (Simon's, Guillaume's and yours)
shall be taken into account as soon as you can. It's easier to fix
problems soon. If you need help on a subject, ask us. But don't
leave things un-repaired! (This hold for ChangeLog entries, too.)
As you're starting to better understand the project and the techniques
involved, I'd like to pass on the idea that ``something done right
the first time'' is easier to handle than ``something done quick n'
dirty at first, then fixed/patched a dozen times''.
Also, if you prefer reading French instead of English, ask me so and
I'll comment your patches in French.
Matthieu Garrigues <garrigues(a)lrde.epita.fr> writes:
URL:
https://svn.lrde.epita.fr/svn/oln/trunk/milena
ChangeLog:
2007-10-26 Matthieu Garrigues <garrigues(a)lrde.epita.fr>
Improve fllt. Add more tests.
s/fllt/FLLT/
* mln/set/is_subset_of.hh: New, Test if a point set is a subset of
another.
Indentation is wrong. No capital after a comma.
* mln/util/branch_iter.hh: Update
Would you care to say more about the changes? For instance, you
didn't mention the addition of an operator* (among the rest of
changes).
* mln/util/tree.hh:
(tree<T>::add_child(node<T>*)) New,
Use a period (`.') here, not a comma (`,').
(tree<T>::main_branch()) New.
* sandbox/garrigues/fllt.hh: Improve fllt.
``Improve fllt.'' is not sufficient. You should describe what your
patches does to this file. See
https://www.lrde.epita.fr/dload/guide/guide.html#htoc63
for some examples.
* sandbox/garrigues/test_fllt.cc: Update
``Update'' is not enough. For instance, your patch seems to show you
re-enabled some code; this should be mentioned in this ChangeLog entry.
* sandbox/garrigues/test_fllt2.cc,
* sandbox/garrigues/test_fllt3.cc,
* sandbox/garrigues/test_fllt4.cc,
* sandbox/garrigues/test_fllt5.cc,
* sandbox/garrigues/test_fllt_tiny.cc: New, differents cases of tests
for fllt.
Wrong indentation.
[...]
Index: trunk/milena/mln/set/is_subset_of.hh
===================================================================
--- trunk/milena/mln/set/is_subset_of.hh (revision 0)
+++ trunk/milena/mln/set/is_subset_of.hh (revision 1399)
@@ -0,0 +1,75 @@
+// Copyright (C) 2007 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 MLN_SET_IS_SUBSET_OF_HH
+# define MLN_SET_IS_SUBSET_OF_HH
+
+# include <mln/core/concept/point_set.hh>
+
+namespace mln
+{
+
+ namespace set
+ {
+ /*! \brief Test if a point set is a subset of another point set.
+ *
+ * \relates mln::Point_Set
+ */
+ template <typename Pl, typename Pr>
+ bool
+ is_subset_of(const Point_Set<Pl>& lhs, const Point_Set<Pr>&
rhs);
This function seems to be redundant with mln::PointSet::operator<=
(from mln/core/concept/point_set.hh). You should check with Theo, and
if so, remove this file.
[...]
+#endif // ! MLN_SET_SUBSET_HH
Index: trunk/milena/mln/util/tree.hh
===================================================================
--- trunk/milena/mln/util/tree.hh (revision 1398)
+++ trunk/milena/mln/util/tree.hh (revision 1399)
@@ -71,10 +71,14 @@
children_t& children();
/// Access to the parent node.
+ node<T>* parent();
//node<T>*& parent();
Please don't leave dead code.
- const node<T>* parent() const;
+ /// \{ Add a child to the node
node<T>* add_child(T elt);
+ node<T>* add_child(node<T>* node);
Are we sure we want to manipulate these argument by copy? I'm
referring particularly to the first overloaded method (add_child).
[...]
@@ -147,7 +151,7 @@
branch<T>
tree<T>::main_branch()
{
- return branch<T>(*this, root());
+ return branch<T>(*this, *root());
}
template <typename T>
@@ -222,6 +226,16 @@
return s;
}
+
+ template <typename T>
+ node<T>*
+ node<T>::add_child(node<T>* node)
+ {
+ node->parent_ = this;
+ this->children().push_back(node);
+ return node;
+ }
Mention this new method in your ChangeLog entry, please.
[...]
Index: trunk/milena/mln/util/branch_iter.hh
===================================================================
--- trunk/milena/mln/util/branch_iter.hh (revision 1398)
+++ trunk/milena/mln/util/branch_iter.hh (revision 1399)
@@ -50,6 +50,7 @@
/// Convertion to node.
operator util::node<T>&() const;
+ util::node<T>& operator *();
In our coding conventions, we prefer to stick the star to the
`operator' keyword:
util::node<T>& operator* ();
Which is, as matter of fact...
@@ -94,6 +95,14 @@
}
template <typename T>
+ util::node<T>&
+ branch_iter<T>::operator*()
+ {
+ mln_assertion(n_);
+ return *n_;
+ }
...(almost) the convention you chose in the implementation.
+
+ template <typename T>
bool
branch_iter<T>::is_valid() const
{
@@ -131,7 +140,6 @@
if (s_.top().first == s_.top().second)
//if (*(s_.top().first) == 0)
{
- mln_assertion(n_);
s_.pop();
next();
return;
@@ -141,6 +149,13 @@
n_ = *(s_.top().first);
s_.top().first++;
+ if (!n_)
+ {
+ std::cout << "browsing warning : nul pointer" << std::endl;
Please, flag this debugging using
// FIXME: Debug.
[...]
Index: trunk/milena/sandbox/garrigues/fllt.hh
===================================================================
--- trunk/milena/sandbox/garrigues/fllt.hh (revision 1398)
+++ trunk/milena/sandbox/garrigues/fllt.hh (revision 1399)
@@ -61,8 +61,10 @@
# include <mln/set/uni.hh>
# include <mln/set/diff.hh>
# include <mln/set/inter.hh>
+# include <mln/set/is_subset_of.hh>
# include <mln/util/tree.hh>
+# include <mln/util/branch_iter.hh>
# include <mln/labeling/regional_minima.hh>
# include <mln/labeling/regional_maxima.hh>
@@ -84,15 +86,18 @@
{
template <typename P, typename V>
- struct fllt_node
+ struct fllt_node_elt
{
V value;
set_p<P> points;
set_p<P> holes;
};
- # define fllt_tree(P, V) util::tree< fllt_node<P, V> >
- # define fllt_node(P, V) util::node< fllt_node<P, V> >
+ # define fllt_tree(P, V) util::tree< fllt_node_elt<P, V> >
+ # define fllt_node(P, V) util::node< fllt_node_elt<P, V> >
+ # define fllt_branch(P, V) util::branch< fllt_node_elt<P, V> >
+ # define fllt_branch_iter(P, V) util::branch_iter< fllt_node_elt<P, V>
>
The convention is to prefix macros with `mln_' to avoid name clashes.
// # define fllt_node(P, V) typename
fllt_tree(P, V)::node_t
No dead code please.
[...]
@@ -381,7 +390,6 @@
// debug::println_with_border(u);
image2d<bool> tagged(ima.domain());
fllt_node(P, V)* current_region;
- image2d<fllt_node(P, V)*> regions(ima.domain());
// INIT
Don't shriek!
// Init.
is just fine.
@@ -471,7 +479,7 @@
// debug::println(regions);
//debug::println(ima | regions(make:defined reference to
`mln::fllt::lower<mln::value::int_u<8u>
>::inc':point2d(-4,-1))->elt().points);
Ouch! This line is both (a) too long; and (b) dead.
[...]
@@ -530,16 +538,71 @@
static const neighb2d& reg_nbh() { return c8(); }
};
+ template <typename P, typename V>
+ void
+ move_shape(fllt_node(P, V)& node,
+ fllt_node(P, V)& hole,
+ fllt_tree(P, V)& tree,
+ const image2d<fllt_node(P, V)*>& other_reg)
+ {
+ fill_a_shape(hole, tree, other_reg);
+ node.elt().points = set::uni(hole.elt().points, node.elt().points);
+ node.add_child(&hole);
+ }
Unmentioned new function in ChangeLog. Likewise for the other new
functions below.
The last line is subject to discussion: do we really want to
manipulate argument `hole' by its address? We should discuss this.
-// template <>
-// void find_shape_of_holes(fllt_node(P, V)* lower,
-// fllt_node(P, V)* upper)
-// {
-// }
+ template <typename P, typename V>
+ fllt_node(P, V)*
+ find_the_hole(fllt_node(P, V)& node,
+ const P p,
+ const image2d<fllt_node(P, V)*>& other_reg)
+ {
+ fllt_node(P, V)* s = other_reg(p);
+
+ mln_assertion(s);
+ while (s->parent() && (s->parent()->elt().value <
node.elt().value))
+ {
+ mln_assertion(s);
+ s = s->parent();
+ mln_assertion(s);
+ }
+ return s;
+ }
+
+ template <typename P, typename V>
+ void
+ fill_a_shape(fllt_node(P, V)& node,
+ fllt_tree(P, V)& tree,
+ const image2d<fllt_node(P, V)*>& other_reg)
+ {
+ mln_piter(set_p<P>) p(node.elt().holes);
+ for_all(p)
+ {
+ bool h = true;
+ fllt_node(P, V)* hole = find_the_hole(node, point2d(p), other_reg);
+ typename fllt_node(P, V)::children_t::iterator it;
+ for (it = node.children().begin();
+ it != node.children().end();
+ it++)
Prefer `++it' over `it++' whenever you can.
+ {
+ if (set::is_subset_of(hole->elt().points,
+ (*it)->elt().points))
+ {
+ h = false;
+ break;
+ }
+ }
+ if (h)
+ move_shape(node, *hole, tree, other_reg);
+
+ }
+ }
[...]
@@ -548,35 +611,64 @@
// put the shape of the hole H (and all its descendants) as child of
// the shape .
- fllt_node(P, V)* it = lower;
-
- if (lower->elt().holes.size() > 0)
- {
-
- }
- // FIXME : add an method to tree to get the childen.
- // FIXME : add an iterator to browse a tree.
-
- mln_piter(set_p<P>) p(lower->child_);
+ fllt_branch_iter(P, V) p(lower.main_branch());
for_all(p)
{
- merge_trees(lower, upper);
+ fllt_node(P, V)& n(p);
+ fill_a_shape(n, lower, upp_reg);
}
+// fllt_branch_iter(P, V) q(upper.main_branch());
+// for_all(q)
+// {
+// fllt_node(P, V)& n(p);
+// fill_a_shape(n, upper, low_reg);
+// }
}
template <typename V>
// Fixme : return type
Use capitals for FIXME: it's easier to spot them while reading the
code afterwards.
- void fllt(const image2d<V>& ima)
+ void
+ fllt(const image2d<V>& ima)
{
typedef point2d P;
- fllt_tree(P, V)* upper_tree;
- fllt_tree(P, V)* lower_tree;
+ fllt_tree(P, V) upper_tree;
+ fllt_tree(P, V) lower_tree;
+ image2d<fllt_node(P, V)*> low_reg(ima.domain());
+ image2d<fllt_node(P, V)*> upp_reg(ima.domain());
+
+ lower_tree = compute_level_set<V, lower<V> >(ima, low_reg);
+ upper_tree = compute_level_set<V, upper<V> >(ima, upp_reg);
- lower_tree = compute_level_set<V, lower<V> >(ima);
- upper_tree = compute_level_set<V, upper<V> >(ima);
+ merge_trees(lower_tree, upper_tree, low_reg, upp_reg);
- //merge_trees(lower_tree, upper_tree);
+
+
+ image2d<value::int_u8> output (ima.domain ());
+ util::tree_to_image (lower_tree, output);
+
+ if (output != ima)
+ {
+ std::cerr << "BUG!!!" << std::endl;
+ abort();
+ }
You should comment this output with
// FIXME: Debug.
+
+ io::pgm::save(output, "out_final.pgm");
If this test is to be automated, we'd rather not want to hard-code
file names.
+ std::cout << "out_final.pgm
generate"
+ << std::endl;
+
+
+ fllt_branch_iter(P, V) p(lower_tree.main_branch());
+ for_all(p)
+ {
+ std::cout << "region mere : " << (*p).parent() <<
std::endl;
s/region mere/parent region/
+ std::cout << " ^"
<< std::endl;
+ std::cout << " |" << std::endl;
+ std::cout << "region : " << &*p << std::endl;
+
+ debug::println(ima | (*p).elt().points);
+ std::cout << std::endl;
+ }
}
Likewise: flag this debugging code using FIXMEs.
} // end of namespace mln::fllt
[...]
Index: trunk/milena/sandbox/garrigues/test_fllt2.cc
===================================================================
[...]
Index: trunk/milena/sandbox/garrigues/test_fllt3.cc
===================================================================
[...]
Index:
trunk/milena/sandbox/garrigues/test_fllt_tiny.cc
===================================================================
[...]
Index: trunk/milena/sandbox/garrigues/test_fllt4.cc
===================================================================
[...]
Index: trunk/milena/sandbox/garrigues/test_fllt5.cc
===================================================================
[...]
All these tests are very similar: the changing part(s) is (are)
essentially the input(s). You should factor common parts. Or use
several ASCII PGM images as inputs (which are as readable as
hard-coded data matrices, BTW).