Milena (Olena)  User documentation 2.0a Id
 All Classes Namespaces Functions Variables Typedefs Enumerator Groups Pages
mesh-complex-max-curv-segm.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 
30 
31 #include <cstdlib>
32 #include <cmath>
33 
34 #include <utility>
35 #include <iostream>
36 
37 #include <mln/core/image/complex_image.hh>
38 #include <mln/core/image/complex_neighborhoods.hh>
39 
40 #include <mln/morpho/closing/area.hh>
41 #include <mln/morpho/meyer_wst.hh>
42 
43 #include <mln/math/max.hh>
44 #include <mln/math/sqr.hh>
45 
46 #include <mln/literal/white.hh>
47 
48 #include <mln/io/off/load.hh>
49 #include <mln/io/off/save.hh>
50 
51 #include "trimesh/misc.hh"
52 
53 
54 // Doesn't C++ have a better way to express Pi?
55 static const float pi = 4 * atanf(1);
56 
57 
58 int main(int argc, char* argv[])
59 {
60  if (argc != 4)
61  {
62  std::cerr << "usage: " << argv[0] << " input.off lambda output.off"
63  << std::endl;
64  std::exit(1);
65  }
66 
67  std::string input_filename = argv[1];
68  unsigned lambda = atoi(argv[2]);
69  std::string output_filename = argv[3];
70 
71  /*----------------.
72  | Complex image. |
73  `----------------*/
74 
75  // Image type.
76  typedef mln::float_2complex_image3df ima_t;
77  // Dimension of the image (and therefore of the complex).
78  static const unsigned D = ima_t::dim;
79  // Geometry of the image.
80  typedef mln_geom_(ima_t) G;
81 
82  mln::bin_2complex_image3df bin_input;
83  mln::io::off::load(bin_input, input_filename);
84  std::pair<ima_t, ima_t> curv = mln::geom::mesh_curvature(bin_input.domain());
85 
86  // Compute the pseudo_inverse curvature at each vertex.
87  ima_t input(bin_input.domain());
88  mln::p_n_faces_fwd_piter<D, G> v(input.domain(), 0);
89  for_all(v)
90  {
91  float h = (curv.first(v) + curv.second(v)) / 2;
92  // Pseudo-inverse curvature.
93  float h_inv = 1 / pi * (atan(-h) + pi / 2);
94  input(v) = h_inv;
95  // FIXME: The program should allow the user to choose the kind
96  // of measure.
97 // input(v) = mln::math::max(mln::math::sqr(curv.first(v)),
98 // mln::math::sqr(curv.second(v)));
99  }
100 
101  // Values on edges.
102  mln::p_n_faces_fwd_piter<D, G> e(input.domain(), 1);
103  typedef mln::complex_lower_neighborhood<D, G> adj_vertices_nbh_t;
104  adj_vertices_nbh_t adj_vertices_nbh;
105  mln_niter_(adj_vertices_nbh_t) adj_v(adj_vertices_nbh, e);
106  // Iterate on edges (1-faces).
107  for_all(e)
108  {
109  float s = 0.0f;
110  unsigned n = 0;
111  // Iterate on vertices (0-faces).
112  for_all(adj_v)
113  {
114  s += input(adj_v);
115  ++n;
116  }
117  input(e) = s / n;
118  // An edge should be adjacent to exactly two vertices.
119  mln_invariant(n <= 2);
120  }
121 
122  /*-----------------.
123  | Simplification. |
124  `-----------------*/
125 
127  typedef
128  mln::complex_higher_dim_connected_n_face_neighborhood<D, G>
129  adj_edges_nbh_t;
130  adj_edges_nbh_t adj_edges_nbh;
131 
132  ima_t closed_input = mln::morpho::closing::area(input, adj_edges_nbh, lambda);
133 
134  /*------.
135  | WST. |
136  `------*/
137 
138  /* FIXME: Note that the WST is doing too much work, since we have
139  not constrained the domain of the image to 1-faces only.
140  It would be great if we could use something like this:
141 
142  closed_input | mln::p_faces<1, D, G>(closed_input.domain())
143 
144  as input of the WST. */
145 
146  // Compute the WST on edges.
147  typedef unsigned wst_val_t;
148  wst_val_t nbasins;
149  typedef mln::unsigned_2complex_image3df wst_ima_t;
150  wst_ima_t wshed =
151  mln::morpho::meyer_wst(closed_input, adj_edges_nbh, nbasins);
152  std::cout << "nbasins = " << nbasins << std::endl;
153 
154  // Label polygons (i.e., propagate labels from edges to polygons).
155  typedef mln::complex_higher_neighborhood<D, G> adj_polygons_nbh_t;
156  adj_polygons_nbh_t adj_polygons_nbh;
157  mln_niter_(adj_polygons_nbh_t) adj_p(adj_polygons_nbh, e);
158  for_all(e)
159  if (wshed(e) != 0)
160  for_all(adj_p)
161  wshed(adj_p) = wshed(e);
162 
163  /*---------.
164  | Output. |
165  `---------*/
166 
167  mln::rgb8_2complex_image3df output(wshed.domain());
168  mln::data::fill(output, mln::literal::white);
169 
170  // FIXME: Use a colorize functor instead.
171  // Choose random colors for each basin number.
172  std::vector<mln::value::rgb8> basin_color (nbasins + 1);
173  for (unsigned i = 0; i <= nbasins; ++i)
174  basin_color[i] = mln::value::rgb8(random() % 256,
175  random() % 256,
176  random() % 256);
177  mln_piter_(ima_t) f(wshed.domain());
178  for_all(f)
179  output(f) = basin_color[wshed(f)];
180 
181  mln::io::off::save(output, output_filename);
182 }