[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]

flatmorphology.hxx
1 /************************************************************************/
2 /* */
3 /* Copyright 1998-2002 by Ullrich Koethe */
4 /* */
5 /* This file is part of the VIGRA computer vision library. */
6 /* The VIGRA Website is */
7 /* http://hci.iwr.uni-heidelberg.de/vigra/ */
8 /* Please direct questions, bug reports, and contributions to */
9 /* ullrich.koethe@iwr.uni-heidelberg.de or */
10 /* vigra@informatik.uni-hamburg.de */
11 /* */
12 /* Permission is hereby granted, free of charge, to any person */
13 /* obtaining a copy of this software and associated documentation */
14 /* files (the "Software"), to deal in the Software without */
15 /* restriction, including without limitation the rights to use, */
16 /* copy, modify, merge, publish, distribute, sublicense, and/or */
17 /* sell copies of the Software, and to permit persons to whom the */
18 /* Software is furnished to do so, subject to the following */
19 /* conditions: */
20 /* */
21 /* The above copyright notice and this permission notice shall be */
22 /* included in all copies or substantial portions of the */
23 /* Software. */
24 /* */
25 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32 /* OTHER DEALINGS IN THE SOFTWARE. */
33 /* */
34 /************************************************************************/
35 
36 
37 #ifndef VIGRA_FLATMORPHOLOGY_HXX
38 #define VIGRA_FLATMORPHOLOGY_HXX
39 
40 #include <cmath>
41 #include <vector>
42 #include "utilities.hxx"
43 
44 namespace vigra {
45 
46 /** \addtogroup Morphology Basic Morphological Operations
47  Perform erosion, dilation, and median with disc structuring functions
48 
49  See also: \ref MultiArrayMorphology Separable morphology with parabola structuring functions in arbitrary dimensions
50 */
51 //@{
52 
53 /********************************************************/
54 /* */
55 /* discRankOrderFilter */
56 /* */
57 /********************************************************/
58 
59 /** \brief Apply rank order filter with disc structuring function to the image.
60 
61  The pixel values of the source image <b> must</b> be in the range
62  0...255. Radius must be >= 0. Rank must be in the range 0.0 <= rank
63  <= 1.0. The filter acts as a minimum filter if rank = 0.0,
64  as a median if rank = 0.5, and as a maximum filter if rank = 1.0.
65  Accessor are used to access the pixel data.
66 
67  <b> Declarations:</b>
68 
69  pass arguments explicitely:
70  \code
71  namespace vigra {
72  template <class SrcIterator, class SrcAccessor,
73  class DestIterator, class DestAccessor>
74  void
75  discRankOrderFilter(SrcIterator upperleft1,
76  SrcIterator lowerright1, SrcAccessor sa,
77  DestIterator upperleft2, DestAccessor da,
78  int radius, float rank)
79  }
80  \endcode
81 
82 
83  use argument objects in conjunction with \ref ArgumentObjectFactories :
84  \code
85  namespace vigra {
86  template <class SrcIterator, class SrcAccessor,
87  class DestIterator, class DestAccessor>
88  void
89  discRankOrderFilter(triple<SrcIterator, SrcIterator, SrcAccessor> src,
90  pair<DestIterator, DestAccessor> dest,
91  int radius, float rank)
92  }
93  \endcode
94 
95  <b> Usage:</b>
96 
97  <b>\#include</b> <<a href="flatmorphology_8hxx-source.html">vigra/flatmorphology.hxx</a>><br>
98  Namespace: vigra
99 
100  \code
101  vigra::CImage src, dest;
102 
103  // do median filtering
104  vigra::discRankOrderFilter(srcImageRange(src), destImage(dest), 10, 0.5);
105  \endcode
106 
107  <b> Required Interface:</b>
108 
109  \code
110  SrcIterator src_upperleft;
111  DestIterator dest_upperleft;
112  int x, y;
113  unsigned char value;
114 
115  SrcAccessor src_accessor;
116  DestAccessor dest_accessor;
117 
118  // value_type of accessor must be convertible to unsigned char
119  value = src_accessor(src_upperleft, x, y);
120 
121  dest_accessor.set(value, dest_upperleft, x, y);
122  \endcode
123 
124  <b> Preconditions:</b>
125 
126  \code
127  for all source pixels: 0 <= value <= 255
128 
129  (rank >= 0.0) && (rank <= 1.0)
130  radius >= 0
131  \endcode
132 
133 */
135 
136 template <class SrcIterator, class SrcAccessor,
137  class DestIterator, class DestAccessor>
138 void
139 discRankOrderFilter(SrcIterator upperleft1,
140  SrcIterator lowerright1, SrcAccessor sa,
141  DestIterator upperleft2, DestAccessor da,
142  int radius, float rank)
143 {
144  vigra_precondition((rank >= 0.0) && (rank <= 1.0),
145  "discRankOrderFilter(): Rank must be between 0 and 1"
146  " (inclusive).");
147 
148  vigra_precondition(radius >= 0,
149  "discRankOrderFilter(): Radius must be >= 0.");
150 
151  int i, x, y, xmax, ymax, xx, yy;
152  int rankpos, winsize, leftsum;
153 
154  long hist[256];
155 
156  // prepare structuring function
157  std::vector<int> struct_function(radius+1);
158  struct_function[0] = radius;
159 
160  double r2 = (double)radius*radius;
161  for(i=1; i<=radius; ++i)
162  {
163  double r = (double) i - 0.5;
164  struct_function[i] = (int)(VIGRA_CSTD::sqrt(r2 - r*r) + 0.5);
165  }
166 
167  int w = lowerright1.x - upperleft1.x;
168  int h = lowerright1.y - upperleft1.y;
169 
170  SrcIterator ys(upperleft1);
171  DestIterator yd(upperleft2);
172 
173  for(y=0; y<h; ++y, ++ys.y, ++yd.y)
174  {
175  SrcIterator xs(ys);
176  DestIterator xd(yd);
177 
178  // first column
179  int x0 = 0;
180  int y0 = y;
181  int x1 = w - 1;
182  int y1 = h - y - 1;
183 
184  // clear histogram
185  for(i=0; i<256; ++i) hist[i] = 0;
186  winsize = 0;
187 
188  // init histogram
189  ymax = (y1 < radius) ? y1 : radius;
190  for(yy=0; yy<=ymax; ++yy)
191  {
192  xmax = (x1 < struct_function[yy]) ? x1 : struct_function[yy];
193  for(xx=0; xx<=xmax; ++xx)
194  {
195  hist[sa(xs, Diff2D(xx, yy))]++;
196  winsize++;
197  }
198  }
199 
200  ymax = (y0 < radius) ? y0 : radius;
201  for(yy=1; yy<=ymax; ++yy)
202  {
203  xmax = (x1 < struct_function[yy]) ? x1 : struct_function[yy];
204  for(xx=0; xx<=xmax; ++xx)
205  {
206  hist[sa(xs, Diff2D(xx, -yy))]++;
207  winsize++;
208  }
209  }
210 
211  // find the desired histogramm bin
212  leftsum = 0;
213  if(rank == 0.0)
214  {
215  for(i=0; i<256; i++)
216  {
217  if(hist[i]) break;
218  }
219  rankpos = i;
220  }
221  else
222  {
223  for(i=0; i<256; i++)
224  {
225  if((float)(hist[i]+leftsum) / winsize >= rank) break;
226  leftsum += hist[i];
227  }
228  rankpos = i;
229  }
230 
231  da.set(rankpos, xd);
232 
233  ++xs.x;
234  ++xd.x;
235 
236  // inner columns
237  for(x=1; x<w; ++x, ++xs.x, ++xd.x)
238  {
239  x0 = x;
240  y0 = y;
241  x1 = w - x - 1;
242  y1 = h - y - 1;
243 
244  // update histogramm
245  // remove pixels at left border
246  yy = (y1 < radius) ? y1 : radius;
247  for(; yy>=0; yy--)
248  {
249  unsigned char cur;
250  xx = struct_function[yy]+1;
251  if(xx > x0) break;
252 
253  cur = sa(xs, Diff2D(-xx, yy));
254 
255  hist[cur]--;
256  if(cur < rankpos) leftsum--;
257  winsize--;
258  }
259  yy = (y0 < radius) ? y0 : radius;
260  for(; yy>=1; yy--)
261  {
262  unsigned char cur;
263  xx = struct_function[yy]+1;
264  if(xx > x0) break;
265 
266  cur = sa(xs, Diff2D(-xx, -yy));
267 
268  hist[cur]--;
269  if(cur < rankpos) leftsum--;
270  winsize--;
271  }
272 
273  // add pixels at right border
274  yy = (y1 < radius) ? y1 : radius;
275  for(; yy>=0; yy--)
276  {
277  unsigned char cur;
278  xx = struct_function[yy];
279  if(xx > x1) break;
280 
281  cur = sa(xs, Diff2D(xx, yy));
282 
283  hist[cur]++;
284  if(cur < rankpos) leftsum++;
285  winsize++;
286  }
287  yy = (y0 < radius) ? y0 : radius;
288  for(; yy>=1; yy--)
289  {
290  unsigned char cur;
291  xx = struct_function[yy];
292  if(xx > x1) break;
293 
294  cur = sa(xs, Diff2D(xx, -yy));
295 
296  hist[cur]++;
297  if(cur < rankpos) leftsum++;
298  winsize++;
299  }
300 
301  // find the desired histogramm bin
302  if(rank == 0.0)
303  {
304  if(leftsum == 0)
305  {
306  // search to the right
307  for(i=rankpos; i<256; i++)
308  {
309  if(hist[i]) break;
310  }
311  rankpos = i;
312  }
313  else
314  {
315  // search to the left
316  for(i=rankpos-1; i>=0; i--)
317  {
318  leftsum -= hist[i];
319  if(leftsum == 0) break;
320  }
321  rankpos = i;
322  }
323  }
324  else // rank > 0.0
325  {
326  if((float)leftsum / winsize < rank)
327  {
328  // search to the right
329  for(i=rankpos; i<256; i++)
330  {
331  if((float)(hist[i]+leftsum) / winsize >= rank) break;
332  leftsum+=hist[i];
333  }
334  rankpos = i;
335  }
336  else
337  {
338  // search to the left
339  for(i=rankpos-1; i>=0; i--)
340  {
341  leftsum-=hist[i];
342  if((float)leftsum / winsize < rank) break;
343  }
344  rankpos = i;
345  }
346  }
347 
348  da.set(rankpos, xd);
349  }
350  }
351 }
352 
353 template <class SrcIterator, class SrcAccessor,
354  class DestIterator, class DestAccessor>
355 void
356 discRankOrderFilter(triple<SrcIterator, SrcIterator, SrcAccessor> src,
357  pair<DestIterator, DestAccessor> dest,
358  int radius, float rank)
359 {
360  discRankOrderFilter(src.first, src.second, src.third,
361  dest.first, dest.second,
362  radius, rank);
363 }
364 
365 /********************************************************/
366 /* */
367 /* discErosion */
368 /* */
369 /********************************************************/
370 
371 /** \brief Apply erosion (minimum) filter with disc of given radius to image.
372 
373  This is an abbreviation vor the rank order filter with rank = 0.0.
374  See \ref discRankOrderFilter() for more information.
375 
376  <b> Declarations:</b>
377 
378  pass arguments explicitely:
379  \code
380  namespace vigra {
381  template <class SrcIterator, class SrcAccessor,
382  class DestIterator, class DestAccessor>
383  void
384  discErosion(SrcIterator upperleft1,
385  SrcIterator lowerright1, SrcAccessor sa,
386  DestIterator upperleft2, DestAccessor da,
387  int radius)
388  }
389  \endcode
390 
391 
392  use argument objects in conjunction with \ref ArgumentObjectFactories :
393  \code
394  namespace vigra {
395  template <class SrcIterator, class SrcAccessor,
396  class DestIterator, class DestAccessor>
397  void
398  discErosion(triple<SrcIterator, SrcIterator, SrcAccessor> src,
399  pair<DestIterator, DestAccessor> dest,
400  int radius)
401  }
402  \endcode
403 
404 */
405 doxygen_overloaded_function(template <...> void discErosion)
406 
407 template <class SrcIterator, class SrcAccessor,
408  class DestIterator, class DestAccessor>
409 inline void
410 discErosion(SrcIterator upperleft1,
411  SrcIterator lowerright1, SrcAccessor sa,
412  DestIterator upperleft2, DestAccessor da,
413  int radius)
414 {
415  vigra_precondition(radius >= 0, "discErosion(): Radius must be >= 0.");
416 
417  discRankOrderFilter(upperleft1, lowerright1, sa,
418  upperleft2, da, radius, 0.0);
419 }
420 
421 template <class SrcIterator, class SrcAccessor,
422  class DestIterator, class DestAccessor>
423 void
424 discErosion(triple<SrcIterator, SrcIterator, SrcAccessor> src,
425  pair<DestIterator, DestAccessor> dest,
426  int radius)
427 {
428  vigra_precondition(radius >= 0, "discErosion(): Radius must be >= 0.");
429 
430  discRankOrderFilter(src.first, src.second, src.third,
431  dest.first, dest.second,
432  radius, 0.0);
433 }
434 
435 /********************************************************/
436 /* */
437 /* discDilation */
438 /* */
439 /********************************************************/
440 
441 /** \brief Apply dilation (maximum) filter with disc of given radius to image.
442 
443  This is an abbreviation vor the rank order filter with rank = 1.0.
444  See \ref discRankOrderFilter() for more information.
445 
446  <b> Declarations:</b>
447 
448  pass arguments explicitely:
449  \code
450  namespace vigra {
451  template <class SrcIterator, class SrcAccessor,
452  class DestIterator, class DestAccessor>
453  void
454  discDilation(SrcIterator upperleft1,
455  SrcIterator lowerright1, SrcAccessor sa,
456  DestIterator upperleft2, DestAccessor da,
457  int radius)
458  }
459  \endcode
460 
461 
462  use argument objects in conjunction with \ref ArgumentObjectFactories :
463  \code
464  namespace vigra {
465  template <class SrcIterator, class SrcAccessor,
466  class DestIterator, class DestAccessor>
467  void
468  discDilation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
469  pair<DestIterator, DestAccessor> dest,
470  int radius)
471  }
472  \endcode
473 
474 */
475 doxygen_overloaded_function(template <...> void discDilation)
476 
477 template <class SrcIterator, class SrcAccessor,
478  class DestIterator, class DestAccessor>
479 inline void
480 discDilation(SrcIterator upperleft1,
481  SrcIterator lowerright1, SrcAccessor sa,
482  DestIterator upperleft2, DestAccessor da,
483  int radius)
484 {
485  vigra_precondition(radius >= 0, "discDilation(): Radius must be >= 0.");
486 
487  discRankOrderFilter(upperleft1, lowerright1, sa,
488  upperleft2, da, radius, 1.0);
489 }
490 
491 template <class SrcIterator, class SrcAccessor,
492  class DestIterator, class DestAccessor>
493 void
494 discDilation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
495  pair<DestIterator, DestAccessor> dest,
496  int radius)
497 {
498  vigra_precondition(radius >= 0, "discDilation(): Radius must be >= 0.");
499 
500  discRankOrderFilter(src.first, src.second, src.third,
501  dest.first, dest.second,
502  radius, 1.0);
503 }
504 
505 /********************************************************/
506 /* */
507 /* discMedian */
508 /* */
509 /********************************************************/
510 
511 /** \brief Apply median filter with disc of given radius to image.
512 
513  This is an abbreviation vor the rank order filter with rank = 0.5.
514  See \ref discRankOrderFilter() for more information.
515 
516  <b> Declarations:</b>
517 
518  pass arguments explicitely:
519  \code
520  namespace vigra {
521  template <class SrcIterator, class SrcAccessor,
522  class DestIterator, class DestAccessor>
523  void
524  discMedian(SrcIterator upperleft1,
525  SrcIterator lowerright1, SrcAccessor sa,
526  DestIterator upperleft2, DestAccessor da,
527  int radius)
528  }
529  \endcode
530 
531 
532  use argument objects in conjunction with \ref ArgumentObjectFactories :
533  \code
534  namespace vigra {
535  template <class SrcIterator, class SrcAccessor,
536  class DestIterator, class DestAccessor>
537  void
538  discMedian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
539  pair<DestIterator, DestAccessor> dest,
540  int radius)
541  }
542  \endcode
543 
544 */
545 doxygen_overloaded_function(template <...> void discMedian)
546 
547 template <class SrcIterator, class SrcAccessor,
548  class DestIterator, class DestAccessor>
549 inline void
550 discMedian(SrcIterator upperleft1,
551  SrcIterator lowerright1, SrcAccessor sa,
552  DestIterator upperleft2, DestAccessor da,
553  int radius)
554 {
555  vigra_precondition(radius >= 0, "discMedian(): Radius must be >= 0.");
556 
557  discRankOrderFilter(upperleft1, lowerright1, sa,
558  upperleft2, da, radius, 0.5);
559 }
560 
561 template <class SrcIterator, class SrcAccessor,
562  class DestIterator, class DestAccessor>
563 void
564 discMedian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
565  pair<DestIterator, DestAccessor> dest,
566  int radius)
567 {
568  vigra_precondition(radius >= 0, "discMedian(): Radius must be >= 0.");
569 
570  discRankOrderFilter(src.first, src.second, src.third,
571  dest.first, dest.second,
572  radius, 0.5);
573 }
574 
575 /********************************************************/
576 /* */
577 /* discRankOrderFilterWithMask */
578 /* */
579 /********************************************************/
580 
581 /** \brief Apply rank order filter with disc structuring function to the image
582  using a mask.
583 
584  The pixel values of the source image <b> must</b> be in the range
585  0...255. Radius must be >= 0. Rank must be in the range 0.0 <= rank
586  <= 1.0. The filter acts as a minimum filter if rank = 0.0,
587  as a median if rank = 0.5, and as a maximum filter if rank = 1.0.
588  Accessor are used to access the pixel data.
589 
590  The mask is only applied to th input image, i.e. the function
591  generates an output wherever the current disc contains at least
592  one pixel with mask value 'true'. Source pixels with mask value
593  'false' are ignored during the calculation of the rank order.
594 
595  <b> Declarations:</b>
596 
597  pass arguments explicitely:
598  \code
599  namespace vigra {
600  template <class SrcIterator, class SrcAccessor,
601  class MaskIterator, class MaskAccessor,
602  class DestIterator, class DestAccessor>
603  void
604  discRankOrderFilterWithMask(SrcIterator upperleft1,
605  SrcIterator lowerright1, SrcAccessor sa,
606  MaskIterator upperleftm, MaskAccessor mask,
607  DestIterator upperleft2, DestAccessor da,
608  int radius, float rank)
609  }
610  \endcode
611 
612 
613  group arguments (use in conjunction with \ref ArgumentObjectFactories):
614  \code
615  namespace vigra {
616  template <class SrcIterator, class SrcAccessor,
617  class MaskIterator, class MaskAccessor,
618  class DestIterator, class DestAccessor>
619  void
620  discRankOrderFilterWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src,
621  pair<MaskIterator, MaskAccessor> mask,
622  pair<DestIterator, DestAccessor> dest,
623  int radius, float rank)
624  }
625  \endcode
626 
627  <b> Usage:</b>
628 
629  <b>\#include</b> <<a href="flatmorphology_8hxx-source.html">vigra/flatmorphology.hxx</a>><br>
630  Namespace: vigra
631 
632  \code
633  vigra::CImage src, dest, mask;
634 
635  // do median filtering
636  vigra::discRankOrderFilterWithMask(srcImageRange(src),
637  maskImage(mask), destImage(dest), 10, 0.5);
638  \endcode
639 
640  <b> Required Interface:</b>
641 
642  \code
643  SrcIterator src_upperleft;
644  DestIterator dest_upperleft;
645  MaskIterator mask_upperleft;
646  int x, y;
647  unsigned char value;
648 
649  SrcAccessor src_accessor;
650  DestAccessor dest_accessor;
651  MaskAccessor mask_accessor;
652 
653  mask_accessor(mask_upperleft, x, y) // convertible to bool
654 
655  // value_type of accessor must be convertible to unsigned char
656  value = src_accessor(src_upperleft, x, y);
657 
658  dest_accessor.set(value, dest_upperleft, x, y);
659  \endcode
660 
661  <b> Preconditions:</b>
662 
663  \code
664  for all source pixels: 0 <= value <= 255
665 
666  (rank >= 0.0) && (rank <= 1.0)
667  radius >= 0
668  \endcode
669 
670 */
672 
673 template <class SrcIterator, class SrcAccessor,
674  class MaskIterator, class MaskAccessor,
675  class DestIterator, class DestAccessor>
676 void
677 discRankOrderFilterWithMask(SrcIterator upperleft1,
678  SrcIterator lowerright1, SrcAccessor sa,
679  MaskIterator upperleftm, MaskAccessor mask,
680  DestIterator upperleft2, DestAccessor da,
681  int radius, float rank)
682 {
683  vigra_precondition((rank >= 0.0) && (rank <= 1.0),
684  "discRankOrderFilter(): Rank must be between 0 and 1"
685  " (inclusive).");
686 
687  vigra_precondition(radius >= 0, "discRankOrderFilter(): Radius must be >= 0.");
688 
689  int i, x, y, xmax, ymax, xx, yy;
690  int rankpos, winsize, leftsum;
691 
692  long hist[256];
693 
694  // prepare structuring function
695  std::vector<int> struct_function(radius+1);
696  struct_function[0] = radius;
697 
698  double r2 = (double)radius*radius;
699  for(i=1; i<=radius; ++i)
700  {
701  double r = (double) i - 0.5;
702  struct_function[i] = (int)(VIGRA_CSTD::sqrt(r2 - r*r) + 0.5);
703  }
704 
705  int w = lowerright1.x - upperleft1.x;
706  int h = lowerright1.y - upperleft1.y;
707 
708  SrcIterator ys(upperleft1);
709  MaskIterator ym(upperleftm);
710  DestIterator yd(upperleft2);
711 
712  for(y=0; y<h; ++y, ++ys.y, ++yd.y, ++ym.y)
713  {
714  SrcIterator xs(ys);
715  MaskIterator xm(ym);
716  DestIterator xd(yd);
717 
718  // first column
719  int x0 = 0;
720  int y0 = y;
721  int x1 = w - 1;
722  int y1 = h - y - 1;
723 
724  // clear histogram
725  for(i=0; i<256; ++i) hist[i] = 0;
726  winsize = 0;
727  leftsum = 0;
728  rankpos = 0;
729 
730  // init histogram
731  ymax = (y1 < radius) ? y1 : radius;
732  for(yy=0; yy<=ymax; ++yy)
733  {
734  xmax = (x1 < struct_function[yy]) ? x1 : struct_function[yy];
735  for(xx=0; xx<=xmax; ++xx)
736  {
737  Diff2D pos(xx, yy);
738  if(mask(xm, pos))
739  {
740  hist[sa(xs, pos)]++;
741  winsize++;
742  }
743  }
744  }
745 
746  ymax = (y0 < radius) ? y0 : radius;
747  for(yy=1; yy<=ymax; ++yy)
748  {
749  xmax = (x1 < struct_function[yy]) ? x1 : struct_function[yy];
750  for(xx=0; xx<=xmax; ++xx)
751  {
752  Diff2D pos(xx, -yy);
753  if(mask(xm, pos))
754  {
755  hist[sa(xs, pos)]++;
756  winsize++;
757  }
758  }
759  }
760 
761  // find the desired histogramm bin
762  if(winsize)
763  {
764  if(rank == 0.0)
765  {
766  for(i=0; i<256; i++)
767  {
768  if(hist[i]) break;
769  }
770  rankpos = i;
771  }
772  else
773  {
774  for(i=0; i<256; i++)
775  {
776  if((float)(hist[i]+leftsum) / winsize >= rank) break;
777  leftsum += hist[i];
778  }
779  rankpos = i;
780  }
781 
782  da.set(rankpos, xd);
783  }
784 
785  ++xs.x;
786  ++xd.x;
787  ++xm.x;
788 
789  // inner columns
790  for(x=1; x<w; ++x, ++xs.x, ++xd.x, ++xm.x)
791  {
792  x0 = x;
793  y0 = y;
794  x1 = w - x - 1;
795  y1 = h - y - 1;
796 
797  // update histogramm
798  // remove pixels at left border
799  yy = (y1 < radius) ? y1 : radius;
800  for(; yy>=0; yy--)
801  {
802  unsigned char cur;
803  xx = struct_function[yy]+1;
804  if(xx > x0) break;
805 
806  Diff2D pos(-xx, yy);
807  if(mask(xm, pos))
808  {
809  cur = sa(xs, pos);
810 
811  hist[cur]--;
812  if(cur < rankpos) leftsum--;
813  winsize--;
814  }
815  }
816  yy = (y0 < radius) ? y0 : radius;
817  for(; yy>=1; yy--)
818  {
819  unsigned char cur;
820  xx = struct_function[yy]+1;
821  if(xx > x0) break;
822 
823  Diff2D pos(-xx, -yy);
824  if(mask(xm, pos))
825  {
826  cur = sa(xs, pos);
827 
828  hist[cur]--;
829  if(cur < rankpos) leftsum--;
830  winsize--;
831  }
832  }
833 
834  // add pixels at right border
835  yy = (y1 < radius) ? y1 : radius;
836  for(; yy>=0; yy--)
837  {
838  unsigned char cur;
839  xx = struct_function[yy];
840  if(xx > x1) break;
841 
842  Diff2D pos(xx, yy);
843  if(mask(xm, pos))
844  {
845  cur = sa(xs, pos);
846 
847  hist[cur]++;
848  if(cur < rankpos) leftsum++;
849  winsize++;
850  }
851  }
852  yy = (y0 < radius) ? y0 : radius;
853  for(; yy>=1; yy--)
854  {
855  unsigned char cur;
856  xx = struct_function[yy];
857  if(xx > x1) break;
858 
859  Diff2D pos(xx, -yy);
860  if(mask(xm, pos))
861  {
862  cur = sa(xs, pos);
863 
864  hist[cur]++;
865  if(cur < rankpos) leftsum++;
866  winsize++;
867  }
868  }
869 
870  // find the desired histogramm bin
871  if(winsize)
872  {
873  if(rank == 0.0)
874  {
875  if(leftsum == 0)
876  {
877  // search to the right
878  for(i=rankpos; i<256; i++)
879  {
880  if(hist[i]) break;
881  }
882  rankpos = i;
883  }
884  else
885  {
886  // search to the left
887  for(i=rankpos-1; i>=0; i--)
888  {
889  leftsum -= hist[i];
890  if(leftsum == 0) break;
891  }
892  rankpos = i;
893  }
894  }
895  else // rank > 0.0
896  {
897  if((float)leftsum / winsize < rank)
898  {
899  // search to the right
900  for(i=rankpos; i<256; i++)
901  {
902  if((float)(hist[i]+leftsum) / winsize >= rank) break;
903  leftsum+=hist[i];
904  }
905  rankpos = i;
906  }
907  else
908  {
909  // search to the left
910  for(i=rankpos-1; i>=0; i--)
911  {
912  leftsum-=hist[i];
913  if((float)leftsum / winsize < rank) break;
914  }
915  rankpos = i;
916  }
917  }
918 
919  da.set(rankpos, xd);
920  }
921  else
922  {
923  leftsum = 0;
924  rankpos = 0;
925  }
926  }
927  }
928 }
929 
930 template <class SrcIterator, class SrcAccessor,
931  class MaskIterator, class MaskAccessor,
932  class DestIterator, class DestAccessor>
933 void
934 discRankOrderFilterWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src,
935  pair<MaskIterator, MaskAccessor> mask,
936  pair<DestIterator, DestAccessor> dest,
937  int radius, float rank)
938 {
939  discRankOrderFilterWithMask(src.first, src.second, src.third,
940  mask.first, mask.second,
941  dest.first, dest.second,
942  radius, rank);
943 }
944 
945 /********************************************************/
946 /* */
947 /* discErosionWithMask */
948 /* */
949 /********************************************************/
950 
951 /** \brief Apply erosion (minimum) filter with disc of given radius to image
952  using a mask.
953 
954  This is an abbreviation vor the masked rank order filter with
955  rank = 0.0. See \ref discRankOrderFilterWithMask() for more information.
956 
957  <b> Declarations:</b>
958 
959  pass arguments explicitely:
960  \code
961  namespace vigra {
962  template <class SrcIterator, class SrcAccessor,
963  class MaskIterator, class MaskAccessor,
964  class DestIterator, class DestAccessor>
965  void
966  discErosionWithMask(SrcIterator upperleft1,
967  SrcIterator lowerright1, SrcAccessor sa,
968  MaskIterator upperleftm, MaskAccessor mask,
969  DestIterator upperleft2, DestAccessor da,
970  int radius)
971  }
972  \endcode
973 
974 
975  group arguments (use in conjunction with \ref ArgumentObjectFactories):
976  \code
977  namespace vigra {
978  template <class SrcIterator, class SrcAccessor,
979  class MaskIterator, class MaskAccessor,
980  class DestIterator, class DestAccessor>
981  void
982  discErosionWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src,
983  pair<MaskIterator, MaskAccessor> mask,
984  pair<DestIterator, DestAccessor> dest,
985  int radius)
986  }
987  \endcode
988 
989 */
991 
992 template <class SrcIterator, class SrcAccessor,
993  class MaskIterator, class MaskAccessor,
994  class DestIterator, class DestAccessor>
995 inline void
996 discErosionWithMask(SrcIterator upperleft1,
997  SrcIterator lowerright1, SrcAccessor sa,
998  MaskIterator upperleftm, MaskAccessor mask,
999  DestIterator upperleft2, DestAccessor da,
1000  int radius)
1001 {
1002  vigra_precondition(radius >= 0, "discErosionWithMask(): Radius must be >= 0.");
1003 
1004  discRankOrderFilterWithMask(upperleft1, lowerright1, sa,
1005  upperleftm, mask,
1006  upperleft2, da,
1007  radius, 0.0);
1008 }
1009 
1010 template <class SrcIterator, class SrcAccessor,
1011  class MaskIterator, class MaskAccessor,
1012  class DestIterator, class DestAccessor>
1013 inline void
1014 discErosionWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1015  pair<MaskIterator, MaskAccessor> mask,
1016  pair<DestIterator, DestAccessor> dest,
1017  int radius)
1018 {
1019  vigra_precondition(radius >= 0, "discErosionWithMask(): Radius must be >= 0.");
1020 
1021  discRankOrderFilterWithMask(src.first, src.second, src.third,
1022  mask.first, mask.second,
1023  dest.first, dest.second,
1024  radius, 0.0);
1025 }
1026 
1027 /********************************************************/
1028 /* */
1029 /* discDilationWithMask */
1030 /* */
1031 /********************************************************/
1032 
1033 /** \brief Apply dilation (maximum) filter with disc of given radius to image
1034  using a mask.
1035 
1036  This is an abbreviation vor the masked rank order filter with
1037  rank = 1.0. See \ref discRankOrderFilterWithMask() for more information.
1038 
1039  <b> Declarations:</b>
1040 
1041  pass arguments explicitely:
1042  \code
1043  namespace vigra {
1044  template <class SrcIterator, class SrcAccessor,
1045  class MaskIterator, class MaskAccessor,
1046  class DestIterator, class DestAccessor>
1047  void
1048  discDilationWithMask(SrcIterator upperleft1,
1049  SrcIterator lowerright1, SrcAccessor sa,
1050  MaskIterator upperleftm, MaskAccessor mask,
1051  DestIterator upperleft2, DestAccessor da,
1052  int radius)
1053  }
1054  \endcode
1055 
1056 
1057  group arguments (use in conjunction with \ref ArgumentObjectFactories):
1058  \code
1059  namespace vigra {
1060  template <class SrcIterator, class SrcAccessor,
1061  class MaskIterator, class MaskAccessor,
1062  class DestIterator, class DestAccessor>
1063  void
1064  discDilationWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1065  pair<MaskIterator, MaskAccessor> mask,
1066  pair<DestIterator, DestAccessor> dest,
1067  int radius)
1068  }
1069  \endcode
1070 
1071 */
1073 
1074 template <class SrcIterator, class SrcAccessor,
1075  class MaskIterator, class MaskAccessor,
1076  class DestIterator, class DestAccessor>
1077 inline void
1078 discDilationWithMask(SrcIterator upperleft1,
1079  SrcIterator lowerright1, SrcAccessor sa,
1080  MaskIterator upperleftm, MaskAccessor mask,
1081  DestIterator upperleft2, DestAccessor da,
1082  int radius)
1083 {
1084  vigra_precondition(radius >= 0, "discDilationWithMask(): Radius must be >= 0.");
1085 
1086  discRankOrderFilterWithMask(upperleft1, lowerright1, sa,
1087  upperleftm, mask,
1088  upperleft2, da,
1089  radius, 1.0);
1090 }
1091 
1092 template <class SrcIterator, class SrcAccessor,
1093  class MaskIterator, class MaskAccessor,
1094  class DestIterator, class DestAccessor>
1095 inline void
1096 discDilationWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1097  pair<MaskIterator, MaskAccessor> mask,
1098  pair<DestIterator, DestAccessor> dest,
1099  int radius)
1100 {
1101  vigra_precondition(radius >= 0, "discDilationWithMask(): Radius must be >= 0.");
1102 
1103  discRankOrderFilterWithMask(src.first, src.second, src.third,
1104  mask.first, mask.second,
1105  dest.first, dest.second,
1106  radius, 1.0);
1107 }
1108 
1109 /********************************************************/
1110 /* */
1111 /* discMedianWithMask */
1112 /* */
1113 /********************************************************/
1114 
1115 /** \brief Apply median filter with disc of given radius to image
1116  using a mask.
1117 
1118  This is an abbreviation vor the masked rank order filter with
1119  rank = 0.5. See \ref discRankOrderFilterWithMask() for more information.
1120 
1121  <b> Declarations:</b>
1122 
1123  pass arguments explicitely:
1124  \code
1125  namespace vigra {
1126  template <class SrcIterator, class SrcAccessor,
1127  class MaskIterator, class MaskAccessor,
1128  class DestIterator, class DestAccessor>
1129  void
1130  discMedianWithMask(SrcIterator upperleft1,
1131  SrcIterator lowerright1, SrcAccessor sa,
1132  MaskIterator upperleftm, MaskAccessor mask,
1133  DestIterator upperleft2, DestAccessor da,
1134  int radius)
1135  }
1136  \endcode
1137 
1138 
1139  group arguments (use in conjunction with \ref ArgumentObjectFactories):
1140  \code
1141  namespace vigra {
1142  template <class SrcIterator, class SrcAccessor,
1143  class MaskIterator, class MaskAccessor,
1144  class DestIterator, class DestAccessor>
1145  void
1146  discMedianWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1147  pair<MaskIterator, MaskAccessor> mask,
1148  pair<DestIterator, DestAccessor> dest,
1149  int radius)
1150  }
1151  \endcode
1152 
1153 */
1155 
1156 template <class SrcIterator, class SrcAccessor,
1157  class MaskIterator, class MaskAccessor,
1158  class DestIterator, class DestAccessor>
1159 inline void
1160 discMedianWithMask(SrcIterator upperleft1,
1161  SrcIterator lowerright1, SrcAccessor sa,
1162  MaskIterator upperleftm, MaskAccessor mask,
1163  DestIterator upperleft2, DestAccessor da,
1164  int radius)
1165 {
1166  vigra_precondition(radius >= 0, "discMedianWithMask(): Radius must be >= 0.");
1167 
1168  discRankOrderFilterWithMask(upperleft1, lowerright1, sa,
1169  upperleftm, mask,
1170  upperleft2, da,
1171  radius, 0.5);
1172 }
1173 
1174 template <class SrcIterator, class SrcAccessor,
1175  class MaskIterator, class MaskAccessor,
1176  class DestIterator, class DestAccessor>
1177 inline void
1178 discMedianWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1179  pair<MaskIterator, MaskAccessor> mask,
1180  pair<DestIterator, DestAccessor> dest,
1181  int radius)
1182 {
1183  vigra_precondition(radius >= 0, "discMedianWithMask(): Radius must be >= 0.");
1184 
1185  discRankOrderFilterWithMask(src.first, src.second, src.third,
1186  mask.first, mask.second,
1187  dest.first, dest.second,
1188  radius, 0.5);
1189 }
1190 
1191 //@}
1192 
1193 } // namespace vigra
1194 
1195 #endif // VIGRA_FLATMORPHOLOGY_HXX

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de)
Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany

html generated using doxygen and Python
vigra 1.7.1 (Wed Mar 12 2014)