$extrastylesheet
Olena  User documentation 2.1
An Image Processing Platform
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
complex_image_wst.cc
1 // Copyright (C) 2008, 2009, 2010 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 #include <iostream>
33 #include <fstream>
34 #include <sstream>
35 #include <iomanip>
36 
37 #include <mln/value/int_u8.hh>
38 #include <mln/value/rgb8.hh>
39 #include <mln/literal/black.hh>
40 #include <mln/literal/white.hh>
41 
42 #include <mln/core/concept/function.hh>
43 #include <mln/core/alias/point2d.hh>
44 #include <mln/core/site_set/p_faces.hh>
45 #include <mln/core/image/complex_image.hh>
46 // FIXME: Include these elsewhere? (In complex_image.hh?)
47 #include <mln/core/image/complex_neighborhoods.hh>
48 #include <mln/core/image/complex_neighborhood_piter.hh>
49 
50 #include <mln/data/fill.hh>
51 
52 #include <mln/norm/l2.hh>
53 
54 #include <mln/morpho/closing/area.hh>
55 #include <mln/morpho/watershed/flooding.hh>
56 
57 #include <mln/convert/to.hh>
58 
59 #include <mln/debug/iota.hh>
60 
61 // FIXME: To be put elsewhere (from milena/sandbox/geraud/wst_edge.cc).
62 struct colorize : mln::Function_v2v< colorize >
63 {
64  typedef mln::value::rgb8 result;
65  colorize(unsigned max)
66  : lut(max + 1)
67  {
68  lut[0] = mln::literal::black;
69  for (unsigned i = 1; i <= max; ++i)
70  lut[i] = result(100 + std::rand() % 150,
71  100 + std::rand() % 150,
72  100 + std::rand() % 150);
73  }
74  result operator()(unsigned i) const
75  {
76  return lut[i];
77  }
78  std::vector<result> lut;
79 };
80 
81 
82 
83 int main()
84 {
85  using namespace mln;
86  using mln::value::int_u8;
87 
88  /*----------------------------------------.
89  | Complex + complex geometry (location). |
90  `----------------------------------------*/
91 
92  /* A (simplicial) 1-complex and its adjacency graph.
93 
94  c 0 1 2 3
95  r .------------------------
96  | v0 e3 v3
97  0 | o-----------o v0----e3----v3
98  | / \ / / \ /
99  | / \ / / \ /
100  1 | e0 / e1 / e4 e0 e1 e4
101  | / \ / / \ /
102  | / \ / / \ /
103  2 | o-----------o v1----e2----v2
104  | v1 e2 v2
105 
106  v = vertex
107  e = edge
108  */
109 
110 
111  const unsigned D = 1;
112 
114 
115  typedef point2d P;
117  G geom;
118 
119  // Convenience typedefs.
120  typedef topo::n_face<0, D> vertex;
121  typedef topo::n_face<1, D> edge;
122 
123  // 0-faces (vertices).
124  vertex v0 = c.add_face(); geom.add_location(point2d(0,1));
125  vertex v1 = c.add_face(); geom.add_location(point2d(2,0));
126  vertex v2 = c.add_face(); geom.add_location(point2d(2,2));
127  vertex v3 = c.add_face(); geom.add_location(point2d(0,3));
128 
129  // 1-faces (edges).
130  edge e0 = c.add_face(-v1 + v0);
131  edge e1 = c.add_face(-v2 + v0);
132  edge e2 = c.add_face(-v2 + v1);
133  edge e3 = c.add_face(-v0 + v3);
134  edge e4 = c.add_face(-v3 + v2);
135 
136  /*---------------------.
137  | Complex-based pset. |
138  `---------------------*/
139 
140  p_complex<D, G> pc(c, geom);
141 
142  /*----------------------.
143  | Complex-based image. |
144  `----------------------*/
145 
146  // An image type built on a 1-complex with unsigned values on each
147  // face (both vertices and edges).
148  typedef complex_image<D, G, unsigned> dist_ima_t;
149 
150  // Create and initialize an image based on PC.
151  dist_ima_t dist_ima(pc);
152  data::fill(dist_ima, 0u);
153 
154  /*--------------------------------.
155  | Complex-based image iterators. |
156  `--------------------------------*/
157 
158  // For each edge (1-face), compute the distance between the two
159  // adjacent vertices (0-faces).
160  p_n_faces_fwd_piter<D, G> e(dist_ima.domain(), 1);
161  typedef complex_lower_neighborhood<D, G> v_nbh_t;
162  v_nbh_t v_nbh;
163  mln_niter_(v_nbh_t) v(v_nbh, e);
164  for_all(e)
165  {
166  v.start();
167  point2d p1 = v.to_site().front();
168  v.next();
169  point2d p2 = v.to_site().front();
170  v.next();
171  mln_invariant(!v.is_valid());
172 
173  dist_ima(e) = convert::to<unsigned>(10 * norm::l2_distance(p1.to_vec(), p2.to_vec()));
174  }
175  // Initialize 0-faces to a dummy value, to prevent the watershed from
176  // finding minima on 0-faces.
177  p_n_faces_fwd_piter<D, G> v_(dist_ima.domain(), 0);
178  for_all(v_)
179  dist_ima(v_) = mln_max(mln_value_(dist_ima_t));
180 
181  // For all edges, iterate on adjacent edges (i.e., on edges sharing
182  // an adjacent vertex).
184  nbh_t nbh;
185  // Neighbor edge.
186  mln_niter_(nbh_t) ne(nbh, e);
187  for_all(e)
188  {
189  std::cout << "dist_ima(" << e << ") = " << dist_ima(e)
190  << " -- adjacent edges :" << std::endl;
191  for_all(ne)
192  std::cout << " " << ne << std::endl;
193  }
194 
195  /*-----------------.
196  | Simplification. |
197  `-----------------*/
198 
199  // Currently, does nothing (lambda = 1).
200  dist_ima_t closed_dist_ima = morpho::closing::area(dist_ima, nbh, 1);
201 
202  /*------.
203  | WST. |
204  `------*/
205 
206  // Perform a Watershed Transform.
207  typedef unsigned wst_val_t;
208  wst_val_t nbasins;
209  typedef complex_image<D, G, wst_val_t> wst_ima_t;
210  wst_ima_t wshed = morpho::watershed::flooding(closed_dist_ima, nbh, nbasins);
211  /* Note that since the image is based not only on the 1-faces but
212  also on the 0-faces of the complex, and given the above
213  neighborhood, the domain seen by the WST is not connected! It is
214  actually composed of five components :
215 
216  - a component containing all the 1-faces (egdes) which are all
217  connected through
218  mln::complex_lower_dim_connected_n_face_neighborhood;
219 
220  - four (singleton) components corresponding to the 0-faces
221  (vertices), connected to no other part of the complex according to
222  mln::complex_lower_dim_connected_n_face_neighborhood.
223 
224  Since the component made of the edges contains two local minima,
225  the number of basins is equal to 6:
226 
227  2 minima for the edges' component
228  + 4 * 1 minima for the vertices's components
229  --------------------------------------------
230  6 basins.
231 
232  Hence the result.
233 
234 
235  We definitely need a complex_image that can accept a subset of a
236  complex as domain (or at least a p_face<N, D, P>. */
237  wst_val_t actual_nbasins = nbasins - c.nfaces_of_static_dim<0>();
238  std::cout << "nbasins = " << actual_nbasins << std::endl;
239 
240 
241  colorize color(nbasins);
242 
243  std::ofstream g("complex_image_wst-wst.neato");
244  g << "graph wst" << std::endl
245  << "{" << std::endl
246  << " graph [bgcolor = \"#000000\"]" << std::endl
247  << " edge [color = \"#FFFFFF\"]" << std::endl
248  << " node [color = \"#FFFFFF\", fontcolor = \"#FFFFFF\" ]" << std::endl;
249 
250  // Vertices.
251  typedef complex_higher_neighborhood<D, G> e_nbh_t;
252  e_nbh_t e_nbh;
253  mln_niter_(e_nbh_t) v_e(e_nbh, v_);
254  for_all(v_)
255  {
256  // Find the adjacent basin (color).
257  value::rgb8 basin_color = literal::white;
258  for_all(v_e)
259  if (wshed(v_e) != 0)
260  {
261  basin_color = color(wshed(v_e));
262  break;
263  }
264  std::ostringstream basin_color_str;
265  basin_color_str << '#'
266  << std::hex
267  << std::setfill('0')
268  << std::setw(2) << basin_color.red()
269  << std::setw(2) << basin_color.green()
270  << std::setw(2) << basin_color.blue()
271  << std::dec;
272 
273  g << " v" << v_.unproxy_().face_id()
274  << " [pos = \""
275  << std::fixed << std::setprecision(1)
276  << (float)v_.to_site().front()[1] << ", "
277  << -(float)v_.to_site().front()[0]
278  << "\", color = \"" << basin_color_str.str()
279  << "\", fillcolor = \"" << basin_color_str.str()
280  << "\", pin = \"true\", style=\"filled,setlinewidth(3)\"];"
281  << std::endl;
282  }
283 
284  for_all(e)
285  {
286  value::rgb8 basin_color = color(wshed(e));
287  std::ostringstream basin_color_str;
288  basin_color_str << '#'
289  << std::hex
290  << std::setfill('0')
291  << std::setw(2) << basin_color.red()
292  << std::setw(2) << basin_color.green()
293  << std::setw(2) << basin_color.blue()
294  << std::dec;
295 
296  // Adjacent vertices.
297  v.start();
298  topo::face<1> v1 = v.unproxy_().face();
299  point2d p1 = v.to_site().front();
300  (void) p1;
301  v.next();
302  topo::face<1> v2 = v.unproxy_().face();
303  point2d p2 = v.to_site().front();
304  (void) p2;
305  v.next();
306  mln_invariant(!v.is_valid());
307 
308  // Edges.
309  g << " v" << v1.face_id() << " -- v" << v2.face_id() << " ";
310  if (wshed(e) == 0)
311  g << "[color = \"#FFFFFF\"];" << std::endl;
312  else
313  g << "[color = \"" << basin_color_str.str()
314  << "\", style=\"setlinewidth(3)\"];" << std::endl;
315  }
316 
317  g << "}" << std::endl;
318  g.close();
319 }