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