* 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