$extrastylesheet
Olena  User documentation 2.1
An Image Processing Platform
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
component_precise_outline.hh
1 // Copyright (C) 2011 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 
26 #ifndef SCRIBO_UTIL_COMPONENT_PRECISE_OUTLINE_HH
27 # define SCRIBO_UTIL_COMPONENT_PRECISE_OUTLINE_HH
28 
38 # include <mln/io/pbm/load.hh>
39 # include <mln/literal/colors.hh>
40 # include <mln/io/ppm/save.hh>
41 # include <mln/data/convert.hh>
42 # include <mln/opt/at.hh>
43 # include <mln/extension/adjust_fill.hh>
44 
45 # include <iostream>
46 
47 #include <mln/io/pgm/save.hh>
48 #include <mln/data/wrap.hh>
49 #include <mln/data/convert.hh>
50 
51 
52 namespace scribo
53 {
54 
55  namespace util
56  {
57 
58  using namespace mln;
59 
60 
61  template <typename I>
63  component_precise_outline(const Image<I>& input_, const mln_value(I)& id,
64  bool compress_points);
65 
66  template <typename I>
68  component_precise_outline(const Image<I>& input_, const mln_value(I)& id);
69 
70  template <typename I>
72  component_precise_outline(const Image<I>& input_);
73 
74 
75 # ifndef MLN_INCLUDE_ONLY
76 
77  namespace internal
78  {
79 
80 
81  static const int offset[4][8][2] =
82  {
83  { { -1, 0 }, { 0, -1 }, { -1, -1 }, { 1, 0 }, { 1, -1 }, { 0, 1 }, {
84  1, 1 }, { -1, 1 } },
85  { { 0, -1 }, { 1, 0 }, { 1, -1 }, { 0, 1 }, { 1, 1 }, { -1, 0 }, {
86  -1, 1 }, { -1, -1 } },
87  { { 1, 0 }, { 0, 1 }, { 1, 1 }, { -1, 0 }, { -1, 1 }, { 0, -1 }, {
88  -1, -1 }, { 1, -1 } },
89  { { 0, 1 }, { -1, 0 }, { -1, 1 }, { 0, -1 }, { -1, -1 }, { 1, 0 }, {
90  1, -1 }, { 1, 1 } }
91  };
92 
93 
94  template <typename I>
95  void
96  find_first_point(const I& input,
97  point2d& p,
98  const mln_value(I)& id)
99  {
100  const mln::def::coord
101  mid_row = geom::min_row(input) + (geom::nrows(input) >> 1);
102 
103  for (mln::def::coord i = geom::min_col(input);
104  i <= geom::max_col(input); ++i)
105  {
106  if (opt::at(input, mid_row, i) == id)
107  {
108  p.row() = mid_row;
109  p.col() = i;
110  break;
111  }
112  }
113  }
114 
115  template <typename I>
116  void
117  left_up(int& direction,
118  const I& input,
119  const point2d& cur_pt,
120  const mln_value(I)& id)
121  {
122  const point2d p2(cur_pt.row() + offset[direction][5][1],
123  cur_pt.col() + offset[direction][5][0]);
124  const point2d p3(cur_pt.row() + offset[direction][7][1],
125  cur_pt.col() + offset[direction][7][0]);
126 
127  if ((input.has(p2) && input(p2) != id) && (input.has(p3) && input(p3) == id))
128  {
129  direction = 3;
130  return;
131  }
132  }
133 
134  inline
135  void
136  left_up_after(int& direction,
137  const unsigned i)
138  {
139  if (i == 3 || i == 4)
140  direction = 1;
141  else if (i == 5 || i == 6)
142  direction = 2;
143  else if (i == 7)
144  direction = 3;
145  }
146 
147  template <typename I>
148  void
149  right_up(int& direction,
150  const I& input,
151  const point2d& cur_pt,
152  const mln_value(I)& id)
153  {
154  const point2d p1(cur_pt.row() + offset[direction][0][1],
155  cur_pt.col() + offset[direction][0][0]);
156  const point2d p2(cur_pt.row() + offset[direction][5][1],
157  cur_pt.col() + offset[direction][5][0]);
158  const point2d p3(cur_pt.row() + offset[direction][7][1],
159  cur_pt.col() + offset[direction][7][0]);
160 
161  if ((input(p2) != id) && ((input(p1) == id) || (input(p3) == id)))
162  {
163  direction = 0;
164  return;
165  }
166  }
167 
168  inline
169  void
170  right_up_after(int& direction,
171  const unsigned i)
172  {
173  if (i == 3 || i == 4)
174  direction = 2;
175  else if (i == 5 || i == 6)
176  direction = 3;
177  else if (i == 7)
178  direction = 0;
179  }
180 
181  template <typename I>
182  void
183  right_down(int& direction,
184  const I& input,
185  const point2d& cur_pt,
186  const mln_value(I)& id)
187  {
188  const point2d p2(cur_pt.row() + offset[direction][5][1],
189  cur_pt.col() + offset[direction][5][0]);
190  const point2d p3(cur_pt.row() + offset[direction][7][1],
191  cur_pt.col() + offset[direction][7][0]);
192 
193  if ((input.has(p2) && input(p2) != id) && (input.has(p3) && input(p3) == id))
194  {
195  direction = 1;
196  return;
197  }
198  }
199 
200  inline
201  void
202  right_down_after(int& direction,
203  const unsigned i)
204  {
205  if (i == 3 || i == 4)
206  direction = 3;
207  else if (i == 5 || i == 6)
208  direction = 0;
209  else if (i == 7)
210  direction = 1;
211  }
212 
213  template <typename I>
214  void
215  left_down(int& direction,
216  const I& input,
217  const point2d& cur_pt,
218  const mln_value(I)& id)
219  {
220  const point2d p1(cur_pt.row() + offset[direction][0][1],
221  cur_pt.col() + offset[direction][0][0]);
222  const point2d p2(cur_pt.row() + offset[direction][5][1],
223  cur_pt.col() + offset[direction][5][0]);
224  const point2d p3(cur_pt.row() + offset[direction][7][1],
225  cur_pt.col() + offset[direction][7][0]);
226 
227  if ((input.has(p2) && input(p2) != id)
228  && ((input.has(p1) && input(p1) == id) || (input.has(p3) && input(p3) == id)))
229  {
230  direction = 2;
231  return;
232  }
233  }
234 
235  inline
236  void
237  left_down_after(int& direction,
238  const unsigned i)
239  {
240  if (i == 3 || i == 4)
241  direction = 0;
242  else if (i == 5 || i == 6)
243  direction = 1;
244  else if (i == 7)
245  direction = 2;
246  }
247 
248 
249  template <typename I>
250  void
251  find_next_point(const I& input,
252  point2d& cur_pt,
253  int& direction,
254  const mln_value(I)& id)
255  {
256  unsigned i = 0;
257  point2d tmp;
258 
259  switch (direction)
260  {
261  case 0: left_up(direction, input, cur_pt, id); break;
262  case 1: right_up(direction , input, cur_pt, id); break;
263  case 2: right_down(direction, input, cur_pt, id); break;
264  case 3: left_down(direction, input, cur_pt, id); break;
265  }
266 
267  for (; i < 8; ++i)
268  {
269  tmp = point2d(cur_pt.row() + offset[direction][i][1],
270  cur_pt.col() + offset[direction][i][0]);
271 
272  if (input.has(tmp) && input(tmp) == id)
273  break;
274  }
275 
276  // Should not happen
277  if (i == 8)
278  return;
279 
280  switch (direction)
281  {
282  case 0: left_up_after(direction, i); break;
283  case 1: right_up_after(direction , i); break;
284  case 2: right_down_after(direction, i); break;
285  case 3: left_down_after(direction, i); break;
286  }
287 
288  cur_pt = tmp;
289  }
290 
291  inline
292  void
293  filter_points(const mln::p_array<point2d>& points,
294  mln::p_array<point2d>& waypoints)
295  {
296  const unsigned nelements = points.nsites();
297 
298  if (nelements > 2)
299  {
300  const point2d* first_pt = & points[0];
301  const point2d* last_pt = first_pt;
302  waypoints.append(*first_pt);
303  unsigned i = 1;
304  const point2d* cur_pt = & points[i];
305  bool has_changed = false;
306 
307  while (i < nelements)
308  {
309  has_changed = false;
310 
311  while (cur_pt->row() == first_pt->row()
312  || cur_pt->col() == first_pt->col())
313  {
314  has_changed = true;
315  ++i;
316  if (i == nelements)
317  break;
318 
319  const point2d* llast_pt = last_pt;
320  last_pt = cur_pt;
321  cur_pt = & points[i];
322 
323  if (llast_pt->col() == last_pt->col() && last_pt->col() == cur_pt->col())
324  {
325  if (llast_pt->row() == cur_pt->row())
326  break;
327  }
328  else if(llast_pt->row() == last_pt->row() && last_pt->row() == cur_pt->row())
329  {
330  if (llast_pt->col() == cur_pt->col())
331  break;
332  }
333  }
334 
335  if (!has_changed)
336  {
337  ++i;
338  last_pt = cur_pt;
339  if (i < nelements)
340  cur_pt = & points[i];
341  }
342 
343  if (i == nelements)
344  break;
345 
346  waypoints.append(*last_pt);
347  first_pt = last_pt;
348  last_pt = first_pt;
349  }
350 
351  waypoints.append(*cur_pt);
352  }
353  else
354  {
355  for (unsigned i = 0; i < nelements; ++i)
356  waypoints.append(points[i]);
357  }
358  }
359  } // end of namespace scribo::util::internal
360 
361 
362  template <typename I>
364  component_precise_outline(const Image<I>& input_, const mln_value(I)& id,
365  bool compress_points)
366  {
367  mln_trace("scribo::util::component_precise_outline");
368 
369  const I& input = exact(input_);
370  typedef mln_site(I) P;
371 
372  extension::adjust_fill(input, 3, 0);
373 
374  mln::p_array<P> points;
375  points.reserve(std::max(geom::ncols(input), geom::nrows(input)));
376 
377  point2d start_pt;
378  int direction = 0;
379 
380  internal::find_first_point(input, start_pt, id);
381 
382  P cur_pt = start_pt;
383 
384  internal::find_next_point(input, cur_pt, direction, id);
385  points.append(cur_pt);
386 
387  while (cur_pt != start_pt)
388  {
389  internal::find_next_point(input, cur_pt, direction, id);
390  points.append(cur_pt);
391  }
392 
393  internal::find_next_point(input, cur_pt, direction, id);
394 
395  const std::vector<point2d>& vec_points = points.hook_std_vector_();
396 
397  if (std::find(vec_points.begin(),
398  vec_points.end(), cur_pt) == vec_points.end())
399  {
400  points.append(cur_pt);
401 
402  while (cur_pt != start_pt)
403  {
404  internal::find_next_point(input, cur_pt, direction, id);
405  points.append(cur_pt);
406  }
407  }
408 
409  if (compress_points)
410  {
411  mln::p_array<P> waypoints;
412  internal::filter_points(points, waypoints);
413 
414  return waypoints;
415  }
416 
417  return points;
418  }
419 
420  template <typename I>
422  component_precise_outline(const Image<I>& input, const mln_value(I)& id)
423  {
424  return component_precise_outline(input, id, true);
425  }
426 
427  template <typename I>
429  component_precise_outline(const Image<I>& input)
430  {
431  return component_precise_outline(input, true, true);
432  }
433 
434 # endif // ! MLN_INCLUDE_ONLY
435 
436  } // end of namespace scribo::util
437 
438 } // end of namespace scribo
439 
440 #endif // ! SCRIBO_UTIL_COMPONENT_PRECISE_OUTLINE_HH