https://svn.lrde.epita.fr/svn/oln/trunk/milena
The only tests that do not work on my laptop now are:
- milena/tests/value/graylevel.cc
- milena/tests/value/graylevel_f.cc
because of an ambiguous conversion.
I have no time to try and fix it today, but any help is welcome! :)
Index: ChangeLog
from Roland Levillain <roland(a)lrde.epita.fr>
Have most of the test suite compile again.
* mln/algebra/quat.hh: Include missing header for mln/math/abs.hh.
* mln/draw/graph.hh
(graph(Image<I>&, const p_graph<P>&, mln_value(I), mln_value(I))):
s/n1/v1/.
s/n2/v2/.
* tests/draw/graph.cc (test): s/add_node/add_vertex/.
mln/algebra/quat.hh | 1 +
mln/draw/graph.hh | 4 ++--
tests/draw/graph.cc | 2 +-
3 files changed, 4 insertions(+), 3 deletions(-)
Index: mln/algebra/quat.hh
--- mln/algebra/quat.hh (revision 2060)
+++ mln/algebra/quat.hh (working copy)
@@ -42,6 +42,7 @@
# include <mln/trait/value_.hh>
# include <mln/algebra/vec.hh>
+# include <mln/math/abs.hh>
# include <mln/norm/l2.hh>
//FIXME: pow, exp etc... are def here and in value::...
Index: mln/draw/graph.hh
--- mln/draw/graph.hh (revision 2060)
+++ mln/draw/graph.hh (working copy)
@@ -99,8 +99,8 @@
line (exact(ima),
// FIXME: Too low-level. See similar remarks
// in mln/core/graph_image.hh
- pg.gr_->vertex_data(pg.gr_->edge(l).n1()),
- pg.gr_->vertex_data(pg.gr_->edge(l).n2()),
+ pg.gr_->vertex_data(pg.gr_->edge(l).v1()),
+ pg.gr_->vertex_data(pg.gr_->edge(l).v2()),
edge_v);
// Draw the points (vertices).
for (size_t p = 0; p < pg.npoints(); ++p)
Index: tests/draw/graph.cc
--- tests/draw/graph.cc (revision 2060)
+++ tests/draw/graph.cc (working copy)
@@ -64,7 +64,7 @@
util::graph<mln::point2d> g;
// Populate the graph with nodes.
for (unsigned i = 0; i < points.size(); ++i)
- g.add_node (points[i]);
+ g.add_vertex(points[i]);
// Populate the graph with edges.
for (edges_type::const_iterator i = edges.begin(); i != edges.end(); ++i)
g.add_edge (i->first, i->second);
https://svn.lrde.epita.fr/svn/oln/trunk/milena
Now you can compile tests (without running them) by using `make tests' in
any subdirectory of milena/tests/:
make -C _build/milena/tests tests
It can be convenient for tests that take a long time to execute (for
instance, the ones from milena/tests/core/ and milena/tests/morpho/).
However, you are still encouraged to often run the test suite before
sending your patches! :)
Index: ChangeLog
from Roland Levillain <roland(a)lrde.epita.fr>
Add a tests target to Makefiles of tests/.
* tests/tests-recursive.mk: New file.
Include it...
* tests/tests.mk: ...here.
tests-recursive.mk | 52 ++++++++++++++++++++++++++++++++++++++++++++++++++++
tests.mk | 5 ++++-
2 files changed, 56 insertions(+), 1 deletion(-)
Index: tests/tests.mk
--- tests/tests.mk (revision 2059)
+++ tests/tests.mk (working copy)
@@ -1,4 +1,4 @@
-## FIXME: Revamp (see Olena 0.11's test suite).
+## FIXME: Revamp (see Olena 0.11's test suite). -*- Automake -*-
# Look for Milena header in srcdir and for (generated) test headers
# (like data.hh) in builddir.
@@ -15,3 +15,6 @@
TESTS_CXXFLAGS_SPEED = @TESTS_CXXFLAGS_SPEED@
TESTS_CXXFLAGS_DEBUG = @TESTS_CXXFLAGS_DEBUG@
+
+# Inject rules to compile tests (recursively), without running them.
+include $(top_srcdir)/milena/tests/tests-recursive.mk
Index: tests/tests-recursive.mk
--- tests/tests-recursive.mk (revision 0)
+++ tests/tests-recursive.mk (revision 0)
@@ -0,0 +1,52 @@
+# tests-recursive.mk -*- Automake -*-
+# Compile tests recursively, but don't them.
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2008 Free Software Foundation, Inc.
+# This Makefile.in is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY, to the extent permitted by law; without
+# even the implied warranty of MERCHANTABILITY or FITNESS FOR A
+# PARTICULAR PURPOSE.
+
+
+# Sometimes, we just want to check whether tests compile, without
+# actually running them. Hence this `tests' target, which does half
+# the job of the `check' target.
+
+.PHONY: tests-am tests-recursive tests
+# ``Halved'' version of check-am.
+tests-am: $(check_PROGRAMS)
+ $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS)
+# FIXME: Copied from a generated Makefile.in (rule `$(RECURSIVE_TARGETS)').
+# (Automake does not allow us to interact with the code it generates in
+# Makefile.in.) We might want to propose this as a patch to the Automake
+# project.
+tests-recursive:
+ @failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+tests: tests-recursive
https://svn.lrde.epita.fr/svn/oln/trunk/milena
Index: ChangeLog
from Roland Levillain <roland(a)lrde.epita.fr>
Fix the labeling in Meyer's WST algorithm.
* mln/morpho/meyer_wst.hh: Use 0 for the label of the watershed,
to be consistent with other labeling algorithms (computation of
regional minima, for instance).
meyer_wst.hh | 3 ++-
1 file changed, 2 insertions(+), 1 deletion(-)
Index: mln/morpho/meyer_wst.hh
--- mln/morpho/meyer_wst.hh (revision 2056)
+++ mln/morpho/meyer_wst.hh (working copy)
@@ -110,7 +110,8 @@
/* FIXME: Ensure the input image has scalar values. */
typedef L marker;
- const marker unmarked = mln_min(marker);
+ // FIXME: Use literal::zero.
+ const marker unmarked = 0;
// Initialize the output with the markers (minima components).
mln_ch_value(I, marker) output =
https://svn.lrde.epita.fr/svn/oln/trunk/milena
Index: ChangeLog
from Roland Levillain <roland(a)lrde.epita.fr>
Start a 3-D mesh surface skeletonization tool.
* apps/statues/mesh-skel.cc: New.
* apps/statues/io.hh: Update header guards.
(write_faces_asc_binary, write_off_binary): New functions.
* apps/statues/Makefile.am (bin_PROGRAMS): Add mesh-skel.
(mesh_skel_SOURCES): New.
Add mesh-skel.cc and io.hh.
Makefile.am | 3
io.hh | 48 ++++++++++++-
mesh-skel.cc | 211 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 258 insertions(+), 4 deletions(-)
Index: apps/statues/mesh-skel.cc
--- apps/statues/mesh-skel.cc (revision 0)
+++ apps/statues/mesh-skel.cc (revision 0)
@@ -0,0 +1,211 @@
+// Copyright (C) 2008 EPITA Research and Development Laboratory (LRDE)
+//
+// This file is part of the Olena Library. This library is free
+// software; you can redistribute it and/or modify it under the terms
+// of the GNU General Public License version 2 as published by the
+// Free Software Foundation.
+//
+// This library 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 this library; see the file COPYING. If not, write to
+// the Free Software Foundation, 51 Franklin Street, Fifth Floor,
+// Boston, MA 02111-1307, USA.
+//
+// As a special exception, you may use this file as part of a free
+// software library 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 apps/statues/mesh-segm.cc
+/// \brief A program computing a skeleton of the surface of the
+/// (triangle) mesh of a statue.
+
+// FIXME: Factor commons parts between mesh-segm and mesh-skel.
+
+#include <cstdlib>
+#include <cmath>
+
+#include <utility>
+#include <iostream>
+
+#include <TriMesh.h>
+
+#include <mln/value/rgb8.hh>
+
+#include <mln/core/point3d.hh>
+#include <mln/make/point3d.hh>
+
+#include <mln/util/graph.hh>
+#include <mln/core/graph_image.hh>
+#include <mln/core/graph_elt_neighborhood.hh>
+
+#include <mln/morpho/closing_area.hh>
+#include <mln/labeling/regional_minima.hh>
+
+#include "io.hh"
+
+
+// Doesn't C++ have a better way to express Pi ?
+const float pi = 4 * atanf(1);
+
+
+int main(int argc, char* argv[])
+{
+ if (argc != 4)
+ {
+ std::cerr << "usage: " << argv[1] << " input.off lambda output.off";
+ exit(1);
+ }
+
+ std::string input_filename = argv[1];
+ unsigned lambda = atoi(argv[2]);
+ std::string output_filename = argv[3];
+
+
+ /*-------.
+ | Mesh. |
+ `-------*/
+
+ // TriMesh is a pain: it systematically allocates on the heap.
+ // Introduce another name to manipulate the mesh as a (non-pointer)
+ // object.
+ TriMesh* mesh_ptr = TriMesh::read(input_filename.c_str());
+ if (!mesh_ptr)
+ exit(2);
+ TriMesh& mesh = *mesh_ptr;
+
+ // Computes faces (triangles).
+ mesh.need_faces();
+ // Computation of the mean curvature on each vertex of the mesh.
+ mesh.need_curvatures();
+ std::vector<float> vertex_h_inv(mesh.faces.size(), 0.f);
+ for (unsigned v = 0; v < mesh.vertices.size(); ++v)
+ {
+ float h = (mesh.curv1[v] + mesh.curv2[v]) / 2;
+ float h_inv = 1 / pi * atan(-h) + pi / 2;
+ vertex_h_inv[v] = h_inv;
+ }
+ // Computation of the mean curvature on each face of the mesh.
+ /* FIXME: Our implementation of the computation of the regional
+ minima doesn't work well with floats (yet). Convert floating
+ point values to a proportional integer value for the moment. */
+ typedef int curv_t;
+ std::vector<curv_t> face_h_inv(mesh.faces.size(), 0.f);
+ for (unsigned f = 0; f < mesh.faces.size(); ++f)
+ {
+ float h_inv =
+ (vertex_h_inv[mesh.faces[f][0]] +
+ vertex_h_inv[mesh.faces[f][1]] +
+ vertex_h_inv[mesh.faces[f][2]])
+ / 3;
+ /* FIXME: This coefficient is used to distinguish small
+ curvature values. We should get rid of it as soon as
+ labeling::regional_minima works correctly on images of float
+ values. */
+ face_h_inv[f] = 1000 * h_inv;
+ }
+
+ /*--------.
+ | Graph. |
+ `--------*/
+
+ /* Build a graph whose vertices correspond to the faces of the mesh,
+ whose edges (between two vertices) correspond to edges (between
+ two faces) of the mesh. */
+
+ /* FIXME: We don't have the required site type yet. Simulate with a
+ dummy type (point3d). */
+ mln::util::graph<mln::point3d> g;
+ // Populate the graph with vertices.
+ for (unsigned i = 0; i < mesh.faces.size(); ++i)
+ g.add_vertex (mln::make::point3d(i, i, i));
+
+ // Populate the graph with edges.
+ mesh.need_across_edge();
+ for (unsigned f = 0; f < mesh.faces.size(); ++f)
+ for (unsigned e = 0; e < 3; ++e)
+ {
+ int f_adj = mesh.across_edge[f][e];
+ if (f_adj != -1)
+ // Add an edge into the graph.
+ g.add_edge(f, f_adj);
+ }
+
+ /*--------------.
+ | Graph image. |
+ `--------------*/
+
+ mln::p_graph<mln::point3d> pg(g);
+
+ typedef mln::graph_image<mln::point3d, curv_t> ima_t;
+ ima_t g_ima(pg, face_h_inv);
+
+ /*-----------------.
+ | Simplification. |
+ `-----------------*/
+
+ typedef mln::graph_elt_neighborhood<mln::point3d> nbh_t;
+ nbh_t nbh;
+
+ ima_t closed_g_ima (g_ima.domain());
+ mln::morpho::closing_area(g_ima, nbh, lambda, closed_g_ima);
+
+ /*------------------.
+ | Regional minima. |
+ `------------------*/
+
+ typedef unsigned label_t;
+ label_t nlabels;
+ typedef mln::graph_image<mln::point3d, label_t> label_ima_t;
+ label_ima_t minima =
+ mln::labeling::regional_minima(closed_g_ima, nbh, nlabels);
+ std::cout << "nlabels = " << nlabels << std::endl;
+
+ /*-----------.
+ | Skeleton. |
+ `-----------*/
+
+ // FIXME: To do.
+
+ /*---------.
+ | Output. |
+ `---------*/
+
+ /* FIXME We should created a boolean graph_image instead. But as
+ we cannot directly save a graph_image as an OFF file now, just
+ store the values of this would-be image into an array. */
+ // Assign a boolean value to graph vertices (mesh faces).
+ std::vector<bool> face_value (minima.domain().nvertices(), true);
+ mln_piter_(label_ima_t) pm(minima.domain());
+ for_all(pm)
+ // FIXME: Use literal::zero.
+ if (minima(pm) != 0)
+ {
+ // The face belongs to a regional minima: ``remove'' it from
+ // the mesh by tagging it as false.
+ mln_psite_(label_ima_t) pp(pm);
+ face_value[pp.id().to_equiv()] = false;
+ }
+
+ // Taken and adapted from TriMesh_io.cc
+ FILE* f_out = fopen(output_filename.c_str(), "wb");
+ if (!f_out)
+ {
+ std::cerr << "Error opening " << output_filename.c_str()
+ << " for writing." << std::endl;
+ exit(2);
+ }
+ write_off_binary(mesh_ptr, face_value, f_out);
+ fclose(f_out);
+
+ delete mesh_ptr;
+}
Index: apps/statues/io.hh
--- apps/statues/io.hh (revision 2054)
+++ apps/statues/io.hh (working copy)
@@ -25,11 +25,17 @@
// reasons why the executable file might be covered by the GNU General
// Public License.
-#ifndef SANDBOX_LEVILLAIN_IO_HH
-# define SANDBOX_LEVILLAIN_IO_HH
+#ifndef APPS_STATUES_IO_HH
+# define APPS_STATUES_IO_HH
+/// \file apps/statues/io.hh
/// \brief I/O routines adapted from TriMesh's ones.
+#include <algorithm>
+
+#include <TriMesh.h>
+
+
/// Taken from TriMesh_io.cc
/// \{
// Convert colors float -> uchar
@@ -112,4 +118,40 @@
/// \}
-#endif // ! SANDBOX_LEVILLAIN_IO_HH
+/// Taken and adapted from TriMesh_io.cc
+/// \{
+/// Write a bunch of faces to an ASCII file, removing the ones tagged
+/// as ``false'' in \a face_value.
+inline void write_faces_asc_binary(TriMesh *mesh,
+ const std::vector<bool>& face_value,
+ FILE *f,
+ const char *before_face,
+ const char *after_line)
+{
+ mesh->need_faces();
+ for (int i = 0; i < mesh->faces.size(); i++)
+ if (face_value[i])
+ {
+ fprintf(f, "%s%d %d %d%s\n",
+ before_face,
+ mesh->faces[i][0], mesh->faces[i][1], mesh->faces[i][2],
+ after_line);
+ }
+}
+
+/// Write an off file, removing faces tagged as ``false'' in \a face_value.
+inline void write_off_binary(TriMesh *mesh,
+ const std::vector<bool>& face_value,
+ FILE *f)
+{
+ fprintf(f, "OFF\n");
+ mesh->need_faces();
+ unsigned long nfaces =
+ std::count(face_value.begin(), face_value.end(), true);
+ fprintf(f, "%lu %lu 0\n", (unsigned long) mesh->vertices.size(), nfaces);
+ write_verts_asc(mesh, f, "", 0, 0, false, 0, "");
+ write_faces_asc_binary(mesh, face_value, f, "3 ", "");
+}
+/// \}
+
+#endif // ! APPS_STATUES_IO_HH
Index: apps/statues/Makefile.am
--- apps/statues/Makefile.am (revision 2054)
+++ apps/statues/Makefile.am (working copy)
@@ -7,7 +7,8 @@
# Find trimesh archive.
AM_LDFLAGS = -L$(top_builddir)/external/trimesh/libsrc -ltrimesh
-bin_PROGRAMS = mesh-segm
+bin_PROGRAMS = mesh-segm mesh-skel
mesh_segm_SOURCES = mesh-segm.cc io.hh
+mesh_skel_SOURCES = mesh-skel.cc io.hh
TESTS = test