
https://svn.lrde.epita.fr/svn/oln/trunk/milena Index: ChangeLog from Roland Levillain <roland@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); }