https://svn.lrde.epita.fr/svn/oln/trunk/milena
Index: ChangeLog
from Roland Levillain <roland(a)lrde.epita.fr>
Fix mln::mesh_image.
* mln/core/mesh_image.hh
(internal::data_< mesh_image<P, V> >::mesh_): Turn this attribute
into a reference to mesh_p<P>.
(init_(tag::image_t, mesh_image<P, V>&, const mesh_image<P, V>&)):
New specialization for mesh_image.
(mesh_image<P, V>::init_): New method.
Use it...
(mesh_image<P, V>::mesh_image): ...in this ctor.
* mln/core/mesh_p_piter.hh (mesh_p_piter_<P>::to_point)
(mesh_p_piter_<P>::to_psite): Don't check the validity of the
iterator, as it is incompatible with the current convention on the
use of window/neighborhood iterators.
* mln/core/mesh_p.hh: Add a FIXME.
* mln/draw/mesh.hh
(draw::mesh(Image<I>&, const mesh_image<P, V>&, mln_value(I))):
Add a third argument to choose the value used to print edges.
* tests/core/mesh_image.cc: Adjust.
Perform dilation and erosion on graph-based images (i.e.,
mesh_image objects).
mln/core/mesh_image.hh | 59 ++++++++++++++++++++++++++++++++++++++++++++---
mln/core/mesh_p.hh | 3 ++
mln/core/mesh_p_piter.hh | 20 +++++++++++++++
mln/draw/mesh.hh | 18 +++++++++++---
tests/core/mesh_image.cc | 52 +++++++++++++++++++++++++++++++++++------
5 files changed, 137 insertions(+), 15 deletions(-)
Index: mln/core/mesh_image.hh
--- mln/core/mesh_image.hh (revision 1624)
+++ mln/core/mesh_image.hh (working copy)
@@ -58,7 +58,7 @@
data_(mesh_p<P>& mesh, std::vector<V>& val);
std::vector<V> val_;
- mesh_p<P> mesh_;
+ mesh_p<P>& mesh_;
};
} // end of namespace mln::internal
@@ -117,6 +117,9 @@
mesh_image(mesh_p<P>& mesh, std::vector<V>& val);
mesh_image();
+ /// Initialize an empty image.
+ void init_(mesh_p<P>& mesh, std::vector<V>& val);
+
/// Read-only access of pixel value at point site \p p.
const V& operator()(const mesh_psite<P>& p) const;
@@ -126,6 +129,7 @@
/// Give the set of values of the image.
const vset& values() const;
+ // FIXME: Keep this name?
const std::vector<V>& data_values () const;
const mesh_p<P>& domain() const;
@@ -137,11 +141,39 @@
const P& access_location_link_node2 (const unsigned& i) const;
};
-
+ // Fwd decl.
+ template <typename P, typename V>
+ void init_(tag::image_t,
+ mesh_image<P, V>& target, const mesh_image<P, V>& model);
# ifndef MLN_INCLUDE_ONLY
+ /*-----------------.
+ | Initialization. |
+ `-----------------*/
+
+ template <typename P, typename V>
+ inline
+ void init_(tag::image_t,
+ mesh_image<P, V>& target, const mesh_image<P, V>& model)
+ {
+ /* FIXME: Unfortunately, we cannot simply use
+
+ target.init_(model.domain(), model.data_values ());
+
+ here, since domain() and data_values() return const data, and
+ init_ expects non mutable data. These constness problems exist
+ also in mesh_psite (see uses of const_cast<>). Hence the
+ inelegant use of const_cast<>'s. */
+ target.init_(const_cast<mesh_p<P>&> (model.domain()),
+ const_cast<std::vector<V>&> (model.data_values ()));
+ }
+
+ /*-------.
+ | Data. |
+ `-------*/
+
namespace internal
{
template <typename P, typename V>
@@ -154,11 +186,15 @@
} // end of namespace mln::internal
+ /*---------------.
+ | Construction. |
+ `---------------*/
+
template <typename P, typename V>
inline
mesh_image<P, V>::mesh_image(mesh_p<P>& mesh, std::vector<V>&
val)
{
- this->data_ = new internal::data_< mesh_image<P, V> > (mesh, val);
+ init_(mesh, val);
}
template <typename P, typename V>
@@ -169,6 +205,23 @@
template <typename P, typename V>
inline
+ void
+ mesh_image<P, V>::init_(mesh_p<P>& mesh, std::vector<V>&
val)
+ {
+ /* FIXME: We leak memory here: calling init_ twice loses the
+ previous content pointed by data_.
+
+ We should definitely write down formal guidelines on
+ initializaion and memory management in general! */
+ this->data_ = new internal::data_< mesh_image<P, V> > (mesh, val);
+ }
+
+ /*---------------.
+ | Manipulation. |
+ `---------------*/
+
+ template <typename P, typename V>
+ inline
const V&
mesh_image<P, V>::operator()(const mesh_psite<P>& p) const
{
Index: mln/core/mesh_p_piter.hh
--- mln/core/mesh_p_piter.hh (revision 1624)
+++ mln/core/mesh_p_piter.hh (working copy)
@@ -174,7 +174,17 @@
const P&
mesh_p_piter_<P>::to_point() const
{
+ /* We don't check whether the iterator is valid before returning
+ the value using
+
mln_precondition(is_valid());
+
+ since this method may be called *before* the iterator is
+ actually initialized. This is the case for instance when this
+ point iterator (say, P) is used to initialize another iterator
+ on window or neighborhood (say, Q); most of the time, for_all()
+ is responsible for the initialization of P, but it takes place
+ *after* the creation of Q. */
return p_;
}
@@ -183,7 +193,17 @@
const mesh_psite<P>&
mesh_p_piter_<P>::to_psite() const
{
+ /* We don't check whether the iterator is valid before returning
+ the value using
+
mln_precondition(is_valid());
+
+ since this method may be called *before* the iterator is
+ actually initialized. This is the case for instance when this
+ point iterator (say, P) is used to initialize another iterator
+ on window or neighborhood (say, Q); most of the time, for_all()
+ is responsible for the initialization of P, but it takes place
+ *after* the creation of Q. */
return psite_;
}
Index: mln/core/mesh_p.hh
--- mln/core/mesh_p.hh (revision 1624)
+++ mln/core/mesh_p.hh (working copy)
@@ -75,6 +75,9 @@
graph gr_;
std::vector<P> loc_;
// FIXME: (Roland) Is it really useful/needed?
+ /* 2007-12-19: It seems so, since mesh_image must implement a method
+ named bbox(). Now the question is: should each image type have a
+ bounding box? */
box_<P> bb_;
};
Index: mln/draw/mesh.hh
--- mln/draw/mesh.hh (revision 1624)
+++ mln/draw/mesh.hh (working copy)
@@ -45,6 +45,10 @@
namespace draw
{
+ /* FIXME: `draw::mesh' is not a good name. These functions do not
+ actually draw the mesh/mesh_image; it *converts* it to a
+ printable image. These functions should be put elsewhere
+ (e.g., in debug::). */
/*! Draw an image \p ima from a mesh_p \p m, with value \p node_v
* for nodes, value \p link_v for links and 0 for the background.
@@ -67,15 +71,20 @@
* \param[in,out] ima The image to be drawn.
* \param[in] mesh The mesh_image which contains nodes, links
* positions and the values of it.
+ * \param[in] link_v The value to assign to pixels which contains links,
+ * defaulting to 1.
*
*/
+ // FIXME: The type of the last argument cannot always been
+ // constructed from `int'! We should remove this last argument.
template <typename I, typename P, typename V>
void
- mesh(Image<I>& ima, const mesh_image<P, V>& mesh);
+ mesh(Image<I>& ima, const mesh_image<P, V>& mesh,
+ mln_value(I) link_v = 1);
# ifndef MLN_INCLUDE_ONLY
- // FIXME: Add assertions on the size of the image: it must be big
+ // FIXME: Add assertions on the size of the image: it must be large
// enough to hold the reprensentation of the graph.
template <typename I, typename P>
@@ -100,7 +109,8 @@
template <typename I, typename P, typename V>
inline
void
- mesh(Image<I>& ima, const mesh_image<P, V>& mesh)
+ mesh(Image<I>& ima, const mesh_image<P, V>& mesh,
+ mln_value(I) link_v)
{
level::fill(ima, 0);
@@ -108,7 +118,7 @@
line (exact(ima),
mesh.access_location_link_node1 (i),
mesh.access_location_link_node2 (i),
- 1);
+ link_v);
for (unsigned i = 0; i < mesh.domain().gr_.nb_node_; ++i)
exact(ima)(mesh.domain().loc_[i]) = mesh.data_values ()[i];
Index: tests/core/mesh_image.cc
--- tests/core/mesh_image.cc (revision 1624)
+++ tests/core/mesh_image.cc (working copy)
@@ -25,10 +25,8 @@
// reasons why the executable file might be covered by the GNU General
// Public License.
-/*! \file tests/core/mesh_image.cc
- *
- * \brief Tests on mln::mesh_image.
- */
+/// \file tests/core/mesh_image.cc
+/// \brief Tests on mln::mesh_image.
#include <vector>
@@ -37,6 +35,9 @@
#include <mln/core/mesh_elt_window.hh>
#include <mln/core/mesh_window_piter.hh>
+#include <mln/morpho/dilation.hh>
+
+#include <mln/draw/mesh.hh>
#include <mln/debug/iota.hh>
#include <mln/debug/println.hh>
@@ -86,9 +87,32 @@
ima_t ima(mesh, values);
// Initialize values.
debug::iota(ima);
- // The printed result does not show the graph, only the values.
+ // Print the image.
+ /* FIXME: Unfortunately, displaying mesh images is not easy right
+ now (2007-12-19). We could use
+
debug::println(ima);
+ but there's not specialization working for mesh_image; the one
+ selected by the compiler is based on a 2-D bbox, and expects the
+ interface of mesh_image to work with points (not psites).
+ Moreover, this iplementation only shows *values*, not the graph
+ itslef.
+
+ An alternative is to use draw::mesh (which, again, is misnamed),
+ but it doesn't show the values, only the nodes and edges of the
+ graph.
+
+ The current solution is a mix between draw::mesh and hand-made
+ iterations. */
+ image2d<int> ima_rep(ima.bbox());
+ // We use the value 9 in draw::mesh instead of the default (which is
+ // 1) to represent edges to distinguish it from nodes holding a
+ // value of 1.
+ draw::mesh (ima_rep, ima, 9);
+ debug::println (ima_rep);
+
+
/*------------.
| Iterators. |
`------------*/
@@ -99,11 +123,11 @@
std::cout << "ima (" << p << ") = " <<
ima(p) << std::endl;
// Manual iterations over the neighborhoods of each point site of IMA.
+ /* FIXME: In fact, this class should be named
+ `mesh_elt_neighborhood' (there's no such thing as an elementary
+ window on a mesh/graph!). */
typedef mesh_elt_window<point2d> win_t;
win_t win;
- // Reinitialize P, otherwise Q will trigger an assertion about P
- // being unable to convert to a valid mesh_piter object.
- p.start();
mln_qiter_(win_t) q(win, p);
for_all (p)
{
@@ -112,4 +136,16 @@
for_all (q)
std::cout << " " << q << " (level = "
<< ima(q) << ")" << std::endl;
}
+
+ /*-------------------------.
+ | Processing mesh images. |
+ `-------------------------*/
+
+ mesh_image<point2d, int> ima_dil = morpho::dilation(ima, win);
+ draw::mesh(ima_rep, ima_dil, 9);
+ debug::println(ima_rep);
+
+ mesh_image<point2d, int> ima_ero = morpho::erosion(ima, win);
+ draw::mesh(ima_rep, ima_ero, 9);
+ debug::println(ima_rep);
}