$extrastylesheet
Olena  User documentation 2.1
An Image Processing Platform
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
classif-1complex.cc
1 // Copyright (C) 2008, 2009, 2011 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 
27 #include <iostream>
28 
29 #include <vector>
30 
31 #include <mln/core/image/image2d.hh>
32 #include <mln/core/alias/neighb2d.hh>
33 
34 #include <mln/labeling/blobs.hh>
35 #include <mln/io/pbm/load.hh>
36 #include <mln/io/pgm/save.hh>
37 #include <mln/io/ppm/save.hh>
38 #include <mln/debug/println.hh>
39 #include <mln/draw/line.hh>
40 
41 #include <mln/value/int_u8.hh>
42 #include <mln/core/alias/point2d.hh>
43 
44 #include <mln/core/site_set/p_faces.hh>
45 #include <mln/core/image/complex_image.hh>
46 #include <mln/core/alias/complex_image.hh>
47 
48 #include <mln/core/image/complex_neighborhoods.hh>
49 #include <mln/core/image/complex_neighborhood_piter.hh>
50 
51 #include <mln/data/fill.hh>
52 #include <mln/norm/l2.hh>
53 
54 #include <mln/labeling/colorize.hh>
55 
56 #include "influence_zones.hh"
57 #include "chain.hh"
58 
59 
65 make_complex_image(const mln::image2d<bool>& seeds)
66 {
67  using namespace mln;
68  using mln::value::int_u8;
69 
71 
72  /*-----------------------.
73  | Connected components. |
74  `-----------------------*/
75 
76  unsigned nlabels;
77  image2d<unsigned> label = labeling::blobs(seeds, c4(), nlabels);
78 
79  std::cout << "n seeds = " << nlabels << std::endl;
80  {
81  image2d<int_u8> lab(label.domain());
82  data::paste(label, lab);
83 #if 0
84  io::pgm::save(lab, "label.pgm");
85 #endif
86  }
87 
88  /*------------------.
89  | Influence zones. |
90  `------------------*/
91 
92  image2d<unsigned> iz = influence_zones(label, c4());
93  {
94  image2d<int_u8> IZ(iz.domain());
95  data::paste(iz, IZ);
96 #if 0
97  io::pgm::save(IZ, "iz.pgm");
98 #endif
99  }
100 
101  /*--------------------------------.
102  | Construction of the 1-complex. |
103  `--------------------------------*/
104 
105  // Adjacency matrix.
106  std::vector< std::vector<bool> > adj(nlabels + 1);
107  for (unsigned l = 1; l <= nlabels; ++l)
108  adj[l].resize(nlabels + 1, false);
109 
110  {
111  box2d::piter p(iz.domain());
112  for_all(p)
113  {
114  point2d r = p + right, b = p + down;
115  if (iz.has(r) && iz(p) != iz(r))
116  {
117  if (iz(p) != iz(r))
118  adj[iz(p)][iz(r)] = true;
119  else
120  adj[iz(r)][iz(p)] = true;
121  }
122  if (iz.has(b) && iz(p) != iz(b))
123  {
124  if (iz(p) != iz(b))
125  adj[iz(p)][iz(b)] = true;
126  else
127  adj[iz(b)][iz(p)] = true;
128  }
129  }
130  }
131 
132 
133  const unsigned D = 1;
134  // 1-complex data structure.
136 
137  typedef point2d P;
138  // Geometry (spatial locations) associated to the complex's faces.
140  G geom;
141 
142  // Convenience typedefs.
143  typedef topo::n_face<0, D> vertex;
144  typedef topo::n_face<1, D> edge;
145 
146  {
147  // 0-faces (vertices).
148  std::vector<vertex> v;
149  {
150  box2d::piter p(label.domain());
151  for_all(p)
152  if (label(p) != 0)
153  {
154  geom.add_location(p);
155  v.push_back(c.add_face());
156  }
157  }
158  std::cout << "v size = " << v.size() << std::endl;
159 
160  // 1-faces (edges).
161  std::vector<edge> e;
162  {
163  for (unsigned l = 1; l <= nlabels; ++l)
164  for (unsigned ll = l + 1; ll <= nlabels; ++ll)
165  if (adj[l][ll])
166  // Create an edge as an oriented (``algebraic'') face.
167  e.push_back(c.add_face(-v[l-1] + v[ll-1]));
168  }
169  std::cout << "e size = " << e.size() << std::endl;
170  }
171 
172  /*-------------------------.
173  | Complex-based site set. |
174  `-------------------------*/
175 
176  p_complex<D, G> pc(c, geom);
177 
178  /*----------------------.
179  | Complex-based image. |
180  `----------------------*/
181 
182  // An image type built on a 1-complex with int_u8 values on each
183  // face (both vertices and edges).
184  typedef complex_image<D, G, int_u8> dist_ima_t;
185 
186  // Create and initialize an image based on PC.
187  dist_ima_t dist_ima(pc);
188  data::fill(dist_ima, 0u);
189 
190  /*--------------------------------.
191  | Complex-based image iterators. |
192  `--------------------------------*/
193 
194  accu::stat::max<int_u8> dist_max;
195 
196  // Output image for visualization purpose only.
197  image2d<int_u8> canvas(seeds.domain());
198  data::fill(canvas, 0);
199 
200  // Iterator on the edges of DIST_IMA.
201  p_n_faces_fwd_piter<D, G> e(dist_ima.domain(), 1);
202  // n-face to (n-1)-faces neighborhood (here, the pair of vertices
203  // adjacent to an edge).
204  typedef complex_lower_neighborhood<D, G> v_nbh_t;
205  v_nbh_t v_nbh;
206  // For each edge (1-face), compute the distance between the two
207  // adjacent vertices (0-faces).
208  mln_niter_(v_nbh_t) v(v_nbh, e);
209  for_all(e)
210  {
211  v.start();
212  point2d p1 = v.to_site().front();
213  v.next();
214  point2d p2 = v.to_site().front();
215  v.next();
216  mln_invariant(!v.is_valid());
217 
218  dist_ima(e) = norm::l2_distance(p1.to_vec(), p2.to_vec());
219  dist_max.take(dist_ima(e));
220 
221  draw::line(canvas, p1, p2, dist_ima(e));
222  canvas(p1) = 255;
223  canvas(p2) = 255;
224  }
225 
226  std::cout << "distance max = " << dist_max << std::endl;
227 
228 #if 0
229  io::pgm::save(canvas, "canvas.pgm");
230 #endif
231 
232  return dist_ima;
233 }
234 
235 
236 int
237 main(int argc, char* argv[])
238 {
239  if (argc != 4)
240  {
241  std::cerr << "usage: " << argv[0] << " input.pbm lambda output.ppm"
242  << std::endl;
243  std::exit(1);
244  }
245  std::string input_filename = argv[1];
246  unsigned lambda = atoi(argv[2]);
247  std::string output_filename = argv[3];
248 
249  using namespace mln;
250  using mln::value::int_u8;
251 
252  // Seeds.
253  image2d<bool> seeds;
254  io::pbm::load(seeds, input_filename);
255 
256  // Shortcut: type of a 1-complex image located in a discrete 2D
257  // space with int_u8 values for each face.
258  typedef int_u8_1complex_image2d ima_t;
259  // Shortcuts: dimension and geometry (set of spatial locations)
260  // associated to this image type.
261  const unsigned D = 1;
262  typedef mln_geom_(ima_t) G;
263 
264  // Image computed from the graph of influence zones (IZ) of seeds.
265  ima_t ima = make_complex_image(seeds);
266 
267  // Adjacency relation between two n-faces through a shared adjacent
268  // (n-1)-face. (An edge is adjacent to its neighboring edges; a
269  // vertex has no neighbors.)
271  nbh_t nbh;
272 
273  typedef unsigned wst_val_t;
274  wst_val_t nbasins;
275  // Output image type.
276  typedef complex_image<D, G, wst_val_t> wst_ima_t;
277 
278  // Chain.
279  wst_ima_t wst_ima = chain(ima, nbh, lambda, nbasins);
280 
281  // Output image showing the results of the above chain on an image
282  // similar to the input.
283  image2d<int_u8> canvas_wst(seeds.domain());
284  data::fill(canvas_wst, 0);
285 
286  // Iterator on the edges (1-faces) of WST_IMA.
287  p_n_faces_fwd_piter<D, G> e(wst_ima.domain(), 1);
288  typedef complex_lower_neighborhood<D, G> v_nbh_t;
289  v_nbh_t v_nbh;
290  // Iterator on the vertices adjacent to E.
291  mln_niter_(v_nbh_t) v(v_nbh, e);
292 
293  for_all(e)
294  {
295  v.start();
296  point2d p1 = v.to_site().front();
297  v.next();
298  point2d p2 = v.to_site().front();
299  v.next();
300  mln_invariant(!v.is_valid());
301 
302  draw::line(canvas_wst, p1, p2, wst_ima(e));
303  }
304 
305  io::ppm::save(labeling::colorize(value::rgb8(), canvas_wst, nbasins),
306  output_filename);
307 }