Olena-patches
Threads by month
- ----- 2025 -----
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2024 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2023 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2022 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2021 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2020 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2019 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2018 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2017 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2016 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2015 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2014 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2013 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2012 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2011 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2010 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2009 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2008 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2007 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2006 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2005 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
- February
- January
- ----- 2004 -----
- December
- November
- October
- September
- August
- July
- June
- May
- April
- March
September 2009
- 9 participants
- 188 discussions
* apps/graph-morpho/Makefile.am (complex1d_SOURCES):
Add io.hh and morpho.hh.
* apps/graph-morpho/morpho.hh: Typo.
Aesthetic changes.
---
milena/ChangeLog | 9 +++++++++
milena/apps/graph-morpho/Makefile.am | 2 +-
milena/apps/graph-morpho/morpho.hh | 8 ++++----
3 files changed, 14 insertions(+), 5 deletions(-)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index d40aae2..175d674 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,14 @@
2009-09-10 Roland Levillain <roland(a)lrde.epita.fr>
+ Misc. changes in apps/graph-morpho.
+
+ * apps/graph-morpho/Makefile.am (complex1d_SOURCES):
+ Add io.hh and morpho.hh.
+ * apps/graph-morpho/morpho.hh: Typo.
+ Aesthetic changes.
+
+2009-09-10 Roland Levillain <roland(a)lrde.epita.fr>
+
Simplify apps/graph-morpho/complex1d.cc.
* apps/graph-morpho/io.hh (println): Take an extra argument to
diff --git a/milena/apps/graph-morpho/Makefile.am b/milena/apps/graph-morpho/Makefile.am
index faa0fd4..f3440c4 100644
--- a/milena/apps/graph-morpho/Makefile.am
+++ b/milena/apps/graph-morpho/Makefile.am
@@ -21,7 +21,7 @@ APPS_CXXFLAGS = @APPS_CXXFLAGS@
AM_CXXFLAGS = $(APPS_CXXFLAGS)
noinst_PROGRAMS = complex1d
-complex1d_SOURCES = complex1d.cc
+complex1d_SOURCES = complex1d.cc io.hh morpho.hh
TESTS = complex1d
diff --git a/milena/apps/graph-morpho/morpho.hh b/milena/apps/graph-morpho/morpho.hh
index bc9a361..ef11951 100644
--- a/milena/apps/graph-morpho/morpho.hh
+++ b/milena/apps/graph-morpho/morpho.hh
@@ -45,12 +45,12 @@
# include <mln/core/image/complex_neighborhood_piter.hh>
-/*--------------------------.
-| Vertex-edges combinator. |
-`--------------------------*/
+/*----------------------------.
+| Vertices-edges combinator. |
+`----------------------------*/
/// Combine the vertices and the edges of two images to create a new
-/// graph image (operator \f$\ovee\f$).
+/// graph image (``operator'' \f$\ovee\f$).
template <typename I>
inline
mln_concrete(I)
--
1.6.4.2
1
0
* apps/graph-morpho/io.hh (println): Take an extra argument to
print a (leading) message.
* apps/graph-morpho/complex1d.cc: Adjust and simplify.
---
milena/ChangeLog | 8 +++
milena/apps/graph-morpho/complex1d.cc | 83 ++++++++------------------------
milena/apps/graph-morpho/io.hh | 4 +-
3 files changed, 32 insertions(+), 63 deletions(-)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index c48cbd0..d40aae2 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,13 @@
2009-09-10 Roland Levillain <roland(a)lrde.epita.fr>
+ Simplify apps/graph-morpho/complex1d.cc.
+
+ * apps/graph-morpho/io.hh (println): Take an extra argument to
+ print a (leading) message.
+ * apps/graph-morpho/complex1d.cc: Adjust and simplify.
+
+2009-09-10 Roland Levillain <roland(a)lrde.epita.fr>
+
Make apps/graph-morpho/complex1d.cc more modular.
* apps/graph-morpho/complex1d.cc: Move I/O-related functions...
diff --git a/milena/apps/graph-morpho/complex1d.cc b/milena/apps/graph-morpho/complex1d.cc
index 9cf23b4..d3650a3 100644
--- a/milena/apps/graph-morpho/complex1d.cc
+++ b/milena/apps/graph-morpho/complex1d.cc
@@ -56,87 +56,46 @@ int main()
// Dilations and erosions. //
// ------------------------ //
- /* Set the values so that X corresponds to the graph X of the ISMM
- 2009 paper from Jean Cousty et al. */
+ /* Create an image corresponding to the graph X of the ISMM 2009
+ paper from Jean Cousty et al. */
image2d<bool> x_pbm = io::pbm::load(MLN_APPS_DIR "/graph-morpho/x.pbm");
ima_t x = make_regular_complex1d_image(x_pbm);
box2d x_box(x_pbm.nrows() / 2 + 1, x_pbm.ncols() / 2 + 1);
- std::cout << "x:" << std::endl;
- println(x, x_box);
+ println("x:", x, x_box);
- ima_t dil_e2v_ima = dilation_e2v(x);
- std::cout << "dil_e2v_ima:" << std::endl;
- println(dil_e2v_ima, x_box);
+ println("dilation_e2v(x):", dilation_e2v(x), x_box);
+ println("erosion_v2e(x):", erosion_v2e(x), x_box);
- ima_t ero_v2e_ima = erosion_v2e(x);
- std::cout << "ero_v2e_ima:" << std::endl;
- println(ero_v2e_ima, x_box);
+ println("erosion_e2v(x):", erosion_e2v(x), x_box);
+ println("dilation_v2e(x):", dilation_v2e(x), x_box);
+ println("dilation_graph(x):", dilation_graph(x), x_box);
+ println("erosion_graph(x):", erosion_graph(x), x_box);
- ima_t ero_e2v_ima = erosion_e2v(x);
- std::cout << "ero_e2v_ima:" << std::endl;
- println(ero_e2v_ima, x_box);
-
- ima_t dil_v2e_ima = dilation_v2e(x);
- std::cout << "dil_v2e_ima:" << std::endl;
- println(dil_v2e_ima, x_box);
-
-
- ima_t dil_ima = dilation_graph(x);
- std::cout << "dil_ima:" << std::endl;
- println(dil_ima, x_box);
-
- ima_t ero_ima = erosion_graph(x);
- std::cout << "ero_ima:" << std::endl;
- println(ero_ima, x_box);
-
-
- ima_t alpha3_ima = alpha3(x);
- std::cout << "alpha3_ima:" << std::endl;
- println(alpha3_ima, x_box);
-
- ima_t beta3_ima = beta3(x);
- std::cout << "beta3_ima:" << std::endl;
- println(beta3_ima, x_box);
+ println("alpha3(x):", alpha3(x), x_box);
+ println("beta3(x):", beta3(x), x_box);
// --------- //
// Filters. //
// --------- //
+ // Create an image corresponding to the graph Y.
image2d<bool> y_pbm = io::pbm::load(MLN_APPS_DIR "/graph-morpho/y.pbm");
ima_t y = make_regular_complex1d_image(y_pbm);
box2d y_box(y_pbm.nrows() / 2 + 1, y_pbm.ncols() / 2 + 1);
- std::cout << "y:" << std::endl;
- println(y, y_box);
-
- ima_t ope_ima = opening_graph(y);
- std::cout << "ope_ima:" << std::endl;
- println(ope_ima, y_box);
-
- ima_t half_ope_ima = half_opening_graph(y);
- std::cout << "half_ope_ima:" << std::endl;
- println(half_ope_ima, y_box);
-
- ima_t beta3_o_alpha3_ima = beta3(alpha3(y));
- std::cout << "beta3_o_alpha3_ima:" << std::endl;
- println(beta3_o_alpha3_ima, y_box);
+ println("y:", y, y_box);
+ println("opening_graph(y):", opening_graph(y), y_box);
+ println("half_opening_graph(y):", half_opening_graph(y), y_box);
+ println("beta3(alpha3(y)):", beta3(alpha3(y)), y_box);
+ // Create an image corresponding to the graph Z.
image2d<bool> z_pbm = io::pbm::load(MLN_APPS_DIR "/graph-morpho/z.pbm");
ima_t z = make_regular_complex1d_image(z_pbm);
box2d z_box(z_pbm.nrows() / 2 + 1, z_pbm.ncols() / 2 + 1);
- std::cout << "z:" << std::endl;
- println(z, z_box);
-
- ima_t clo_ima = closing_graph(z);
- std::cout << "clo_ima:" << std::endl;
- println(clo_ima, z_box);
-
- ima_t half_clo_ima = half_closing_graph(z);
- std::cout << "half_clo_ima:" << std::endl;
- println(half_clo_ima, z_box);
+ println("z:", z, z_box);
- ima_t alpha3_o_beta3_ima = alpha3(beta3(z));
- std::cout << "alpha3_o_beta3_ima:" << std::endl;
- println(alpha3_o_beta3_ima, z_box);
+ println("closing_graph(z):", closing_graph(z), z_box);
+ println("half_closing_graph(z):", half_closing_graph(z), z_box);
+ println("alpha3(beta3(z)):", alpha3(beta3(z)), z_box);
}
diff --git a/milena/apps/graph-morpho/io.hh b/milena/apps/graph-morpho/io.hh
index 5b7a809..f2dfa9a 100644
--- a/milena/apps/graph-morpho/io.hh
+++ b/milena/apps/graph-morpho/io.hh
@@ -155,7 +155,8 @@ make_regular_complex1d_image(const mln::Image<I>& input_)
inline
void
-println(const mln::bin_1complex_image2d& ima, const mln::box2d& support)
+println(const std::string& message, const mln::bin_1complex_image2d& ima,
+ const mln::box2d& support)
{
using namespace mln;
@@ -205,6 +206,7 @@ println(const mln::bin_1complex_image2d& ima, const mln::box2d& support)
}
}
+ std::cout << message << std::endl;
for (int row = vertices.domain().pmin().row();
row <= vertices.domain().pmax().row(); ++row)
{
--
1.6.4.2
1
0
10 Sep '09
* apps/graph-morpho/complex1d.cc: Move I/O-related functions...
* apps/graph-morpho/io.hh: ...here (new file).
* apps/graph-morpho/complex1d.cc: Move morpho-related functions...
* apps/graph-morpho/morpho.hh: ...here (new file).
---
milena/ChangeLog | 9 +
milena/apps/graph-morpho/complex1d.cc | 647 +--------------------------------
milena/apps/graph-morpho/io.hh | 235 ++++++++++++
milena/apps/graph-morpho/morpho.hh | 503 +++++++++++++++++++++++++
4 files changed, 762 insertions(+), 632 deletions(-)
create mode 100644 milena/apps/graph-morpho/io.hh
create mode 100644 milena/apps/graph-morpho/morpho.hh
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 65dfce9..c48cbd0 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,14 @@
2009-09-10 Roland Levillain <roland(a)lrde.epita.fr>
+ Make apps/graph-morpho/complex1d.cc more modular.
+
+ * apps/graph-morpho/complex1d.cc: Move I/O-related functions...
+ * apps/graph-morpho/io.hh: ...here (new file).
+ * apps/graph-morpho/complex1d.cc: Move morpho-related functions...
+ * apps/graph-morpho/morpho.hh: ...here (new file).
+
+2009-09-10 Roland Levillain <roland(a)lrde.epita.fr>
+
Alias for binary 1-complex-based images in the dicrete plane.
* mln/core/alias/complex_image.hh (mln::bin_1complex_image2d):
diff --git a/milena/apps/graph-morpho/complex1d.cc b/milena/apps/graph-morpho/complex1d.cc
index e220fca..9cf23b4 100644
--- a/milena/apps/graph-morpho/complex1d.cc
+++ b/milena/apps/graph-morpho/complex1d.cc
@@ -1,4 +1,4 @@
-// Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE)
+// Copyright (C) 2009 EPITA Research and Development Laboratory (LRDE)
//
// This file is part of Olena.
//
@@ -28,646 +28,29 @@
/// 1-complex images.
///
/// \todo There should be a second version of this program, where the
-/// graph structure is implemented with an actual graph.
-
-#include <mln/core/image/complex_image.hh>
-#include <mln/geom/complex_geometry.hh>
-#include <mln/core/image/complex_neighborhoods.hh>
-#include <mln/core/image/complex_neighborhood_piter.hh>
-
-#include <mln/core/image/image2d.hh>
-#include <mln/core/alias/point2d.hh>
-#include <mln/core/alias/box2d.hh>
-
-#include <mln/core/site_set/p_set.hh>
-#include <mln/util/site_pair.hh>
-
-#include <mln/core/routine/duplicate.hh>
-
-#include <mln/math/abs.hh>
+/// graph structure is implemented with an actual mln::util::graph.
#include <mln/io/pbm/load.hh>
-#include "apps/data.hh"
-
-using namespace mln;
-
-// A graph is considered as a 1-complex here.
-const unsigned dim = 1;
-typedef topo::complex<dim> complex_t;
-
-// Binary graph-based image with vertices aligned on a discrete 2D grid.
-typedef point2d site_t;
-typedef geom::complex_geometry<dim, site_t> geom_t;
-typedef complex_image<dim, geom_t, bool> ima_t;
-
-// Iterator type on faces (vertices and edges).
-typedef p_n_faces_fwd_piter<dim, geom_t> face_iter;
-// Edge-to-vertices neighborhood.
-typedef complex_lower_neighborhood<dim, geom_t> e2v_t;
-const e2v_t e2v;
-// Vertex-to-edges neighborhood.
-typedef complex_higher_neighborhood<dim, geom_t> v2e_t;
-const v2e_t v2e;
-
-
-// FIXME: We should turn this routine into something much more
-// generic, and move it to the library (into make/).
-ima_t
-build_regular_complex1d_image(const box2d& support)
-{
- unsigned nrows = support.pmax().row() - support.pmin().row() + 1;
- unsigned ncols = support.pmax().col() - support.pmin().col() + 1;
-
- typedef topo::n_face<0, dim> vertex_t;
-
- complex_t c;
- geom_t geom;
-
- // Vertices.
- for (unsigned row = 0; row < nrows; ++row)
- for (unsigned col = 0; col < ncols; ++col)
- {
- c.add_face();
- geom.add_location(point2d(row,col));
- }
-
- // Edges.
- for (unsigned row = 0; row < nrows; ++row)
- {
- // Horizontal edges.
- for (unsigned col = 1; col < ncols; ++col)
- {
- // First vertex.
- vertex_t v1(c, row * ncols + col - 1);
- // Second vertex.
- vertex_t v2(c, row * ncols + col);
- // Edge bewteen V1 and V2.
- c.add_face(v1 + v2);
- }
-
- // Vertical edges.
- if (row != 0)
- for (unsigned col = 0; col < ncols; ++col)
- {
- // First vertex.
- vertex_t v1(c, (row - 1) * ncols + col);
- // Second vertex.
- vertex_t v2(c, row * ncols + col);
- // Edge bewteen V1 and V2.
- c.add_face(v1 + v2);
- }
- }
-
- // Site set (domain) of the image.
- p_complex<dim, geom_t> pc(c, geom);
-
- // Image based on this site set.
- ima_t ima(pc);
- return ima;
-}
-
-template <typename I>
-ima_t
-make_regular_complex1d_image(const Image<I>& input_)
-{
- const I& input = exact(input_);
- const box2d& input_box = input.domain();
- // The input image must have an odd number of rows and columns.
- mln_precondition(input_box.nrows() % 2 == 1);
- mln_precondition(input_box.ncols() % 2 == 1);
-
- // The domain of the graph image is twice as small, since we
- // consider only vertices (edges are set ``between'' vertices).
- box2d output_box(input_box.nrows() / 2 + 1,
- input_box.ncols() / 2 + 1);
- ima_t output = build_regular_complex1d_image(output_box);
-
- // Add values on vertices.
- p_n_faces_fwd_piter<dim, geom_t> v(output.domain(), 0);
- for_all(v)
- {
- mln_site_(geom_t) s(v);
- // Site S is point2d multi-site and should be a singleton (since V
- // iterates on vertices).
- mln_invariant(s.size() == 1);
- point2d p = s.front();
- point2d q(p.row() * 2, p.col() * 2);
- output(v) = input(q);
- }
-
- // Add values on edges.
- p_n_faces_fwd_piter<dim, geom_t> e(output.domain(), 1);
- for_all(e)
- {
- mln_site_(geom_t) s(e);
- // Site S is point2d multi-site and should be a pair (since E
- // iterates on vertices).
- mln_invariant(s.size() == 2);
- point2d p1 = s[0];
- point2d p2 = s[1];
- mln_invariant(math::abs(p1.row() - p2.row()) == 1
- || math::abs(p1.col() - p2.col()) == 1);
- point2d q (p1.row() + p2.row(), p1.col() + p2.col());
- output(e) = input(q);
- }
-
- return output;
-}
-
-
-template <typename T>
-void
-println(const complex_image<dim, geom_t, T>& ima, const box2d& support)
-{
- // These are admittedly loose preconditions, but we cannot check
- // much.
- mln_precondition(ima.nsites() == support.nsites());
-
- image2d<bool> vertices(support);
- image2d<bool> h_edges(box2d(support.pmin(), support.pmax() - dpoint2d(0, 1)));
- image2d<bool> v_edges(box2d(support.pmin(), support.pmax() - dpoint2d(1, 0)));
-
- // Iterator on vertices.
- p_n_faces_fwd_piter<dim, geom_t> v(ima.domain(), 0);
- for_all(v)
- {
- mln_site_(geom_t) s(v);
- // Site S is point2d multi-site and should be a singleton (since V
- // iterates on vertices).
- mln_invariant(s.size() == 1);
- point2d p = s.front();
- vertices(p) = ima(v);
- }
-
- // Iterator on edges.
- p_n_faces_fwd_piter<dim, geom_t> e(ima.domain(), 1);
- for_all(e)
- {
- mln_site_(geom_t) s(e);
- // Site S is point2d multi-site and should be a pair (since E
- // iterates on vertices).
- mln_invariant(s.size() == 2);
- point2d p1 = s[0];
- point2d p2 = s[1];
- if (p1.row() == p2.row())
- {
- // Horizontal edge.
- h_edges(p1) = ima(e);
- }
- else
- {
- // Vertical edge.
- mln_assertion(p1.col() == p2.col());
- v_edges(p1) = ima(e);
- }
- }
-
- for (int row = vertices.domain().pmin().row();
- row <= vertices.domain().pmax().row(); ++row)
- {
- for (int col = vertices.domain().pmin().col();
- col <= vertices.domain().pmax().col(); ++col)
- {
- point2d p(row, col);
- // Vertex.
- std::cout << (vertices(p) ? "O" : ".");
- // Potential horizontal edge on the right of the vertex.
- if (col != vertices.domain().pmax().col())
- std::cout << (h_edges(p) ? " - " : " ");
- }
- std::cout << std::endl;
-
- // Potential vertical edge below the vertices of the current ROW.
- if (row != vertices.domain().pmax().row())
- for (int col = vertices.domain().pmin().col();
- col <= vertices.domain().pmax().col(); ++col)
- {
- point2d p(row, col);
- std::cout << (v_edges(p) ? "| " : " ");
- }
- std::cout << std::endl;
- }
-}
-
-
-/*------------------------------------.
-| Morphological operators on graphs. |
-`------------------------------------*/
-
-// ------------------------ //
-// Dilations and erosions. //
-// ------------------------ //
-
-/* FIXME: By constraining the domain of the input and passing the
- neighborhood, one should be able to use a truly generic dilation
- (resp. erosion), or even use Milena's standard morpho::dilation
- (resp. morpho::erosion). */
-
-/// Dilation from edges to vertices (\f$\delta^\bullet\f$).
-template <typename I>
-mln_concrete(I)
-dilation_e2v(const Image<I>& input_)
-{
- const I& input = exact(input_);
- mln_concrete(I) output;
- initialize(output, input);
- /* FIXME: It'd be better to write something like this:
-
- mln_piter(...) v(output | vertices);
-
- We can actually write this, but `vertices' has to be a predicate
- on sites (p2b function), which is not efficient, since both
- vertices and edges will be browsed.
-
- It would be very nice if `vertices' could be an actual site set,
- so that `output | vertices' creates a morpher smart enough to
- browse /only/ vertices. */
- p_n_faces_fwd_piter<dim, geom_t> v(input.domain(), 0);
- mln_niter_(v2e_t) e(v2e, v);
- for_all(v)
- {
- output(v) = false;
- for_all(e)
- if (input(e))
- {
- output(v) = true;
- break;
- }
- }
- return output;
-}
-
-/// Erosion from vertices to edges (\f$\epsilon^\times\f$).
-template <typename I>
-mln_concrete(I)
-erosion_v2e(const Image<I>& input_)
-{
- const I& input = exact(input_);
- mln_concrete(I) output;
- initialize(output, input);
- p_n_faces_fwd_piter<dim, geom_t> e(input.domain(), 1);
- mln_niter_(e2v_t) v(e2v, e);
- for_all(e)
- {
- output(e) = true;
- for_all(v)
- if (!input(v))
- {
- output(e) = false;
- break;
- }
- }
- return output;
-}
-
-/// Erosion from edges to vertices (\f$\epsilon^\bullet\f$).
-template <typename I>
-mln_concrete(I)
-erosion_e2v(const Image<I>& input_)
-{
- const I& input = exact(input_);
- mln_concrete(I) output;
- initialize(output, input);
- p_n_faces_fwd_piter<dim, geom_t> v(input.domain(), 0);
- mln_niter_(v2e_t) e(v2e, v);
- for_all(v)
- {
- output(v) = true;
- for_all(e)
- if (!input(e))
- {
- output(v) = false;
- break;
- }
- }
- return output;
-}
-
-/// Dilation from vertices to edges (\f$\delta^\times\f$).
-template <typename I>
-mln_concrete(I)
-dilation_v2e(const Image<I>& input_)
-{
- const I& input = exact(input_);
- mln_concrete(I) output;
- initialize(output, input);
- p_n_faces_fwd_piter<dim, geom_t> e(input.domain(), 1);
- mln_niter_(e2v_t) v(e2v, e);
- for_all(e)
- {
- output(e) = false;
- for_all(v)
- if (input(v))
- {
- output(e) = true;
- break;
- }
- }
- return output;
-}
-
-
-/// Vertex dilation (\f$delta\f$).
-template <typename I>
-mln_concrete(I)
-dilation_vertex(const Image<I>& input)
-{
- return dilation_e2v(dilation_v2e(input));
-}
-
-/// Vertex erosion (\f$epsilon\f$).
-template <typename I>
-mln_concrete(I)
-erosion_vertex(const Image<I>& input)
-{
- return erosion_e2v(erosion_v2e(input));
-}
-
-
-/// Edge dilation (\f$Delta\f$).
-template <typename I>
-mln_concrete(I)
-dilation_edge(const Image<I>& input)
-{
- return dilation_v2e(dilation_e2v(input));
-}
-
-/// Edge erosion (\f$Epsilon\f$).
-template <typename I>
-mln_concrete(I)
-erosion_edge(const Image<I>& input)
-{
- return erosion_v2e(erosion_e2v(input));
-}
-
-
-/// Combine the vertices and the edges of two images to create a new
-/// graph image.
-template <typename I>
-mln_concrete(I)
-combine(const Image<I>& vertices_, const Image<I>& edges_)
-{
- const I vertices = exact(vertices_);
- const I edges = exact(edges_);
- mln_precondition(vertices.domain() == edges.domain());
-
- mln_concrete(I) output;
- initialize(output, vertices);
- p_n_faces_fwd_piter<dim, geom_t> v(output.domain(), 0);
- for_all(v)
- output(v) = vertices(v);
- p_n_faces_fwd_piter<dim, geom_t> e(output.domain(), 1);
- for_all(e)
- output(e) = edges(e);
- return output;
-}
-
-
-/// Graph dilation (\f$delta \ovee Delta\f$).
-template <typename I>
-mln_concrete(I)
-dilation_graph(const Image<I>& input)
-{
- return combine(dilation_vertex(input), dilation_edge(input));
-}
-
-/// Graph erosion (\f$epsilon \ovee Epsilon\f$).
-template <typename I>
-mln_concrete(I)
-erosion_graph(const Image<I>& input)
-{
- return combine(erosion_vertex(input), erosion_edge(input));
-}
-
-
-// ------------------------ //
-// Additional adjunctions. //
-// ------------------------ //
-
-template <typename I>
-mln_concrete(I)
-alpha1(const Image<I>& input)
-{
- mln_concrete(I) vertices;
- initialize(vertices, input);
- data::fill(vertices, true);
- return combine(vertices, input);
-}
-
-template <typename I>
-mln_concrete(I)
-beta1(const Image<I>& input)
-{
- return combine(dilation_e2v(input), input);
-}
-
-template <typename I>
-mln_concrete(I)
-alpha2(const Image<I>& input)
-{
- return combine(input, erosion_v2e(input));
-}
-
-template <typename I>
-mln_concrete(I)
-beta2(const Image<I>& input)
-{
- mln_concrete(I) edges;
- initialize(edges, input);
- data::fill(edges, false);
- return combine(input, edges);
-}
-
-template <typename I>
-mln_concrete(I)
-alpha3(const Image<I>& input)
-{
- return combine(erosion_e2v(input), erosion_v2e(erosion_e2v(input)));
-}
-
-template <typename I>
-mln_concrete(I)
-beta3(const Image<I>& input)
-{
- return combine(dilation_e2v(dilation_v2e(input)), dilation_v2e(input));
-}
-
-
-// ----------------------- //
-// Openings and closings. //
-// ----------------------- //
-
-/// Vertex opening (\f$\gamma_1\f$).
-template <typename I>
-mln_concrete(I)
-opening_vertex(const Image<I>& input)
-{
- return dilation_vertex(erosion_vertex(input));
-}
-
-/// Vertex closing (\f$\phi_1\f$).
-template <typename I>
-mln_concrete(I)
-closing_vertex(const Image<I>& input)
-{
- return erosion_vertex(dilation_vertex(input));
-}
-
-
-/// Edge opening (\f$\Gamma_1\f$).
-template <typename I>
-mln_concrete(I)
-opening_edge(const Image<I>& input)
-{
- return dilation_edge(erosion_edge(input));
-}
-
-/// Edge closing (\f$\Phi_1\f$).
-template <typename I>
-mln_concrete(I)
-closing_edge(const Image<I>& input)
-{
- return erosion_edge(dilation_edge(input));
-}
-
-
-/// Graph opening (\f${\gamma \ovee \Gamma}_1\f$).
-template <typename I>
-mln_concrete(I)
-opening_graph(const Image<I>& input)
-{
- return combine(opening_vertex(input), opening_edge(input));
-}
-
-/// Graph closing (\f${\phi \ovee \Phi}_1\f$).
-template <typename I>
-mln_concrete(I)
-closing_graph(const Image<I>& input)
-{
- return combine(closing_vertex(input), closing_edge(input));
-}
-
-
-// --------------------------------- //
-// Half-openings and half-closings. //
-// --------------------------------- //
-
-/// Vertex half-opening (\f$\gamma_{1/2}\f$).
-template <typename I>
-mln_concrete(I)
-half_opening_vertex(const Image<I>& input)
-{
- return dilation_e2v(erosion_v2e(input));
-}
-
-/// Vertex half-closing (\f$\phi_{1/2}\f$).
-template <typename I>
-mln_concrete(I)
-half_closing_vertex(const Image<I>& input)
-{
- return erosion_e2v(dilation_v2e(input));
-}
-
-
-/// Edge half-opening (\f$\Gamma_{1/2}\f$).
-template <typename I>
-mln_concrete(I)
-half_opening_edge(const Image<I>& input)
-{
- return dilation_v2e(erosion_e2v(input));
-}
-
-/// Edge half-closing (\f$\Phi_{1/2}\f$).
-template <typename I>
-mln_concrete(I)
-half_closing_edge(const Image<I>& input)
-{
- return erosion_v2e(dilation_e2v(input));
-}
-
+#include "apps/graph-morpho/morpho.hh"
-/// Graph half-opening (\f${\gamma \ovee \Gamma}_{1/2}\f$).
-template <typename I>
-mln_concrete(I)
-half_opening_graph(const Image<I>& input)
-{
- return combine(half_opening_vertex(input), half_opening_edge(input));
-}
-
-/// Graph half-closing (\f${\phi \ovee \Phi}_{1/2}\f$).
-template <typename I>
-mln_concrete(I)
-half_closing_graph(const Image<I>& input)
-{
- return combine(half_closing_vertex(input), half_closing_edge(input));
-}
-
-
-// ------------------------------------------------------ //
-// Parameterized openings and closings (granulometries). //
-// ------------------------------------------------------ //
-
-/// Opening (\f${\gamma \ovee \Gamma}_{\lambda/2}\f$).
-template <typename I>
-mln_concrete(I)
-opening(const Image<I>& input, unsigned lambda)
-{
- unsigned i = lambda / 2;
- unsigned j = lambda % 2;
- mln_concrete(I) output = duplicate(input);
- for (unsigned m = 0; m < i; ++m)
- output = erosion_graph(output);
- for (unsigned m = 0; m < j; ++m)
- output = half_opening_graph(output);
- for (unsigned m = 0; m < i; ++m)
- output = dilation_graph(output);
- return output;
-}
-
-/// Opening (\f${\phi \ovee \Phi}_{\lambda/2}\f$).
-template <typename I>
-mln_concrete(I)
-closing(const Image<I>& input, unsigned lambda)
-{
- unsigned i = lambda / 2;
- unsigned j = lambda % 2;
- mln_concrete(I) output = duplicate(input);
- for (unsigned m = 0; m < i; ++m)
- output = dilation_graph(output);
- for (unsigned m = 0; m < j; ++m)
- output = half_closing_graph(output);
- for (unsigned m = 0; m < i; ++m)
- output = erosion_graph(output);
- return output;
-}
+#include "apps/graph-morpho/io.hh"
+#include "apps/data.hh"
-// ----------------------------- //
-// Alternate Sequential Filter. //
-// ----------------------------- //
-/// Alternate Sequential Filter (ASF) (\f${ASF}_{\lambda/2}\f$).
-template <typename I>
-mln_concrete(I)
-asf(const Image<I>& input, unsigned lambda)
+int main()
{
- mln_concrete(I) output = duplicate(input);
- for (unsigned m = 0; m < lambda; ++m)
- output = half_opening_graph(half_closing_graph(output));
- return output;
-}
-
-
+ using namespace mln;
-/*-----------------------------------.
-| Applying morphological operators. |
-`-----------------------------------*/
+ // A graph is considered as a 1-complex here.
+ const unsigned dim = 1;
+ typedef topo::complex<dim> complex_t;
+ /* Binary graph-based image with vertices aligned on a discrete 2D grid.
-int main()
-{
- /* Build a ``regular'' graph image. Of course, it would have been
- better, simpler and faster to use a cubical 1-complex here, but
- they are not yet available (as of 2009-09-10). */
+ Of course, it would have been better, simpler and faster to use a
+ cubical 1-complex here, but they are not yet available (as of
+ 2009-09-10). */
+ typedef mln::bin_1complex_image2d ima_t;
// ------------------------ //
// Dilations and erosions. //
diff --git a/milena/apps/graph-morpho/io.hh b/milena/apps/graph-morpho/io.hh
new file mode 100644
index 0000000..5b7a809
--- /dev/null
+++ b/milena/apps/graph-morpho/io.hh
@@ -0,0 +1,235 @@
+// Copyright (C) 2009 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.
+
+#ifndef APPS_GRAPH_MORPHO_IO_HH
+# define APPS_GRAPH_MORPHO_IO_HH
+
+/// \file apps/graph-morpho/io.hh
+/// \brief I/O routines for graphs (1-complexes).
+
+# include <mln/core/alias/complex_image.hh>
+# include <mln/core/image/image2d.hh>
+
+# include <mln/math/abs.hh>
+
+// FIXME: We should turn these routines into something much more
+// generic, and move it to the library (into make/).
+
+inline
+mln::bin_1complex_image2d
+build_regular_complex1d_image(const mln::box2d& support)
+{
+ using namespace mln;
+
+ unsigned nrows = support.pmax().row() - support.pmin().row() + 1;
+ unsigned ncols = support.pmax().col() - support.pmin().col() + 1;
+
+ const unsigned dim = 1;
+ typedef topo::n_face<0, dim> vertex_t;
+
+ typedef topo::complex<dim> complex_t;
+ complex_t c;
+ typedef geom::complex_geometry<dim, point2d> geom_t;
+ geom_t geom;
+
+ // Vertices.
+ for (unsigned row = 0; row < nrows; ++row)
+ for (unsigned col = 0; col < ncols; ++col)
+ {
+ c.add_face();
+ geom.add_location(point2d(row,col));
+ }
+
+ // Edges.
+ for (unsigned row = 0; row < nrows; ++row)
+ {
+ // Horizontal edges.
+ for (unsigned col = 1; col < ncols; ++col)
+ {
+ // First vertex.
+ vertex_t v1(c, row * ncols + col - 1);
+ // Second vertex.
+ vertex_t v2(c, row * ncols + col);
+ // Edge bewteen V1 and V2.
+ c.add_face(v1 + v2);
+ }
+
+ // Vertical edges.
+ if (row != 0)
+ for (unsigned col = 0; col < ncols; ++col)
+ {
+ // First vertex.
+ vertex_t v1(c, (row - 1) * ncols + col);
+ // Second vertex.
+ vertex_t v2(c, row * ncols + col);
+ // Edge bewteen V1 and V2.
+ c.add_face(v1 + v2);
+ }
+ }
+
+ // Site set (domain) of the image.
+ p_complex<dim, geom_t> pc(c, geom);
+
+ // Image based on this site set.
+ bin_1complex_image2d ima(pc);
+ return ima;
+}
+
+
+template <typename I>
+inline
+mln::bin_1complex_image2d
+make_regular_complex1d_image(const mln::Image<I>& input_)
+{
+ using namespace mln;
+
+ const I& input = exact(input_);
+ const box2d& input_box = input.domain();
+ // The input image must have an odd number of rows and columns.
+ mln_precondition(input_box.nrows() % 2 == 1);
+ mln_precondition(input_box.ncols() % 2 == 1);
+
+ // The domain of the graph image is twice as small, since we
+ // consider only vertices (edges are set ``between'' vertices).
+ box2d output_box(input_box.nrows() / 2 + 1,
+ input_box.ncols() / 2 + 1);
+ bin_1complex_image2d output = build_regular_complex1d_image(output_box);
+
+ const unsigned dim = 1;
+ typedef geom::complex_geometry<dim, point2d> geom_t;
+
+ // Add values on vertices.
+ p_n_faces_fwd_piter<dim, geom_t> v(output.domain(), 0);
+ for_all(v)
+ {
+ mln_site_(geom_t) s(v);
+ // Site S is point2d multi-site and should be a singleton (since V
+ // iterates on vertices).
+ mln_invariant(s.size() == 1);
+ point2d p = s.front();
+ point2d q(p.row() * 2, p.col() * 2);
+ output(v) = input(q);
+ }
+
+ // Add values on edges.
+ p_n_faces_fwd_piter<dim, geom_t> e(output.domain(), 1);
+ for_all(e)
+ {
+ mln_site_(geom_t) s(e);
+ // Site S is point2d multi-site and should be a pair (since E
+ // iterates on vertices).
+ mln_invariant(s.size() == 2);
+ point2d p1 = s[0];
+ point2d p2 = s[1];
+ mln_invariant(math::abs(p1.row() - p2.row()) == 1
+ || math::abs(p1.col() - p2.col()) == 1);
+ point2d q (p1.row() + p2.row(), p1.col() + p2.col());
+ output(e) = input(q);
+ }
+
+ return output;
+}
+
+
+inline
+void
+println(const mln::bin_1complex_image2d& ima, const mln::box2d& support)
+{
+ using namespace mln;
+
+ // These are admittedly loose preconditions, but we cannot check
+ // much anyway.
+ mln_precondition(ima.nsites() == support.nsites());
+
+ image2d<bool> vertices(support);
+ image2d<bool> h_edges(box2d(support.pmin(), support.pmax() - dpoint2d(0, 1)));
+ image2d<bool> v_edges(box2d(support.pmin(), support.pmax() - dpoint2d(1, 0)));
+
+ const unsigned dim = 1;
+ typedef geom::complex_geometry<dim, point2d> geom_t;
+
+ // Iterator on vertices.
+ p_n_faces_fwd_piter<dim, geom_t> v(ima.domain(), 0);
+ for_all(v)
+ {
+ mln_site_(geom_t) s(v);
+ // Site S is point2d multi-site and should be a singleton (since V
+ // iterates on vertices).
+ mln_invariant(s.size() == 1);
+ point2d p = s.front();
+ vertices(p) = ima(v);
+ }
+
+ // Iterator on edges.
+ p_n_faces_fwd_piter<dim, geom_t> e(ima.domain(), 1);
+ for_all(e)
+ {
+ mln_site_(geom_t) s(e);
+ // Site S is point2d multi-site and should be a pair (since E
+ // iterates on vertices).
+ mln_invariant(s.size() == 2);
+ point2d p1 = s[0];
+ point2d p2 = s[1];
+ if (p1.row() == p2.row())
+ {
+ // Horizontal edge.
+ h_edges(p1) = ima(e);
+ }
+ else
+ {
+ // Vertical edge.
+ mln_assertion(p1.col() == p2.col());
+ v_edges(p1) = ima(e);
+ }
+ }
+
+ for (int row = vertices.domain().pmin().row();
+ row <= vertices.domain().pmax().row(); ++row)
+ {
+ for (int col = vertices.domain().pmin().col();
+ col <= vertices.domain().pmax().col(); ++col)
+ {
+ point2d p(row, col);
+ // Vertex.
+ std::cout << (vertices(p) ? "O" : ".");
+ // Potential horizontal edge on the right of the vertex.
+ if (col != vertices.domain().pmax().col())
+ std::cout << (h_edges(p) ? " - " : " ");
+ }
+ std::cout << std::endl;
+
+ // Potential vertical edge below the vertices of the current ROW.
+ if (row != vertices.domain().pmax().row())
+ for (int col = vertices.domain().pmin().col();
+ col <= vertices.domain().pmax().col(); ++col)
+ {
+ point2d p(row, col);
+ std::cout << (v_edges(p) ? "| " : " ");
+ }
+ std::cout << std::endl;
+ }
+}
+
+#endif // ! APPS_GRAPH_MORPHO_IO_HH
diff --git a/milena/apps/graph-morpho/morpho.hh b/milena/apps/graph-morpho/morpho.hh
new file mode 100644
index 0000000..bc9a361
--- /dev/null
+++ b/milena/apps/graph-morpho/morpho.hh
@@ -0,0 +1,503 @@
+// Copyright (C) 2009 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.
+
+#ifndef APPS_GRAPH_MORPHO_MORPHO_HH
+# define APPS_GRAPH_MORPHO_MORPHO_HH
+
+/** \file apps/graph-morpho/morpho.hh
+ \brief Morphological operators on graphs (1-complexes).
+
+ Reference:
+
+ Jean Cousty, Laurent Najman and Jean Serra. Some morphological
+ operators in graph spaces. In: Proceedings of the Ninth
+ International Symposium on Mathematical Morphology (ISMM), 2009,
+ Groningen, The Netherlands. */
+
+# include <mln/core/concept/image.hh>
+
+# include <mln/core/routine/duplicate.hh>
+
+# include <mln/core/site_set/p_n_faces_piter.hh>
+# include <mln/core/image/complex_neighborhoods.hh>
+# include <mln/core/image/complex_neighborhood_piter.hh>
+
+
+/*--------------------------.
+| Vertex-edges combinator. |
+`--------------------------*/
+
+/// Combine the vertices and the edges of two images to create a new
+/// graph image (operator \f$\ovee\f$).
+template <typename I>
+inline
+mln_concrete(I)
+combine(const mln::Image<I>& vertices_, const mln::Image<I>& edges_)
+{
+ const I vertices = mln::exact(vertices_);
+ const I edges = mln::exact(edges_);
+ mln_precondition(vertices.domain() == edges.domain());
+
+ mln_concrete(I) output;
+ mln::initialize(output, vertices);
+ mln::p_n_faces_fwd_piter<I::dim, mln_geom(I)> v(output.domain(), 0);
+ for_all(v)
+ output(v) = vertices(v);
+ mln::p_n_faces_fwd_piter<I::dim, mln_geom(I)> e(output.domain(), 1);
+ for_all(e)
+ output(e) = edges(e);
+ return output;
+}
+
+
+/*-------------------------.
+| Dilations and erosions. |
+`-------------------------*/
+
+/* FIXME: By constraining the domain of the input and passing the
+ neighborhood, one should be able to use a truly generic dilation
+ (resp. erosion), or even use Milena's standard morpho::dilation
+ (resp. morpho::erosion).
+
+ It'd be convenient to write something like this:
+
+ dilation(ima | vertices);
+
+ We can /actually/ write this, but `vertices' has to be a predicate
+ on sites (p2b function), which is not efficient, since both
+ vertices and edges will be browsed.
+
+ It would be very nice if `vertices' could be an actual site set,
+ so that `ima | vertices' creates a morpher smart enough to
+ browse /only/ vertices. */
+
+/// Dilation from edges to vertices (\f$\delta^\bullet\f$).
+template <typename I>
+inline
+mln_concrete(I)
+dilation_e2v(const mln::Image<I>& input_)
+{
+ const I& input = mln::exact(input_);
+ mln_concrete(I) output;
+ mln::initialize(output, input);
+ // Iterator on vertices.
+ mln::p_n_faces_fwd_piter<I::dim, mln_geom(I)> v(input.domain(), 0);
+ // Vertex-to-edges neighborhood.
+ typedef mln::complex_higher_neighborhood<I::dim, mln_geom(I)> v2e_t;
+ const v2e_t v2e;
+ mln_niter(v2e_t) e(v2e, v);
+ for_all(v)
+ {
+ output(v) = false;
+ for_all(e)
+ if (input(e))
+ {
+ output(v) = true;
+ break;
+ }
+ }
+ return output;
+}
+
+/// Erosion from vertices to edges (\f$\epsilon^\times\f$).
+template <typename I>
+inline
+mln_concrete(I)
+erosion_v2e(const mln::Image<I>& input_)
+{
+ const I& input = mln::exact(input_);
+ mln_concrete(I) output;
+ mln::initialize(output, input);
+ // Iterator on edges.
+ mln::p_n_faces_fwd_piter<I::dim, mln_geom(I)> e(input.domain(), 1);
+ // Edge-to-vertices neighborhood.
+ typedef mln::complex_lower_neighborhood<I::dim, mln_geom(I)> e2v_t;
+ const e2v_t e2v;
+ mln_niter(e2v_t) v(e2v, e);
+ for_all(e)
+ {
+ output(e) = true;
+ for_all(v)
+ if (!input(v))
+ {
+ output(e) = false;
+ break;
+ }
+ }
+ return output;
+}
+
+/// Erosion from edges to vertices (\f$\epsilon^\bullet\f$).
+template <typename I>
+inline
+mln_concrete(I)
+erosion_e2v(const mln::Image<I>& input_)
+{
+ const I& input = mln::exact(input_);
+ mln_concrete(I) output;
+ mln::initialize(output, input);
+ // Iterator on vertices.
+ mln::p_n_faces_fwd_piter<I::dim, mln_geom(I)> v(input.domain(), 0);
+ // Vertex-to-edges neighborhood.
+ typedef mln::complex_higher_neighborhood<I::dim, mln_geom(I)> v2e_t;
+ const v2e_t v2e;
+ mln_niter(v2e_t) e(v2e, v);
+ for_all(v)
+ {
+ output(v) = true;
+ for_all(e)
+ if (!input(e))
+ {
+ output(v) = false;
+ break;
+ }
+ }
+ return output;
+}
+
+/// Dilation from vertices to edges (\f$\delta^\times\f$).
+template <typename I>
+inline
+mln_concrete(I)
+dilation_v2e(const mln::Image<I>& input_)
+{
+ const I& input = mln::exact(input_);
+ mln_concrete(I) output;
+ mln::initialize(output, input);
+ // Iterator on edges.
+ mln::p_n_faces_fwd_piter<I::dim, mln_geom(I)> e(input.domain(), 1);
+ // Edge-to-vertices neighborhood.
+ typedef mln::complex_lower_neighborhood<I::dim, mln_geom(I)> e2v_t;
+ const e2v_t e2v;
+ mln_niter(e2v_t) v(e2v, e);
+ for_all(e)
+ {
+ output(e) = false;
+ for_all(v)
+ if (input(v))
+ {
+ output(e) = true;
+ break;
+ }
+ }
+ return output;
+}
+
+
+/// Vertex dilation (\f$delta\f$).
+template <typename I>
+inline
+mln_concrete(I)
+dilation_vertex(const mln::Image<I>& input)
+{
+ return dilation_e2v(dilation_v2e(input));
+}
+
+/// Vertex erosion (\f$epsilon\f$).
+template <typename I>
+inline
+mln_concrete(I)
+erosion_vertex(const mln::Image<I>& input)
+{
+ return erosion_e2v(erosion_v2e(input));
+}
+
+
+/// Edge dilation (\f$Delta\f$).
+template <typename I>
+inline
+mln_concrete(I)
+dilation_edge(const mln::Image<I>& input)
+{
+ return dilation_v2e(dilation_e2v(input));
+}
+
+/// Edge erosion (\f$Epsilon\f$).
+template <typename I>
+inline
+mln_concrete(I)
+erosion_edge(const mln::Image<I>& input)
+{
+ return erosion_v2e(erosion_e2v(input));
+}
+
+
+/// Graph dilation (\f$delta \ovee Delta\f$).
+template <typename I>
+inline
+mln_concrete(I)
+dilation_graph(const mln::Image<I>& input)
+{
+ return combine(dilation_vertex(input), dilation_edge(input));
+}
+
+/// Graph erosion (\f$epsilon \ovee Epsilon\f$).
+template <typename I>
+inline
+mln_concrete(I)
+erosion_graph(const mln::Image<I>& input)
+{
+ return combine(erosion_vertex(input), erosion_edge(input));
+}
+
+
+/*-------------------------.
+| Additional adjunctions. |
+`-------------------------*/
+
+template <typename I>
+inline
+mln_concrete(I)
+alpha1(const mln::Image<I>& input)
+{
+ mln_concrete(I) vertices;
+ mln::initialize(vertices, input);
+ mln::data::fill(vertices, true);
+ return combine(vertices, input);
+}
+
+template <typename I>
+inline
+mln_concrete(I)
+beta1(const mln::Image<I>& input)
+{
+ return combine(dilation_e2v(input), input);
+}
+
+template <typename I>
+inline
+mln_concrete(I)
+alpha2(const mln::Image<I>& input)
+{
+ return combine(input, erosion_v2e(input));
+}
+
+template <typename I>
+inline
+mln_concrete(I)
+beta2(const mln::Image<I>& input)
+{
+ mln_concrete(I) edges;
+ mln::initialize(edges, input);
+ mln::data::fill(edges, false);
+ return combine(input, edges);
+}
+
+template <typename I>
+inline
+mln_concrete(I)
+alpha3(const mln::Image<I>& input)
+{
+ return combine(erosion_e2v(input), erosion_v2e(erosion_e2v(input)));
+}
+
+template <typename I>
+inline
+mln_concrete(I)
+beta3(const mln::Image<I>& input)
+{
+ return combine(dilation_e2v(dilation_v2e(input)), dilation_v2e(input));
+}
+
+
+/*------------------------.
+| Openings and closings. |
+`------------------------*/
+
+/// Vertex opening (\f$\gamma_1\f$).
+template <typename I>
+inline
+mln_concrete(I)
+opening_vertex(const mln::Image<I>& input)
+{
+ return dilation_vertex(erosion_vertex(input));
+}
+
+/// Vertex closing (\f$\phi_1\f$).
+template <typename I>
+inline
+mln_concrete(I)
+closing_vertex(const mln::Image<I>& input)
+{
+ return erosion_vertex(dilation_vertex(input));
+}
+
+
+/// Edge opening (\f$\Gamma_1\f$).
+template <typename I>
+inline
+mln_concrete(I)
+opening_edge(const mln::Image<I>& input)
+{
+ return dilation_edge(erosion_edge(input));
+}
+
+/// Edge closing (\f$\Phi_1\f$).
+template <typename I>
+inline
+mln_concrete(I)
+closing_edge(const mln::Image<I>& input)
+{
+ return erosion_edge(dilation_edge(input));
+}
+
+
+/// Graph opening (\f${\gamma \ovee \Gamma}_1\f$).
+template <typename I>
+inline
+mln_concrete(I)
+opening_graph(const mln::Image<I>& input)
+{
+ return combine(opening_vertex(input), opening_edge(input));
+}
+
+/// Graph closing (\f${\phi \ovee \Phi}_1\f$).
+template <typename I>
+inline
+mln_concrete(I)
+closing_graph(const mln::Image<I>& input)
+{
+ return combine(closing_vertex(input), closing_edge(input));
+}
+
+
+/*----------------------------------.
+| Half-openings and half-closings. |
+`----------------------------------*/
+
+/// Vertex half-opening (\f$\gamma_{1/2}\f$).
+template <typename I>
+inline
+mln_concrete(I)
+half_opening_vertex(const mln::Image<I>& input)
+{
+ return dilation_e2v(erosion_v2e(input));
+}
+
+/// Vertex half-closing (\f$\phi_{1/2}\f$).
+template <typename I>
+inline
+mln_concrete(I)
+half_closing_vertex(const mln::Image<I>& input)
+{
+ return erosion_e2v(dilation_v2e(input));
+}
+
+
+/// Edge half-opening (\f$\Gamma_{1/2}\f$).
+template <typename I>
+inline
+mln_concrete(I)
+half_opening_edge(const mln::Image<I>& input)
+{
+ return dilation_v2e(erosion_e2v(input));
+}
+
+/// Edge half-closing (\f$\Phi_{1/2}\f$).
+template <typename I>
+inline
+mln_concrete(I)
+half_closing_edge(const mln::Image<I>& input)
+{
+ return erosion_v2e(dilation_e2v(input));
+}
+
+
+/// Graph half-opening (\f${\gamma \ovee \Gamma}_{1/2}\f$).
+template <typename I>
+inline
+mln_concrete(I)
+half_opening_graph(const mln::Image<I>& input)
+{
+ return combine(half_opening_vertex(input), half_opening_edge(input));
+}
+
+/// Graph half-closing (\f${\phi \ovee \Phi}_{1/2}\f$).
+template <typename I>
+inline
+mln_concrete(I)
+half_closing_graph(const mln::Image<I>& input)
+{
+ return combine(half_closing_vertex(input), half_closing_edge(input));
+}
+
+
+/*-------------------------------------------------------.
+| Parameterized openings and closings (granulometries). |
+`-------------------------------------------------------*/
+
+/// Opening (\f${\gamma \ovee \Gamma}_{\lambda/2}\f$).
+template <typename I>
+inline
+mln_concrete(I)
+opening(const mln::Image<I>& input, unsigned lambda)
+{
+ unsigned i = lambda / 2;
+ unsigned j = lambda % 2;
+ mln_concrete(I) output = mln::duplicate(input);
+ for (unsigned m = 0; m < i; ++m)
+ output = erosion_graph(output);
+ for (unsigned m = 0; m < j; ++m)
+ output = half_opening_graph(output);
+ for (unsigned m = 0; m < i; ++m)
+ output = dilation_graph(output);
+ return output;
+}
+
+/// Opening (\f${\phi \ovee \Phi}_{\lambda/2}\f$).
+template <typename I>
+inline
+mln_concrete(I)
+closing(const mln::Image<I>& input, unsigned lambda)
+{
+ unsigned i = lambda / 2;
+ unsigned j = lambda % 2;
+ mln_concrete(I) output = mln::duplicate(input);
+ for (unsigned m = 0; m < i; ++m)
+ output = dilation_graph(output);
+ for (unsigned m = 0; m < j; ++m)
+ output = half_closing_graph(output);
+ for (unsigned m = 0; m < i; ++m)
+ output = erosion_graph(output);
+ return output;
+}
+
+/*-------------------------------.
+| Alternate Sequential Filters. |
+`-------------------------------*/
+
+/// Alternate Sequential Filter (ASF) (\f${ASF}_{\lambda/2}\f$).
+template <typename I>
+inline
+mln_concrete(I)
+asf(const mln::Image<I>& input, unsigned lambda)
+{
+ mln_concrete(I) output = mln::duplicate(input);
+ for (unsigned m = 0; m < lambda; ++m)
+ output = half_opening_graph(half_closing_graph(output));
+ return output;
+}
+
+#endif // ! APPS_GRAPH_MORPHO_MORPHO_HH
--
1.6.4.2
1
0
[PATCH 4/6] Alias for binary 1-complex-based images in the dicrete plane.
by Roland Levillain 10 Sep '09
by Roland Levillain 10 Sep '09
10 Sep '09
* mln/core/alias/complex_image.hh (mln::bin_1complex_image2d):
New typedef.
---
milena/ChangeLog | 7 +++++++
milena/mln/core/alias/complex_image.hh | 7 +++++++
2 files changed, 14 insertions(+), 0 deletions(-)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 0451a79..65dfce9 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,12 @@
2009-09-10 Roland Levillain <roland(a)lrde.epita.fr>
+ Alias for binary 1-complex-based images in the dicrete plane.
+
+ * mln/core/alias/complex_image.hh (mln::bin_1complex_image2d):
+ New typedef.
+
+2009-09-10 Roland Levillain <roland(a)lrde.epita.fr>
+
Implement the remaining morphological operators on graphs.
* apps/graph-morpho/complex1d.cc
diff --git a/milena/mln/core/alias/complex_image.hh b/milena/mln/core/alias/complex_image.hh
index 57b67ae..89a8241 100644
--- a/milena/mln/core/alias/complex_image.hh
+++ b/milena/mln/core/alias/complex_image.hh
@@ -45,6 +45,13 @@ namespace mln
| 2-d plane 1-complex aliases. |
`------------------------------*/
+ /// \brief Type alias for a binary image based on a
+ /// 1-complex, where 0-faces are located at discrete (integer)
+ /// 2-dimensional points.
+ typedef
+ mln::complex_image<1, mln::discrete_plane_1complex_geometry, bool>
+ bin_1complex_image2d;
+
/// \brief Type alias for an 8-bit gray-level image based on a
/// 1-complex, where 0-faces are located at discrete (integer)
/// 2-dimensional points.
--
1.6.4.2
1
0
[PATCH 3/6] Implement the remaining morphological operators on graphs.
by Roland Levillain 10 Sep '09
by Roland Levillain 10 Sep '09
10 Sep '09
* apps/graph-morpho/complex1d.cc
(alpha1, beta1, alpha2, beta2, alpha3, beta3)
(opening_vertex, closing_vertex)
(opening_edge, closing_edge)
(opening_graph, closing_graph)
(half_opening_vertex, half_closing_vertex)
(half_opening_edge, half_closing_edge)
(half_opening_graph, half_closing_graph)
(opening, closing, asf):
New functions.
Exercise some of them...
(main): ...here.
* apps/graph-morpho/y.pbm,
* apps/graph-morpho/z.pbm:
New images.
* apps/graph-morpho/Makefile.am (EXTRA_DIST): Add y.pbm and z.pbm.
---
milena/ChangeLog | 21 +++
milena/apps/graph-morpho/Makefile.am | 2 +-
milena/apps/graph-morpho/complex1d.cc | 286 +++++++++++++++++++++++++++++++++
milena/apps/graph-morpho/y.pbm | 22 +++
milena/apps/graph-morpho/z.pbm | 22 +++
5 files changed, 352 insertions(+), 1 deletions(-)
create mode 100644 milena/apps/graph-morpho/y.pbm
create mode 100644 milena/apps/graph-morpho/z.pbm
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 3f74480..0451a79 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,26 @@
2009-09-10 Roland Levillain <roland(a)lrde.epita.fr>
+ Implement the remaining morphological operators on graphs.
+
+ * apps/graph-morpho/complex1d.cc
+ (alpha1, beta1, alpha2, beta2, alpha3, beta3)
+ (opening_vertex, closing_vertex)
+ (opening_edge, closing_edge)
+ (opening_graph, closing_graph)
+ (half_opening_vertex, half_closing_vertex)
+ (half_opening_edge, half_closing_edge)
+ (half_opening_graph, half_closing_graph)
+ (opening, closing, asf):
+ New functions.
+ Exercise some of them...
+ (main): ...here.
+ * apps/graph-morpho/y.pbm,
+ * apps/graph-morpho/z.pbm:
+ New images.
+ * apps/graph-morpho/Makefile.am (EXTRA_DIST): Add y.pbm and z.pbm.
+
+2009-09-10 Roland Levillain <roland(a)lrde.epita.fr>
+
Simplify graph-based image I/O in apps/graph-morpho.
* apps/graph-morpho/complex1d.cc (make_regular_complex1d_image):
diff --git a/milena/apps/graph-morpho/Makefile.am b/milena/apps/graph-morpho/Makefile.am
index 0d7f9e7..faa0fd4 100644
--- a/milena/apps/graph-morpho/Makefile.am
+++ b/milena/apps/graph-morpho/Makefile.am
@@ -25,4 +25,4 @@ complex1d_SOURCES = complex1d.cc
TESTS = complex1d
-EXTRA_DIST = x.pbm
+EXTRA_DIST = x.pbm y.pbm z.pbm
diff --git a/milena/apps/graph-morpho/complex1d.cc b/milena/apps/graph-morpho/complex1d.cc
index 6e98310..e220fca 100644
--- a/milena/apps/graph-morpho/complex1d.cc
+++ b/milena/apps/graph-morpho/complex1d.cc
@@ -42,6 +42,8 @@
#include <mln/core/site_set/p_set.hh>
#include <mln/util/site_pair.hh>
+#include <mln/core/routine/duplicate.hh>
+
#include <mln/math/abs.hh>
#include <mln/io/pbm/load.hh>
@@ -248,10 +250,15 @@ println(const complex_image<dim, geom_t, T>& ima, const box2d& support)
}
}
+
/*------------------------------------.
| Morphological operators on graphs. |
`------------------------------------*/
+// ------------------------ //
+// Dilations and erosions. //
+// ------------------------ //
+
/* FIXME: By constraining the domain of the input and passing the
neighborhood, one should be able to use a truly generic dilation
(resp. erosion), or even use Milena's standard morpho::dilation
@@ -265,6 +272,17 @@ dilation_e2v(const Image<I>& input_)
const I& input = exact(input_);
mln_concrete(I) output;
initialize(output, input);
+ /* FIXME: It'd be better to write something like this:
+
+ mln_piter(...) v(output | vertices);
+
+ We can actually write this, but `vertices' has to be a predicate
+ on sites (p2b function), which is not efficient, since both
+ vertices and edges will be browsed.
+
+ It would be very nice if `vertices' could be an actual site set,
+ so that `output | vertices' creates a morpher smart enough to
+ browse /only/ vertices. */
p_n_faces_fwd_piter<dim, geom_t> v(input.domain(), 0);
mln_niter_(v2e_t) e(v2e, v);
for_all(v)
@@ -423,6 +441,224 @@ erosion_graph(const Image<I>& input)
}
+// ------------------------ //
+// Additional adjunctions. //
+// ------------------------ //
+
+template <typename I>
+mln_concrete(I)
+alpha1(const Image<I>& input)
+{
+ mln_concrete(I) vertices;
+ initialize(vertices, input);
+ data::fill(vertices, true);
+ return combine(vertices, input);
+}
+
+template <typename I>
+mln_concrete(I)
+beta1(const Image<I>& input)
+{
+ return combine(dilation_e2v(input), input);
+}
+
+template <typename I>
+mln_concrete(I)
+alpha2(const Image<I>& input)
+{
+ return combine(input, erosion_v2e(input));
+}
+
+template <typename I>
+mln_concrete(I)
+beta2(const Image<I>& input)
+{
+ mln_concrete(I) edges;
+ initialize(edges, input);
+ data::fill(edges, false);
+ return combine(input, edges);
+}
+
+template <typename I>
+mln_concrete(I)
+alpha3(const Image<I>& input)
+{
+ return combine(erosion_e2v(input), erosion_v2e(erosion_e2v(input)));
+}
+
+template <typename I>
+mln_concrete(I)
+beta3(const Image<I>& input)
+{
+ return combine(dilation_e2v(dilation_v2e(input)), dilation_v2e(input));
+}
+
+
+// ----------------------- //
+// Openings and closings. //
+// ----------------------- //
+
+/// Vertex opening (\f$\gamma_1\f$).
+template <typename I>
+mln_concrete(I)
+opening_vertex(const Image<I>& input)
+{
+ return dilation_vertex(erosion_vertex(input));
+}
+
+/// Vertex closing (\f$\phi_1\f$).
+template <typename I>
+mln_concrete(I)
+closing_vertex(const Image<I>& input)
+{
+ return erosion_vertex(dilation_vertex(input));
+}
+
+
+/// Edge opening (\f$\Gamma_1\f$).
+template <typename I>
+mln_concrete(I)
+opening_edge(const Image<I>& input)
+{
+ return dilation_edge(erosion_edge(input));
+}
+
+/// Edge closing (\f$\Phi_1\f$).
+template <typename I>
+mln_concrete(I)
+closing_edge(const Image<I>& input)
+{
+ return erosion_edge(dilation_edge(input));
+}
+
+
+/// Graph opening (\f${\gamma \ovee \Gamma}_1\f$).
+template <typename I>
+mln_concrete(I)
+opening_graph(const Image<I>& input)
+{
+ return combine(opening_vertex(input), opening_edge(input));
+}
+
+/// Graph closing (\f${\phi \ovee \Phi}_1\f$).
+template <typename I>
+mln_concrete(I)
+closing_graph(const Image<I>& input)
+{
+ return combine(closing_vertex(input), closing_edge(input));
+}
+
+
+// --------------------------------- //
+// Half-openings and half-closings. //
+// --------------------------------- //
+
+/// Vertex half-opening (\f$\gamma_{1/2}\f$).
+template <typename I>
+mln_concrete(I)
+half_opening_vertex(const Image<I>& input)
+{
+ return dilation_e2v(erosion_v2e(input));
+}
+
+/// Vertex half-closing (\f$\phi_{1/2}\f$).
+template <typename I>
+mln_concrete(I)
+half_closing_vertex(const Image<I>& input)
+{
+ return erosion_e2v(dilation_v2e(input));
+}
+
+
+/// Edge half-opening (\f$\Gamma_{1/2}\f$).
+template <typename I>
+mln_concrete(I)
+half_opening_edge(const Image<I>& input)
+{
+ return dilation_v2e(erosion_e2v(input));
+}
+
+/// Edge half-closing (\f$\Phi_{1/2}\f$).
+template <typename I>
+mln_concrete(I)
+half_closing_edge(const Image<I>& input)
+{
+ return erosion_v2e(dilation_e2v(input));
+}
+
+
+/// Graph half-opening (\f${\gamma \ovee \Gamma}_{1/2}\f$).
+template <typename I>
+mln_concrete(I)
+half_opening_graph(const Image<I>& input)
+{
+ return combine(half_opening_vertex(input), half_opening_edge(input));
+}
+
+/// Graph half-closing (\f${\phi \ovee \Phi}_{1/2}\f$).
+template <typename I>
+mln_concrete(I)
+half_closing_graph(const Image<I>& input)
+{
+ return combine(half_closing_vertex(input), half_closing_edge(input));
+}
+
+
+// ------------------------------------------------------ //
+// Parameterized openings and closings (granulometries). //
+// ------------------------------------------------------ //
+
+/// Opening (\f${\gamma \ovee \Gamma}_{\lambda/2}\f$).
+template <typename I>
+mln_concrete(I)
+opening(const Image<I>& input, unsigned lambda)
+{
+ unsigned i = lambda / 2;
+ unsigned j = lambda % 2;
+ mln_concrete(I) output = duplicate(input);
+ for (unsigned m = 0; m < i; ++m)
+ output = erosion_graph(output);
+ for (unsigned m = 0; m < j; ++m)
+ output = half_opening_graph(output);
+ for (unsigned m = 0; m < i; ++m)
+ output = dilation_graph(output);
+ return output;
+}
+
+/// Opening (\f${\phi \ovee \Phi}_{\lambda/2}\f$).
+template <typename I>
+mln_concrete(I)
+closing(const Image<I>& input, unsigned lambda)
+{
+ unsigned i = lambda / 2;
+ unsigned j = lambda % 2;
+ mln_concrete(I) output = duplicate(input);
+ for (unsigned m = 0; m < i; ++m)
+ output = dilation_graph(output);
+ for (unsigned m = 0; m < j; ++m)
+ output = half_closing_graph(output);
+ for (unsigned m = 0; m < i; ++m)
+ output = erosion_graph(output);
+ return output;
+}
+
+// ----------------------------- //
+// Alternate Sequential Filter. //
+// ----------------------------- //
+
+/// Alternate Sequential Filter (ASF) (\f${ASF}_{\lambda/2}\f$).
+template <typename I>
+mln_concrete(I)
+asf(const Image<I>& input, unsigned lambda)
+{
+ mln_concrete(I) output = duplicate(input);
+ for (unsigned m = 0; m < lambda; ++m)
+ output = half_opening_graph(half_closing_graph(output));
+ return output;
+}
+
+
+
/*-----------------------------------.
| Applying morphological operators. |
`-----------------------------------*/
@@ -470,4 +706,54 @@ int main()
ima_t ero_ima = erosion_graph(x);
std::cout << "ero_ima:" << std::endl;
println(ero_ima, x_box);
+
+
+ ima_t alpha3_ima = alpha3(x);
+ std::cout << "alpha3_ima:" << std::endl;
+ println(alpha3_ima, x_box);
+
+ ima_t beta3_ima = beta3(x);
+ std::cout << "beta3_ima:" << std::endl;
+ println(beta3_ima, x_box);
+
+ // --------- //
+ // Filters. //
+ // --------- //
+
+ image2d<bool> y_pbm = io::pbm::load(MLN_APPS_DIR "/graph-morpho/y.pbm");
+ ima_t y = make_regular_complex1d_image(y_pbm);
+ box2d y_box(y_pbm.nrows() / 2 + 1, y_pbm.ncols() / 2 + 1);
+ std::cout << "y:" << std::endl;
+ println(y, y_box);
+
+ ima_t ope_ima = opening_graph(y);
+ std::cout << "ope_ima:" << std::endl;
+ println(ope_ima, y_box);
+
+ ima_t half_ope_ima = half_opening_graph(y);
+ std::cout << "half_ope_ima:" << std::endl;
+ println(half_ope_ima, y_box);
+
+ ima_t beta3_o_alpha3_ima = beta3(alpha3(y));
+ std::cout << "beta3_o_alpha3_ima:" << std::endl;
+ println(beta3_o_alpha3_ima, y_box);
+
+
+ image2d<bool> z_pbm = io::pbm::load(MLN_APPS_DIR "/graph-morpho/z.pbm");
+ ima_t z = make_regular_complex1d_image(z_pbm);
+ box2d z_box(z_pbm.nrows() / 2 + 1, z_pbm.ncols() / 2 + 1);
+ std::cout << "z:" << std::endl;
+ println(z, z_box);
+
+ ima_t clo_ima = closing_graph(z);
+ std::cout << "clo_ima:" << std::endl;
+ println(clo_ima, z_box);
+
+ ima_t half_clo_ima = half_closing_graph(z);
+ std::cout << "half_clo_ima:" << std::endl;
+ println(half_clo_ima, z_box);
+
+ ima_t alpha3_o_beta3_ima = alpha3(beta3(z));
+ std::cout << "alpha3_o_beta3_ima:" << std::endl;
+ println(alpha3_o_beta3_ima, z_box);
}
diff --git a/milena/apps/graph-morpho/y.pbm b/milena/apps/graph-morpho/y.pbm
new file mode 100644
index 0000000..6e14dde
--- /dev/null
+++ b/milena/apps/graph-morpho/y.pbm
@@ -0,0 +1,22 @@
+P1
+# y.pbm
+15 19
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 0 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 0 1 1 1 1 1 1 1 1 1 1
+1 1 0 0 0 0 0 0 0 1 1 1 1 1 1
+1 1 1 1 0 1 1 1 0 1 1 1 1 1 1
+1 1 1 1 0 1 1 1 0 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 0 1 1 1 1 1 1
+1 1 1 1 0 1 1 1 0 0 0 1 1 1 1
+1 1 1 1 0 1 1 1 0 1 0 1 1 1 1
+1 1 1 1 0 1 0 0 0 0 0 0 0 1 1
+1 1 1 1 0 1 1 1 0 1 0 1 1 1 1
+1 1 0 0 0 1 1 1 0 1 0 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 0 1 0 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 0 1 1 1 1 1 0 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
diff --git a/milena/apps/graph-morpho/z.pbm b/milena/apps/graph-morpho/z.pbm
new file mode 100644
index 0000000..1eb2ee2
--- /dev/null
+++ b/milena/apps/graph-morpho/z.pbm
@@ -0,0 +1,22 @@
+P1
+# z.pbm
+15 19
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 0 0 0 0 0 1 1 1 1
+1 1 1 1 1 1 0 1 1 1 0 1 1 1 1
+1 1 1 1 1 1 0 1 1 1 0 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 0 1 1 1 1
+1 1 0 0 0 1 0 1 0 0 0 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 0 1 1 1 1
+1 1 1 1 1 1 0 1 1 1 0 1 1 1 1
+1 1 1 1 1 1 0 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 0 1 1 1 0 1 1 1 1
+1 1 1 1 1 1 0 1 1 1 0 1 1 1 1
+1 1 0 1 1 1 0 0 0 0 0 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 0 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1 1 1 1 1
--
1.6.4.2
1
0
---
ChangeLog | 4 ++++
configure.ac | 4 ++++
2 files changed, 8 insertions(+), 0 deletions(-)
diff --git a/ChangeLog b/ChangeLog
index e2991df..f7fa700 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2009-09-10 Roland Levillain <roland(a)lrde.epita.fr>
+
+ * configure.ac: Configure milena/apps/data.hh.
+
2009-09-08 Roland Levillain <roland(a)lrde.epita.fr>
* configure.ac: Configure milena/apps/graph-morpho/Makefile.
diff --git a/configure.ac b/configure.ac
index c7a2487..efbbb27 100644
--- a/configure.ac
+++ b/configure.ac
@@ -390,6 +390,10 @@ dnl>>
## Applications. ##
## -------------- ##
+# Ask for the creation of a milena/apps/data.hh, used to access to
+# data (images) from apps.
+AC_CONFIG_FILES([milena/apps/data.hh])
+
AC_ARG_ENABLE([apps],
[AS_HELP_STRING([--enable-apps],
[enable application])])
--
1.6.4.2
1
0
10 Sep '09
* apps/graph-morpho/complex1d.cc (make_regular_complex1d_image):
New function.
Use it...
(main): ...here, to simplify the construction of the input image,
by reading it from...
* apps/graph-morpho/x.pbm: ...this (new) image.
* apps/data.hh.in: New.
* apps/graph-morpho/Makefile.am (AM_CPPFLAGS):
Add -I$(top_builddir)/milena.
(bin_PROGRAMS): Rename as...
(noinst_PROGRAMS): ...this.
(EXTRA_DIST): New.
Add x.pbm.
---
milena/ChangeLog | 18 ++++
milena/apps/data.hh.in | 41 ++++++++
milena/apps/graph-morpho/Makefile.am | 6 +-
milena/apps/graph-morpho/complex1d.cc | 162 ++++++++++++++++----------------
milena/apps/graph-morpho/x.pbm | 20 ++++
5 files changed, 164 insertions(+), 83 deletions(-)
create mode 100644 milena/apps/data.hh.in
create mode 100644 milena/apps/graph-morpho/x.pbm
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 700906c..3f74480 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,3 +1,21 @@
+2009-09-10 Roland Levillain <roland(a)lrde.epita.fr>
+
+ Simplify graph-based image I/O in apps/graph-morpho.
+
+ * apps/graph-morpho/complex1d.cc (make_regular_complex1d_image):
+ New function.
+ Use it...
+ (main): ...here, to simplify the construction of the input image,
+ by reading it from...
+ * apps/graph-morpho/x.pbm: ...this (new) image.
+ * apps/data.hh.in: New.
+ * apps/graph-morpho/Makefile.am (AM_CPPFLAGS):
+ Add -I$(top_builddir)/milena.
+ (bin_PROGRAMS): Rename as...
+ (noinst_PROGRAMS): ...this.
+ (EXTRA_DIST): New.
+ Add x.pbm.
+
2009-09-10 Fabien Freling <fabien.freling(a)lrde.epita.fr>
Fix luminance value computation for RGB to HSL.
diff --git a/milena/apps/data.hh.in b/milena/apps/data.hh.in
new file mode 100644
index 0000000..8adb35f
--- /dev/null
+++ b/milena/apps/data.hh.in
@@ -0,0 +1,41 @@
+// Copyright (C) 2008, 2009 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.
+
+#ifndef APPS_DATA_HH
+# define APPS_DATA_HH
+
+# include <string>
+
+/* Macros are evil, but they save us an extra compilation unit here
+ (as well as additional burden in Makefiles, too.). */
+
+/// The absolute path to the img directory of Milena.
+# define MLN_IMG_DIR "@abs_top_srcdir@/milena/img"
+
+/// The absolute path to the apps directory of Milena.
+# define MLN_APPS_DIR "@abs_top_srcdir@/milena/apps/"
+
+#endif // ! APPS_DATA_HH
diff --git a/milena/apps/graph-morpho/Makefile.am b/milena/apps/graph-morpho/Makefile.am
index 590e756..0d7f9e7 100644
--- a/milena/apps/graph-morpho/Makefile.am
+++ b/milena/apps/graph-morpho/Makefile.am
@@ -15,12 +15,14 @@
# along with Olena. If not, see <http://www.gnu.org/licenses/>.
# Find Milena headers.
-AM_CPPFLAGS = -I$(top_srcdir)/milena
+AM_CPPFLAGS = -I$(top_srcdir)/milena -I$(top_builddir)/milena
# Produce fast code.
APPS_CXXFLAGS = @APPS_CXXFLAGS@
AM_CXXFLAGS = $(APPS_CXXFLAGS)
-bin_PROGRAMS = complex1d
+noinst_PROGRAMS = complex1d
complex1d_SOURCES = complex1d.cc
TESTS = complex1d
+
+EXTRA_DIST = x.pbm
diff --git a/milena/apps/graph-morpho/complex1d.cc b/milena/apps/graph-morpho/complex1d.cc
index 93eab21..6e98310 100644
--- a/milena/apps/graph-morpho/complex1d.cc
+++ b/milena/apps/graph-morpho/complex1d.cc
@@ -42,6 +42,11 @@
#include <mln/core/site_set/p_set.hh>
#include <mln/util/site_pair.hh>
+#include <mln/math/abs.hh>
+
+#include <mln/io/pbm/load.hh>
+
+#include "apps/data.hh"
using namespace mln;
@@ -120,6 +125,54 @@ build_regular_complex1d_image(const box2d& support)
return ima;
}
+template <typename I>
+ima_t
+make_regular_complex1d_image(const Image<I>& input_)
+{
+ const I& input = exact(input_);
+ const box2d& input_box = input.domain();
+ // The input image must have an odd number of rows and columns.
+ mln_precondition(input_box.nrows() % 2 == 1);
+ mln_precondition(input_box.ncols() % 2 == 1);
+
+ // The domain of the graph image is twice as small, since we
+ // consider only vertices (edges are set ``between'' vertices).
+ box2d output_box(input_box.nrows() / 2 + 1,
+ input_box.ncols() / 2 + 1);
+ ima_t output = build_regular_complex1d_image(output_box);
+
+ // Add values on vertices.
+ p_n_faces_fwd_piter<dim, geom_t> v(output.domain(), 0);
+ for_all(v)
+ {
+ mln_site_(geom_t) s(v);
+ // Site S is point2d multi-site and should be a singleton (since V
+ // iterates on vertices).
+ mln_invariant(s.size() == 1);
+ point2d p = s.front();
+ point2d q(p.row() * 2, p.col() * 2);
+ output(v) = input(q);
+ }
+
+ // Add values on edges.
+ p_n_faces_fwd_piter<dim, geom_t> e(output.domain(), 1);
+ for_all(e)
+ {
+ mln_site_(geom_t) s(e);
+ // Site S is point2d multi-site and should be a pair (since E
+ // iterates on vertices).
+ mln_invariant(s.size() == 2);
+ point2d p1 = s[0];
+ point2d p2 = s[1];
+ mln_invariant(math::abs(p1.row() - p2.row()) == 1
+ || math::abs(p1.col() - p2.col()) == 1);
+ point2d q (p1.row() + p2.row(), p1.col() + p2.col());
+ output(e) = input(q);
+ }
+
+ return output;
+}
+
template <typename T>
void
@@ -370,104 +423,51 @@ erosion_graph(const Image<I>& input)
}
+/*-----------------------------------.
+| Applying morphological operators. |
+`-----------------------------------*/
int main()
{
- /*--------------.
- | Input image. |
- `--------------*/
-
/* Build a ``regular'' graph image. Of course, it would have been
better, simpler and faster to use a cubical 1-complex here, but
- they are not yet available. */
- box2d b(9, 6);
- ima_t ima = build_regular_complex1d_image(b);
-
- /* Set the values so that IMA corresponds to the graph X of the ISMM
- 2009 paper from Jean Cousty et al. */
-
- // The set of vertices of the graph.
- p_set<point2d> vertices;
- vertices.insert(point2d(1, 2));
- vertices.insert(point2d(2, 1));
- vertices.insert(point2d(2, 2));
- vertices.insert(point2d(3, 4));
- vertices.insert(point2d(5, 2));
- vertices.insert(point2d(5, 3));
- vertices.insert(point2d(5, 4));
- vertices.insert(point2d(6, 1));
- vertices.insert(point2d(6, 2));
- vertices.insert(point2d(6, 3));
- vertices.insert(point2d(6, 4));
- vertices.insert(point2d(7, 2));
- vertices.insert(point2d(7, 3));
- // Add vertices.
- p_n_faces_fwd_piter<dim, geom_t> v(ima.domain(), 0);
- for_all(v)
- {
- mln_site_(geom_t) s(v);
- // Site S is point2d multi-site and should be a singleton (since V
- // iterates on vertices).
- mln_invariant(s.size() == 1);
- point2d p = s.front();
- ima(v) = vertices.has(p);
- }
-
- // The set of edges of the graph.
- typedef util::site_pair<point2d> point2d_pair;
- p_set< util::site_pair<point2d> > edges;
- edges.insert(point2d_pair(point2d(2, 1), point2d(2, 2)));
- edges.insert(point2d_pair(point2d(5, 3), point2d(5, 4)));
- edges.insert(point2d_pair(point2d(5, 2), point2d(6, 2)));
- edges.insert(point2d_pair(point2d(5, 3), point2d(6, 3)));
- edges.insert(point2d_pair(point2d(6, 1), point2d(6, 2)));
- edges.insert(point2d_pair(point2d(6, 2), point2d(6, 3)));
- edges.insert(point2d_pair(point2d(6, 3), point2d(6, 4)));
- edges.insert(point2d_pair(point2d(6, 2), point2d(7, 2)));
- edges.insert(point2d_pair(point2d(6, 3), point2d(7, 3)));
- edges.insert(point2d_pair(point2d(7, 2), point2d(7, 3)));
- // Add edges.
- p_n_faces_fwd_piter<dim, geom_t> e(ima.domain(), 1);
- for_all(e)
- {
- mln_site_(geom_t) s(e);
- // Site S is point2d multi-site and should be a pair (since E
- // iterates on vertices).
- mln_invariant(s.size() == 2);
- point2d p1 = s[0];
- point2d p2 = s[1];
- ima(e) =
- edges.has(point2d_pair(p1, p2)) || edges.has(point2d_pair(p2, p1));
- }
- std::cout << "ima:" << std::endl;
- println(ima, b);
+ they are not yet available (as of 2009-09-10). */
- /*-----------------------------------.
- | Applying morphological operators. |
- `-----------------------------------*/
+ // ------------------------ //
+ // Dilations and erosions. //
+ // ------------------------ //
- ima_t dil_e2v_ima = dilation_e2v(ima);
+ /* Set the values so that X corresponds to the graph X of the ISMM
+ 2009 paper from Jean Cousty et al. */
+ image2d<bool> x_pbm = io::pbm::load(MLN_APPS_DIR "/graph-morpho/x.pbm");
+ ima_t x = make_regular_complex1d_image(x_pbm);
+ box2d x_box(x_pbm.nrows() / 2 + 1, x_pbm.ncols() / 2 + 1);
+ std::cout << "x:" << std::endl;
+ println(x, x_box);
+
+ ima_t dil_e2v_ima = dilation_e2v(x);
std::cout << "dil_e2v_ima:" << std::endl;
- println(dil_e2v_ima, b);
+ println(dil_e2v_ima, x_box);
- ima_t ero_v2e_ima = erosion_v2e(ima);
+ ima_t ero_v2e_ima = erosion_v2e(x);
std::cout << "ero_v2e_ima:" << std::endl;
- println(ero_v2e_ima, b);
+ println(ero_v2e_ima, x_box);
+
- ima_t ero_e2v_ima = erosion_e2v(ima);
+ ima_t ero_e2v_ima = erosion_e2v(x);
std::cout << "ero_e2v_ima:" << std::endl;
- println(ero_e2v_ima, b);
+ println(ero_e2v_ima, x_box);
- ima_t dil_v2e_ima = dilation_v2e(ima);
+ ima_t dil_v2e_ima = dilation_v2e(x);
std::cout << "dil_v2e_ima:" << std::endl;
- println(dil_v2e_ima, b);
+ println(dil_v2e_ima, x_box);
- ima_t dil_ima = dilation_graph(ima);
+ ima_t dil_ima = dilation_graph(x);
std::cout << "dil_ima:" << std::endl;
- println(dil_ima, b);
+ println(dil_ima, x_box);
- ima_t ero_ima = erosion_graph(ima);
+ ima_t ero_ima = erosion_graph(x);
std::cout << "ero_ima:" << std::endl;
- println(ero_ima, b);
+ println(ero_ima, x_box);
}
diff --git a/milena/apps/graph-morpho/x.pbm b/milena/apps/graph-morpho/x.pbm
new file mode 100644
index 0000000..5bbea77
--- /dev/null
+++ b/milena/apps/graph-morpho/x.pbm
@@ -0,0 +1,20 @@
+P1
+# x.pbm
+11 17
+1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 0 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1
+1 1 0 0 0 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 0 1 1
+1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 0 1 0 0 0 1 1
+1 1 1 1 0 1 0 1 1 1 1
+1 1 0 0 0 0 0 0 0 1 1
+1 1 1 1 0 1 0 1 1 1 1
+1 1 1 1 0 0 0 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1
+1 1 1 1 1 1 1 1 1 1 1
--
1.6.4.2
1
0
Re: [Olena-patches] 4454: Write down 3d currently used formulaes.
by Alexandre Duret-Lutz 10 Sep '09
by Alexandre Duret-Lutz 10 Sep '09
10 Sep '09
Coucou Yann,
Quelques typos
>>> "YJ" == Yann Jacquelet <jacquelet(a)lrde.epita.fr> writes:
YJ> +
YJ> +%% \df
YJ> +%% input : the set which the dim we are intering in
the set whose dimension we are interested in?
YJ> +\begin{itemize}
YJ> + \item Use lowercase and normal font for the scalar variables.
YJ> + \item Use lowercase and bold font for the vector variables.
YJ> + \item Use uppercase and normal font for the matrix variables.
YJ> + \item Use uppercase and double font for the set variables.
YJ> +\end {itemize}
s/the//
YJ> +
YJ> +%=================================================================
YJ> +\subsection{Sets}
YJ> +
YJ> +There is three particular sets that we use every time:
s/is/are/
YJ> +\begin{itemize}
YJ> + \item The color space $\fm{C}$ in which the pixels take their value.
YJ> + \item The dataset $\fm{P}$ which contains every pixel we take care.
we care about.
YJ> + \item The group set $\fm{G}$ that define any splitting of the dataset.
defines
YJ> +We use the euclidian distance.
*E*uclidian
YJ> +$$
Use the backslash/bracket pair ("\[ ...\]") instead of a double
dollar construct ("$$ ... $$") for single line displays.
The double dollar sign as a begin/end marker for displayed math
material is a relic from plain TeX, but has been officially
deprecated in LaTeX. In fact, many LaTeX books don't even
mention it, since it is not supposed to be used. While it works
just fine in most situations, and many authors use it with
impunity, there are a few situations where it causes problems,
and it may not work under future versions of TeX. If you come
from a plain TeX/Amstex background and are in the habit of
typing $$'s, try to gradually switch over to using the
backslash/bracket pair. If you are new to Tex/LaTeX, learn it
right from the start (i.e., use the backslash/bracket method).
http://www.math.uiuc.edu/~hildebr/tex/tips-mathdisplays.html
YJ> +%=================================================================
YJ> +\subsection{The group}
YJ> +
YJ> +We can define the group set $\fm{G}$ in thow context:
in this context?
YJ> +When we study some mixed population, the total variance can be splitted in the
YJ> +the variance between the groups and in the variance whithin each group.
s/splitted/split/
s/in the the/in the/
s/whithin/within/
YJ> +
YJ> +%=================================================================
YJ> +\subsection{Decomposing the variance}
YJ> +When we study some mixed population, the total variance can be splitted in the
YJ> +the variance between the groups and in the variance whithin each group.
s/splitted/split/
s/in the the/in the/
s/whithin/within/
YJ> +%%=================================================================
YJ> +\subsection{Eigenvalues and eigenvectors}
YJ> +
YJ> +We assume that we work on variance/covariance matrix which is real and symetric.
s/on/on a/
s/symetric/symmetric/
YJ> +In this case, all the three eigen values are real.
s/eigen values/eigenvalues/
YJ> +\subsection{MCO for eigenvalues}
YJ> +
YJ> +In 3d, it's difficult to extract the cubic roots from the characteristic
YJ> +polynomia. The difficulties disappear when we find one of the three roots.
YJ> +A planar regression allows us to reach the equation of the plane. From the
YJ> +equation, we can determine its normal vector $\bm{w}$. It satisfies the
YJ> +following equation $A\bm{w} = \lambda_3\bm{w}$. Thus we know $\lambda_3$.
YJ> +By the way, as far as $trace(A) = \lambda_1 + \lambda_2 + \lambda_3$ and
YJ> +$det(A) = \lambda_1 \lambda_2 \lambda_3$, then we can access to the value of
Je ne comprends pas le "as far as". N'est-ce pas toujours vrai ?
s/access to the value of/determine/
YJ> +the two others eigenvalues (just solve $\lambda^2 - (trace(A) - \lambda_3)
YJ> +\lambda + \frac{det(A)}{\lambda_3} = 0$). The knowledge of $\lambda_1$ and
YJ> +$\lambda_2$ let us find $\bm{u}$ and $\bm{v}$ by the equations $A\bm{u} =
YJ> +\lambda_1\bm{u}$ and $A\bm{v} = \lambda_2\bm{v}$.
YJ> +
YJ> +Let's center the points by susbtracting their center of
YJ> mass. Now, we have
s/susbtracting/subtracting/
--
Alexandre Duret-Lutz
1
0
10 Sep '09
URL: https://svn.lrde.epita.fr/svn/oln/trunk/milena
ChangeLog:
2009-09-10 Fabien Freling <fabien.freling(a)lrde.epita.fr>
Fix luminance value computation for RGB to HSL.
* mln/fun/v2v/rgb_to_hsl.hh: Fix luminance value computation
to fit in [0,1].
* mln/io/magick/load.hh: Minor update.
* mln/io/magick/save.hh: Minor update.
---
fun/v2v/rgb_to_hsl.hh | 4 ++--
io/magick/load.hh | 31 +++++++++++++++++++++++++++----
io/magick/save.hh | 21 +++++++++++++++++++++
3 files changed, 50 insertions(+), 6 deletions(-)
Index: trunk/milena/mln/fun/v2v/rgb_to_hsl.hh
===================================================================
--- trunk/milena/mln/fun/v2v/rgb_to_hsl.hh (revision 4456)
+++ trunk/milena/mln/fun/v2v/rgb_to_hsl.hh (revision 4457)
@@ -103,14 +103,14 @@
else
hsl.hue() = (60. * (rgb.red() - rgb.green()) / (rmax - rmin)) + 240;
- hsl.lum() = ((double) rmax + (double) rmin) / 2;
-
// We want min and max between 0 and 1
rmax -= mln_min(typename T_rgb::red_t);
rmin -= mln_min(typename T_rgb::red_t);
double nmax = (double) rmax / (mln_max(typename T_rgb::red_t) - mln_min(typename T_rgb::red_t));
double nmin = (double) rmin / (mln_max(typename T_rgb::red_t) - mln_min(typename T_rgb::red_t));
+ hsl.lum() = ((double) nmax + (double) nmin) / 2;
+
if (rmin == rmax)
hsl.sat() = 0;
else
Index: trunk/milena/mln/io/magick/save.hh
===================================================================
--- trunk/milena/mln/io/magick/save.hh (revision 4456)
+++ trunk/milena/mln/io/magick/save.hh (revision 4457)
@@ -58,6 +58,15 @@
void save(const Image<I>& ima,
const std::string& filename);
+ /*! Save a Milena tiled image in a magick image.
+ *
+ * \param[out] ima A reference to the image to save.
+ * \param[in] filename The output.
+ */
+ template <typename T>
+ void save(Image< tiled2d<T> >& ima,
+ const std::string& filename);
+
# ifndef MLN_INCLUDE_ONLY
@@ -117,6 +126,18 @@
trace::exiting("mln::io::magick::save");
}
+ template <typename T>
+ void save(Image< tiled2d<T> >& ima_, const std::string& filename)
+ {
+ trace::entering("mln::io::magick::save");
+
+ tiled2d<T>& ima = exact(ima_);
+
+ ima.buffer().write(filename);
+
+ trace::exiting("mln::io::magick::save");
+ }
+
# endif // ! MLN_INCLUDE_ONLY
Index: trunk/milena/mln/io/magick/load.hh
===================================================================
--- trunk/milena/mln/io/magick/load.hh (revision 4456)
+++ trunk/milena/mln/io/magick/load.hh (revision 4457)
@@ -53,8 +53,16 @@
* \param[in] filename The source.
*/
template <typename I>
- void load(Image<I>& ima,
- const std::string& filename);
+ void load(Image<I>& ima, const std::string& filename);
+
+ /*! Load a magick image in a tiled image.
+ *
+ * \param[out] ima A reference to the image which will receive
+ * data.
+ * \param[in] filename The source.
+ */
+ template <typename T>
+ void load(Image<tiled2d<T> >& ima, const std::string& filename);
# ifndef MLN_INCLUDE_ONLY
@@ -102,8 +110,7 @@
template <typename I>
inline
- void load(Image<I>& ima_,
- const std::string& filename)
+ void load(Image<I>& ima_, const std::string& filename)
{
trace::entering("mln::io::magick::load");
@@ -156,6 +163,22 @@
}
+ template<typename T>
+ inline
+ void load(Image<tiled2d<T> >& ima_, const std::string& filename)
+ {
+ trace::entering("mln::io::magick::load");
+
+ tiled2d<T>& ima = exact(ima_);
+
+ tiled2d<T> result(filename);
+
+ ima = result;
+ trace::exiting("mln::io::magick::load");
+ }
+
+
+
# endif // ! MLN_INCLUDE_ONLY
} // end of namespace mln::io::magick
1
0
* apps/graph-morpho/complex1d.cc: Improve documentation.
(dilation_vertex, erosion_vertex, dilation_edge, erosion_edge)
(combine, dilation_graph, erosion_graph):
New functions.
(main): Exercise some of them.
---
milena/ChangeLog | 10 ++++
milena/apps/graph-morpho/complex1d.cc | 93 +++++++++++++++++++++++++++++++--
2 files changed, 98 insertions(+), 5 deletions(-)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index f716134..f1eb252 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,3 +1,13 @@
+2009-09-09 Roland Levillain <roland(a)lrde.epita.fr>
+
+ More morphological operators on graphs.
+
+ * apps/graph-morpho/complex1d.cc: Improve documentation.
+ (dilation_vertex, erosion_vertex, dilation_edge, erosion_edge)
+ (combine, dilation_graph, erosion_graph):
+ New functions.
+ (main): Exercise some of them.
+
2009-09-09 Edwin Carlinet <carlinet(a)lrde.epita.fr>
Add mask-based max tree computation based on union-find algorithm.
diff --git a/milena/apps/graph-morpho/complex1d.cc b/milena/apps/graph-morpho/complex1d.cc
index 8587040..93eab21 100644
--- a/milena/apps/graph-morpho/complex1d.cc
+++ b/milena/apps/graph-morpho/complex1d.cc
@@ -204,7 +204,7 @@ println(const complex_image<dim, geom_t, T>& ima, const box2d& support)
(resp. erosion), or even use Milena's standard morpho::dilation
(resp. morpho::erosion). */
-/// Dilation from edges to vertices (delta^dot).
+/// Dilation from edges to vertices (\f$\delta^\bullet\f$).
template <typename I>
mln_concrete(I)
dilation_e2v(const Image<I>& input_)
@@ -227,7 +227,7 @@ dilation_e2v(const Image<I>& input_)
return output;
}
-/// Erosion from vertices to edges (erosion^cross).
+/// Erosion from vertices to edges (\f$\epsilon^\times\f$).
template <typename I>
mln_concrete(I)
erosion_v2e(const Image<I>& input_)
@@ -250,7 +250,7 @@ erosion_v2e(const Image<I>& input_)
return output;
}
-/// Erosion from edges to vertices (erosion^dot).
+/// Erosion from edges to vertices (\f$\epsilon^\bullet\f$).
template <typename I>
mln_concrete(I)
erosion_e2v(const Image<I>& input_)
@@ -273,7 +273,7 @@ erosion_e2v(const Image<I>& input_)
return output;
}
-/// Dilation from vertices to edges (dilation^cross).
+/// Dilation from vertices to edges (\f$\delta^\times\f$).
template <typename I>
mln_concrete(I)
dilation_v2e(const Image<I>& input_)
@@ -297,6 +297,80 @@ dilation_v2e(const Image<I>& input_)
}
+/// Vertex dilation (\f$delta\f$).
+template <typename I>
+mln_concrete(I)
+dilation_vertex(const Image<I>& input)
+{
+ return dilation_e2v(dilation_v2e(input));
+}
+
+/// Vertex erosion (\f$epsilon\f$).
+template <typename I>
+mln_concrete(I)
+erosion_vertex(const Image<I>& input)
+{
+ return erosion_e2v(erosion_v2e(input));
+}
+
+
+/// Edge dilation (\f$Delta\f$).
+template <typename I>
+mln_concrete(I)
+dilation_edge(const Image<I>& input)
+{
+ return dilation_v2e(dilation_e2v(input));
+}
+
+/// Edge erosion (\f$Epsilon\f$).
+template <typename I>
+mln_concrete(I)
+erosion_edge(const Image<I>& input)
+{
+ return erosion_v2e(erosion_e2v(input));
+}
+
+
+/// Combine the vertices and the edges of two images to create a new
+/// graph image.
+template <typename I>
+mln_concrete(I)
+combine(const Image<I>& vertices_, const Image<I>& edges_)
+{
+ const I vertices = exact(vertices_);
+ const I edges = exact(edges_);
+ mln_precondition(vertices.domain() == edges.domain());
+
+ mln_concrete(I) output;
+ initialize(output, vertices);
+ p_n_faces_fwd_piter<dim, geom_t> v(output.domain(), 0);
+ for_all(v)
+ output(v) = vertices(v);
+ p_n_faces_fwd_piter<dim, geom_t> e(output.domain(), 1);
+ for_all(e)
+ output(e) = edges(e);
+ return output;
+}
+
+
+/// Graph dilation (\f$delta \ovee Delta\f$).
+template <typename I>
+mln_concrete(I)
+dilation_graph(const Image<I>& input)
+{
+ return combine(dilation_vertex(input), dilation_edge(input));
+}
+
+/// Graph erosion (\f$epsilon \ovee Epsilon\f$).
+template <typename I>
+mln_concrete(I)
+erosion_graph(const Image<I>& input)
+{
+ return combine(erosion_vertex(input), erosion_edge(input));
+}
+
+
+
int main()
{
/*--------------.
@@ -309,7 +383,7 @@ int main()
box2d b(9, 6);
ima_t ima = build_regular_complex1d_image(b);
- /* Set the values so that IMA corresponds to the graph G of the ISMM
+ /* Set the values so that IMA corresponds to the graph X of the ISMM
2009 paper from Jean Cousty et al. */
// The set of vertices of the graph.
@@ -387,4 +461,13 @@ int main()
ima_t dil_v2e_ima = dilation_v2e(ima);
std::cout << "dil_v2e_ima:" << std::endl;
println(dil_v2e_ima, b);
+
+
+ ima_t dil_ima = dilation_graph(ima);
+ std::cout << "dil_ima:" << std::endl;
+ println(dil_ima, b);
+
+ ima_t ero_ima = erosion_graph(ima);
+ std::cout << "ero_ima:" << std::endl;
+ println(ero_ima, b);
}
--
1.6.3.1
1
0