$extrastylesheet
Olena  User documentation 2.1
An Image Processing Platform
 All Classes Namespaces Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
morpho.hh
1 // Copyright (C) 2009, 2012 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 APPS_GRAPH_MORPHO_MORPHO_HH
28 # define APPS_GRAPH_MORPHO_MORPHO_HH
29 
40 # include <mln/core/alias/complex_image.hh>
41 # include <mln/core/image/image2d.hh>
42 
43 # include <mln/core/image/dmorph/image_if.hh>
44 
45 # include <mln/core/image/dmorph/extension_ima.hh>
46 
47 # include <mln/core/routine/extend.hh>
48 # include <mln/core/routine/duplicate.hh>
49 
50 # include <mln/core/site_set/p_n_faces_piter.hh>
51 # include <mln/core/image/complex_neighborhoods.hh>
52 # include <mln/core/image/complex_neighborhood_piter.hh>
53 
54 # include <mln/world/inter_pixel/dim2/is_pixel.hh>
55 # include <mln/world/inter_pixel/dim2/is_edge.hh>
56 # include <mln/world/inter_pixel/neighb2d.hh>
57 
58 # include <mln/data/paste.hh>
59 
60 # include <mln/morpho/dilation.hh>
61 # include <mln/morpho/erosion.hh>
62 
63 # include <mln/topo/is_n_face.hh>
64 
65 
66 /*---------------.
67 | Graph traits. |
68 `---------------*/
69 
70 namespace trait
71 {
76  template <typename I>
77  struct graph
78  {
79  /* Empty by default.
80 
81  Specializations must provide these static member functions:
82 
83  static F1 is_vertex()
84  static F2 is_edge()
85  static W1 v2e()
86  static W2 e2v()
87 
88  where F1, F2, W1 and W2 are types depending on I.
89  */
90  };
91 
92  // ----------------------------------------------------------- //
93  // Graph traits for (mln::image2d-based) cubical 2-complexes. //
94  // ----------------------------------------------------------- //
95 
100  template <typename T>
101  struct graph< mln::image2d<T> >
102  {
103  // Return a functor saying whether a psite is a vertex or not.
104  static
106  {
107  static mln::world::inter_pixel::dim2::is_pixel is_vertex_fun;
108  return is_vertex_fun;
109  }
110 
111  // Return a functor saying whether a psite is a vertex or not.
112  static
114  {
115  static mln::world::inter_pixel::dim2::is_edge is_edge_fun;
116  return is_edge_fun;
117  }
118 
119  // Return a window containing the edges adjacent to a vertex.
120  static
121  const mln::window2d& v2e()
122  {
124  }
125 
126  // Return a window containing the vertices adjacent to an edge.
127  static
129  {
131  }
132  };
133 
134  // ---------------------------------------- //
135  // Graph traits for (general) 1-complexes. //
136  // ---------------------------------------- //
137 
142  template <typename G, typename V>
143  struct graph< mln::complex_image<1, G, V> >
144  {
145  // Return a functor saying whether a psite is a vertex or not.
146  static
148  {
149  static mln::topo::is_n_face<mln::complex_psite<1, G>, 0> is_vertex_fun;
150  return is_vertex_fun;
151  }
152 
153  // Return a functor saying whether a psite is a vertex or not.
154  static
156  {
157  static mln::topo::is_n_face<mln::complex_psite<1, G>, 1> is_edge_fun;
158  return is_edge_fun;
159  }
160 
161  // Return a window containing the edges adjacent to a vertex.
162  static
164  {
165  static mln::complex_higher_window<1, G> v2e_win;
166  return v2e_win;
167  }
168 
169  // Return a window containing the vertices adjacent to an edge.
170  static
172  {
173  static mln::complex_lower_window<1, G> e2v_win;
174  return e2v_win;
175  }
176  };
177 
178 } // end of namespace trait
179 
180 
181 /*----------------------------.
182 | Vertices-edges combinator. |
183 `----------------------------*/
184 
185 /* The original paper uses an operator `\ovee' to combine node and
186  edge graphs. However, this symbol requires the use of the
187  `stmaryrd' package, and Doyxgen provides no means to require it.
188  So, we use a more ``standard'' symbol instead (`\oplus'). */
189 
192 template <typename I>
193 inline
194 mln_concrete(I)
195 combine(const mln::Image<I>& vertices_, const mln::Image<I>& edges_)
196 {
197  typedef trait::graph<I> T;
198  const I& vertices = mln::exact(vertices_);
199  const I& edges = mln::exact(edges_);
200 
201  mln_precondition(vertices.domain() == edges.domain());
202  mln_concrete(I) output;
203  mln::initialize(output, vertices);
204  mln::data::fill(output, false);
205  mln::data::paste(vertices | T::is_vertex(), output);
206  mln::data::paste(edges | T::is_edge(), output);
207  return output;
208 }
209 
210 
211 /*-------------------------.
212 | Dilations and erosions. |
213 `-------------------------*/
214 
215 // ----------------------------- //
216 // Core dilations and erosions. //
217 // ----------------------------- //
218 
219 /* Note: When writing
220 
221  dilation(ima | vertices);
222 
223  `vertices' is a predicate on sites (p2b function), which
224  is not efficient, since both vertices and edges will be browsed.
225 
226  It would be very nice if `vertices' could be an actual site set,
227  so that `ima | vertices' creates a morpher smart enough to
228  browse /only/ vertices. */
229 
230 
232 template <typename I>
233 inline
234 mln_concrete(I)
235 dilation_e2v(const mln::Image<I>& input)
236 {
237  typedef trait::graph<I> T;
238 
239  mln_concrete(I) output;
240  mln::initialize(output, mln::exact(input));
241  mln::data::fill(output, false);
242  mln::data::paste(mln::morpho::dilation(mln::extend(input | T::is_vertex(),
243  input),
244  T::v2e()),
245  output);
246  return output;
247 }
248 
250 template <typename I>
251 inline
252 mln_concrete(I)
253 erosion_v2e(const mln::Image<I>& input)
254 {
255  typedef trait::graph<I> T;
256 
257  mln_concrete(I) output;
258  mln::initialize(output, mln::exact(input));
259  mln::data::fill(output, false);
260  mln::data::paste(mln::morpho::erosion(mln::extend(input | T::is_edge(),
261  input),
262  T::e2v()),
263  output);
264  return output;
265 }
266 
268 template <typename I>
269 inline
270 mln_concrete(I)
271 erosion_e2v(const mln::Image<I>& input)
272 {
273  typedef trait::graph<I> T;
274 
275  mln_concrete(I) output;
276  mln::initialize(output, mln::exact(input));
277  mln::data::fill(output, false);
278  mln::data::paste(mln::morpho::erosion(mln::extend(input | T::is_vertex(),
279  input),
280  T::v2e()),
281  output);
282  return output;
283 }
284 
286 template <typename I>
287 inline
288 mln_concrete(I)
289 dilation_v2e(const mln::Image<I>& input)
290 {
291  typedef trait::graph<I> T;
292 
293  mln_concrete(I) output;
294  mln::initialize(output, mln::exact(input));
295  mln::data::fill(output, false);
296  mln::data::paste(mln::morpho::dilation(mln::extend(input | T::is_edge(),
297  input),
298  T::e2v()),
299  output);
300  return output;
301 }
302 
303 
304 // ------------------------------ //
305 // Other dilations and erosions. //
306 // ------------------------------ //
307 
309 template <typename I>
310 inline
311 mln_concrete(I)
312 dilation_vertex(const mln::Image<I>& input)
313 {
314  return dilation_e2v(dilation_v2e(input));
315 }
316 
318 template <typename I>
319 inline
320 mln_concrete(I)
321 erosion_vertex(const mln::Image<I>& input)
322 {
323  return erosion_e2v(erosion_v2e(input));
324 }
325 
326 
328 template <typename I>
329 inline
330 mln_concrete(I)
331 dilation_edge(const mln::Image<I>& input)
332 {
333  return dilation_v2e(dilation_e2v(input));
334 }
335 
337 template <typename I>
338 inline
339 mln_concrete(I)
340 erosion_edge(const mln::Image<I>& input)
341 {
342  return erosion_v2e(erosion_e2v(input));
343 }
344 
345 
347 template <typename I>
348 inline
349 mln_concrete(I)
350 dilation_graph(const mln::Image<I>& input)
351 {
352  return combine(dilation_vertex(input), dilation_edge(input));
353 }
354 
356 template <typename I>
357 inline
358 mln_concrete(I)
359 erosion_graph(const mln::Image<I>& input)
360 {
361  return combine(erosion_vertex(input), erosion_edge(input));
362 }
363 
364 
365 /*-------------------------.
366 | Additional adjunctions. |
367 `-------------------------*/
368 
369 template <typename I>
370 inline
371 mln_concrete(I)
372 alpha1(const mln::Image<I>& input)
373 {
374  mln_concrete(I) vertices;
375  mln::initialize(vertices, input);
376  mln::data::fill(vertices, true);
377  return combine(vertices, input);
378 }
379 
380 template <typename I>
381 inline
382 mln_concrete(I)
383 beta1(const mln::Image<I>& input)
384 {
385  return combine(dilation_e2v(input), input);
386 }
387 
388 template <typename I>
389 inline
390 mln_concrete(I)
391 alpha2(const mln::Image<I>& input)
392 {
393  return combine(input, erosion_v2e(input));
394 }
395 
396 template <typename I>
397 inline
398 mln_concrete(I)
399 beta2(const mln::Image<I>& input)
400 {
401  mln_concrete(I) edges;
402  mln::initialize(edges, input);
403  mln::data::fill(edges, false);
404  return combine(input, edges);
405 }
406 
407 template <typename I>
408 inline
409 mln_concrete(I)
410 alpha3(const mln::Image<I>& input)
411 {
412  return combine(erosion_e2v(input), erosion_v2e(erosion_e2v(input)));
413 }
414 
415 template <typename I>
416 inline
417 mln_concrete(I)
418 beta3(const mln::Image<I>& input)
419 {
420  return combine(dilation_e2v(dilation_v2e(input)), dilation_v2e(input));
421 }
422 
423 
424 /*------------------------.
425 | Openings and closings. |
426 `------------------------*/
427 
429 template <typename I>
430 inline
431 mln_concrete(I)
432 opening_vertex(const mln::Image<I>& input)
433 {
434  return dilation_vertex(erosion_vertex(input));
435 }
436 
438 template <typename I>
439 inline
440 mln_concrete(I)
441 closing_vertex(const mln::Image<I>& input)
442 {
443  return erosion_vertex(dilation_vertex(input));
444 }
445 
446 
448 template <typename I>
449 inline
450 mln_concrete(I)
451 opening_edge(const mln::Image<I>& input)
452 {
453  return dilation_edge(erosion_edge(input));
454 }
455 
457 template <typename I>
458 inline
459 mln_concrete(I)
460 closing_edge(const mln::Image<I>& input)
461 {
462  return erosion_edge(dilation_edge(input));
463 }
464 
465 
467 template <typename I>
468 inline
469 mln_concrete(I)
470 opening_graph(const mln::Image<I>& input)
471 {
472  return combine(opening_vertex(input), opening_edge(input));
473 }
474 
476 template <typename I>
477 inline
478 mln_concrete(I)
479 closing_graph(const mln::Image<I>& input)
480 {
481  return combine(closing_vertex(input), closing_edge(input));
482 }
483 
484 
485 /*----------------------------------.
486 | Half-openings and half-closings. |
487 `----------------------------------*/
488 
490 template <typename I>
491 inline
492 mln_concrete(I)
493 half_opening_vertex(const mln::Image<I>& input)
494 {
495  return dilation_e2v(erosion_v2e(input));
496 }
497 
499 template <typename I>
500 inline
501 mln_concrete(I)
502 half_closing_vertex(const mln::Image<I>& input)
503 {
504  return erosion_e2v(dilation_v2e(input));
505 }
506 
507 
509 template <typename I>
510 inline
511 mln_concrete(I)
512 half_opening_edge(const mln::Image<I>& input)
513 {
514  return dilation_v2e(erosion_e2v(input));
515 }
516 
518 template <typename I>
519 inline
520 mln_concrete(I)
521 half_closing_edge(const mln::Image<I>& input)
522 {
523  return erosion_v2e(dilation_e2v(input));
524 }
525 
526 
528 template <typename I>
529 inline
530 mln_concrete(I)
531 half_opening_graph(const mln::Image<I>& input)
532 {
533  return combine(half_opening_vertex(input), half_opening_edge(input));
534 }
535 
537 template <typename I>
538 inline
539 mln_concrete(I)
540 half_closing_graph(const mln::Image<I>& input)
541 {
542  return combine(half_closing_vertex(input), half_closing_edge(input));
543 }
544 
545 
546 /*-------------------------------------------------------.
547 | Parameterized openings and closings (granulometries). |
548 `-------------------------------------------------------*/
549 
551 template <typename I>
552 inline
553 mln_concrete(I)
554 opening(const mln::Image<I>& input, unsigned lambda)
555 {
556  unsigned i = lambda / 2;
557  unsigned j = lambda % 2;
558  mln_concrete(I) output = mln::duplicate(input);
559  for (unsigned m = 0; m < i; ++m)
560  output = erosion_graph(output);
561  for (unsigned m = 0; m < j; ++m)
562  output = half_opening_graph(output);
563  for (unsigned m = 0; m < i; ++m)
564  output = dilation_graph(output);
565  return output;
566 }
567 
569 template <typename I>
570 inline
571 mln_concrete(I)
572 closing(const mln::Image<I>& input, unsigned lambda)
573 {
574  unsigned i = lambda / 2;
575  unsigned j = lambda % 2;
576  mln_concrete(I) output = mln::duplicate(input);
577  for (unsigned m = 0; m < i; ++m)
578  output = dilation_graph(output);
579  for (unsigned m = 0; m < j; ++m)
580  output = half_closing_graph(output);
581  for (unsigned m = 0; m < i; ++m)
582  output = erosion_graph(output);
583  return output;
584 }
585 
586 /*-------------------------------.
587 | Alternate Sequential Filters. |
588 `-------------------------------*/
589 
591 template <typename I>
592 inline
593 mln_concrete(I)
594 asf(const mln::Image<I>& input, unsigned lambda)
595 {
596  mln_concrete(I) output = mln::duplicate(input);
597  for (unsigned m = 1; m <= lambda; ++m)
598  output = opening(closing(output, m), m);
599  return output;
600 }
601 
602 #endif // ! APPS_GRAPH_MORPHO_MORPHO_HH