$extrastylesheet
Olena  User documentation 2.1
An Image Processing Platform
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
mesh-complex-pinv-curv-segm.cc
1 // Copyright (C) 2008, 2009, 2010, 2013 EPITA Research and Development
2 // Laboratory (LRDE)
3 //
4 // This file is part of Olena.
5 //
6 // Olena is free software: you can redistribute it and/or modify it under
7 // the terms of the GNU General Public License as published by the Free
8 // Software Foundation, version 2 of the License.
9 //
10 // Olena is distributed in the hope that it will be useful,
11 // but WITHOUT ANY WARRANTY; without even the implied warranty of
12 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 // General Public License for more details.
14 //
15 // You should have received a copy of the GNU General Public License
16 // along with Olena. If not, see <http://www.gnu.org/licenses/>.
17 //
18 // As a special exception, you may use this file as part of a free
19 // software project without restriction. Specifically, if other files
20 // instantiate templates or use macros or inline functions from this
21 // file, or you compile this file and link it with other files to produce
22 // an executable, this file does not by itself cause the resulting
23 // executable to be covered by the GNU General Public License. This
24 // exception does not however invalidate any other reasons why the
25 // executable file might be covered by the GNU General Public License.
26 
31 
32 // Factor with mesh-complex-max-curv-segm.cc.
33 
34 #include <cstdlib>
35 #include <cmath>
36 
37 #include <utility>
38 #include <iostream>
39 
40 #include <mln/core/image/complex_image.hh>
41 #include <mln/core/image/complex_neighborhoods.hh>
42 
43 #include <mln/morpho/closing/area.hh>
44 #include <mln/morpho/watershed/flooding.hh>
45 
46 #include <mln/math/pi.hh>
47 #include <mln/math/max.hh>
48 #include <mln/math/sqr.hh>
49 
50 #include <mln/literal/white.hh>
51 
52 #include <mln/io/off/load.hh>
53 #include <mln/io/off/save.hh>
54 
55 #include "misc.hh"
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 float_ima_t;
77  // Dimension of the image (and therefore of the complex).
78  static const unsigned D = float_ima_t::dim;
79  // Geometry of the image.
80  typedef mln_geom_(float_ima_t) G;
81 
82  mln::bin_2complex_image3df bin_input;
83  mln::io::off::load(bin_input, input_filename);
84  std::pair<float_ima_t, float_ima_t> curv =
85  mln::geom::mesh_curvature(bin_input.domain());
86 
87  // Compute the pseudo_inverse curvature at each vertex.
88  float_ima_t float_ima(bin_input.domain());
89  mln::p_n_faces_fwd_piter<D, G> v(float_ima.domain(), 0);
90  for_all(v)
91  {
92  float h = (curv.first(v) + curv.second(v)) / 2;
93  // Pseudo-inverse curvature.
94  float h_inv =
95  1 / float(mln::math::pi) * (atanf(-h) + float(mln::math::pi) / 2);
96  float_ima(v) = h_inv;
97  }
98 
99  // Values on edges.
100  mln::p_n_faces_fwd_piter<D, G> e(float_ima.domain(), 1);
101  typedef mln::complex_lower_neighborhood<D, G> adj_vertices_nbh_t;
102  adj_vertices_nbh_t adj_vertices_nbh;
103  mln_niter_(adj_vertices_nbh_t) adj_v(adj_vertices_nbh, e);
104  // Iterate on edges (1-faces).
105  for_all(e)
106  {
107  float s = 0.0f;
108  unsigned n = 0;
109  // Iterate on vertices (0-faces).
110  for_all(adj_v)
111  {
112  s += float_ima(adj_v);
113  ++n;
114  }
115  float_ima(e) = s / n;
116  // An edge should be adjacent to exactly two vertices.
117  mln_invariant(n <= 2);
118  }
119 
120  // Convert the float image into an unsigned image because some
121  // algorithms do not handle float images well.
122  /* FIXME: This is bad: float images should be handled as-is. At
123  least, we should use a decent conversion, using an optimal affine
124  transformation (stretching/shrinking) or any other kind of
125  interpolation. */
126  typedef mln::unsigned_2complex_image3df ima_t;
127  ima_t ima(float_ima.domain());
128  mln_piter_(ima_t) p(float_ima.domain());
129  for_all(p)
130  ima(p) = 1000 * float_ima(p);
131 
132  /*-----------------.
133  | Simplification. |
134  `-----------------*/
135 
137  typedef
138  mln::complex_higher_dim_connected_n_face_neighborhood<D, G>
139  adj_edges_nbh_t;
140  adj_edges_nbh_t adj_edges_nbh;
141 
142  ima_t closed_ima = mln::morpho::closing::area(ima, adj_edges_nbh, lambda);
143 
144  /*------.
145  | WST. |
146  `------*/
147 
148  /* FIXME: Note that the WST is doing too much work, since we have
149  not constrained the domain of the image to 1-faces only.
150  It would be great if we could use something like this:
151 
152  closed_ima | mln::p_faces<1, D, G>(closed_ima.domain())
153 
154  as input of the WST. */
155 
156  // Compute the WST on edges.
157  typedef unsigned wst_val_t;
158  wst_val_t nbasins;
159  typedef mln::unsigned_2complex_image3df wst_ima_t;
160  wst_ima_t wshed =
161  mln::morpho::watershed::flooding(closed_ima, adj_edges_nbh, nbasins);
162  std::cout << "nbasins = " << nbasins << std::endl;
163 
164  // Label polygons (i.e., propagate labels from edges to polygons).
165  typedef mln::complex_higher_neighborhood<D, G> adj_polygons_nbh_t;
166  adj_polygons_nbh_t adj_polygons_nbh;
167  mln_niter_(adj_polygons_nbh_t) adj_p(adj_polygons_nbh, e);
168  for_all(e)
169  if (wshed(e) != 0)
170  for_all(adj_p)
171  wshed(adj_p) = wshed(e);
172 
173  /*---------.
174  | Output. |
175  `---------*/
176 
177  mln::rgb8_2complex_image3df output(wshed.domain());
178  mln::data::fill(output, mln::literal::white);
179 
180  // FIXME: Use a colorize functor instead.
181  // Choose random colors for each basin number.
182  std::vector<mln::value::rgb8> basin_color (nbasins + 1);
183  for (unsigned i = 0; i <= nbasins; ++i)
184  basin_color[i] = mln::value::rgb8(random() % 256,
185  random() % 256,
186  random() % 256);
187  mln_piter_(ima_t) f(wshed.domain());
188  for_all(f)
189  output(f) = basin_color[wshed(f)];
190 
191  mln::io::off::save(output, output_filename);
192 }