Commit b654f0d4 authored by Roland Levillain's avatar Roland Levillain
Browse files

Merge branch 'apps-ismm-2009' into next

Conflicts:
	milena/ChangeLog
parents e3372705 d590e49d
2011-11-24 Roland Levillain <roland@lrde.epita.fr>
Honor a precondition in classification examples (ISMM 2009).
* apps/papers/levillain.09.ismm/classif-graph.cc,
* apps/papers/levillain.09.ismm/classif-1complex.cc:
Do not use a value outside the range [0, nbasins] in `canvas_wst'
to prevent a failed precondition in labeling::colorize (when
NDEBUG is not defined).
Reported by David Coeurjolly <david.coeurjolly at liris.cnrs.fr>.
2011-10-11 Roland Levillain <roland@lrde.epita.fr>
Graph-based version of the classification example.
* apps/papers/levillain.09.ismm/classif-graph.cc: New.
* apps/papers/levillain.09.ismm/Makefile.am (noinst_PROGRAMS):
Add classif-graph.
(classif_graph_SOURCES): New.
(noinst_DATA): Add classwst-graph.ppm.
(classwst-graph.ppm): New target.
2011-10-10 Roland Levillain <roland@lrde.epita.fr>
Rename apps/papers/levillain.09.ismm/classif.cc.
* apps/papers/levillain.09.ismm/classif.cc: Rename as...
* apps/papers/levillain.09.ismm/classif-1complex.cc: ...this.
* apps/papers/levillain.09.ismm/Makefile.am
(noinst_PROGRAMS, noinst_DATA): s/classif/classif-1complex/.
(classif_SOURCES, classwst.pnm): Replace by...
(classif_1complex_SOURCES, classwst-1complex.ppm): ...these.
2011-10-10 Roland Levillain <roland@lrde.epita.fr>
Aesthetic changes in apps/papers/levillain.09.ismm/classif.cc.
* apps/papers/levillain.09.ismm/classif.cc: Here.
Remove useless headers inclusions.
Adjust comments.
2011-10-05 Roland Levillain <roland@lrde.epita.fr>
Fix and clean up apps/papers/levillain.09.ismm/classif.cc.
* apps/papers/levillain.09.ismm/classif.cc (main): Actually use
the chain() routine from chain.hh instead of ad hoc code.
Move code related to the construction of the 1-complex (graph)
image on which the processing chain is run...
(make_complex_image): ...here.
* apps/papers/levillain.09.ismm/Makefile.am (classwst.pnm): Change
the lambda (area) parameter to 4.
2011-10-04 Roland Levillain <roland@lrde.epita.fr>
Import the WST-based classification in apps/papers/levillain.09.ismm.
* apps/papers/levillain.09.ismm/Makefile.am
(noinst_PROGRAMS): Add classif.
(classif_SOURCES): Add classif.cc
(dist_noinst_DATA): Add classseedsi.pbm.
(noinst_DATA): Add classwst.pnm.
(classwst.pnm): New target.
* apps/papers/levillain.09.ismm/classif.cc: New.
Copied and adapted from
sandbox/theo/esiee/laurent/presentation/classif.cc.
* apps/papers/levillain.09.ismm/classseedsi.pbm: New.
2011-10-04 Roland Levillain <roland@lrde.epita.fr>
Split apps/papers/levillain.09.ismm/graph.cc.
* apps/papers/levillain.09.ismm/graph.cc: Misc. changes.
(mln::influence_zones)
(mln::io::neato::save):
Move functions...
* apps/papers/levillain.09.ismm/influence_zones.hh,
* apps/papers/levillain.09.ismm/io.hh:
...here (new files).
* apps/papers/levillain.09.ismm/Makefile.am (noinst_HEADERS):
Add io.hh and influence_zones.hh
2011-11-29 Guillaume Lazzara <z@lrde.epita.fr>
 
Fix the initialization of all global constants (ticket #43)
# Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE).
# Copyright (C) 2008, 2009, 2011 EPITA Research and Development
# Laboratory (LRDE).
#
# This file is part of Olena.
#
......@@ -14,7 +15,7 @@
# You should have received a copy of the GNU General Public License
# along with Olena. If not, see <http://www.gnu.org/licenses/>.
# Illustrations from the ISMM 2009 paper.
# Illustrations from the ISMM 2009 paper and presentation (slides).
# Find Milena headers.
AM_CPPFLAGS = -I$(top_srcdir)/milena -I$(top_builddir)/milena
......@@ -22,21 +23,30 @@ AM_CPPFLAGS = -I$(top_srcdir)/milena -I$(top_builddir)/milena
APPS_CXXFLAGS = @APPS_CXXFLAGS@
AM_CXXFLAGS = $(APPS_CXXFLAGS)
noinst_HEADERS = chain.hh
noinst_HEADERS = chain.hh io.hh influence_zones.hh
noinst_PROGRAMS = image2d graph complex
noinst_PROGRAMS = image2d graph complex classif-graph classif-1complex
image2d_SOURCES = image2d.cc
graph_SOURCES = graph.cc
complex_SOURCES = complex.cc
# This example (implemented both with graph- and 1-complex-based
# images) has been shown in the ISMM 2009 presentation only (not in
# the paper).
classif_graph_SOURCES = classif-graph.cc
classif_1complex_SOURCES = classif-1complex.cc
# Input images.
# FIXME: Move them to milena/img/?
dist_noinst_DATA = seeds.pgm m283-c.off
dist_noinst_DATA = seeds.pgm m283-c.off classseedsi.pbm
# Output images.
noinst_DATA = lena-s.ppm graph-s.png m283-s.off
noinst_DATA = \
lena-s.ppm graph-s.png m283-s.off \
classwst-graph.ppm classwst-1complex.ppm
MOSTLYCLEANFILES = $(noinst_DATA) graph-s.neato
# FIXME: Also generate intermediate images (gradients, etc.).
lena-s.ppm: $(top_srcdir)/milena/img/lena.pgm image2d$(EXEEXT)
./image2d$(EXEEXT) $< 1000 $@
......@@ -47,3 +57,9 @@ graph-s.neato: seeds.pgm graph$(EXEEXT)
m283-s.off: m283-c.off complex$(EXEEXT)
./complex$(EXEEXT) $< 100 $@
classwst-graph.ppm: classseedsi.pbm classif-graph$(EXEEXT)
./classif-graph$(EXEEXT) $< 4 $@
classwst-1complex.ppm: classseedsi.pbm classif-1complex$(EXEEXT)
./classif-1complex$(EXEEXT) $< 4 $@
// Copyright (C) 2008, 2009, 2011 EPITA Research and Development
// Laboratory (LRDE)
//
// This file is part of Olena.
//
// Olena is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation, version 2 of the License.
//
// Olena 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 Olena. If not, see <http://www.gnu.org/licenses/>.
//
// As a special exception, you may use this file as part of a free
// software project 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.
#include <iostream>
#include <vector>
#include <mln/core/image/image2d.hh>
#include <mln/core/alias/neighb2d.hh>
#include <mln/labeling/blobs.hh>
#include <mln/io/pbm/load.hh>
#include <mln/io/pgm/save.hh>
#include <mln/io/ppm/save.hh>
#include <mln/debug/println.hh>
#include <mln/draw/line.hh>
#include <mln/value/int_u8.hh>
#include <mln/core/alias/point2d.hh>
#include <mln/core/site_set/p_faces.hh>
#include <mln/core/image/complex_image.hh>
#include <mln/core/alias/complex_image.hh>
#include <mln/core/image/complex_neighborhoods.hh>
#include <mln/core/image/complex_neighborhood_piter.hh>
#include <mln/data/fill.hh>
#include <mln/norm/l2.hh>
#include <mln/labeling/colorize.hh>
#include "influence_zones.hh"
#include "chain.hh"
/** Create a 1-complex (graph) image from the connected components of
\a seeds. The values associated to a 1-face (edge) is equal to
the L2-distance between its two adjacent vertices. The values on
a 0-face (vertex) is set to 0. */
mln::int_u8_1complex_image2d
make_complex_image(const mln::image2d<bool>& seeds)
{
using namespace mln;
using mln::value::int_u8;
border::thickness = 0;
/*-----------------------.
| Connected components. |
`-----------------------*/
unsigned nlabels;
image2d<unsigned> label = labeling::blobs(seeds, c4(), nlabels);
std::cout << "n seeds = " << nlabels << std::endl;
{
image2d<int_u8> lab(label.domain());
data::paste(label, lab);
#if 0
io::pgm::save(lab, "label.pgm");
#endif
}
/*------------------.
| Influence zones. |
`------------------*/
image2d<unsigned> iz = influence_zones(label, c4());
{
image2d<int_u8> IZ(iz.domain());
data::paste(iz, IZ);
#if 0
io::pgm::save(IZ, "iz.pgm");
#endif
}
/*--------------------------------.
| Construction of the 1-complex. |
`--------------------------------*/
// Adjacency matrix.
std::vector< std::vector<bool> > adj(nlabels + 1);
for (unsigned l = 1; l <= nlabels; ++l)
adj[l].resize(nlabels + 1, false);
{
box2d::piter p(iz.domain());
for_all(p)
{
point2d r = p + right, b = p + down;
if (iz.has(r) && iz(p) != iz(r))
{
if (iz(p) != iz(r))
adj[iz(p)][iz(r)] = true;
else
adj[iz(r)][iz(p)] = true;
}
if (iz.has(b) && iz(p) != iz(b))
{
if (iz(p) != iz(b))
adj[iz(p)][iz(b)] = true;
else
adj[iz(b)][iz(p)] = true;
}
}
}
const unsigned D = 1;
// 1-complex data structure.
topo::complex<D> c;
typedef point2d P;
// Geometry (spatial locations) associated to the complex's faces.
typedef geom::complex_geometry<D, P> G;
G geom;
// Convenience typedefs.
typedef topo::n_face<0, D> vertex;
typedef topo::n_face<1, D> edge;
{
// 0-faces (vertices).
std::vector<vertex> v;
{
box2d::piter p(label.domain());
for_all(p)
if (label(p) != 0)
{
geom.add_location(p);
v.push_back(c.add_face());
}
}
std::cout << "v size = " << v.size() << std::endl;
// 1-faces (edges).
std::vector<edge> e;
{
for (unsigned l = 1; l <= nlabels; ++l)
for (unsigned ll = l + 1; ll <= nlabels; ++ll)
if (adj[l][ll])
// Create an edge as an oriented (``algebraic'') face.
e.push_back(c.add_face(-v[l-1] + v[ll-1]));
}
std::cout << "e size = " << e.size() << std::endl;
}
/*-------------------------.
| Complex-based site set. |
`-------------------------*/
p_complex<D, G> pc(c, geom);
/*----------------------.
| Complex-based image. |
`----------------------*/
// An image type built on a 1-complex with int_u8 values on each
// face (both vertices and edges).
typedef complex_image<D, G, int_u8> dist_ima_t;
// Create and initialize an image based on PC.
dist_ima_t dist_ima(pc);
data::fill(dist_ima, 0u);
/*--------------------------------.
| Complex-based image iterators. |
`--------------------------------*/
accu::stat::max<int_u8> dist_max;
// Output image for visualization purpose only.
image2d<int_u8> canvas(seeds.domain());
data::fill(canvas, 0);
// Iterator on the edges of DIST_IMA.
p_n_faces_fwd_piter<D, G> e(dist_ima.domain(), 1);
// n-face to (n-1)-faces neighborhood (here, the pair of vertices
// adjacent to an edge).
typedef complex_lower_neighborhood<D, G> v_nbh_t;
v_nbh_t v_nbh;
// For each edge (1-face), compute the distance between the two
// adjacent vertices (0-faces).
mln_niter_(v_nbh_t) v(v_nbh, e);
for_all(e)
{
v.start();
point2d p1 = v.to_site().front();
v.next();
point2d p2 = v.to_site().front();
v.next();
mln_invariant(!v.is_valid());
dist_ima(e) = norm::l2_distance(p1.to_vec(), p2.to_vec());
dist_max.take(dist_ima(e));
draw::line(canvas, p1, p2, dist_ima(e));
canvas(p1) = 255;
canvas(p2) = 255;
}
std::cout << "distance max = " << dist_max << std::endl;
#if 0
io::pgm::save(canvas, "canvas.pgm");
#endif
return dist_ima;
}
int
main(int argc, char* argv[])
{
if (argc != 4)
{
std::cerr << "usage: " << argv[0] << " input.pbm lambda output.ppm"
<< std::endl;
std::exit(1);
}
std::string input_filename = argv[1];
unsigned lambda = atoi(argv[2]);
std::string output_filename = argv[3];
using namespace mln;
using mln::value::int_u8;
// Seeds.
image2d<bool> seeds;
io::pbm::load(seeds, input_filename);
// Shortcut: type of a 1-complex image located in a discrete 2D
// space with int_u8 values for each face.
typedef int_u8_1complex_image2d ima_t;
// Shortcuts: dimension and geometry (set of spatial locations)
// associated to this image type.
const unsigned D = 1;
typedef mln_geom_(ima_t) G;
// Image computed from the graph of influence zones (IZ) of seeds.
ima_t ima = make_complex_image(seeds);
// Adjacency relation between two n-faces through a shared adjacent
// (n-1)-face. (An edge is adjacent to its neighboring edges; a
// vertex has no neighbors.)
typedef complex_lower_dim_connected_n_face_neighborhood<D, G> nbh_t;
nbh_t nbh;
typedef unsigned wst_val_t;
wst_val_t nbasins;
// Output image type.
typedef complex_image<D, G, wst_val_t> wst_ima_t;
// Chain.
wst_ima_t wst_ima = chain(ima, nbh, lambda, nbasins);
// Output image showing the results of the above chain on an image
// similar to the input.
image2d<int_u8> canvas_wst(seeds.domain());
data::fill(canvas_wst, 0);
// Iterator on the edges (1-faces) of WST_IMA.
p_n_faces_fwd_piter<D, G> e(wst_ima.domain(), 1);
typedef complex_lower_neighborhood<D, G> v_nbh_t;
v_nbh_t v_nbh;
// Iterator on the vertices adjacent to E.
mln_niter_(v_nbh_t) v(v_nbh, e);
for_all(e)
{
v.start();
point2d p1 = v.to_site().front();
v.next();
point2d p2 = v.to_site().front();
v.next();
mln_invariant(!v.is_valid());
draw::line(canvas_wst, p1, p2, wst_ima(e));
}
io::ppm::save(labeling::colorize(value::rgb8(), canvas_wst, nbasins),
output_filename);
}
// Copyright (C) 2008, 2009, 2011 EPITA Research and Development
// Laboratory (LRDE)
//
// This file is part of Olena.
//
// Olena is free software: you can redistribute it and/or modify it under
// the terms of the GNU General Public License as published by the Free
// Software Foundation, version 2 of the License.
//
// Olena 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 Olena. If not, see <http://www.gnu.org/licenses/>.
//
// As a special exception, you may use this file as part of a free
// software project 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.
#include <iostream>
#include <vector>
#include <mln/core/image/image2d.hh>
#include <mln/core/alias/neighb2d.hh>
#include <mln/labeling/blobs.hh>
#include <mln/io/pbm/load.hh>
#include <mln/io/pgm/save.hh>
#include <mln/io/ppm/save.hh>
#include <mln/debug/println.hh>
#include <mln/draw/line.hh>
#include <mln/value/int_u8.hh>
#include <mln/core/alias/point2d.hh>
#include <mln/util/site_pair.hh>
#include <mln/core/image/edge_image.hh>
#include <mln/data/fill.hh>
#include <mln/norm/l2.hh>
#include <mln/labeling/colorize.hh>
#include "influence_zones.hh"
#include "chain.hh"
/* FIXME: Introduce aliases for common specializations of graph images
such as the return type of make_graph_image. */
/** Create a 1-complex (graph) image from the connected components of
\a seeds. The values associated to a 1-face (edge) is equal to
the L2-distance between its two adjacent vertices. The values on
a 0-face (vertex) is set to 0. */
mln::edge_image<mln::util::site_pair<mln::point2d>, mln::value::int_u8>
make_graph_image(const mln::image2d<bool>& seeds)
{
using namespace mln;
using mln::value::int_u8;
border::thickness = 0;
/*-----------------------.
| Connected components. |
`-----------------------*/
unsigned nlabels;
image2d<unsigned> label = labeling::blobs(seeds, c4(), nlabels);
std::cout << "n seeds = " << nlabels << std::endl;
{
image2d<int_u8> lab(label.domain());
data::paste(label, lab);
#if 0
io::pgm::save(lab, "label.pgm");
#endif
}
/*------------------.
| Influence zones. |
`------------------*/
image2d<unsigned> iz = influence_zones(label, c4());
{
image2d<int_u8> IZ(iz.domain());
data::paste(iz, IZ);
#if 0
io::pgm::save(IZ, "iz.pgm");
#endif
}
/*----------------------------.
| Construction of the graph. |
`----------------------------*/
// Adjacency matrix.
std::vector< std::vector<bool> > adj(nlabels + 1);
for (unsigned l = 1; l <= nlabels; ++l)
adj[l].resize(nlabels + 1, false);
{
box2d::piter p(iz.domain());
for_all(p)
{
point2d r = p + right, b = p + down;
if (iz.has(r) && iz(p) != iz(r))
{
if (iz(p) != iz(r))
adj[iz(p)][iz(r)] = true;
else
adj[iz(r)][iz(p)] = true;
}
if (iz.has(b) && iz(p) != iz(b))
{
if (iz(p) != iz(b))
adj[iz(p)][iz(b)] = true;
else
adj[iz(b)][iz(p)] = true;
}
}
}
// Graph structure.
typedef util::graph G;
G g;
// Vertices. Note that vertex 0 corresponds to the background, and
// is therefore not connected to any other vertex.
g.add_vertices(nlabels + 1);
// Sites associated to edges.
typedef util::site_pair<point2d> site_t;
typedef fun::i2v::array<site_t> fsite_t;
fsite_t sites;
{
// Vertices locations.
std::vector<point2d> v_site (nlabels + 1, point2d(0,0));
{
box2d::piter p(label.domain());
for_all(p)
if (label(p) != 0)
v_site[label(p)] = p;
}
std::cout << "v_site size = " << v_site.size() << std::endl;
// Edges.
std::vector<util::edge_id_t> e;
{
for (unsigned l = 1; l <= nlabels; ++l)
for (unsigned ll = l + 1; ll <= nlabels; ++ll)