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

flatmorphology.hxx VIGRA

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 #include "multi_shape.hxx"
44 
45 namespace vigra {
46 
47 /** \addtogroup Morphology Basic Morphological Operations
48  Perform erosion, dilation, and median with disc structuring functions
49 
50  See also: \ref MultiArrayMorphology Separable morphology with parabola structuring functions in arbitrary dimensions
51 */
52 //@{
53 
54 /********************************************************/
55 /* */
56 /* discRankOrderFilter */
57 /* */
58 /********************************************************/
59 
60 /** \brief Apply rank order filter with disc structuring function to the image.
61 
62  The pixel values of the source image <b> must</b> be in the range
63  0...255. Radius must be >= 0. Rank must be in the range 0.0 <= rank
64  <= 1.0. The filter acts as a minimum filter if rank = 0.0,
65  as a median if rank = 0.5, and as a maximum filter if rank = 1.0.
66  Accessor are used to access the pixel data.
67 
68  <b> Declarations:</b>
69 
70  pass 2D array views:
71  \code
72  namespace vigra {
73  template <class T1, class S1,
74  class T2, class S2>
75  void
76  discRankOrderFilter(MultiArrayView<2, T1, S1> const & src,
77  MultiArrayView<2, T2, S2> dest,
78  int radius, float rank);
79  }
80  \endcode
81 
82  \deprecatedAPI{discRankOrderFilter}
83  pass \ref ImageIterators and \ref DataAccessors :
84  \code
85  namespace vigra {
86  template <class SrcIterator, class SrcAccessor,
87  class DestIterator, class DestAccessor>
88  void
89  discRankOrderFilter(SrcIterator upperleft1,
90  SrcIterator lowerright1, SrcAccessor sa,
91  DestIterator upperleft2, DestAccessor da,
92  int radius, float rank)
93  }
94  \endcode
95  use argument objects in conjunction with \ref ArgumentObjectFactories :
96  \code
97  namespace vigra {
98  template <class SrcIterator, class SrcAccessor,
99  class DestIterator, class DestAccessor>
100  void
101  discRankOrderFilter(triple<SrcIterator, SrcIterator, SrcAccessor> src,
102  pair<DestIterator, DestAccessor> dest,
103  int radius, float rank)
104  }
105  \endcode
106  \deprecatedEnd
107 
108  <b> Usage:</b>
109 
110  <b>\#include</b> <vigra/flatmorphology.hxx><br>
111  Namespace: vigra
112 
113  \code
114  MultiArray<2, unsigned char> src(w, h), dest(w, h);
115 
116  // do median filtering (because rank=0.5) in a cricle with radius 10
117  discRankOrderFilter(src, dest, 10, 0.5);
118  \endcode
119 
120  \deprecatedUsage{discRankOrderFilter}
121  \code
122  vigra::CImage src, dest;
123 
124  // do median filtering
125  vigra::discRankOrderFilter(srcImageRange(src), destImage(dest), 10, 0.5);
126  \endcode
127  <b> Required Interface:</b>
128  \code
129  SrcIterator src_upperleft;
130  DestIterator dest_upperleft;
131  int x, y;
132  unsigned char value;
133 
134  SrcAccessor src_accessor;
135  DestAccessor dest_accessor;
136 
137  // value_type of accessor must be convertible to unsigned char
138  value = src_accessor(src_upperleft, x, y);
139 
140  dest_accessor.set(value, dest_upperleft, x, y);
141  \endcode
142  \deprecatedEnd
143 
144  <b> Preconditions:</b>
145 
146  \code
147  for all source pixels: 0 <= value <= 255
148 
149  (rank >= 0.0) && (rank <= 1.0)
150  radius >= 0
151  \endcode
152 */
154 
155 template <class SrcIterator, class SrcAccessor,
156  class DestIterator, class DestAccessor>
157 void
158 discRankOrderFilter(SrcIterator upperleft1,
159  SrcIterator lowerright1, SrcAccessor sa,
160  DestIterator upperleft2, DestAccessor da,
161  int radius, float rank)
162 {
163  vigra_precondition((rank >= 0.0) && (rank <= 1.0),
164  "discRankOrderFilter(): Rank must be between 0 and 1"
165  " (inclusive).");
166 
167  vigra_precondition(radius >= 0,
168  "discRankOrderFilter(): Radius must be >= 0.");
169 
170  int i, x, y, xmax, ymax, xx, yy;
171  int rankpos, winsize, leftsum;
172 
173  long hist[256];
174 
175  // prepare structuring function
176  std::vector<int> struct_function(radius+1);
177  struct_function[0] = radius;
178 
179  double r2 = (double)radius*radius;
180  for(i=1; i<=radius; ++i)
181  {
182  double r = (double) i - 0.5;
183  struct_function[i] = (int)(VIGRA_CSTD::sqrt(r2 - r*r) + 0.5);
184  }
185 
186  int w = lowerright1.x - upperleft1.x;
187  int h = lowerright1.y - upperleft1.y;
188 
189  SrcIterator ys(upperleft1);
190  DestIterator yd(upperleft2);
191 
192  for(y=0; y<h; ++y, ++ys.y, ++yd.y)
193  {
194  SrcIterator xs(ys);
195  DestIterator xd(yd);
196 
197  // first column
198  int x0 = 0;
199  int y0 = y;
200  int x1 = w - 1;
201  int y1 = h - y - 1;
202 
203  // clear histogram
204  for(i=0; i<256; ++i) hist[i] = 0;
205  winsize = 0;
206 
207  // init histogram
208  ymax = (y1 < radius) ? y1 : radius;
209  for(yy=0; yy<=ymax; ++yy)
210  {
211  xmax = (x1 < struct_function[yy]) ? x1 : struct_function[yy];
212  for(xx=0; xx<=xmax; ++xx)
213  {
214  hist[sa(xs, Diff2D(xx, yy))]++;
215  winsize++;
216  }
217  }
218 
219  ymax = (y0 < radius) ? y0 : radius;
220  for(yy=1; yy<=ymax; ++yy)
221  {
222  xmax = (x1 < struct_function[yy]) ? x1 : struct_function[yy];
223  for(xx=0; xx<=xmax; ++xx)
224  {
225  hist[sa(xs, Diff2D(xx, -yy))]++;
226  winsize++;
227  }
228  }
229 
230  // find the desired histogram bin
231  leftsum = 0;
232  if(rank == 0.0)
233  {
234  for(i=0; i<256; i++)
235  {
236  if(hist[i]) break;
237  }
238  rankpos = i;
239  }
240  else
241  {
242  for(i=0; i<256; i++)
243  {
244  if((float)(hist[i]+leftsum) / winsize >= rank) break;
245  leftsum += hist[i];
246  }
247  rankpos = i;
248  }
249 
250  da.set(rankpos, xd);
251 
252  ++xs.x;
253  ++xd.x;
254 
255  // inner columns
256  for(x=1; x<w; ++x, ++xs.x, ++xd.x)
257  {
258  x0 = x;
259  y0 = y;
260  x1 = w - x - 1;
261  y1 = h - y - 1;
262 
263  // update histogram
264  // remove pixels at left border
265  yy = (y1 < radius) ? y1 : radius;
266  for(; yy>=0; yy--)
267  {
268  unsigned char cur;
269  xx = struct_function[yy]+1;
270  if(xx > x0) break;
271 
272  cur = sa(xs, Diff2D(-xx, yy));
273 
274  hist[cur]--;
275  if(cur < rankpos) leftsum--;
276  winsize--;
277  }
278  yy = (y0 < radius) ? y0 : radius;
279  for(; yy>=1; yy--)
280  {
281  unsigned char cur;
282  xx = struct_function[yy]+1;
283  if(xx > x0) break;
284 
285  cur = sa(xs, Diff2D(-xx, -yy));
286 
287  hist[cur]--;
288  if(cur < rankpos) leftsum--;
289  winsize--;
290  }
291 
292  // add pixels at right border
293  yy = (y1 < radius) ? y1 : radius;
294  for(; yy>=0; yy--)
295  {
296  unsigned char cur;
297  xx = struct_function[yy];
298  if(xx > x1) break;
299 
300  cur = sa(xs, Diff2D(xx, yy));
301 
302  hist[cur]++;
303  if(cur < rankpos) leftsum++;
304  winsize++;
305  }
306  yy = (y0 < radius) ? y0 : radius;
307  for(; yy>=1; yy--)
308  {
309  unsigned char cur;
310  xx = struct_function[yy];
311  if(xx > x1) break;
312 
313  cur = sa(xs, Diff2D(xx, -yy));
314 
315  hist[cur]++;
316  if(cur < rankpos) leftsum++;
317  winsize++;
318  }
319 
320  // find the desired histogram bin
321  if(rank == 0.0)
322  {
323  if(leftsum == 0)
324  {
325  // search to the right
326  for(i=rankpos; i<256; i++)
327  {
328  if(hist[i]) break;
329  }
330  rankpos = i;
331  }
332  else
333  {
334  // search to the left
335  for(i=rankpos-1; i>=0; i--)
336  {
337  leftsum -= hist[i];
338  if(leftsum == 0) break;
339  }
340  rankpos = i;
341  }
342  }
343  else // rank > 0.0
344  {
345  if((float)leftsum / winsize < rank)
346  {
347  // search to the right
348  for(i=rankpos; i<256; i++)
349  {
350  if((float)(hist[i]+leftsum) / winsize >= rank) break;
351  leftsum+=hist[i];
352  }
353  rankpos = i;
354  }
355  else
356  {
357  // search to the left
358  for(i=rankpos-1; i>=0; i--)
359  {
360  leftsum-=hist[i];
361  if((float)leftsum / winsize < rank) break;
362  }
363  rankpos = i;
364  }
365  }
366 
367  da.set(rankpos, xd);
368  }
369  }
370 }
371 
372 template <class SrcIterator, class SrcAccessor,
373  class DestIterator, class DestAccessor>
374 inline void
375 discRankOrderFilter(triple<SrcIterator, SrcIterator, SrcAccessor> src,
376  pair<DestIterator, DestAccessor> dest,
377  int radius, float rank)
378 {
379  discRankOrderFilter(src.first, src.second, src.third,
380  dest.first, dest.second,
381  radius, rank);
382 }
383 
384 template <class T1, class S1,
385  class T2, class S2>
386 inline void
387 discRankOrderFilter(MultiArrayView<2, T1, S1> const & src,
388  MultiArrayView<2, T2, S2> dest,
389  int radius, float rank)
390 {
391  vigra_precondition(src.shape() == dest.shape(),
392  "discRankOrderFilter(): shape mismatch between input and output.");
393  discRankOrderFilter(srcImageRange(src),
394  destImage(dest),
395  radius, rank);
396 }
397 
398 /********************************************************/
399 /* */
400 /* discErosion */
401 /* */
402 /********************************************************/
403 
404 /** \brief Apply erosion (minimum) filter with disc of given radius to image.
405 
406  This is an abbreviation for the rank order filter with rank = 0.0.
407  See \ref discRankOrderFilter() for more information.
408 
409  <b> Declarations:</b>
410 
411  pass 2D array views:
412  \code
413  namespace vigra {
414  template <class T1, class S1,
415  class T2, class S2>
416  void
417  discErosion(MultiArrayView<2, T1, S1> const & src,
418  MultiArrayView<2, T2, S2> dest,
419  int radius);
420  }
421  \endcode
422 
423  \deprecatedAPI{discErosion}
424  pass \ref ImageIterators and \ref DataAccessors :
425  \code
426  namespace vigra {
427  template <class SrcIterator, class SrcAccessor,
428  class DestIterator, class DestAccessor>
429  void
430  discErosion(SrcIterator upperleft1,
431  SrcIterator lowerright1, SrcAccessor sa,
432  DestIterator upperleft2, DestAccessor da,
433  int radius)
434  }
435  \endcode
436  use argument objects in conjunction with \ref ArgumentObjectFactories :
437  \code
438  namespace vigra {
439  template <class SrcIterator, class SrcAccessor,
440  class DestIterator, class DestAccessor>
441  void
442  discErosion(triple<SrcIterator, SrcIterator, SrcAccessor> src,
443  pair<DestIterator, DestAccessor> dest,
444  int radius)
445  }
446  \endcode
447  \deprecatedEnd
448 */
449 doxygen_overloaded_function(template <...> void discErosion)
450 
451 template <class SrcIterator, class SrcAccessor,
452  class DestIterator, class DestAccessor>
453 inline void
454 discErosion(SrcIterator upperleft1,
455  SrcIterator lowerright1, SrcAccessor sa,
456  DestIterator upperleft2, DestAccessor da,
457  int radius)
458 {
459  vigra_precondition(radius >= 0, "discErosion(): Radius must be >= 0.");
460 
461  discRankOrderFilter(upperleft1, lowerright1, sa,
462  upperleft2, da, radius, 0.0);
463 }
464 
465 template <class SrcIterator, class SrcAccessor,
466  class DestIterator, class DestAccessor>
467 void
468 discErosion(triple<SrcIterator, SrcIterator, SrcAccessor> src,
469  pair<DestIterator, DestAccessor> dest,
470  int radius)
471 {
472  vigra_precondition(radius >= 0, "discErosion(): Radius must be >= 0.");
473 
474  discRankOrderFilter(src.first, src.second, src.third,
475  dest.first, dest.second,
476  radius, 0.0);
477 }
478 
479 template <class T1, class S1,
480  class T2, class S2>
481 inline void
482 discErosion(MultiArrayView<2, T1, S1> const & src,
483  MultiArrayView<2, T2, S2> dest,
484  int radius)
485 {
486  vigra_precondition(src.shape() == dest.shape(),
487  "discErosion(): shape mismatch between input and output.");
488  discErosion(srcImageRange(src), destImage(dest), radius);
489 }
490 
491 /********************************************************/
492 /* */
493 /* discDilation */
494 /* */
495 /********************************************************/
496 
497 /** \brief Apply dilation (maximum) filter with disc of given radius to image.
498 
499  This is an abbreviation for the rank order filter with rank = 1.0.
500  See \ref discRankOrderFilter() for more information.
501 
502  <b> Declarations:</b>
503 
504  pass 2D array views:
505  \code
506  namespace vigra {
507  template <class T1, class S1,
508  class T2, class S2>
509  void
510  discDilation(MultiArrayView<2, T1, S1> const & src,
511  MultiArrayView<2, T2, S2> dest,
512  int radius);
513  }
514  \endcode
515 
516  \deprecatedAPI{discDilation}
517  pass \ref ImageIterators and \ref DataAccessors :
518  \code
519  namespace vigra {
520  template <class SrcIterator, class SrcAccessor,
521  class DestIterator, class DestAccessor>
522  void
523  discDilation(SrcIterator upperleft1,
524  SrcIterator lowerright1, SrcAccessor sa,
525  DestIterator upperleft2, DestAccessor da,
526  int radius)
527  }
528  \endcode
529  use argument objects in conjunction with \ref ArgumentObjectFactories :
530  \code
531  namespace vigra {
532  template <class SrcIterator, class SrcAccessor,
533  class DestIterator, class DestAccessor>
534  void
535  discDilation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
536  pair<DestIterator, DestAccessor> dest,
537  int radius)
538  }
539  \endcode
540  \deprecatedEnd
541 */
542 doxygen_overloaded_function(template <...> void discDilation)
543 
544 template <class SrcIterator, class SrcAccessor,
545  class DestIterator, class DestAccessor>
546 inline void
547 discDilation(SrcIterator upperleft1,
548  SrcIterator lowerright1, SrcAccessor sa,
549  DestIterator upperleft2, DestAccessor da,
550  int radius)
551 {
552  vigra_precondition(radius >= 0, "discDilation(): Radius must be >= 0.");
553 
554  discRankOrderFilter(upperleft1, lowerright1, sa,
555  upperleft2, da, radius, 1.0);
556 }
557 
558 template <class SrcIterator, class SrcAccessor,
559  class DestIterator, class DestAccessor>
560 void
561 discDilation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
562  pair<DestIterator, DestAccessor> dest,
563  int radius)
564 {
565  vigra_precondition(radius >= 0, "discDilation(): Radius must be >= 0.");
566 
567  discRankOrderFilter(src.first, src.second, src.third,
568  dest.first, dest.second,
569  radius, 1.0);
570 }
571 
572 template <class T1, class S1,
573  class T2, class S2>
574 inline void
575 discDilation(MultiArrayView<2, T1, S1> const & src,
576  MultiArrayView<2, T2, S2> dest,
577  int radius)
578 {
579  vigra_precondition(src.shape() == dest.shape(),
580  "discDilation(): shape mismatch between input and output.");
581  discDilation(srcImageRange(src), destImage(dest), radius);
582 }
583 
584 /********************************************************/
585 /* */
586 /* discMedian */
587 /* */
588 /********************************************************/
589 
590 /** \brief Apply median filter with disc of given radius to image.
591 
592  This is an abbreviation for the rank order filter with rank = 0.5.
593  See \ref discRankOrderFilter() for more information.
594 
595  <b> Declarations:</b>
596 
597  pass 2D array views:
598  \code
599  namespace vigra {
600  template <class T1, class S1,
601  class T2, class S2>
602  void
603  discMedian(MultiArrayView<2, T1, S1> const & src,
604  MultiArrayView<2, T2, S2> dest,
605  int radius);
606  }
607  \endcode
608 
609  \deprecatedAPI{discMedian}
610  pass \ref ImageIterators and \ref DataAccessors :
611  \code
612  namespace vigra {
613  template <class SrcIterator, class SrcAccessor,
614  class DestIterator, class DestAccessor>
615  void
616  discMedian(SrcIterator upperleft1,
617  SrcIterator lowerright1, SrcAccessor sa,
618  DestIterator upperleft2, DestAccessor da,
619  int radius)
620  }
621  \endcode
622  use argument objects in conjunction with \ref ArgumentObjectFactories :
623  \code
624  namespace vigra {
625  template <class SrcIterator, class SrcAccessor,
626  class DestIterator, class DestAccessor>
627  void
628  discMedian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
629  pair<DestIterator, DestAccessor> dest,
630  int radius)
631  }
632  \endcode
633  \deprecatedEnd
634 */
635 doxygen_overloaded_function(template <...> void discMedian)
636 
637 template <class SrcIterator, class SrcAccessor,
638  class DestIterator, class DestAccessor>
639 inline void
640 discMedian(SrcIterator upperleft1,
641  SrcIterator lowerright1, SrcAccessor sa,
642  DestIterator upperleft2, DestAccessor da,
643  int radius)
644 {
645  vigra_precondition(radius >= 0, "discMedian(): Radius must be >= 0.");
646 
647  discRankOrderFilter(upperleft1, lowerright1, sa,
648  upperleft2, da, radius, 0.5);
649 }
650 
651 template <class SrcIterator, class SrcAccessor,
652  class DestIterator, class DestAccessor>
653 void
654 discMedian(triple<SrcIterator, SrcIterator, SrcAccessor> src,
655  pair<DestIterator, DestAccessor> dest,
656  int radius)
657 {
658  vigra_precondition(radius >= 0, "discMedian(): Radius must be >= 0.");
659 
660  discRankOrderFilter(src.first, src.second, src.third,
661  dest.first, dest.second,
662  radius, 0.5);
663 }
664 
665 template <class T1, class S1,
666  class T2, class S2>
667 inline void
668 discMedian(MultiArrayView<2, T1, S1> const & src,
669  MultiArrayView<2, T2, S2> dest,
670  int radius)
671 {
672  vigra_precondition(src.shape() == dest.shape(),
673  "discMedian(): shape mismatch between input and output.");
674  discMedian(srcImageRange(src), destImage(dest), radius);
675 }
676 
677 /********************************************************/
678 /* */
679 /* discRankOrderFilterWithMask */
680 /* */
681 /********************************************************/
682 
683 /** \brief Apply rank order filter with disc structuring function to the image
684  using a mask.
685 
686  The pixel values of the source image <b> must</b> be in the range
687  0...255. Radius must be >= 0. Rank must be in the range 0.0 <= rank
688  <= 1.0. The filter acts as a minimum filter if rank = 0.0,
689  as a median if rank = 0.5, and as a maximum filter if rank = 1.0.
690  Accessor are used to access the pixel data.
691 
692  The mask is only applied to th input image, i.e. the function
693  generates an output wherever the current disc contains at least
694  one pixel with mask value 'true'. Source pixels with mask value
695  'false' are ignored during the calculation of the rank order.
696 
697  <b> Declarations:</b>
698 
699  pass 2D array views:
700  \code
701  namespace vigra {
702  template <class T1, class S1,
703  class TM, class SM,
704  class T2, class S2>
705  void
706  discRankOrderFilterWithMask(MultiArrayView<2, T1, S1> const & src,
707  MultiArrayView<2, TM, SM> const & mask,
708  MultiArrayView<2, T2, S2> dest,
709  int radius, float rank);
710  }
711  \endcode
712 
713  \deprecatedAPI{discRankOrderFilterWithMask}
714  pass \ref ImageIterators and \ref DataAccessors :
715  \code
716  namespace vigra {
717  template <class SrcIterator, class SrcAccessor,
718  class MaskIterator, class MaskAccessor,
719  class DestIterator, class DestAccessor>
720  void
721  discRankOrderFilterWithMask(SrcIterator upperleft1,
722  SrcIterator lowerright1, SrcAccessor sa,
723  MaskIterator upperleftm, MaskAccessor mask,
724  DestIterator upperleft2, DestAccessor da,
725  int radius, float rank)
726  }
727  \endcode
728  group arguments (use in conjunction with \ref ArgumentObjectFactories):
729  \code
730  namespace vigra {
731  template <class SrcIterator, class SrcAccessor,
732  class MaskIterator, class MaskAccessor,
733  class DestIterator, class DestAccessor>
734  void
735  discRankOrderFilterWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src,
736  pair<MaskIterator, MaskAccessor> mask,
737  pair<DestIterator, DestAccessor> dest,
738  int radius, float rank)
739  }
740  \endcode
741  \deprecatedEnd
742 
743  <b> Usage:</b>
744 
745  <b>\#include</b> <vigra/flatmorphology.hxx><br>
746  Namespace: vigra
747 
748  \code
749  MultiArray<2, unsigned char> src(w, h), dest(w, h), mask(w, h);
750  ...
751  // do median filtering (since rank=0.5) in a circle with radius 10
752  // but change only the pixels under the mask
753  discRankOrderFilterWithMask(src, mask, dest, 10, 0.5);
754  \endcode
755 
756  \deprecatedUsage{discRankOrderFilterWithMask}
757  \code
758  vigra::CImage src, dest, mask;
759 
760  // do median filtering
761  vigra::discRankOrderFilterWithMask(srcImageRange(src),
762  maskImage(mask), destImage(dest), 10, 0.5);
763  \endcode
764  <b> Required Interface:</b>
765  \code
766  SrcIterator src_upperleft;
767  DestIterator dest_upperleft;
768  MaskIterator mask_upperleft;
769  int x, y;
770  unsigned char value;
771 
772  SrcAccessor src_accessor;
773  DestAccessor dest_accessor;
774  MaskAccessor mask_accessor;
775 
776  mask_accessor(mask_upperleft, x, y) // convertible to bool
777 
778  // value_type of accessor must be convertible to unsigned char
779  value = src_accessor(src_upperleft, x, y);
780 
781  dest_accessor.set(value, dest_upperleft, x, y);
782  \endcode
783  \deprecatedEnd
784 
785  <b> Preconditions:</b>
786 
787  \code
788  for all source pixels: 0 <= value <= 255
789 
790  (rank >= 0.0) && (rank <= 1.0)
791  radius >= 0
792  \endcode
793 */
795 
796 template <class SrcIterator, class SrcAccessor,
797  class MaskIterator, class MaskAccessor,
798  class DestIterator, class DestAccessor>
799 void
800 discRankOrderFilterWithMask(SrcIterator upperleft1,
801  SrcIterator lowerright1, SrcAccessor sa,
802  MaskIterator upperleftm, MaskAccessor mask,
803  DestIterator upperleft2, DestAccessor da,
804  int radius, float rank)
805 {
806  vigra_precondition((rank >= 0.0) && (rank <= 1.0),
807  "discRankOrderFilter(): Rank must be between 0 and 1"
808  " (inclusive).");
809 
810  vigra_precondition(radius >= 0, "discRankOrderFilter(): Radius must be >= 0.");
811 
812  int i, x, y, xmax, ymax, xx, yy;
813  int rankpos, winsize, leftsum;
814 
815  long hist[256];
816 
817  // prepare structuring function
818  std::vector<int> struct_function(radius+1);
819  struct_function[0] = radius;
820 
821  double r2 = (double)radius*radius;
822  for(i=1; i<=radius; ++i)
823  {
824  double r = (double) i - 0.5;
825  struct_function[i] = (int)(VIGRA_CSTD::sqrt(r2 - r*r) + 0.5);
826  }
827 
828  int w = lowerright1.x - upperleft1.x;
829  int h = lowerright1.y - upperleft1.y;
830 
831  SrcIterator ys(upperleft1);
832  MaskIterator ym(upperleftm);
833  DestIterator yd(upperleft2);
834 
835  for(y=0; y<h; ++y, ++ys.y, ++yd.y, ++ym.y)
836  {
837  SrcIterator xs(ys);
838  MaskIterator xm(ym);
839  DestIterator xd(yd);
840 
841  // first column
842  int x0 = 0;
843  int y0 = y;
844  int x1 = w - 1;
845  int y1 = h - y - 1;
846 
847  // clear histogram
848  for(i=0; i<256; ++i) hist[i] = 0;
849  winsize = 0;
850  leftsum = 0;
851  rankpos = 0;
852 
853  // init histogram
854  ymax = (y1 < radius) ? y1 : radius;
855  for(yy=0; yy<=ymax; ++yy)
856  {
857  xmax = (x1 < struct_function[yy]) ? x1 : struct_function[yy];
858  for(xx=0; xx<=xmax; ++xx)
859  {
860  Diff2D pos(xx, yy);
861  if(mask(xm, pos))
862  {
863  hist[sa(xs, pos)]++;
864  winsize++;
865  }
866  }
867  }
868 
869  ymax = (y0 < radius) ? y0 : radius;
870  for(yy=1; yy<=ymax; ++yy)
871  {
872  xmax = (x1 < struct_function[yy]) ? x1 : struct_function[yy];
873  for(xx=0; xx<=xmax; ++xx)
874  {
875  Diff2D pos(xx, -yy);
876  if(mask(xm, pos))
877  {
878  hist[sa(xs, pos)]++;
879  winsize++;
880  }
881  }
882  }
883 
884  // find the desired histogram bin
885  if(winsize)
886  {
887  if(rank == 0.0)
888  {
889  for(i=0; i<256; i++)
890  {
891  if(hist[i]) break;
892  }
893  rankpos = i;
894  }
895  else
896  {
897  for(i=0; i<256; i++)
898  {
899  if((float)(hist[i]+leftsum) / winsize >= rank) break;
900  leftsum += hist[i];
901  }
902  rankpos = i;
903  }
904 
905  da.set(rankpos, xd);
906  }
907 
908  ++xs.x;
909  ++xd.x;
910  ++xm.x;
911 
912  // inner columns
913  for(x=1; x<w; ++x, ++xs.x, ++xd.x, ++xm.x)
914  {
915  x0 = x;
916  y0 = y;
917  x1 = w - x - 1;
918  y1 = h - y - 1;
919 
920  // update histogram
921  // remove pixels at left border
922  yy = (y1 < radius) ? y1 : radius;
923  for(; yy>=0; yy--)
924  {
925  unsigned char cur;
926  xx = struct_function[yy]+1;
927  if(xx > x0) break;
928 
929  Diff2D pos(-xx, yy);
930  if(mask(xm, pos))
931  {
932  cur = sa(xs, pos);
933 
934  hist[cur]--;
935  if(cur < rankpos) leftsum--;
936  winsize--;
937  }
938  }
939  yy = (y0 < radius) ? y0 : radius;
940  for(; yy>=1; yy--)
941  {
942  unsigned char cur;
943  xx = struct_function[yy]+1;
944  if(xx > x0) break;
945 
946  Diff2D pos(-xx, -yy);
947  if(mask(xm, pos))
948  {
949  cur = sa(xs, pos);
950 
951  hist[cur]--;
952  if(cur < rankpos) leftsum--;
953  winsize--;
954  }
955  }
956 
957  // add pixels at right border
958  yy = (y1 < radius) ? y1 : radius;
959  for(; yy>=0; yy--)
960  {
961  unsigned char cur;
962  xx = struct_function[yy];
963  if(xx > x1) break;
964 
965  Diff2D pos(xx, yy);
966  if(mask(xm, pos))
967  {
968  cur = sa(xs, pos);
969 
970  hist[cur]++;
971  if(cur < rankpos) leftsum++;
972  winsize++;
973  }
974  }
975  yy = (y0 < radius) ? y0 : radius;
976  for(; yy>=1; yy--)
977  {
978  unsigned char cur;
979  xx = struct_function[yy];
980  if(xx > x1) break;
981 
982  Diff2D pos(xx, -yy);
983  if(mask(xm, pos))
984  {
985  cur = sa(xs, pos);
986 
987  hist[cur]++;
988  if(cur < rankpos) leftsum++;
989  winsize++;
990  }
991  }
992 
993  // find the desired histogram bin
994  if(winsize)
995  {
996  if(rank == 0.0)
997  {
998  if(leftsum == 0)
999  {
1000  // search to the right
1001  for(i=rankpos; i<256; i++)
1002  {
1003  if(hist[i]) break;
1004  }
1005  rankpos = i;
1006  }
1007  else
1008  {
1009  // search to the left
1010  for(i=rankpos-1; i>=0; i--)
1011  {
1012  leftsum -= hist[i];
1013  if(leftsum == 0) break;
1014  }
1015  rankpos = i;
1016  }
1017  }
1018  else // rank > 0.0
1019  {
1020  if((float)leftsum / winsize < rank)
1021  {
1022  // search to the right
1023  for(i=rankpos; i<256; i++)
1024  {
1025  if((float)(hist[i]+leftsum) / winsize >= rank) break;
1026  leftsum+=hist[i];
1027  }
1028  rankpos = i;
1029  }
1030  else
1031  {
1032  // search to the left
1033  for(i=rankpos-1; i>=0; i--)
1034  {
1035  leftsum-=hist[i];
1036  if((float)leftsum / winsize < rank) break;
1037  }
1038  rankpos = i;
1039  }
1040  }
1041 
1042  da.set(rankpos, xd);
1043  }
1044  else
1045  {
1046  leftsum = 0;
1047  rankpos = 0;
1048  }
1049  }
1050  }
1051 }
1052 
1053 template <class SrcIterator, class SrcAccessor,
1054  class MaskIterator, class MaskAccessor,
1055  class DestIterator, class DestAccessor>
1056 inline void
1057 discRankOrderFilterWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1058  pair<MaskIterator, MaskAccessor> mask,
1059  pair<DestIterator, DestAccessor> dest,
1060  int radius, float rank)
1061 {
1062  discRankOrderFilterWithMask(src.first, src.second, src.third,
1063  mask.first, mask.second,
1064  dest.first, dest.second,
1065  radius, rank);
1066 }
1067 
1068 template <class T1, class S1,
1069  class TM, class SM,
1070  class T2, class S2>
1071 inline void
1072 discRankOrderFilterWithMask(MultiArrayView<2, T1, S1> const & src,
1073  MultiArrayView<2, TM, SM> const & mask,
1074  MultiArrayView<2, T2, S2> dest,
1075  int radius, float rank)
1076 {
1077  vigra_precondition(src.shape() == mask.shape() && src.shape() == dest.shape(),
1078  "discRankOrderFilterWithMask(): shape mismatch between input and output.");
1079  discRankOrderFilterWithMask(srcImageRange(src),
1080  maskImage(mask),
1081  destImage(dest),
1082  radius, rank);
1083 }
1084 
1085 /********************************************************/
1086 /* */
1087 /* discErosionWithMask */
1088 /* */
1089 /********************************************************/
1090 
1091 /** \brief Apply erosion (minimum) filter with disc of given radius to image
1092  using a mask.
1093 
1094  This is an abbreviation for the masked rank order filter with
1095  rank = 0.0. See \ref discRankOrderFilterWithMask() for more information.
1096 
1097  <b> Declarations:</b>
1098 
1099  pass 2D array views:
1100  \code
1101  namespace vigra {
1102  template <class T1, class S1,
1103  class TM, class SM,
1104  class T2, class S2>
1105  void
1106  discErosionWithMask(MultiArrayView<2, T1, S1> const & src,
1107  MultiArrayView<2, TM, SM> const & mask,
1108  MultiArrayView<2, T2, S2> dest,
1109  int radius);
1110  }
1111  \endcode
1112 
1113  \deprecatedAPI{discErosionWithMask}
1114  pass \ref ImageIterators and \ref DataAccessors :
1115  \code
1116  namespace vigra {
1117  template <class SrcIterator, class SrcAccessor,
1118  class MaskIterator, class MaskAccessor,
1119  class DestIterator, class DestAccessor>
1120  void
1121  discErosionWithMask(SrcIterator upperleft1,
1122  SrcIterator lowerright1, SrcAccessor sa,
1123  MaskIterator upperleftm, MaskAccessor mask,
1124  DestIterator upperleft2, DestAccessor da,
1125  int radius)
1126  }
1127  \endcode
1128  group arguments (use in conjunction with \ref ArgumentObjectFactories):
1129  \code
1130  namespace vigra {
1131  template <class SrcIterator, class SrcAccessor,
1132  class MaskIterator, class MaskAccessor,
1133  class DestIterator, class DestAccessor>
1134  void
1135  discErosionWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1136  pair<MaskIterator, MaskAccessor> mask,
1137  pair<DestIterator, DestAccessor> dest,
1138  int radius)
1139  }
1140  \endcode
1141  \deprecatedEnd
1142 */
1144 
1145 template <class SrcIterator, class SrcAccessor,
1146  class MaskIterator, class MaskAccessor,
1147  class DestIterator, class DestAccessor>
1148 inline void
1149 discErosionWithMask(SrcIterator upperleft1,
1150  SrcIterator lowerright1, SrcAccessor sa,
1151  MaskIterator upperleftm, MaskAccessor mask,
1152  DestIterator upperleft2, DestAccessor da,
1153  int radius)
1154 {
1155  vigra_precondition(radius >= 0, "discErosionWithMask(): Radius must be >= 0.");
1156 
1157  discRankOrderFilterWithMask(upperleft1, lowerright1, sa,
1158  upperleftm, mask,
1159  upperleft2, da,
1160  radius, 0.0);
1161 }
1162 
1163 template <class SrcIterator, class SrcAccessor,
1164  class MaskIterator, class MaskAccessor,
1165  class DestIterator, class DestAccessor>
1166 inline void
1167 discErosionWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1168  pair<MaskIterator, MaskAccessor> mask,
1169  pair<DestIterator, DestAccessor> dest,
1170  int radius)
1171 {
1172  vigra_precondition(radius >= 0, "discErosionWithMask(): Radius must be >= 0.");
1173 
1174  discRankOrderFilterWithMask(src.first, src.second, src.third,
1175  mask.first, mask.second,
1176  dest.first, dest.second,
1177  radius, 0.0);
1178 }
1179 
1180 template <class T1, class S1,
1181  class TM, class SM,
1182  class T2, class S2>
1183 inline void
1184 discErosionWithMask(MultiArrayView<2, T1, S1> const & src,
1185  MultiArrayView<2, TM, SM> const & mask,
1186  MultiArrayView<2, T2, S2> dest,
1187  int radius)
1188 {
1189  vigra_precondition(src.shape() == mask.shape() && src.shape() == dest.shape(),
1190  "discErosionWithMask(): shape mismatch between input and output.");
1191  discErosionWithMask(srcImageRange(src), maskImage(mask), destImage(dest), radius);
1192 }
1193 
1194 /********************************************************/
1195 /* */
1196 /* discDilationWithMask */
1197 /* */
1198 /********************************************************/
1199 
1200 /** \brief Apply dilation (maximum) filter with disc of given radius to image
1201  using a mask.
1202 
1203  This is an abbreviation for the masked rank order filter with
1204  rank = 1.0. See \ref discRankOrderFilterWithMask() for more information.
1205 
1206  <b> Declarations:</b>
1207 
1208  pass 2D array views:
1209  \code
1210  namespace vigra {
1211  template <class T1, class S1,
1212  class TM, class SM,
1213  class T2, class S2>
1214  void
1215  discDilationWithMask(MultiArrayView<2, T1, S1> const & src,
1216  MultiArrayView<2, TM, SM> const & mask,
1217  MultiArrayView<2, T2, S2> dest,
1218  int radius);
1219  }
1220  \endcode
1221 
1222  \deprecatedAPI{discDilationWithMask}
1223  pass \ref ImageIterators and \ref DataAccessors :
1224  \code
1225  namespace vigra {
1226  template <class SrcIterator, class SrcAccessor,
1227  class MaskIterator, class MaskAccessor,
1228  class DestIterator, class DestAccessor>
1229  void
1230  discDilationWithMask(SrcIterator upperleft1,
1231  SrcIterator lowerright1, SrcAccessor sa,
1232  MaskIterator upperleftm, MaskAccessor mask,
1233  DestIterator upperleft2, DestAccessor da,
1234  int radius)
1235  }
1236  \endcode
1237  group arguments (use in conjunction with \ref ArgumentObjectFactories):
1238  \code
1239  namespace vigra {
1240  template <class SrcIterator, class SrcAccessor,
1241  class MaskIterator, class MaskAccessor,
1242  class DestIterator, class DestAccessor>
1243  void
1244  discDilationWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1245  pair<MaskIterator, MaskAccessor> mask,
1246  pair<DestIterator, DestAccessor> dest,
1247  int radius)
1248  }
1249  \endcode
1250  \deprecatedEnd
1251 */
1253 
1254 template <class SrcIterator, class SrcAccessor,
1255  class MaskIterator, class MaskAccessor,
1256  class DestIterator, class DestAccessor>
1257 inline void
1258 discDilationWithMask(SrcIterator upperleft1,
1259  SrcIterator lowerright1, SrcAccessor sa,
1260  MaskIterator upperleftm, MaskAccessor mask,
1261  DestIterator upperleft2, DestAccessor da,
1262  int radius)
1263 {
1264  vigra_precondition(radius >= 0, "discDilationWithMask(): Radius must be >= 0.");
1265 
1266  discRankOrderFilterWithMask(upperleft1, lowerright1, sa,
1267  upperleftm, mask,
1268  upperleft2, da,
1269  radius, 1.0);
1270 }
1271 
1272 template <class SrcIterator, class SrcAccessor,
1273  class MaskIterator, class MaskAccessor,
1274  class DestIterator, class DestAccessor>
1275 inline void
1276 discDilationWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1277  pair<MaskIterator, MaskAccessor> mask,
1278  pair<DestIterator, DestAccessor> dest,
1279  int radius)
1280 {
1281  vigra_precondition(radius >= 0, "discDilationWithMask(): Radius must be >= 0.");
1282 
1283  discRankOrderFilterWithMask(src.first, src.second, src.third,
1284  mask.first, mask.second,
1285  dest.first, dest.second,
1286  radius, 1.0);
1287 }
1288 
1289 template <class T1, class S1,
1290  class TM, class SM,
1291  class T2, class S2>
1292 inline void
1293 discDilationWithMask(MultiArrayView<2, T1, S1> const & src,
1294  MultiArrayView<2, TM, SM> const & mask,
1295  MultiArrayView<2, T2, S2> dest,
1296  int radius)
1297 {
1298  vigra_precondition(src.shape() == mask.shape() && src.shape() == dest.shape(),
1299  "discDilationWithMask(): shape mismatch between input and output.");
1300  discDilationWithMask(srcImageRange(src), maskImage(mask), destImage(dest), radius);
1301 }
1302 
1303 /********************************************************/
1304 /* */
1305 /* discMedianWithMask */
1306 /* */
1307 /********************************************************/
1308 
1309 /** \brief Apply median filter with disc of given radius to image
1310  using a mask.
1311 
1312  This is an abbreviation for the masked rank order filter with
1313  rank = 0.5. See \ref discRankOrderFilterWithMask() for more information.
1314 
1315  <b> Declarations:</b>
1316 
1317  pass 2D array views:
1318  \code
1319  namespace vigra {
1320  template <class T1, class S1,
1321  class TM, class SM,
1322  class T2, class S2>
1323  void
1324  discMedianWithMask(MultiArrayView<2, T1, S1> const & src,
1325  MultiArrayView<2, TM, SM> const & mask,
1326  MultiArrayView<2, T2, S2> dest,
1327  int radius);
1328  }
1329  \endcode
1330 
1331  \deprecatedAPI{discMedianWithMask}
1332  pass \ref ImageIterators and \ref DataAccessors :
1333  \code
1334  namespace vigra {
1335  template <class SrcIterator, class SrcAccessor,
1336  class MaskIterator, class MaskAccessor,
1337  class DestIterator, class DestAccessor>
1338  void
1339  discMedianWithMask(SrcIterator upperleft1,
1340  SrcIterator lowerright1, SrcAccessor sa,
1341  MaskIterator upperleftm, MaskAccessor mask,
1342  DestIterator upperleft2, DestAccessor da,
1343  int radius)
1344  }
1345  \endcode
1346  group arguments (use in conjunction with \ref ArgumentObjectFactories):
1347  \code
1348  namespace vigra {
1349  template <class SrcIterator, class SrcAccessor,
1350  class MaskIterator, class MaskAccessor,
1351  class DestIterator, class DestAccessor>
1352  void
1353  discMedianWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1354  pair<MaskIterator, MaskAccessor> mask,
1355  pair<DestIterator, DestAccessor> dest,
1356  int radius)
1357  }
1358  \endcode
1359  \deprecatedEnd
1360 */
1362 
1363 template <class SrcIterator, class SrcAccessor,
1364  class MaskIterator, class MaskAccessor,
1365  class DestIterator, class DestAccessor>
1366 inline void
1367 discMedianWithMask(SrcIterator upperleft1,
1368  SrcIterator lowerright1, SrcAccessor sa,
1369  MaskIterator upperleftm, MaskAccessor mask,
1370  DestIterator upperleft2, DestAccessor da,
1371  int radius)
1372 {
1373  vigra_precondition(radius >= 0, "discMedianWithMask(): Radius must be >= 0.");
1374 
1375  discRankOrderFilterWithMask(upperleft1, lowerright1, sa,
1376  upperleftm, mask,
1377  upperleft2, da,
1378  radius, 0.5);
1379 }
1380 
1381 template <class SrcIterator, class SrcAccessor,
1382  class MaskIterator, class MaskAccessor,
1383  class DestIterator, class DestAccessor>
1384 inline void
1385 discMedianWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src,
1386  pair<MaskIterator, MaskAccessor> mask,
1387  pair<DestIterator, DestAccessor> dest,
1388  int radius)
1389 {
1390  vigra_precondition(radius >= 0, "discMedianWithMask(): Radius must be >= 0.");
1391 
1392  discRankOrderFilterWithMask(src.first, src.second, src.third,
1393  mask.first, mask.second,
1394  dest.first, dest.second,
1395  radius, 0.5);
1396 }
1397 
1398 template <class T1, class S1,
1399  class TM, class SM,
1400  class T2, class S2>
1401 inline void
1402 discMedianWithMask(MultiArrayView<2, T1, S1> const & src,
1403  MultiArrayView<2, TM, SM> const & mask,
1404  MultiArrayView<2, T2, S2> dest,
1405  int radius)
1406 {
1407  vigra_precondition(src.shape() == mask.shape() && src.shape() == dest.shape(),
1408  "discMedianWithMask(): shape mismatch between input and output.");
1409  discMedianWithMask(srcImageRange(src), maskImage(mask), destImage(dest), radius);
1410 }
1411 
1412 //@}
1413 
1414 } // namespace vigra
1415 
1416 #endif // VIGRA_FLATMORPHOLOGY_HXX
void discDilationWithMask(...)
Apply dilation (maximum) filter with disc of given radius to image using a mask.
void discRankOrderFilter(...)
Apply rank order filter with disc structuring function to the image.
void discErosionWithMask(...)
Apply erosion (minimum) filter with disc of given radius to image using a mask.
void discRankOrderFilterWithMask(...)
Apply rank order filter with disc structuring function to the image using a mask. ...
void discErosion(...)
Apply erosion (minimum) filter with disc of given radius to image.
void discDilation(...)
Apply dilation (maximum) filter with disc of given radius to image.
void discMedian(...)
Apply median filter with disc of given radius to image.
doxygen_overloaded_function(template<...> void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays.
void discMedianWithMask(...)
Apply median filter with disc of given radius to image using a mask.
SquareRootTraits< FixedPoint< IntBits, FracBits > >::SquareRootResult sqrt(FixedPoint< IntBits, FracBits > v)
square root.
Definition: fixedpoint.hxx:616

© 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.11.1 (Fri May 19 2017)