$extrastylesheet
Olena  User documentation 2.1
An Image Processing Platform
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
classif-graph.cc
1 // Copyright (C) 2008, 2009, 2011, 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 
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/util/site_pair.hh>
45 
46 #include <mln/core/image/edge_image.hh>
47 
48 #include <mln/data/fill.hh>
49 #include <mln/norm/l2.hh>
50 
51 #include <mln/labeling/colorize.hh>
52 
53 #include "influence_zones.hh"
54 #include "chain.hh"
55 
56 /* FIXME: Introduce aliases for common specializations of graph images
57  such as the return type of make_graph_image. */
58 
64 make_graph_image(const mln::image2d<bool>& seeds)
65 {
66  using namespace mln;
67  using mln::value::int_u8;
68 
70 
71  /*-----------------------.
72  | Connected components. |
73  `-----------------------*/
74 
75  unsigned nlabels;
76  image2d<unsigned> label = labeling::blobs(seeds, c4(), nlabels);
77 
78  std::cout << "n seeds = " << nlabels << std::endl;
79  {
80  image2d<int_u8> lab(label.domain());
81  data::paste(label, lab);
82 #if 0
83  io::pgm::save(lab, "label.pgm");
84 #endif
85  }
86 
87  /*------------------.
88  | Influence zones. |
89  `------------------*/
90 
91  image2d<unsigned> iz = influence_zones(label, c4());
92  {
93  image2d<int_u8> IZ(iz.domain());
94  data::paste(iz, IZ);
95 #if 0
96  io::pgm::save(IZ, "iz.pgm");
97 #endif
98  }
99 
100  /*----------------------------.
101  | Construction of the graph. |
102  `----------------------------*/
103 
104  // Adjacency matrix.
105  std::vector< std::vector<bool> > adj(nlabels + 1);
106  for (unsigned l = 1; l <= nlabels; ++l)
107  adj[l].resize(nlabels + 1, false);
108 
109  {
110  box2d::piter p(iz.domain());
111  for_all(p)
112  {
113  point2d r = p + right, b = p + down;
114  if (iz.has(r) && iz(p) != iz(r))
115  {
116  if (iz(p) != iz(r))
117  adj[iz(p)][iz(r)] = true;
118  else
119  adj[iz(r)][iz(p)] = true;
120  }
121  if (iz.has(b) && iz(p) != iz(b))
122  {
123  if (iz(p) != iz(b))
124  adj[iz(p)][iz(b)] = true;
125  else
126  adj[iz(b)][iz(p)] = true;
127  }
128  }
129  }
130 
131  // Graph structure.
132  typedef util::graph G;
133  G g;
134 
135  // Vertices. Note that vertex 0 corresponds to the background, and
136  // is therefore not connected to any other vertex.
137  g.add_vertices(nlabels + 1);
138 
139  // Sites associated to edges.
140  typedef util::site_pair<point2d> site_t;
141  typedef fun::i2v::array<site_t> fsite_t;
142  fsite_t sites;
143 
144  {
145  // Vertices locations.
146  std::vector<point2d> v_site (nlabels + 1, point2d(0,0));
147  {
148  box2d::piter p(label.domain());
149  for_all(p)
150  if (label(p) != 0)
151  v_site[label(p)] = p;
152  }
153  std::cout << "v_site size = " << v_site.size() << std::endl;
154 
155  // Edges.
156  std::vector<util::edge_id_t> e;
157  {
158  for (unsigned l = 1; l <= nlabels; ++l)
159  for (unsigned ll = l + 1; ll <= nlabels; ++ll)
160  if (adj[l][ll])
161  {
162  sites.append(site_t(v_site[l], v_site[ll]));
163  e.push_back(g.add_edge(l, ll));
164  }
165  }
166  std::cout << "e size = " << e.size() << std::endl;
167  }
168 
169  /*-------------.
170  | Edge image. |
171  `-------------*/
172 
173  /* FIXME: edge_image should provide a ctor to initialize an instance
174  with just a graph an an edge-to-site function (but no values).
175  Currently this is not possible. Hence the ``adhead of time''
176  creation of these values . */
177  // Values.
178  typedef fun::i2v::array<int_u8> dist_values_t;
179  dist_values_t dist_values(sites.size());
180  for (unsigned i = 0; i < dist_values.size(); ++i)
181  dist_values(i) = 0;
182 
183 
184  // Type of an edge-valued graph image located in a discrete 2D space
185  // with int_u8 values on each edge.
186  typedef edge_image<site_t, int_u8, util::graph> dist_ima_t;
187  dist_ima_t dist_ima(g, sites, dist_values);
188  data::fill(dist_ima, 0u);
189 
190  /*------------------------.
191  | Graph 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  mln_piter_(dist_ima_t) e(dist_ima.domain());
202  for_all(e)
203  {
204  // Site associated to E.
205  point2d p1 = e.first();
206  point2d p2 = e.second();
207 
208  dist_ima(e) = norm::l2_distance(p1.to_vec(), p2.to_vec());
209  dist_max.take(dist_ima(e));
210 
211  draw::line(canvas, p1, p2, dist_ima(e));
212  canvas(p1) = 255;
213  canvas(p2) = 255;
214  }
215 
216  std::cout << "distance max = " << dist_max << std::endl;
217 
218 #if 0
219  io::pgm::save(canvas, "canvas.pgm");
220 #endif
221 
222  return dist_ima;
223 }
224 
225 
226 int
227 main(int argc, char* argv[])
228 {
229  if (argc != 4)
230  {
231  std::cerr << "usage: " << argv[0] << " input.pbm lambda output.ppm"
232  << std::endl;
233  std::exit(1);
234  }
235  std::string input_filename = argv[1];
236  unsigned lambda = atoi(argv[2]);
237  std::string output_filename = argv[3];
238 
239  using namespace mln;
240  using mln::value::int_u8;
241 
242  // Seeds.
243  image2d<bool> seeds;
244  io::pbm::load(seeds, input_filename);
245 
246  // Shortcut: type of an edge-valued graph image located in a
247  // discrete 2D space with int_u8 values for each edge.
248  typedef edge_image<util::site_pair<point2d>, int_u8> ima_t;
249 
250  // Image computed from the graph of influence zones (IZ) of seeds.
251  ima_t ima = make_graph_image(seeds);
252 
253  // IMA's elementary neighborhood: adjacency relation between two
254  // edges through a shared vertex
255  typedef ima_t::nbh_t nbh_t;
256  nbh_t nbh;
257 
258  typedef unsigned wst_val_t;
259  wst_val_t nbasins;
260  // Output image type.
261  typedef edge_image<util::site_pair<point2d>, wst_val_t> wst_ima_t;
262 
263  // Chain.
264  wst_ima_t wst_ima = chain(ima, nbh, lambda, nbasins);
265 
266  // Output image showing the results of the above chain on an image
267  // similar to the input.
268  image2d<int_u8> canvas_wst(seeds.domain());
269  data::fill(canvas_wst, 0);
270 
271  // Iterator on (the edges of) WST_IMA.
272  mln_piter_(wst_ima_t) e(wst_ima.domain());
273 
274  for_all(e)
275  {
276  // Site associated to E.
277  point2d p1 = e.first();
278  point2d p2 = e.second();
279 
280  draw::line(canvas_wst, p1, p2, wst_ima(e));
281  }
282 
283  io::ppm::save(labeling::colorize(value::rgb8(), canvas_wst, nbasins),
284  output_filename);
285 }