vigra - vigra/flatmorphology.hxx Source File

[ 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 #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 */
153 doxygen_overloaded_function(template <...> void discRankOrderFilter)
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 */
794 doxygen_overloaded_function(template <...> void discRankOrderFilterWithMask)
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 */
1143 doxygen_overloaded_function(template <...> void discErosionWithMask)
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 */
1252 doxygen_overloaded_function(template <...> void discDilationWithMask)
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 */
1361 doxygen_overloaded_function(template <...> void discMedianWithMask)
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

© 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.10.0 (Mon Nov 18 2013)