Milena (Olena)  User documentation 2.0a Id
 All Classes Namespaces Functions Variables Typedefs Enumerator Groups Pages
mesh-skel.cc
1 // Copyright (C) 2008, 2009 EPITA Research and Development Laboratory (LRDE)
2 //
3 // This file is part of Olena.
4 //
5 // Olena is free software: you can redistribute it and/or modify it under
6 // the terms of the GNU General Public License as published by the Free
7 // Software Foundation, version 2 of the License.
8 //
9 // Olena is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // General Public License for more details.
13 //
14 // You should have received a copy of the GNU General Public License
15 // along with Olena. If not, see <http://www.gnu.org/licenses/>.
16 //
17 // As a special exception, you may use this file as part of a free
18 // software project without restriction. Specifically, if other files
19 // instantiate templates or use macros or inline functions from this
20 // file, or you compile this file and link it with other files to produce
21 // an executable, this file does not by itself cause the resulting
22 // executable to be covered by the GNU General Public License. This
23 // exception does not however invalidate any other reasons why the
24 // executable file might be covered by the GNU General Public License.
25 
29 
30 // FIXME: Factor commons parts between mesh-segm and mesh-skel.
31 
32 #include <cstdlib>
33 #include <cmath>
34 
35 #include <utility>
36 #include <iostream>
37 
38 #include <TriMesh.h>
39 
40 #include <mln/core/alias/point3d.hh>
41 #include <mln/core/alias/point3d.hh>
42 
43 #include <mln/util/graph.hh>
44 #include <mln/core/image/graph_image.hh>
45 #include <mln/core/image/graph_elt_neighborhood.hh>
46 
47 #include <mln/morpho/closing/area.hh>
48 #include <mln/labeling/regional_minima.hh>
49 
50 #include "io.hh"
51 
52 
53 // Doesn't C++ have a better way to express Pi ?
54 const float pi = 4 * atanf(1);
55 
56 
57 int main(int argc, char* argv[])
58 {
59  if (argc != 4)
60  {
61  std::cerr << "usage: " << argv[0] << " input.off lambda output.off"
62  << std::endl;
63  std::exit(1);
64  }
65 
66  std::string input_filename = argv[1];
67  unsigned lambda = atoi(argv[2]);
68  std::string output_filename = argv[3];
69 
70 
71  /*-------.
72  | Mesh. |
73  `-------*/
74 
75  // TriMesh is a pain: it systematically allocates on the heap.
76  // Introduce another name to manipulate the mesh as a (non-pointer)
77  // object.
78  TriMesh* mesh_ptr = TriMesh::read(input_filename.c_str());
79  if (!mesh_ptr)
80  std::exit(2);
81  TriMesh& mesh = *mesh_ptr;
82 
83  // Computes faces (triangles).
84  mesh.need_faces();
85  // Computation of the mean curvature on each vertex of the mesh.
86  mesh.need_curvatures();
87  std::vector<float> vertex_h_inv(mesh.faces.size(), 0.f);
88  for (unsigned v = 0; v < mesh.vertices.size(); ++v)
89  {
90  float h = (mesh.curv1[v] + mesh.curv2[v]) / 2;
91  float h_inv = 1 / pi * atan(-h) + pi / 2;
92  vertex_h_inv[v] = h_inv;
93  }
94  // Computation of the mean curvature on each face of the mesh.
95  /* FIXME: Our implementation of the computation of the regional
96  minima doesn't work well with floats (yet). Convert floating
97  point values to a proportional integer value for the moment. */
98  typedef int curv_t;
99  std::vector<curv_t> face_h_inv(mesh.faces.size(), 0.f);
100  for (unsigned f = 0; f < mesh.faces.size(); ++f)
101  {
102  float h_inv =
103  (vertex_h_inv[mesh.faces[f][0]] +
104  vertex_h_inv[mesh.faces[f][1]] +
105  vertex_h_inv[mesh.faces[f][2]])
106  / 3;
107  /* FIXME: This coefficient is used to distinguish small
108  curvature values. We should get rid of it as soon as
109  labeling::regional_minima works correctly on images of float
110  values. */
111  face_h_inv[f] = 1000 * h_inv;
112  }
113 
114  /*--------.
115  | Graph. |
116  `--------*/
117 
118  /* Build a graph whose vertices correspond to the faces of the mesh,
119  whose edges (between two vertices) correspond to edges (between
120  two faces) of the mesh. */
121 
122  /* FIXME: We don't have the required site type yet. Simulate with a
123  dummy type (point3d). */
125  // Populate the graph with vertices.
126  for (unsigned i = 0; i < mesh.faces.size(); ++i)
127  g.add_vertex (mln::point3d(i, i, i));
128 
129  // Populate the graph with edges.
130  mesh.need_across_edge();
131  for (unsigned f = 0; f < mesh.faces.size(); ++f)
132  for (unsigned e = 0; e < 3; ++e)
133  {
134  int f_adj = mesh.across_edge[f][e];
135  if (f_adj != -1)
136  // Add an edge into the graph.
137  g.add_edge(f, f_adj);
138  }
139 
140  /*--------------.
141  | Graph image. |
142  `--------------*/
143 
144  mln::p_graph<mln::point3d> pg(g);
145 
146  typedef mln::graph_image<mln::point3d, curv_t> ima_t;
147  ima_t g_ima(pg, face_h_inv);
148 
149  /*-----------------.
150  | Simplification. |
151  `-----------------*/
152 
154  nbh_t nbh;
155 
156  ima_t closed_g_ima = mln::morpho::closing::area(g_ima, nbh, lambda);
157 
158  /*------------------.
159  | Regional minima. |
160  `------------------*/
161 
162  typedef unsigned label_t;
163  label_t nlabels;
164  typedef mln::graph_image<mln::point3d, label_t> label_ima_t;
165  label_ima_t minima =
166  mln::labeling::regional_minima(closed_g_ima, nbh, nlabels);
167  std::cout << "nlabels = " << nlabels << std::endl;
168 
169  /*-----------.
170  | Skeleton. |
171  `-----------*/
172 
173  // FIXME: To do.
174 
175  /*---------.
176  | Output. |
177  `---------*/
178 
179  /* FIXME We should created a boolean graph_image instead. But as
180  we cannot directly save a graph_image as an OFF file now, just
181  store the values of this would-be image into an array. */
182  // Assign a boolean value to graph vertices (mesh faces).
183  std::vector<bool> face_value (minima.domain().nvertices(), true);
184  mln_piter_(label_ima_t) pm(minima.domain());
185  for_all(pm)
186  // FIXME: Use literal::zero.
187  if (minima(pm) != 0)
188  {
189  // The face belongs to a regional minima: ``remove'' it from
190  // the mesh by tagging it as false.
191  mln_psite_(label_ima_t) pp(pm);
192  face_value[pp.id().to_equiv()] = false;
193  }
194 
195  // Taken and adapted from TriMesh_io.cc
196  FILE* f_out = fopen(output_filename.c_str(), "wb");
197  if (!f_out)
198  {
199  std::cerr << "Error opening " << output_filename.c_str()
200  << " for writing." << std::endl;
201  std::exit(2);
202  }
203  write_off_binary(mesh_ptr, face_value, f_out);
204  fclose(f_out);
205 
206  delete mesh_ptr;
207 }