https://svn.lrde.epita.fr/svn/oln/trunk/milena/sandbox
The code is probably finished (and compiles!), but is buggy: the program
gets a SIGSEGV at run time...
Index: ChangeLog
from Roland Levillain <roland(a)lrde.epita.fr>
Finish the computation of the fusion graph test.
* beguin/irm.cc: s/node/vertex/.
(my_mln::mk2_graph): Disable.
(my_mln::region_data, my_mln::abs_diff_threshold): New structs.
(my_mln::make_fg, my_mln::merge_fg): New routines.
(my_mln::main): Adjust.
Compute the fusion graphs and output a result.
* beguin/+irm6.pgm: Rename image as...
* beguin/irm6.pgm: ...this.
irm.cc | 307 +++++++++++++++++++++++++++++++++++++++++++++++++++++------------
1 file changed, 253 insertions(+), 54 deletions(-)
Index: beguin/irm.cc
--- beguin/irm.cc (revision 1995)
+++ beguin/irm.cc (working copy)
@@ -1,6 +1,11 @@
+// g++ -Wall -Wextra -DNDEBUG -O3 -I../.. -o irm irm.cc
+// g++ -Wall -Wextra -ggdb -I../.. -o irm irm.cc
+
#include <iterator>
#include <iostream>
#include <algorithm>
+
+#include <set>
#include <map>
#include <mln/core/image2d.hh>
@@ -12,8 +17,12 @@
#include <mln/io/pgm/load.hh>
#include <mln/io/pgm/save.hh>
+#include <mln/io/ppm/save.hh>
#include <mln/value/int_u8.hh>
+#include <mln/value/rgb8.hh>
+#include <mln/literal/colors.hh>
+
#include <mln/level/transform.hh>
#include <mln/convert/to_window.hh>
@@ -32,7 +41,7 @@
#include <mln/debug/println.hh>
//#include <segm_to_pregraph.hh>
-#include <fusion_graph2.hh>
+// #include <fusion_graph2.hh>
mln::value::int_u8 foo(unsigned u)
{
@@ -42,9 +51,10 @@
}
-namespace mln
-
+namespace my_mln
{
+ using namespace mln;
+
template <typename I>
void region_10(const I& lbl)
@@ -163,12 +173,12 @@
//
// // Graph.
// util::graph<float> g;
-// // Nodes.
+// // Vertices.
// for (unsigned i = 0; i <= nlabels; ++i)
// {
// accu::mean_<unsigned> m;
// level::take(irm | (pw::value(lbl) == pw::cst(i)), m);
-// g.add_node(m.to_result());
+// g.add_vertex(m.to_result());
// }
// // Edges.
// for (unsigned l1 = 1; l1 <= nlabels; ++l1)
@@ -176,11 +186,16 @@
// if (adja[l1][l2])
// g.add_edge(l1, l2);
// //g.print_debug (std::cout);
-// for( int i = 0 ; i < g.nnodes() ; ++i)
-// std::cout << "[" << i << " : " <<
g.node_data(i) << " ] ";
+// for( int i = 0 ; i < g.nvertices() ; ++i)
+// std::cout << "[" << i << " : " <<
g.vertex_data(i) << " ] ";
// std::cout << std::endl;
// }
+
+ /*------------------------.
+ | Region adjacent graph. |
+ `------------------------*/
+
/// Build a region adjacency graph.
template <typename I, typename J, typename N>
util::graph< accu::mean_<mln_value(J)> >
@@ -190,19 +205,19 @@
for (unsigned l = 0; l <= nlabels; ++l)
adja[l].resize(nlabels + 1, false);
- mln_piter(I) p(lbl.domain());
+ mln_piter(I) p(label.domain());
mln_niter(N) n(nbh, p);
// We compute the adjacency matrix of the RAG.
for_all(p)
- if (lbl(p) == 0) // wshed
+ if (label(p) == 0) // wshed
{
std::set<unsigned> s;
- for_all(n) if (lbl.has(n))
+ for_all(n) if (label.has(n))
{
- if (lbl(n) == 0)
+ if (label(n) == 0)
continue;
- s.insert(lbl(n));
+ s.insert(label(n));
}
if (s.size() < 2)
{
@@ -227,12 +242,12 @@
// Graph.
util::graph< accu::mean_<mln_value(J)> > g;
- // Nodes.
+ // Vertices.
for (unsigned i = 0; i <= nlabels; ++i)
{
accu::mean_<mln_value(J)> m;
- level::take(irm | (pw::value(lbl) == pw::cst(i)), m);
- g.add_node(m);
+ level::take(input | (pw::value(label) == pw::cst(i)), m);
+ g.add_vertex(m);
}
// Edges.
for (unsigned l1 = 1; l1 <= nlabels; ++l1)
@@ -240,57 +255,210 @@
if (adja[l1][l2])
g.add_edge(l1, l2);
//g.print_debug (std::cout);
- for( int i = 0 ; i < g.nnodes() ; ++i)
- std::cout << "[" << i << " : " <<
g.node_data(i) << " ] ";
+ for( unsigned i = 0 ; i < g.nvertices() ; ++i)
+ std::cout << "[" << i << " : " <<
g.vertex_data(i) << " ] ";
std::cout << std::endl;
return g;
}
- template <typename I, typename J, typename N>
- void mk2_graph(const I& lbl , const J& irm , const N&
- nbh, int nbasins)
+// template <typename I, typename J, typename N>
+// void mk2_graph(const I& label , const J& input , const N&
+// nbh, int nbasins)
+// {
+// typedef mln::p_set<mln_point(I)> R;
+// std::map<int, R > regions;
+
+// mln_piter(I) p(label.domain());
+// for_all(p)
+// {
+// if (unsigned int i = label(p))
+// regions[i].insert(p);
+// }
+
+// std::cout << "Boite englobante de la r�gion 10 : " <<
regions[10].bbox() << std::endl;
+
+// /*
+// for (unsigned i = 0 ; i<nbasins ; ++i)
+// {
+
+// }
+// for (unsigned i = 0 ; i<regions.size() ; ++i)
+// g.add_vertex(regions[]);
+// */
+// }
+
+
+ /*---------------.
+ | Fusion graph. |
+ `---------------*/
+
+ /// The data associated to the vertex of a fusion graph.
+ template <typename A>
+ struct region_data
{
- typedef mln::p_set<mln_point(I)> R;
- std::map<int, R > regions;
+ // The subregions composing the region.
+ std::set<util::vertex_id> subregions;
+ // An accumulator.
+ A accumulator;
+ };
- mln_piter(I) p(lbl.domain());
- for_all(p)
+
+ /// Build a fusion graph from a RAG.
+ template <typename A>
+ util::graph< region_data<A> >
+ make_fg(const util::graph<A>& rag)
+ {
+ typedef util::graph<A> region_adjacency_graph;
+ typedef util::graph< region_data<A> > fusion_graph;
+
+ fusion_graph fg;
+
+ // Vertices.
+ for (util::vertex_id i = 0; i < rag.nvertices(); ++i)
+ {
+ // The singleton subregion: { I }.
+ std::set<util::vertex_id> sr;
+ sr.insert(i);
+ // The accumulator.
+ A a = rag.vertex_data(i);
+ // The region data
+ region_data<A> data = { sr, a };
+
+ // Add the vertex at index I.
+ fg.add_vertex(data);
+ }
+
+ // Edges.
+ for (typename region_adjacency_graph::edges_t::const_iterator e =
+ rag.edges().begin(); e != rag.edges().end(); ++e)
+ {
+ util::vertex_id v1 = (*e)->v1();
+ util::vertex_id v2 = (*e)->v2();
+ fg.add_edge(v1, v2);
+ }
+
+ return fg;
+ }
+
+ /// Merge regions of the fusion graph.
+ template <typename A, typename C>
+ util::graph< region_data<A> >
+ merge_fg(const util::graph< region_data<A> >& input, const C&
criterion)
+ {
+ typedef util::graph< region_data<A> > fusion_graph;
+
+ // A disjoint set of vertices represented as a forest of rooted
+ // trees (disjoint set forest).
+ std::vector<util::vertex_id> parent(input.nvertices());
+ for (util::vertex_id i = 0; i < parent.size(); ++i)
+ // � make_set �.
+ parent[i] = i;
+
+ // Parent.
+ for (typename fusion_graph::edges_t::const_iterator e =
+ input.edges().begin(); e != input.edges().end(); ++e)
{
- if (unsigned int i = lbl(p))
- regions[i].insert(p);
+ util::vertex_id v1 = (*e)->v1();
+ util::vertex_id v2 = (*e)->v2();
+ A accu1 = input.vertex_data(v1).accumulator;
+ A accu2 = input.vertex_data(v2).accumulator;
+ if (criterion(accu1.to_result(), accu2.to_result()))
+ // � union �.
+ parent[v1] = v2;
}
- std::cout << "Boite englobante de la région 10 : " <<
regions[10].bbox() << std::endl;
+ // Children.
+ typedef std::multimap<util::vertex_id, util::vertex_id> children_t;
+ children_t children;
+ for (typename util::vertex_id i = 0; i < parent.size(); ++i)
+ {
+ // � find �.
+ util::vertex_id r = i;
+ while (r != parent[r])
+ r = parent[r];
+ children.insert(std::make_pair(r, i));
+ }
+
+ /// Data associated to merged regions.
+ typedef std::map< util::vertex_id, region_data<A> >
merged_region_data_t;
+ merged_region_data_t merged_region_data;
+ for (typename children_t::const_iterator i = children.begin();
+ i != children.end(); ++i)
+ {
+ util::vertex_id root = i->first;
+ util::vertex_id child = i->second;
+
+ region_data<A>& root_data = merged_region_data[root];
+ const region_data<A>& child_data = input.vertex_data(child);
+
+ root_data.subregions.insert(child_data.subregions.begin(),
+ child_data.subregions.end());
+ root_data.accumulator.take(child_data.accumulator);
+ }
- /*
- for (unsigned i = 0 ; i<nbasins ; ++i)
+ // Fusion graph.
+ fusion_graph output;
+ std::map<util::vertex_id, util::vertex_id> old_to_new_root;
+ // Vertices.
+ for (typename merged_region_data_t::const_iterator i =
+ merged_region_data.begin(); i != merged_region_data.end(); ++i)
+ {
+ util::vertex_id v = output.add_vertex(i->second);
+ old_to_new_root[i->first] = v;
+ }
+ // Edges.
+ for (typename fusion_graph::edges_t::const_iterator e =
+ input.edges().begin(); e != input.edges().end(); ++e)
{
+ // The root of the first vertex connected to E.
+ util::vertex_id r1 = (*e)->v1();
+ while (r1 != parent[r1])
+ r1 = parent[r1];
+ // The root of the second vertex connected to E.
+ util::vertex_id r2 = (*e)->v2();
+ while (r2 != parent[r2])
+ r2 = parent[r2];
+ if (r1 != r2)
+ {
+ // The regions represented by R1 and R2 are connected.
+ output.add_edge(old_to_new_root[r1], old_to_new_root[r2]);
+ }
}
- for (unsigned i = 0 ; i<regions.size() ; ++i)
- g.add_node(regions[]);
- */
+ return output;
}
+} // end of namespace my_mln
-} // end of namespace mln
-template <typename A>
-struct region_data
+struct abs_diff_threshold
{
- // The subregions composing the region.
- std::set<util::vertex_id> subregions;
- // An accumulator.
- A a;
+ abs_diff_threshold(int threshold)
+ : threshold_(threshold)
+ {
+ }
+
+ template <typename T>
+ bool operator() (const T& a, const T& b) const
+ {
+ return std::abs(a - b) < threshold_;
}
+private:
+ int threshold_;
+};
+
+
+
int main()
{
using namespace mln;
+ using namespace my_mln;
using value::int_u8;
+ using value::rgb8;
image2d<int_u8> irm;
- io::pgm::load(irm, "./+irm6.pgm");
+ io::pgm::load(irm, "./irm6.pgm");
// io::pgm::save( morpho::gradient(irm, win::rectangle2d(3,3)),
// "tmp_grad_3x3.pgm" );
@@ -316,22 +484,53 @@
//typedef fusion_graph<unsigned int, void> _fg;
//_fg fg(wshed , irm , c8() , nbasins);
-// fusion_graph fg(lbl&, irm&, c4(), nbasins);
-// std::cout << "nnodes = " << fg.nnodes() << std::endl
+// fusion_graph fg(label&, irm&, c4(), nbasins);
+// std::cout << "nvertices = " << fg.nvertices() <<
std::endl
// << "nregions = " << fg.nn() << std::endl;
- // Region adjacency graph.
- util::graph< accu::mean_<int_u8> > rag = make_rag(wshed, irm, c4(),
nbasins);
-
- // Fusion graph.
-
- typedef util::graph< region_data< accu::mean<int_u8> > fusion_graph;
-
- fusion_graph output;
+ // Region adjacency graph (RAG).
+ typedef util::graph< accu::mean_<int_u8> > region_adjacency_graph;
+ region_adjacency_graph rag = make_rag(wshed, irm, c4(), nbasins);
+
+ // Fusion graph (FG).
+ typedef util::graph< region_data< accu::mean_<int_u8> > >
fusion_graph;
+ fusion_graph fg = make_fg(rag);
fusion_graph work;
do
- work = output;
- output = merge(work);
- while (work.nvertices() != output.nvertices());
-
+ {
+ work = fg;
+ fg = merge_fg (work, abs_diff_threshold(20));
+ std::cerr << "work.nvertices() = " << work.nvertices()
<< std::endl;
+ std::cerr << "fg.nvertices() = " << fg.nvertices() <<
std::endl;
+ }
+ while (work.nvertices() != fg.nvertices());
+
+ // Compute the values (means) for the output image.
+ std::map<util::vertex_id, int_u8> region_value;
+ for (util::vertex_id v = 0; v < fg.nvertices(); ++v)
+ {
+ // FIXME: Implicit cast. We should rather change the type of
+ // the accumulator instead.
+ int_u8 mean = fg.vertex_data(v).accumulator.to_result();
+ for (std::set<util::vertex_id>::const_iterator sr =
+ fg.vertex_data(v).subregions.begin();
+ sr != fg.vertex_data(v).subregions.end();
+ ++sr)
+ region_value[*sr] = mean;
+ }
+
+ // Output.
+ image2d<rgb8> output(wshed.domain());
+ mln_piter_(image2d<rgb8>) p(output.domain());
+ for_all (p)
+ {
+ if (wshed(p) == 0)
+ output(p) = literal::red;
+ else
+ {
+ int_u8 mean = region_value[wshed(p)];
+ output(p) = rgb8(mean, mean, mean);
+ }
+ }
+ io::ppm::save(output, "out.ppm");
}