$extrastylesheet
Olena  User documentation 2.1
An Image Processing Platform
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
components.hh
1 // Copyright (C) 2010, 2013 EPITA Research and Development Laboratory
2 // (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 #ifndef SCRIBO_AFP_COMPONENTS_HH
28 # define SCRIBO_AFP_COMPONENTS_HH
29 
33 
34 # include <mln/io/pbm/load.hh>
35 # include <mln/io/pgm/save.hh>
36 
37 # include <mln/extension/adjust.hh>
38 # include <mln/extension/fill.hh>
39 # include <mln/data/fill.hh>
40 # include <mln/accu/shape/bbox.hh>
41 
42 # include <mln/core/alias/neighb2d.hh>
43 # include <mln/core/image/dmorph/image_if.hh>
44 # include <mln/pw/value.hh>
45 # include <mln/debug/println.hh>
46 
47 # include <mln/util/timer.hh>
48 # include <mln/labeling/foreground.hh>
49 # include <mln/labeling/wrap.hh>
50 # include <mln/extension/fill.hh>
51 # include <mln/data/compare.hh>
52 
53 // FIXME: Move the contents of this file in the right namespace and/or
54 // refactor.
55 
56 namespace mln
57 {
58 
59  template <typename I>
60  unsigned my_find_root(image2d<I>& data, unsigned x)
61  {
62  if (data.element(x).parent == x)
63  return x;
64  else
65  return data.element(x).parent = my_find_root(data,
66  data.element(x).parent);
67  }
68 
69 
70 
71  struct info
72  {
73  unsigned parent;
74  unsigned card;
75  float row_sum, col_sum;
76  point2d p_min, p_max;
77 
78  int width() const
79  {
80  return p_max.col() - p_min.col();
81  }
82 
83  int height() const
84  {
85  return p_max.row() - p_min.row();
86  }
87 
88  void init(unsigned p, int row, int col)
89  {
90  parent = p;
91  card = 1;
92  row_sum = row;
93  col_sum = col;
94  p_min.row() = row;
95  p_max.row() = row;
96  p_min.col() = col;
97  p_max.col() = col;
98  }
99 
100  void update(info& r)
101  {
102  r.parent = this->parent;
103  card += r.card;
104  row_sum += r.row_sum;
105  col_sum += r.col_sum;
106 
107  // bkd browsing => p is always higher (lower row) than r
108  mln_invariant(p_min.row() <= r.p_min.row());
109 
110  if (r.p_min.col() < p_min.col())
111  p_min.col() = r.p_min.col();
112  if (r.p_max.row() > p_max.row())
113  p_max.row() = r.p_max.row();
114  if (r.p_max.col() > p_max.col())
115  p_max.col() = r.p_max.col();
116  }
117  };
118 
119 
120  template <typename V>
121  image2d<V>
122  extract_components(const image2d<bool>& input,
123  V& nlabels,
124  util::array<std::pair<box2d, std::pair<point2d, unsigned> > >& attribs)
125  {
126  typedef image2d<bool> I;
127 
128  neighb2d nbh = c8();
129  const int
130  nrows = input.nrows(),
131  ncols = input.ncols();
132 
133  attribs.resize(1);
134 
135  image2d<info> data;
136  image2d<V> label;
137  V current_label = 0;
138  int dp_border;
139 
140  // init
141  {
142  extension::adjust(input, nbh);
143  dp_border = 2 * input.border();
144  extension::fill(input, false);
145  initialize(data, input);
146  }
147 
148  // 1st pass
149  {
150  util::array<int> dp = positive_offsets_wrt(input, nbh);
151  const unsigned n_nbhs = dp.nelements();
152 
153  // Backward.
154  unsigned p = input.offset_of_point(point2d(nrows - 1, ncols - 1));
155  for (int row = nrows - 1; row >= 0; --row, p -= dp_border)
156  for (int col = ncols - 1; col >= 0; --col, --p)
157  {
158  if (! input.element(p))
159  continue;
160 
161  data.element(p).init(p, row, col); // init
162 
163  for (unsigned i = 0; i < n_nbhs; ++i)
164  {
165  unsigned n = p + dp[i];
166  if (! input.element(n))
167  continue;
168  unsigned r = my_find_root(data, n);
169  if (r != p)
170  {
171  data.element(p).update( data.element(r) ); // update
172  }
173  }
174  }
175  }
176 
177 
178  // 2nd pass
179  {
180  initialize(label, input);
181  data::fill(label, 0);
182 
183  // Forward.
184  unsigned p = input.offset_of_point(point2d(0, 0));
185  for (int row = 0; row < nrows; ++row, p += dp_border)
186  for (int col = 0; col < ncols; ++col, ++p)
187  {
188  if (! input.element(p))
189  continue;
190  const info& dta = data.element(p);
191  if (dta.parent == p)
192  {
193  if (dta.card > 5
194  && (dta.width() >= 1
195  && dta.height() >= 1))
196  {
197  label.element(p) = ++current_label;
198 
199  attribs.append(
200  std::make_pair(box2d(dta.p_min, dta.p_max),
201  std::make_pair(point2d(dta.row_sum / dta.card,
202  dta.col_sum / dta.card), dta.card)));
203  }
204  }
205  else
206  label.element(p) = label.element(dta.parent);
207  }
208  }
209 
210  nlabels = current_label;
211  return label;
212  }
213 
214 
215 } // mln
216 
217 
218 #endif // ! SCRIBO_AFP_COMPONENTS_HH