* apps/graph-morpho/samples-image2d.cc: New.
* apps/graph-morpho/Makefile.am
(noinst_PROGRAMS): Add samples-image2d.
(samples_image2d_SOURCES): New.
(TESTS): Add samples-image2d.
---
milena/ChangeLog | 10 +++
milena/apps/graph-morpho/Makefile.am | 5 +-
milena/apps/graph-morpho/samples-image2d.cc | 94 +++++++++++++++++++++++++++
3 files changed, 107 insertions(+), 2 deletions(-)
create mode 100644 milena/apps/graph-morpho/samples-image2d.cc
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 84d0dc2..64302c1 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,15 @@
2009-09-21 Roland Levillain <roland(a)lrde.epita.fr>
+ New application: apps/graph-morpho/samples-image2d.
+
+ * apps/graph-morpho/samples-image2d.cc: New.
+ * apps/graph-morpho/Makefile.am
+ (noinst_PROGRAMS): Add samples-image2d.
+ (samples_image2d_SOURCES): New.
+ (TESTS): Add samples-image2d.
+
+2009-09-21 Roland Levillain <roland(a)lrde.epita.fr>
+
Have dilations and erosions delegate to the right implementations.
* apps/graph-morpho/morpho.hh
diff --git a/milena/apps/graph-morpho/Makefile.am b/milena/apps/graph-morpho/Makefile.am
index d87d61b..3c2ee26 100644
--- a/milena/apps/graph-morpho/Makefile.am
+++ b/milena/apps/graph-morpho/Makefile.am
@@ -22,11 +22,12 @@ AM_CXXFLAGS = $(APPS_CXXFLAGS)
noinst_HEADERS = io.hh morpho.hh make_complex2d.hh
-noinst_PROGRAMS = samples-complex1d asf-complex1d
+noinst_PROGRAMS = samples-complex1d samples-image2d asf-complex1d
samples_complex1d_SOURCES = samples-complex1d.cc
+samples_image2d_SOURCES = samples-image2d.cc
asf_complex1d_SOURCES = asf-complex1d.cc
-TESTS = samples-complex1d asf-complex1d
+TESTS = samples-complex1d asf-complex1d samples-image2d
# Graph images stored in 2D PBM files.
EXTRA_DIST = x.pbm y.pbm z.pbm
diff --git a/milena/apps/graph-morpho/samples-image2d.cc b/milena/apps/graph-morpho/samples-image2d.cc
new file mode 100644
index 0000000..455a147
--- /dev/null
+++ b/milena/apps/graph-morpho/samples-image2d.cc
@@ -0,0 +1,94 @@
+// 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.
+
+/// \file
+/// \brief Morphological operators in graph space implemented on
+/// mln::image2d-based cubical complexes.
+
+#include <mln/io/pbm/load.hh>
+
+#include <mln/debug/println.hh>
+
+#include "apps/graph-morpho/morpho.hh"
+
+#include "apps/graph-morpho/io.hh"
+#include "apps/data.hh"
+
+
+int main()
+{
+ using namespace mln;
+
+ // Remove borders so as to avoid side effects.
+ border::thickness = 0;
+
+ /* Binary graph-based image with vertices aligned on a discrete 2D grid.
+
+ 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. //
+ // ------------------------ //
+
+ /* Create an image corresponding to the graph X of the ISMM 2009
+ paper from Jean Cousty et al. */
+ image2d<bool> x = io::pbm::load(MLN_APPS_DIR "/graph-morpho/x.pbm");
+ debug::println("x:", x);
+
+ debug::println("dilation_e2v(x):", dilation_e2v(x)) ;
+ debug::println("erosion_v2e(x):", erosion_v2e(x));
+
+ debug::println("erosion_e2v(x):", erosion_e2v(x));
+ debug::println("dilation_v2e(x):", dilation_v2e(x));
+
+ debug::println("dilation_graph(x):", dilation_graph(x));
+ debug::println("erosion_graph(x):", erosion_graph(x));
+
+ debug::println("alpha3(x):", alpha3(x));
+ debug::println("beta3(x):", beta3(x));
+
+ // --------- //
+ // Filters. //
+ // --------- //
+
+ // Create an image corresponding to the graph Y.
+ image2d<bool> y = io::pbm::load(MLN_APPS_DIR "/graph-morpho/y.pbm");
+ debug::println("y:", y);
+
+ debug::println("opening_graph(y):", opening_graph(y));
+ debug::println("half_opening_graph(y):", half_opening_graph(y));
+ debug::println("beta3(alpha3(y)):", beta3(alpha3(y)));
+
+ // Create an image corresponding to the graph Z.
+ image2d<bool> z = io::pbm::load(MLN_APPS_DIR "/graph-morpho/z.pbm");
+ debug::println("z:", z);
+
+ debug::println("closing_graph(z):", closing_graph(z));
+ debug::println("half_closing_graph(z):", half_closing_graph(z));
+ debug::println("alpha3(beta3(z)):", alpha3(beta3(z)));
+}
--
1.6.4.2
* apps/graph-morpho/image_if_large.hh: New.
---
milena/ChangeLog | 6 +
milena/apps/graph-morpho/image_if_large.hh | 307 ++++++++++++++++++++++++++++
2 files changed, 313 insertions(+), 0 deletions(-)
create mode 100644 milena/apps/graph-morpho/image_if_large.hh
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 1707c7b..b623361 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,11 @@
2009-09-21 Roland Levillain <roland(a)lrde.epita.fr>
+ Introduce a ``tolerant'' image_if morpher.
+
+ * apps/graph-morpho/image_if_large.hh: New.
+
+2009-09-21 Roland Levillain <roland(a)lrde.epita.fr>
+
Add neighborhood-aware and graph-friendly dilation & erosion.
* apps/graph-morpho/morpho.hh
diff --git a/milena/apps/graph-morpho/image_if_large.hh b/milena/apps/graph-morpho/image_if_large.hh
new file mode 100644
index 0000000..37c2d63
--- /dev/null
+++ b/milena/apps/graph-morpho/image_if_large.hh
@@ -0,0 +1,307 @@
+// Copyright (C) 2007, 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_GRAPH_MORPHO_IMAGE_IF_LARGE_HH
+# define APPS_GRAPH_MORPHO_IMAGE_IF_LARGE_HH
+
+/// \file
+///
+/// \brief Definition of a image which domain is restricted by a
+/// function 'site -> Boolean', but where routine has() returns true
+/// for sites of the underlying (morphed) image even if they are not
+/// validating the predicate.
+
+// FIXME: This file is a workaround for the lack of ``tolerant''
+// image_if, but there must be a better way.
+
+# include <mln/core/internal/image_domain_morpher.hh>
+# include <mln/core/site_set/p_if.hh>
+# include <mln/pw/all.hh>
+
+
+namespace mln
+{
+
+ // Forward declaration.
+ template <typename I, typename F> struct image_if_large;
+
+
+ namespace internal
+ {
+
+ /// Data structure for \c mln::image_if_large<I,F>.
+ template <typename I, typename F>
+ struct data< image_if_large<I,F> >
+ {
+ data(I& ima, const F& f);
+
+ I ima_;
+ p_if<mln_domain(I), F> domain_;
+ };
+
+ } // end of namespace mln::internal
+
+
+ namespace trait
+ {
+
+ template <typename I, typename F>
+ struct image_< image_if_large<I,F> >
+ : default_image_morpher< I,
+ mln_value(I),
+ image_if_large<I,F> >
+ {
+ typedef trait::image::category::domain_morpher category;
+
+ // No extension of domain.
+ typedef trait::image::ext_domain::none ext_domain;
+ typedef trait::image::ext_value::irrelevant ext_value;
+ typedef trait::image::ext_io::irrelevant ext_io;
+
+ typedef trait::image::vw_io::none vw_io;
+ typedef trait::image::vw_set::none vw_set;
+ typedef trait::image::value_alignment::not_aligned value_alignment;
+ typedef trait::image::value_storage::disrupted value_storage;
+ };
+
+ } // end of namespace mln::trait
+
+
+
+ /// Image which domain is restricted by a function 'site ->
+ /// Boolean', but where routine has() returns true for sites of the
+ /// underlying (morphed) image even if they are not validating the
+ /// predicate.
+ ///
+ /// \ingroup modimagedomainmorpher
+ //
+ template <typename I, typename F>
+ struct image_if_large
+ : public mln::internal::image_domain_morpher< I,
+ p_if<mln_domain(I), F>,
+ image_if_large<I, F> >
+ {
+ typedef image_if_large<I, F> self;
+ typedef mln_psite(self) psite;
+
+ /// Skeleton.
+ typedef image_if_large< tag::image_<I>, tag::function_<F> > skeleton;
+
+ /// Constructor without argument.
+ image_if_large();
+
+ /// Constructor from an image \p ima and a predicate \p f.
+ image_if_large(I& ima, const F& f);
+
+ void init_(I& ima, const F& f);
+
+ /// \brief Redefined psite membership method, returning true for
+ /// sites of the underlying (morphed) image even if they are not
+ /// validating the predicate.
+ ///
+ /// This is the only difference with mln::image_if.
+ bool has(const psite& p) const;
+
+ /// Give the definition domain.
+ const p_if<mln_domain(I), F>& domain() const;
+
+ /// Const promotion via conversion.
+ operator image_if_large<const I, F>() const;
+ };
+
+
+ // Image || Function_v2b.
+
+ /// ima || f creates an image_if_large with the image ima and the function
+ /// f.
+ //
+ template <typename I, typename F>
+ image_if_large<I,F>
+ operator || (Image<I>& ima, const Function_v2b<F>& f);
+
+ /// ima || f creates an image_if_large with the image ima and the function
+ /// f.
+ //
+ template <typename I, typename F>
+ image_if_large<const I,F>
+ operator || (const Image<I>& ima, const Function_v2b<F>& f);
+
+
+
+ template <typename I, typename A>
+ image_if_large< const I, fun::C<bool(*)(A)> >
+ operator || (const Image<I>& ima, bool (*f)(A) );
+
+ template <typename I, typename A>
+ image_if_large< I, fun::C<bool(*)(A)> >
+ operator || (Image<I>& ima, bool (*f)(A) );
+
+// // Construction helpers.
+
+// template <typename I, typename A>
+// image_if_large< const I, fun::C<bool(*)(A)> >
+// make_image_if_large(const Image<I>& ima, bool (*f)(A) );
+
+// template <typename I, typename A>
+// image_if_large< I, fun::C<bool(*)(A)> >
+// make_image_if_large(Image<I>& ima, bool (*f)(A) );
+
+
+
+# ifndef MLN_INCLUDE_ONLY
+
+ // init_.
+
+ template <typename I, typename F>
+ void init_(tag::function_t, F& f, const image_if_large<I,F>& model)
+ {
+ f = model.domain().predicate();
+ }
+
+ template <typename I, typename F, typename J>
+ void init_(tag::image_t, image_if_large<I,F>& target, const J& model)
+ {
+ I ima;
+ init_(tag::image, ima, exact(model));
+ F f;
+ init_(tag::function, f, exact(model));
+ target.init_(ima, f);
+ }
+
+ // internal::data< image_if_large<I,F> >
+
+ namespace internal
+ {
+
+ template <typename I, typename F>
+ inline
+ data< image_if_large<I,F> >::data(I& ima, const F& f)
+ : ima_(ima),
+ domain_(ima.domain() | f)
+ {
+ }
+
+ }
+
+
+ // image_if_large<I,F>
+
+ template <typename I, typename F>
+ inline
+ image_if_large<I,F>::image_if_large()
+ {
+ }
+
+ template <typename I, typename F>
+ inline
+ image_if_large<I,F>::image_if_large(I& ima, const F& f)
+ {
+ init_(ima, f);
+ }
+
+ template <typename I, typename F>
+ inline
+ void
+ image_if_large<I,F>::init_(I& ima, const F& f)
+ {
+ mln_precondition(! this->is_valid());
+ this->data_ = new internal::data< image_if_large<I,F> >(ima, f);
+ }
+
+ template <typename I, typename F>
+ inline
+ bool
+ image_if_large<I,F>::has(const typename image_if_large<I,F>::psite& p) const
+ {
+ mln_precondition(exact(this)->is_valid());
+ // This method is more tolerant than mln::image_if's one (which
+ // returns this->domain().has(p)).
+ return this->data_->ima_.has(p);
+ }
+
+
+ template <typename I, typename F>
+ inline
+ const p_if<mln_domain(I), F>&
+ image_if_large<I,F>::domain() const
+ {
+ mln_precondition(this->is_valid());
+ return this->data_->domain_;
+ }
+
+ template <typename I, typename F>
+ inline
+ image_if_large<I,F>::operator image_if_large<const I,F>() const
+ {
+ mln_precondition(this->is_valid());
+ image_if_large<const I,F> tmp(this->data_->ima_,
+ this->data_->domain_.predicate());
+ return tmp;
+ }
+
+
+ // Operators.
+
+ template <typename I, typename F>
+ inline
+ image_if_large<I,F>
+ operator || (Image<I>& ima, const Function_v2b<F>& f)
+ {
+ image_if_large<I,F> tmp(exact(ima), exact(f));
+ return tmp;
+ }
+
+ template <typename I, typename F>
+ inline
+ image_if_large<const I, F>
+ operator || (const Image<I>& ima, const Function_v2b<F>& f)
+ {
+ image_if_large<const I, F> tmp(exact(ima), exact(f));
+ return tmp;
+ }
+
+
+ template <typename I, typename A>
+ image_if_large< const I, fun::C<bool(*)(A)> >
+ operator || (const Image<I>& ima, bool (*f)(A) )
+ {
+ return exact(ima) || convert::to_fun(f);
+ }
+
+ template <typename I, typename A>
+ image_if_large< I, fun::C<bool(*)(A)> >
+ operator || (Image<I>& ima, bool (*f)(A) )
+ {
+ return exact(ima) || convert::to_fun(f);
+ }
+
+
+# endif // ! MLN_INCLUDE_ONLY
+
+} // end of namespace mln
+
+
+#endif // ! APPS_GRAPH_MORPHO_IMAGE_IF_LARGE_HH
--
1.6.4.2
* apps/graph-morpho/make_complex2d.hh (unmake_complex2d):
New function.
---
milena/ChangeLog | 7 ++++
milena/apps/graph-morpho/make_complex2d.hh | 42 +++++++++++++++++++++++++++-
2 files changed, 48 insertions(+), 1 deletions(-)
diff --git a/milena/ChangeLog b/milena/ChangeLog
index 23e901b..68b7d0c 100644
--- a/milena/ChangeLog
+++ b/milena/ChangeLog
@@ -1,5 +1,12 @@
2009-09-21 Roland Levillain <roland(a)lrde.epita.fr>
+ Deconstruction of image2d-based complex images.
+
+ * apps/graph-morpho/make_complex2d.hh (unmake_complex2d):
+ New function.
+
+2009-09-21 Roland Levillain <roland(a)lrde.epita.fr>
+
Reify the construction of image2d-based complex images.
* apps/graph-morpho/make_complex2d.hh: New file.
diff --git a/milena/apps/graph-morpho/make_complex2d.hh b/milena/apps/graph-morpho/make_complex2d.hh
index 1859ab0..a79c798 100644
--- a/milena/apps/graph-morpho/make_complex2d.hh
+++ b/milena/apps/graph-morpho/make_complex2d.hh
@@ -37,7 +37,9 @@
The values set on "edge" sites and "square" sites are a
conjunction of the values on the face of the adjacent faces of
- immediate lower dimension. */
+ immediate lower dimension.
+
+ The converse operation is unmake_complex2d. */
template <typename I>
inline
mln_concrete(I)
@@ -88,4 +90,42 @@ make_complex2d(const mln::Image<I>& input_)
return output;
}
+
+/** \brief Create an image of pixels from a binary 2D image
+ representing a cubical 2-complex by dividing the resolution of the
+ image \a input image by two.
+
+ Basically, this is the converse of make_complex2d. */
+template <typename I>
+inline
+mln_concrete(I)
+unmake_complex2d(const mln::Image<I>& input_)
+{
+ using namespace mln;
+
+ const I& input = exact(input_);
+ // The input image must have an odd number of rows and columns.
+ mln_precondition(input.nrows() % 2 == 1);
+ mln_precondition(input.ncols() % 2 == 1);
+
+ // Create a (morpher) image of the pixels of INPUT.
+ typedef image_if< const I, cplx2d::predicate_t > J;
+ J input_pixels = input | cplx2d::is_pixel;
+
+ /* FIXME: The construction of OUTPUT is obvioulsy not generic, since
+ it expects I's domain to provide the interface of an mln::box2d.
+ There should be a static precondition on I at the beginning of
+ this function. */
+ typedef mln_concrete(I) O;
+ // FIXME: This won't work if INPUT's domain does not start at (0,0).
+ O output(input.nrows() / 2 + 1, input.ncols() / 2 + 1);
+
+ mln_piter(J) p_in(input_pixels.domain());
+ mln_piter(O) p_out(output.domain());
+ for_all_2(p_in, p_out)
+ output(p_out) = input(p_in);
+ return output;
+}
+
+
#endif // ! APPS_GRAPH_MORPHO_MAKE_COMPLEX2D_HH
--
1.6.4.2