Milena (Olena)  User documentation 2.0a Id
 All Classes Namespaces Functions Variables Typedefs Enumerator Groups Pages
constrained-connectivity.cc
1 // Copyright (C) 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 
64 #include <cstdio>
65 
66 #include <set>
67 #include <iostream>
68 
69 #include <mln/value/int_u8.hh>
70 #include <mln/core/image/image2d.hh>
71 
72 #include <mln/pw/all.hh>
73 
74 #include <mln/fun/vv2v/diff_abs.hh>
75 #include <mln/world/inter_pixel/immerse.hh>
76 #include <mln/world/inter_pixel/compute.hh>
77 #include <mln/world/inter_pixel/neighb2d.hh>
78 
79 #include <mln/morpho/watershed/topological.hh>
80 
81 #include <mln/morpho/tree/compute_attribute_image.hh>
82 #include <mln/accu/stat/min.hh>
83 #include <mln/accu/stat/max.hh>
84 
85 #include <mln/io/pgm/load.hh>
86 #include <mln/debug/println.hh>
87 
88 #include <mln/core/var.hh>
89 
90 
91 int main(int argc, char* argv[])
92 {
93  if (argc != 2)
94  {
95  std::cerr << "Usage: " << argv[0] << " input.pgm" << std::endl;
96  std::exit(1);
97  }
98 
99  using namespace mln;
100  using mln::value::int_u8;
101 
102  // Load an image.
103  image2d<int_u8> input;
104  io::pgm::load(input, argv[1]);
105 
106  // Double its resolution.
107  image2d<int_u8> f_(input.nrows() * 2, input.ncols() * 2);
108  mln_piter_(image2d<int_u8>) p_ima(f_.domain());
109  for_all(p_ima)
110  {
111  /* This conversion from a ``piter'' type to point2d is required,
112  since an iterator does not expose the interface of the
113  underlying point (among which the methods row(), col(),
114  etc.). */
115  point2d p_ima_ = p_ima;
116  point2d p_f(p_ima_.row() / 2, p_ima_.col() / 2);
117  f_(p_ima) = input(p_f);
118  }
119  debug::println("f_:", f_);
120 
121  image_if<image2d<int_u8>, world::inter_pixel::is_pixel> f =
122  world::inter_pixel::immerse(f_);
123  debug::println("f:", f);
124 
125  // Compute the associated line graph gradient.
126  mln_VAR(g, world::inter_pixel::compute (f, fun::vv2v::diff_abs<int_u8>()));
127 
128  debug::println("g:", g);
129 
130  // Compute a topological watershed transform on this gradient.
131  typedef morpho::watershed::topo_wst<g_t, world::inter_pixel::dbl_neighb2d> tree_t;
132  tree_t tree(g, world::inter_pixel::e2e());
133  tree.go();
134  mln_VAR(w, morpho::watershed::topological(tree));
135  debug::println("w:", w);
136 
137  // Computing the set of values of W.
138  // FIXME: Milena may provide something simpler than this.
139  std::set<int_u8> values;
140  mln_piter_(w_t) p2(w.domain());
141  for_all(p2)
142  values.insert(w(p2));
143 
144  // Thresholding W for each value of the image.
145  for (std::set<int_u8>::const_iterator alpha = values.begin();
146  alpha != values.end(); ++alpha)
147  {
148  mln_VAR(alpha_cc, w | (pw::value(w) > pw::cst(*alpha)));
149  std::cout << *alpha << "-cc:" << std::endl;
150  /* FIXME: There should be variants of debug::println allowing
151  the user to pass an optional ``support'' larger than the
152  actual domain of the image. For now, use a low-level routine
153  as a workaround. */
154  debug::impl::println(w.unmorph_().domain(), alpha_cc);
155  }
156 
157 
158  // Compute the height (max - min) of connected components on the line
159  // graph-based watershed, but with min and max values computed on
160  // vertices.
161 
162  /* FIXME: Of course, we'd like to be able to reuse the component
163  tree within TREE instead of rebuilding a morpho::tree::data...
164  This requires some changes in the topological WST implementation,
165  to make its component tree structure compatible with
166  morpho::tree::data. */
167  typedef p_array<tree_t::site> sites_t;
168  sites_t sites = data::sort_psites_decreasing(w);
169  morpho::tree::data<w_t, sites_t> t(w, sites, world::inter_pixel::e2e());
170 
171  // Create initial images for min and max values on sites (not components).
172  mln_ch_value_(w_t, accu::stat::min<int_u8>) init_min_val;
173  initialize (init_min_val, w);
174  mln_ch_value_(w_t, accu::stat::max<int_u8>) init_max_val;
175  initialize (init_max_val, w);
176 
177  /* Compute the min and max values on vertices (pixels) adjacent to
178  edge E.
179 
180  Unfortunately, the data structure G does not record any
181  information from the image F (i.e., the values on
182  vertices/pixels). We have to convert the coordinates of V to its
183  equivalent in F's domain to get the values on vertices. */
184  mln_piter_(w_t) e(w.domain());
185  mln_niter_(world::inter_pixel::dbl_neighb2d)
186  v_g(world::inter_pixel::e2v(), e);
187  for_all(e)
188  for_all(v_g)
189  {
190  // Same remark as above avour piter to point2d conversions.
191  point2d v_g_ = v_g;
192  point2d v_f(v_g_.row() / 2, v_g_.col() / 2);
193  init_min_val(e).take(f_(v_f));
194  init_max_val(e).take(f_(v_f));
195  }
196  // Attribute images of min and max values on components.
197  accu::stat::min<int_u8> min_accu;
198  mln_ch_value_(w_t, int_u8) min_val =
199  morpho::tree::compute_attribute_image_from(min_accu, t, init_min_val);
200  accu::stat::max<int_u8> max_accu;
201  mln_ch_value_(w_t, int_u8) max_val =
202  morpho::tree::compute_attribute_image_from(max_accu, t, init_max_val);
203  // Attribute image of components' height.
204  mln_ch_value_(w_t, int_u8) height;
205  initialize(height, w);
206  for_all(e)
207  height(e) = max_val(e) - min_val(e);
208  debug::println(height);
209 
210  // Thresholding W using first integer values with a condition on HEIGHT.
211  for (unsigned alpha = 0; alpha <= 6; ++alpha)
212  {
213  mln_VAR(alpha_alpha_cc,
214  w | (pw::value(w) > pw::cst(alpha)
215  || (pw::value(height) > pw::cst(alpha))));
216  std::cout << "(" << alpha << ", " << alpha << ")-cc:" << std::endl;
217  // FIXME: Same remark as above about println.
218  debug::impl::println(w.unmorph_().domain(), alpha_alpha_cc);
219  }
220 }