$extrastylesheet
Olena  User documentation 2.1
An Image Processing Platform
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
area_flooding.cc
1 // Copyright (C) 2008, 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 
31 
48 #include <cstdlib>
49 
50 #include <vector>
51 
52 #include <mln/value/int_u8.hh>
53 #include <mln/value/int_u16.hh>
54 
55 #include <mln/core/routine/duplicate.hh>
56 
57 #include <mln/core/image/image2d.hh>
58 
59 #include <mln/morpho/line_gradient.hh>
60 #include <mln/morpho/closing/area_on_vertices.hh>
61 #include <mln/labeling/regional_minima.hh>
62 #include <mln/morpho/watershed/flooding.hh>
63 
64 #include <mln/io/pgm/load.hh>
65 #include <mln/io/pgm/save.hh>
66 
67 int main(int argc, char* argv[])
68 {
69  if (argc != 4)
70  {
71  std::cerr
72  << "usage: " << argv[0] << " max_nregions input.pgm output.pgm"
73  << std::endl;
74  std::exit(EXIT_FAILURE);
75  }
76 
77  /*--------.
78  | Input. |
79  `--------*/
80 
81  using namespace mln;
82  using value::int_u8;
83  using value::int_u16;
84 
85  typedef int_u8 val_t;
86  typedef image2d<val_t> orig_ima_t;
87 
88  orig_ima_t input;
89  io::pgm::load(input, argv[2]);
90  if (!input.is_valid())
91  {
92  std::cerr << "Error reading input " << argv[2] << std::endl;
93  std::exit(2);
94  }
95 
96  /*----------------.
97  | Line gradient. |
98  `----------------*/
99 
100  // Type of the function mapping graph edges and image sites.
101  typedef util::site_pair<point2d> P;
102  typedef fun::i2v::array<P> fedge_site_t;
103 
104  // Line graph image.
105  typedef fun::i2v::array<val_t> fval_t;
106  fval_t values;
107  typedef edge_image<P,val_t> lg_ima_t;
108  lg_ima_t lg_ima = morpho::line_gradient(input);
109 
110  /*-----------.
111  | Flooding. |
112  `-----------*/
113 
114  /* FIXME: I'm not sure this is the way it should be done. Anyway,
115  we should implement this as a canvas. */
116 
117  typedef lg_ima_t::nbh_t nbh_t;
118  nbh_t nbh;
119 
120  unsigned area = 0;
121  unsigned max_area = input.nsites();
122  unsigned nregions = mln_max(unsigned);
123  unsigned max_nregions = atoi(argv[1]);
124 
125  lg_ima_t result = duplicate(lg_ima);
126  while (area < max_area && nregions > max_nregions)
127  {
128  ++area;
129  std::cerr << "area = " << area << " \t"
130  << "nregions = " << nregions << std::endl;
131  lg_ima_t work = duplicate(result);
132  // Compute the closing.
133  result = morpho::closing::area_on_vertices(work, nbh, area);
134  // Compute the number of local minima (but get rid of the image,
135  // as we don't need it).
136  labeling::regional_minima(result, nbh, nregions);
137  }
138 
139  /*------.
140  | WST. |
141  `------*/
142 
143  // Perform a Watershed Transform.
144  typedef int_u16 wst_val_t;
145  wst_val_t nbasins;
146  typedef edge_image<P,wst_val_t> wshed_t;
147 
148  wshed_t wshed = morpho::watershed::flooding(result, nbh, nbasins);
149  std::cout << "nbasins = " << nbasins << std::endl;
150 
151  /*---------.
152  | Output. |
153  `---------*/
154 
155  const wst_val_t wshed_label = 0;
156 
157  // Create a 2D-equivalent of WSHED.
158  image2d<wst_val_t> wshed2d(input.domain());
159 
160  /* FIXME: It'd better if we could iterate over the *vertices* of a
161  line graph image. We could avoid all this lengthy code. */
162  // Iterate over each edge of the watershed image, and propagate the
163  // label of an edge to its adjacent vertices when this edge is not
164  // part of the watershed.
165  mln_piter_(wshed_t) p(wshed.domain());
166  for_all(p)
167  if (wshed(p) != wshed_label)
168  {
169  wshed2d(p.first()) = wshed(p);
170  wshed2d(p.second()) = wshed(p);
171  }
172 
173  // For each basin, compute the average gray level.
174  std::vector<mln_sum_(val_t)> sum(nbasins + 1, 0);
175  std::vector<unsigned> nsites(nbasins + 1, 0);
176  mln_piter_(orig_ima_t) q(input.domain());
177  for_all(q)
178  {
179  sum[wshed2d(q)] += input(q);
180  ++nsites[wshed2d(q)];
181  }
182  std::vector<float> average(nbasins + 1);
183  for (unsigned i = 1; i <= nbasins; ++i)
184  average[i] = float (sum[i]) / float (nsites[i]);
185 
186  // Create an output image using the average gray levels of the basins.
187  orig_ima_t output(input.domain());
188  for_all(q)
189  output(q) = convert::to<mln_value_(orig_ima_t)>(average[wshed2d(q)]);
190 
191  std::cout << "area = " << area << " \t"
192  << "nregions = " << nregions << std::endl;
193  io::pgm::save(output, argv[3]);
194 }