https://svn.lrde.epita.fr/svn/oln/trunk/milena
Index: ChangeLog
from Alexandre Abraham <abraham(a)lrde.epita.fr>
Add personal folder in sandbox with prototype of najman component tree.
* sandbox/abraham: New.
* sandbox/abraham/morpho: New.
* sandbox/abraham/morpho/basic_najman.hh: New, contains Najman component tree.
* sandbox/abraham/morpho/test.cc: New.
* sandbox/abraham/morpho/images: New.
* sandbox/abraham/morpho/images/test_component_tree.pgm: New.
* sandbox/abraham/morpho/topo_wst.hh: New, draft of topological watershed.
* sandbox/abraham/morpho/Makefile: New.
Makefile | 8 +
basic_najman.hh | 287 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
test.cc | 43 ++++++++
topo_wst.hh | 130 +++++++++++++++++++++++++
4 files changed, 468 insertions(+)
Index: sandbox/abraham/morpho/basic_najman.hh
--- sandbox/abraham/morpho/basic_najman.hh (revision 0)
+++ sandbox/abraham/morpho/basic_najman.hh (revision 0)
@@ -0,0 +1,287 @@
+#include <mln/level/sort_psites.hh>
+#include <mln/level/fill.hh>
+#include <mln/core/image2d.hh>
+
+namespace mln
+{
+
+ namespace morpho
+ {
+
+ template <class I, class N>
+ struct basic_najman
+ {
+
+ typedef mln_psite(I) psite;
+
+ struct node {
+ int level;
+ int area;
+ int highest;
+ p_array<mln_psite(I)> children;
+
+ void addChildren(const node& n)
+ {
+ typename p_array<mln_psite(I)>::fwd_piter it(n.children);
+ for (it.start();
+ it.is_valid();
+ it.next())
+ children.append(it.to_psite());
+ }
+ void addChild(const psite n)
+ {
+ children.append(n);
+ }
+ }; // struct node
+
+
+ const Image<I>& ima;
+ const Neighborhood<N>& nbh;
+ mln_ch_value(I, psite) par;
+
+ mln_ch_value(I, psite) Par_tree;
+ // Par_node is handled by par (from ap_maxtree)
+ mln_ch_value(I, int) Rnk_tree;
+ mln_ch_value(I, int) Rnk_node;
+ mln_ch_value(I, psite) lowestNode;
+ mln_ch_value(I, node) nodes;
+ mln_ch_value(I, bool) isproc;
+ psite Root;
+ p_array<mln_psite(I)> S;
+ // std::map<psite,psite> M; // to keep the root of any point.
+
+ basic_najman(const Image<I>& i,
+ const Neighborhood<N>& n)
+ : ima(i),
+ nbh(n),
+ par(exact(i).domain(), exact(i).border()),
+ Par_tree(exact(i).domain(), exact(i).border()),
+ Rnk_tree(exact(i).domain(), exact(i).border()),
+ Rnk_node(exact(i).domain(), exact(i).border()),
+ lowestNode(exact(i).domain(), exact(i).border()),
+ nodes(exact(i).domain(), exact(i).border()),
+ isproc(exact(i).domain(), exact(i).border())
+ {
+ }
+
+
+ void MakeSet_tree(psite x)
+ {
+ Par_tree(x) = x;
+ Rnk_tree(x) = 0;
+ }
+
+ void MakeSet_node(psite x)
+ {
+ par(x) = x; // was Par_node(x) = x;
+ Rnk_node(x) = 0;
+ }
+
+ psite Find_tree(psite x)
+ {
+ if (Par_tree(x) != x)
+ Par_tree(x) = Find_tree(Par_tree(x));
+ return Par_tree(x);
+ }
+
+ void swap(psite& x, psite& y)
+ {
+ psite memo = x;
+ x = y;
+ y = memo;
+ }
+
+ bool is_root(const psite& x) const
+ {
+ return par(x) == x;
+ }
+
+ bool is_level_root(const psite& x) const
+ {
+ return is_root(x) || exact(ima)(par(x)) < exact(ima)(x);
+ }
+
+ psite find_level_root(const psite& x)
+ {
+ if (is_level_root(x))
+ return x;
+ else
+ return par(x) = find_level_root(par(x));
+ }
+
+ psite Find_node(psite x)
+ {
+ if (par(x) != x)
+ par(x) = Find_node(par(x));
+ return par(x);
+ }
+
+ void go()
+ {
+ init();
+ BuildComponentTree();
+ }
+
+
+ void init()
+ {
+ // Sort the points in increasing order
+ S = level::sort_psites_increasing(ima);
+
+ // Clear the marker map
+ level::fill(isproc, false);
+ for (int ip = 0; ip < int(S.npoints()); ++ip)
+ {
+ psite p = S[ip];
+ MakeSet_node(p);
+ MakeSet_tree(p);
+ // if (lowestNode.hold(p))
+ lowestNode(p) = p;
+ // if (nodes.hold(p))
+ nodes(p) = MakeNode(exact(ima)(p));
+ }
+ }
+
+
+ void BuildComponentTree()
+ {
+ for (int ip = 0; ip < int(S.npoints()); ++ip)
+ {
+ psite p = S[ip];
+ isproc(p) = true;
+
+ psite curTree = Find_tree(p);
+ psite curNode = Find_node(lowestNode(curTree));
+
+ mln_niter(N) q(nbh, p);
+
+ for_all(q)
+ if (exact(ima).has(q) and isproc(q) and exact(ima)(q) >= exact(ima)(p)) // f[q]
>= f[p] parce qu'on prend l'ordre de l'histogramme
+ {
+ psite adjTree = Find_tree(q);
+ psite adjNode = Find_node(lowestNode(adjTree));
+ if (curNode != adjNode)
+ {
+ if (nodes(curNode).level == nodes(adjNode).level)
+ curNode = MergeNode(adjNode, curNode);
+ else
+ {
+ // we have nodes[curNode].level < nodes[adjNode].level
+ nodes(curNode).addChild(adjNode);
+ //apparemment NON :Par_node[adjNode] = curNode; // car adjNode devient fils de
curNode
+ nodes(curNode).area += nodes(adjNode).area;
+ nodes(curNode).highest += nodes(adjNode).highest;
+ }
+ }
+ curTree = Link_tree(adjTree, curTree);
+ lowestNode(curTree) = curNode;
+ }
+ }
+ Root = lowestNode(Find_tree(Find_node(psite(0, 0))));
+ // Pour garder une map de correspondance point <-> local_root
+ // for (int ip = 0; ip < int(S.size()); ++ip)
+ // {
+ // psite p = S[ip];
+ // M(p) = Find_node(p);
+ // }
+
+ mln_piter(I) r(par.domain());
+ for_all(r)
+ par(r) = Find_node(r);
+ }
+
+
+ psite MergeNode(psite& node1, psite& node2)
+ {
+ psite tmpNode = Link_node(node1, node2);
+ psite tmpNode2;
+ if (tmpNode == node2)
+ {
+ nodes(node2).addChildren(nodes(node1));
+ tmpNode2 = node1;
+ }
+ else
+ {
+ nodes(node1).addChildren(nodes(node2));
+ tmpNode2 = node2;
+ }
+ nodes(tmpNode).area += nodes(tmpNode2).area;
+ nodes(tmpNode).highest += nodes(tmpNode2).highest;
+ return tmpNode;
+ }
+
+ psite Link_tree(psite x, psite y)
+ {
+ if (Rnk_tree(x) > Rnk_tree(y))
+ swap(x, y);
+ else
+ if (Rnk_tree(x) == Rnk_tree(y))
+ Rnk_tree(y) += 1;
+ Par_tree(x) = y;
+ return y;
+ }
+
+ psite Link_node(psite x, psite y)
+ {
+ if (Rnk_node(x) > Rnk_node(y))
+ swap(x, y);
+ else
+ if (Rnk_node(x) == Rnk_node(y))
+ Rnk_node(y) += 1;
+ par(x) = y; // was Par_node(x) = y;
+ return y;
+ }
+
+ node MakeNode(int level)
+ {
+ node n;
+ n.level = level;
+ n.area = 1;
+ n.highest = level;
+ return n;
+ }
+
+ template <typename C>
+ void image_output(image2d<C>& img)
+ {
+ for(unsigned int i = 0; i < img.domain().len(0); ++i)
+ {
+ for(unsigned int j = 0; j < img.domain().len(1); ++j)
+ {
+ C l = (img(psite(i, j)));//.row() * img.domain().len(1) + (img(psite(i, j))).col();
+ std::cout << " " << l << " ";
+ }
+ std::cout << std::endl;
+ }
+ }
+
+
+
+ void print_tree(psite p)
+ {
+ node& n = nodes(p);
+ std::cout << "psite " << p << "=" <<
(p.row() * exact(lowestNode).domain().len(1) + p.col()) << " : ";
+
+ typename p_array<mln_psite(I)>::fwd_piter it(n.children);
+ for (it.start();
+ it.is_valid();
+ it.next())
+ {
+ psite q = it.to_psite();
+ std::cout << q << "=" << (q.row() *
lowestNode.domain().len(2) + q.col()) << " ";
+ }
+ std::cout << std::endl;
+
+ for (it.start();
+ it.is_valid();
+ it.next())
+ {
+ print_tree(it.to_psite());
+ }
+ }
+
+ }; // struct basic_najman
+
+ }; // namespace morpho
+
+}; // namespace mln
Index: sandbox/abraham/morpho/test.cc
--- sandbox/abraham/morpho/test.cc (revision 0)
+++ sandbox/abraham/morpho/test.cc (revision 0)
@@ -0,0 +1,43 @@
+#include <mln/core/image2d.hh>
+#include <mln/core/window2d.hh>
+#include <mln/core/neighb2d.hh>
+
+#include <mln/value/int_u8.hh>
+
+//#include <mln/morpho/meyer_wst.hh>
+
+#include <mln/io/pgm/load.hh>
+#include <mln/io/pgm/save.hh>
+
+# include "basic_najman.hh"
+// # include "topo_wst.hh"
+
+int main ()
+{
+ using namespace mln;
+ using value::int_u8;
+
+ // component_tree< image2d<int_u8> > c;
+
+ using namespace mln;
+ using value::int_u8;
+
+ image2d<int_u8> input;
+ io::pgm::load(input, "./images/test_component_tree.pgm");
+
+ morpho::basic_najman< image2d<int_u8>, neighb2d> n(input, c8());
+ n.image_output(input);
+ n.go();
+ n.image_output(n.Par_tree);
+ n.print_tree(n.Root);
+ n.image_output(n.par);
+ std::cout << " --------------------------- " << std::endl;
+ n.image_output(n.Rnk_tree);
+ std::cout << " --------------------------- " << std::endl;
+ n.image_output(n.Rnk_node);
+
+ // image2d<int_u8> output = morpho::topo_wst(input, c4());
+ // io::pgm::save(output, "out.pgm");
+
+ return 0;
+}
Index: sandbox/abraham/morpho/images/test_component_tree.pgm
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: sandbox/abraham/morpho/images/test_component_tree.pgm
___________________________________________________________________
Name: svn:mime-type
+ application/octet-stream
Index: sandbox/abraham/morpho/topo_wst.hh
--- sandbox/abraham/morpho/topo_wst.hh (revision 0)
+++ sandbox/abraham/morpho/topo_wst.hh (revision 0)
@@ -0,0 +1,130 @@
+// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of the Olena Library. This library is free
+// software; you can redistribute it and/or modify it under the terms
+// of the GNU General Public License version 2 as published by the
+// Free Software Foundation.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this library; see the file COPYING. If not, write to
+// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+// Boston, MA 02111-1307, USA.
+//
+// As a special exception, you may use this file as part of a free
+// software library without restriction. Specifically, if other files
+// instantiate templates or use macros or inline functions from this
+// file, or you compile this file and link it with other files to
+// produce an executable, this file does not by itself cause the
+// resulting executable to be covered by the GNU General Public
+// License. This exception does not however invalidate any other
+// reasons why the executable file might be covered by the GNU General
+// Public License.
+
+#ifndef MLN_MORPHO_TOPO_WST_HH
+# define MLN_MORPHO_TOPO_WST_HH
+
+/** \file mln/morpho/topo_wst.hh
+ \brief Topological Watershed Transform (WST) algorithm.
+
+ Reference:
+ Quasi-linear algorithms for the topological watershed. Michel
+ Courie and Laurent Najman and Gilles Bertrand.
+*/
+
+# include <mln/trait/ch_value.hh>
+
+//# include <mln/util/greater_psite.hh>
+# include <mln/morpho/includes.hh>
+//# include <mln/morpho/extrema_components.hh>
+
+# include "component_tree.hh"
+
+namespace mln
+{
+
+ namespace morpho
+ {
+
+ /** \brief Topological Watershed Transform (WST) algorithm.
+
+ \param[in] input The input image.
+ \param[in] nbh The connexity of markers.
+ \param[out] nbasins The number of basins.
+
+ \li \p L is the type of labels, used to number the watershed
+ itself (with the minimal value), and the basins.
+ \li \p I is the exact type of the input image.
+ \li \p N is the exact type of the neighborhood used to express
+ \a input's connexity. */
+ template <typename L, typename I, typename N>
+ mln_ch_value(I, L)
+ topo_wst(const Image<I>& input, const Neighborhood<N>& nbh);
+
+ template <typename I, typename P>
+ bool is_m_destructible(const Image<I>& ima, const Point<P>&
point, component_tree c);
+
+ template <typename L, typename I, typename N>
+ mln_ch_value(I, L)
+ m_wst(const Image<I>& input, const Neighborhood<N>& nbh);
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ template <typename I, typename P>
+ int is_m_destructible(const Image<I>& ima, const mln_psite(I) p, const
Neighborhood<N>& nbh, component_tree c)
+ {
+ p_set<P> v;
+
+ mln_niter(N) n(nbh, p);
+ for_all(n)
+ if (n < p)
+ v = uni(V, c(n));
+ if (v.is_empty())
+ return -1;
+
+ p_set<P>::fwd_piter p = v.begin();
+ if (c(*p).children.size() != 0)
+ return -1;
+
+ component_tree highest_fork = c.highest_fork(v);
+ if (highest_fork.level == -1)
+ return -1;
+
+ return highest_fork.level;
+ }
+
+ template <typename L, typename I, typename N>
+ mln_ch_value(I, L)
+ m_wst(const Image<I>& input, const Neighborhood<N>& nbh);
+ {
+ typedef
+ std::priority_queue< psite, std::vector<psite>, util::greater_psite<I>
>
+ ordered_queue_type;
+
+ ordered_queue_type queue();
+ component_tree c(input);
+
+ mln_piter(I) p(input.domain());
+
+ for_all(p)
+ {
+ if (is_m_destructible(input, p, c4(), c
+ }
+
+ }
+
+
+
+# endif // ! MLN_INCLUDE_ONLY
+
+ } // end of namespace mln::morpho
+
+} // end of namespace mln
+
+
+#endif // ! MLN_MORPHO_TOPOLOGICAL_WST_HH
Index: sandbox/abraham/morpho/Makefile
--- sandbox/abraham/morpho/Makefile (revision 0)
+++ sandbox/abraham/morpho/Makefile (revision 0)
@@ -0,0 +1,8 @@
+SOURCE=test.cc
+OBJECTS=test.o
+CXXFLAGS=-Wall -W -I ../../.. -g
+
+all:${OBJECTS}
+ g++ ${FLAGS} ${OBJECTS} -o test
+
+test.o: basic_najman.hh
\ No newline at end of file