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

stdconvolution.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_STDCONVOLUTION_HXX
38 #define VIGRA_STDCONVOLUTION_HXX
39
40 #include <cmath>
41 #include "stdimage.hxx"
42 #include "bordertreatment.hxx"
43 #include "separableconvolution.hxx"
44 #include "utilities.hxx"
45 #include "sized_int.hxx"
46 #include "multi_iterator.hxx"
47 #include "multi_shape.hxx"
48
49 namespace vigra {
50
51 template <class ARITHTYPE>
52 class Kernel2D;
53
54 /** \addtogroup ConvolutionFilters
55 */
56 //@{
57
58 // documentation is in convolution.hxx
59 template <class SrcIterator, class SrcAccessor,
60 class DestIterator, class DestAccessor,
61 class KernelIterator, class KernelAccessor>
62 void convolveImage(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc,
63 DestIterator dest_ul, DestAccessor dest_acc,
64 KernelIterator ki, KernelAccessor ak,
65 Diff2D kul, Diff2D klr, BorderTreatmentMode border)
66 {
67 vigra_precondition((border == BORDER_TREATMENT_CLIP ||
68 border == BORDER_TREATMENT_AVOID ||
69 border == BORDER_TREATMENT_REFLECT ||
70 border == BORDER_TREATMENT_REPEAT ||
71 border == BORDER_TREATMENT_WRAP ||
72 border == BORDER_TREATMENT_ZEROPAD),
73 "convolveImage():\n"
74 " Border treatment must be one of follow treatments:\n"
75 " - BORDER_TREATMENT_CLIP\n"
76 " - BORDER_TREATMENT_AVOID\n"
77 " - BORDER_TREATMENT_REFLECT\n"
78 " - BORDER_TREATMENT_REPEAT\n"
79 " - BORDER_TREATMENT_WRAP\n"
80 " - BORDER_TREATMENT_ZEROPAD\n");
81
82 vigra_precondition(kul.x <= 0 && kul.y <= 0,
83 "convolveImage(): coordinates of "
84 "kernel's upper left must be <= 0.");
85 vigra_precondition(klr.x >= 0 && klr.y >= 0,
86 "convolveImage(): coordinates of "
87 "kernel's lower right must be >= 0.");
88
89 // use traits to determine SumType as to prevent possible overflow
90 typedef typename
91 PromoteTraits<typename SrcAccessor::value_type,
92 typename KernelAccessor::value_type>::Promote SumType;
93 typedef typename
94 NumericTraits<typename KernelAccessor::value_type>::RealPromote KernelSumType;
95 typedef typename DestAccessor::value_type DestType;
96
97 // calculate width and height of the image
98 int w = src_lr.x - src_ul.x;
99 int h = src_lr.y - src_ul.y;
100
101 // calculate width and height of the kernel
102 int kernel_width = klr.x - kul.x + 1;
103 int kernel_height = klr.y - kul.y + 1;
104
105 vigra_precondition(w >= std::max(klr.x, -kul.x) + 1 && h >= std::max(klr.y, -kul.y) + 1,
106 "convolveImage(): kernel larger than image.");
107
108 KernelSumType norm = KernelSumType();
109 if(border == BORDER_TREATMENT_CLIP)
110 {
111 // calculate the sum of the kernel elements for renormalization
112 KernelIterator yk = ki + klr;
113
114 // determine sum within kernel (= norm)
115 for(int y = 0; y < kernel_height; ++y, --yk.y)
116 {
117 KernelIterator xk = yk;
118 for(int x = 0; x < kernel_width; ++x, --xk.x)
119 {
120 norm += ak(xk);
121 }
122 }
123 vigra_precondition(norm != NumericTraits<KernelSumType>::zero(),
124 "convolveImage(): Cannot use BORDER_TREATMENT_CLIP with a DC-free kernel");
125 }
126
127 DestIterator yd = dest_ul;
128 SrcIterator ys = src_ul;
129
130 // iterate over the interior part
131 for(int y=0; y<h; ++y, ++ys.y, ++yd.y)
132 {
133 // create x iterators
134 DestIterator xd(yd);
135 SrcIterator xs(ys);
136
137 for(int x=0; x < w; ++x, ++xs.x, ++xd.x)
138 {
139 // init the sum
140 SumType sum = NumericTraits<SumType>::zero();
141 KernelIterator ykernel = ki + klr;
142
143 if(x >= klr.x && y >= klr.y && x < w + kul.x && y < h + kul.y)
144 {
145 // kernel is entirely inside the image
146 SrcIterator yys = xs - klr;
147 SrcIterator yyend = xs - kul;
148
149 for(; yys.y <= yyend.y; ++yys.y, --ykernel.y)
150 {
151 typename SrcIterator::row_iterator xxs = yys.rowIterator();
152 typename SrcIterator::row_iterator xxe = xxs + kernel_width;
153 typename KernelIterator::row_iterator xkernel= ykernel.rowIterator();
154
155 for(; xxs < xxe; ++xxs, --xkernel)
156 {
157 sum += ak(xkernel) * src_acc(xxs);
158 }
159 }
160 }
161 else if(border == BORDER_TREATMENT_REPEAT)
162 {
163 Diff2D diff;
164 for(int yk = klr.y; yk >= kul.y; --yk, --ykernel.y)
165 {
166 diff.y = std::min(std::max(y - yk, 0), h-1);
167 typename KernelIterator::row_iterator xkernel = ykernel.rowIterator();
168
169 for(int xk = klr.x; xk >= kul.x; --xk, --xkernel)
170 {
171 diff.x = std::min(std::max(x - xk, 0), w-1);
172 sum += ak(xkernel) * src_acc(src_ul, diff);
173 }
174 }
175 }
176 else if(border == BORDER_TREATMENT_REFLECT)
177 {
178 Diff2D diff;
179 for(int yk = klr.y; yk >= kul.y; --yk , --ykernel.y)
180 {
181 diff.y = abs(y - yk);
182 if(diff.y >= h)
183 diff.y = 2*h - 2 - diff.y;
184 typename KernelIterator::row_iterator xkernel = ykernel.rowIterator();
185
186 for(int xk = klr.x; xk >= kul.x; --xk, --xkernel)
187 {
188 diff.x = abs(x - xk);
189 if(diff.x >= w)
190 diff.x = 2*w - 2 - diff.x;
191 sum += ak(xkernel) * src_acc(src_ul, diff);
192 }
193 }
194 }
195 else if(border == BORDER_TREATMENT_WRAP)
196 {
197 Diff2D diff;
198 for(int yk = klr.y; yk >= kul.y; --yk, --ykernel.y)
199 {
200 diff.y = (y - yk + h) % h;
201 typename KernelIterator::row_iterator xkernel = ykernel.rowIterator();
202
203 for(int xk = klr.x; xk >= kul.x; --xk, --xkernel)
204 {
205 diff.x = (x - xk + w) % w;
206 sum += ak(xkernel) * src_acc(src_ul, diff);
207 }
208 }
209 }
210 else if(border == BORDER_TREATMENT_CLIP)
211 {
212 KernelSumType ksum = NumericTraits<KernelSumType>::zero();
213 Diff2D diff;
214 for(int yk = klr.y; yk >= kul.y; --yk, --ykernel.y)
215 {
216 diff.y = y - yk;
217 if(diff.y < 0 || diff.y >= h)
218 continue;
219 typename KernelIterator::row_iterator xkernel = ykernel.rowIterator();
220
221 for(int xk = klr.x; xk >= kul.x; --xk, --xkernel)
222 {
223 diff.x = x - xk;
224 if(diff.x < 0 || diff.x >= w)
225 continue;
226 ksum += ak(xkernel);
227 sum += ak(xkernel) * src_acc(src_ul, diff);
228 }
229 }
230
231 sum *= norm / ksum;
232 }
233 else if(border == BORDER_TREATMENT_ZEROPAD)
234 {
235 Diff2D diff;
236 for(int yk = klr.y; yk >= kul.y; --yk, --ykernel.y)
237 {
238 diff.y = y - yk;
239 if(diff.y < 0 || diff.y >= h)
240 continue;
241 typename KernelIterator::row_iterator xkernel = ykernel.rowIterator();
242
243 for(int xk = klr.x; xk >= kul.x; --xk, --xkernel)
244 {
245 diff.x = x - xk;
246 if(diff.x < 0 || diff.x >= w)
247 continue;
248 sum += ak(xkernel) * src_acc(src_ul, diff);
249 }
250 }
251 }
252 else if(border == BORDER_TREATMENT_AVOID)
253 {
254 continue;
255 }
256
257 // store convolution result in destination pixel
258 dest_acc.set(detail::RequiresExplicitCast<DestType>::cast(sum), xd);
259 }
260 }
261 }
262
263 template <class SrcIterator, class SrcAccessor,
264 class DestIterator, class DestAccessor,
265 class KernelIterator, class KernelAccessor>
266 inline void
267 convolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
268 pair<DestIterator, DestAccessor> dest,
269 tuple5<KernelIterator, KernelAccessor, Diff2D, Diff2D,
270 BorderTreatmentMode> kernel)
271 {
272 convolveImage(src.first, src.second, src.third,
273 dest.first, dest.second,
274 kernel.first, kernel.second, kernel.third,
275 kernel.fourth, kernel.fifth);
276 }
277
278 template <class T1, class S1,
279 class T2, class S2,
280 class T3>
281 inline void
282 convolveImage(MultiArrayView<2, T1, S1> const & src,
283 MultiArrayView<2, T2, S2> dest,
284 Kernel2D<T3> const & kernel)
285 {
286 vigra_precondition(src.shape() == dest.shape(),
287 "convolveImage(): shape mismatch between input and output.");
288 convolveImage(srcImageRange(src),
289 destImage(dest),
290 kernel2d(kernel));
291 }
292
293 /** \brief Performs a 2-dimensional normalized convolution, i.e. convolution with a mask image.
294
295 This functions computes
296 <a href ="http://homepages.inf.ed.ac.uk/rbf/CVonline/LOCAL_COPIES/PIRODDI1/NormConv/NormConv.html">normalized
297 convolution</a> as defined in
298 Knutsson, H. and Westin, C-F.: <i>Normalized and differential convolution:
299 Methods for Interpolation and Filtering of incomplete and uncertain data</i>.
300 Proc. of the IEEE Conf. on Computer Vision and Pattern Recognition, 1993, 515-523.
301
302 The mask image must be binary and encodes which pixels of the original image
303 are valid. It is used as follows:
304 Only pixel under the mask are used in the calculations. Whenever a part of the
305 kernel lies outside the mask, it is ignored, and the kernel is renormalized to its
306 original norm (analogous to the CLIP \ref BorderTreatmentMode). Thus, a useful convolution
307 result is computed whenever <i>at least one valid pixel is within the current window</i>
308 Thus, destination pixels not under the mask still receive a value if they are <i>near</i>
309 the mask. Therefore, this algorithm is useful as an interpolator of sparse input data.
310 If you are only interested in the destination values under the mask, you can perform
311 a subsequent \ref copyImageIf().
312
313 The KernelIterator must point to the center of the kernel, and
314 the kernel's size is given by its upper left (x and y of distance <= 0) and
315 lower right (distance >= 0) corners. The image must always be larger than the
316 kernel. At those positions where the kernel does not completely fit
317 into the image, the specified \ref BorderTreatmentMode is
318 applied. Only BORDER_TREATMENT_CLIP and BORDER_TREATMENT_AVOID are currently
319 supported.
320
321 The images's pixel type (SrcAccessor::value_type) must be a
322 linear space over the kernel's value_type (KernelAccessor::value_type),
323 i.e. addition of source values, multiplication with kernel values,
324 and NumericTraits must be defined.
325 The kernel's value_type must be an algebraic field,
326 i.e. the arithmetic operations (+, -, *, /) and NumericTraits must
327 be defined.
328
329 <b> Declarations:</b>
330
331 pass 2D array views:
332 \code
333 namespace vigra {
334 template <class T1, class S1,
335 class T2, class S2,
336 class TM, class SM,
337 class T3>
338 void
339 normalizedConvolveImage(MultiArrayView<2, T1, S1> const & src,
340 MultiArrayView<2, TM, SM> const & mask,
341 MultiArrayView<2, T2, S2> dest,
342 Kernel2D<T3> const & kernel);
343 }
344 \endcode
345
346 \deprecatedAPI{normalizedConvolveImage}
347 pass \ref ImageIterators and \ref DataAccessors :
348 \code
349 namespace vigra {
350 template <class SrcIterator, class SrcAccessor,
351 class MaskIterator, class MaskAccessor,
352 class DestIterator, class DestAccessor,
353 class KernelIterator, class KernelAccessor>
354 void
355 normalizedConvolveImage(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc,
356 MaskIterator mul, MaskAccessor am,
357 DestIterator dest_ul, DestAccessor dest_acc,
358 KernelIterator ki, KernelAccessor ak,
359 Diff2D kul, Diff2D klr, BorderTreatmentMode border);
360 }
361 \endcode
362 use argument objects in conjunction with \ref ArgumentObjectFactories :
363 \code
364 namespace vigra {
365 template <class SrcIterator, class SrcAccessor,
366 class MaskIterator, class MaskAccessor,
367 class DestIterator, class DestAccessor,
368 class KernelIterator, class KernelAccessor>
369 void normalizedConvolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
370 pair<MaskIterator, MaskAccessor> mask,
371 pair<DestIterator, DestAccessor> dest,
372 tuple5<KernelIterator, KernelAccessor, Diff2D, Diff2D,
373 BorderTreatmentMode> kernel);
374 }
375 \endcode
376 \deprecatedEnd
377
378 <b> Usage:</b>
379
380 <b>\#include</b> <vigra/stdconvolution.hxx><br>
381 Namespace: vigra
382
383 \code
384 MultiArray<2, float> src(w,h), dest(w,h);
385 MultiArray<2, unsigned char> mask(w,h);
386 ...
387 // define 3x3 binomial filter
388 vigra::Kernel2D<float> binom;
389 binom.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) = // upper left and lower right
390 0.0625, 0.125, 0.0625,
391 0.125, 0.25, 0.125,
392 0.0625, 0.125, 0.0625;
393
394 normalizedConvolveImage(src, mask, dest, binom);
395 \endcode
396
397 \deprecatedUsage{normalizedConvolveImage}
398 \code
399 vigra::FImage src(w,h), dest(w,h);
400 vigra::CImage mask(w,h);
401 ...
402
403 // define 3x3 binomial filter
404 vigra::Kernel2D<float> binom;
405
406 binom.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) = // upper left and lower right
407 0.0625, 0.125, 0.0625,
408 0.125, 0.25, 0.125,
409 0.0625, 0.125, 0.0625;
410
411 vigra::normalizedConvolveImage(srcImageRange(src), maskImage(mask), destImage(dest), kernel2d(binom));
412 \endcode
413 <b> Required Interface:</b>
414 \code
415 ImageIterator src_ul, src_lr;
416 ImageIterator mul;
417 ImageIterator dest_ul;
418 ImageIterator ik;
419
420 SrcAccessor src_accessor;
421 MaskAccessor mask_accessor;
422 DestAccessor dest_accessor;
423 KernelAccessor kernel_accessor;
424
425 NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(src_ul);
426
427 s = s + s;
428 s = kernel_accessor(ik) * s;
429 s -= s;
430
431 if(mask_accessor(mul)) ...;
432
433 dest_accessor.set(
434 NumericTraits<DestAccessor::value_type>::fromRealPromote(s), dest_ul);
435
436 NumericTraits<KernelAccessor::value_type>::RealPromote k = kernel_accessor(ik);
437
438 k += k;
439 k -= k;
440 k = k / k;
441
442 \endcode
443 \deprecatedEnd
444
445 <b> Preconditions:</b>
446
447 <ul>
448 <li> The image must be longer than the kernel radius: <tt>w > std::max(kernel.lowerRight().x, -kernel.upperLeft().x)</tt> and
449 <tt>h > std::max(kernel.lowerRight().y, -kernel.upperLeft().y)</tt>.
450 <li> The sum of kernel elements must be != 0.
451 <li> <tt>border == BORDER_TREATMENT_CLIP || border == BORDER_TREATMENT_AVOID</tt>
452 </ul>
453 */
454 doxygen_overloaded_function(template <...> void normalizedConvolveImage)
455
456 template <class SrcIterator, class SrcAccessor,
457 class DestIterator, class DestAccessor,
458 class MaskIterator, class MaskAccessor,
459 class KernelIterator, class KernelAccessor>
460 void
461 normalizedConvolveImage(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc,
462 MaskIterator mul, MaskAccessor am,
463 DestIterator dest_ul, DestAccessor dest_acc,
464 KernelIterator ki, KernelAccessor ak,
465 Diff2D kul, Diff2D klr, BorderTreatmentMode border)
466 {
467 vigra_precondition((border == BORDER_TREATMENT_CLIP ||
468 border == BORDER_TREATMENT_AVOID),
469 "normalizedConvolveImage(): "
470 "Border treatment must be BORDER_TREATMENT_CLIP or BORDER_TREATMENT_AVOID.");
471
472 vigra_precondition(kul.x <= 0 && kul.y <= 0,
473 "normalizedConvolveImage(): left borders must be <= 0.");
474 vigra_precondition(klr.x >= 0 && klr.y >= 0,
475 "normalizedConvolveImage(): right borders must be >= 0.");
476
477 // use traits to determine SumType as to prevent possible overflow
478 typedef typename
479 NumericTraits<typename SrcAccessor::value_type>::RealPromote SumType;
480 typedef typename
481 NumericTraits<typename KernelAccessor::value_type>::RealPromote KSumType;
482 typedef
483 NumericTraits<typename DestAccessor::value_type> DestTraits;
484
485 // calculate width and height of the image
486 int w = src_lr.x - src_ul.x;
487 int h = src_lr.y - src_ul.y;
488 int kernel_width = klr.x - kul.x + 1;
489 int kernel_height = klr.y - kul.y + 1;
490
491 int x,y;
492 int ystart = (border == BORDER_TREATMENT_AVOID) ? klr.y : 0;
493 int yend = (border == BORDER_TREATMENT_AVOID) ? h+kul.y : h;
494 int xstart = (border == BORDER_TREATMENT_AVOID) ? klr.x : 0;
495 int xend = (border == BORDER_TREATMENT_AVOID) ? w+kul.x : w;
496
497 // create y iterators
498 DestIterator yd = dest_ul + Diff2D(xstart, ystart);
499 SrcIterator ys = src_ul + Diff2D(xstart, ystart);
500 MaskIterator ym = mul + Diff2D(xstart, ystart);
501
502 KSumType norm = ak(ki);
503 int xx, yy;
504 KernelIterator yk = ki + klr;
505 for(yy=0; yy<kernel_height; ++yy, --yk.y)
506 {
507 KernelIterator xk = yk;
508
509 for(xx=0; xx<kernel_width; ++xx, --xk.x)
510 {
511 norm += ak(xk);
512 }
513 }
514 norm -= ak(ki);
515
516
517 for(y=ystart; y < yend; ++y, ++ys.y, ++yd.y, ++ym.y)
518 {
519 // create x iterators
520 DestIterator xd(yd);
521 SrcIterator xs(ys);
522 MaskIterator xm(ym);
523
524 for(x=xstart; x < xend; ++x, ++xs.x, ++xd.x, ++xm.x)
525 {
526 // how much of the kernel fits into the image ?
527 int x0, y0, x1, y1;
528
529 y0 = (y<klr.y) ? -y : -klr.y;
530 y1 = (h-y-1<-kul.y) ? h-y-1 : -kul.y;
531 x0 = (x<klr.x) ? -x : -klr.x;
532 x1 = (w-x-1<-kul.x) ? w-x-1 : -kul.x;
533
534 bool first = true;
535 // init the sum
536 SumType sum = NumericTraits<SumType>::zero();
537 KSumType ksum = NumericTraits<KSumType>::zero();
538
539 SrcIterator yys = xs + Diff2D(x0, y0);
540 MaskIterator yym = xm + Diff2D(x0, y0);
541 KernelIterator yk = ki - Diff2D(x0, y0);
542
543 int kernel_width, kernel_height;
544 kernel_width = x1 - x0 + 1;
545 kernel_height = y1 - y0 + 1;
546 for(yy=0; yy<kernel_height; ++yy, ++yys.y, --yk.y, ++yym.y)
547 {
548 typename SrcIterator::row_iterator xxs = yys.rowIterator();
549 typename SrcIterator::row_iterator xxend = xxs + kernel_width;
550 typename MaskIterator::row_iterator xxm = yym.rowIterator();
551 typename KernelIterator::row_iterator xk = yk.rowIterator();
552
553 for(xx=0; xxs < xxend; ++xxs, --xk, ++xxm)
554 {
555 if(!am(xxm)) continue;
556
557 if(first)
558 {
559 sum = detail::RequiresExplicitCast<SumType>::cast(ak(xk) * src_acc(xxs));
560 ksum = ak(xk);
561 first = false;
562 }
563 else
564 {
565 sum = detail::RequiresExplicitCast<SumType>::cast(sum + ak(xk) * src_acc(xxs));
566 ksum += ak(xk);
567 }
568 }
569 }
570 // store average in destination pixel
571 if(ksum != NumericTraits<KSumType>::zero())
572 {
573 dest_acc.set(DestTraits::fromRealPromote(
574 detail::RequiresExplicitCast<SumType>::cast((norm / ksum) * sum)), xd);
575 }
576 }
577 }
578 }
579
580
581 template <class SrcIterator, class SrcAccessor,
582 class DestIterator, class DestAccessor,
583 class MaskIterator, class MaskAccessor,
584 class KernelIterator, class KernelAccessor>
585 inline void
586 normalizedConvolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> src,
587 pair<MaskIterator, MaskAccessor> mask,
588 pair<DestIterator, DestAccessor> dest,
589 tuple5<KernelIterator, KernelAccessor, Diff2D, Diff2D,
590 BorderTreatmentMode> kernel)
591 {
592 normalizedConvolveImage(src.first, src.second, src.third,
593 mask.first, mask.second,
594 dest.first, dest.second,
595 kernel.first, kernel.second, kernel.third,
596 kernel.fourth, kernel.fifth);
597 }
598
599 template <class T1, class S1,
600 class T2, class S2,
601 class TM, class SM,
602 class T3>
603 inline void
604 normalizedConvolveImage(MultiArrayView<2, T1, S1> const & src,
605 MultiArrayView<2, TM, SM> const & mask,
606 MultiArrayView<2, T2, S2> dest,
607 Kernel2D<T3> const & kernel)
608 {
609 vigra_precondition(src.shape() == mask.shape() && src.shape() == dest.shape(),
610 "normalizedConvolveImage(): shape mismatch between input and output.");
611 normalizedConvolveImage(srcImageRange(src),
612 maskImage(mask),
613 destImage(dest),
614 kernel2d(kernel));
615 }
616
617 /** \brief Deprecated name of 2-dimensional normalized convolution, i.e. convolution with a mask image.
618
619 See \ref normalizedConvolveImage() for documentation.
620
621 <b> Declarations:</b>
622
623 pass 2D array views:
624 \code
625 namespace vigra {
626 template <class SrcIterator, class SrcAccessor,
627 class MaskIterator, class MaskAccessor,
628 class DestIterator, class DestAccessor,
629 class KernelIterator, class KernelAccessor>
630 void
631 convolveImageWithMask(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc,
632 MaskIterator mul, MaskAccessor am,
633 DestIterator dest_ul, DestAccessor dest_acc,
634 KernelIterator ki, KernelAccessor ak,
635 Diff2D kul, Diff2D klr, BorderTreatmentMode border);
636 }
637 \endcode
638
639 \deprecatedAPI{convolveImageWithMask}
640 pass \ref ImageIterators and \ref DataAccessors :
641 \code
642 namespace vigra {
643 template <class SrcIterator, class SrcAccessor,
644 class MaskIterator, class MaskAccessor,
645 class DestIterator, class DestAccessor,
646 class KernelIterator, class KernelAccessor>
647 void
648 convolveImageWithMask(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc,
649 MaskIterator mul, MaskAccessor am,
650 DestIterator dest_ul, DestAccessor dest_acc,
651 KernelIterator ki, KernelAccessor ak,
652 Diff2D kul, Diff2D klr, BorderTreatmentMode border);
653 }
654 \endcode
655 use argument objects in conjunction with \ref ArgumentObjectFactories :
656 \code
657 namespace vigra {
658 template <class SrcIterator, class SrcAccessor,
659 class MaskIterator, class MaskAccessor,
660 class DestIterator, class DestAccessor,
661 class KernelIterator, class KernelAccessor>
662 void convolveImageWithMask(triple<SrcIterator, SrcIterator, SrcAccessor> src,
663 pair<MaskIterator, MaskAccessor> mask,
664 pair<DestIterator, DestAccessor> dest,
665 tuple5<KernelIterator, KernelAccessor, Diff2D, Diff2D,
666 BorderTreatmentMode> kernel);
667 }
668 \endcode
669 \deprecatedEnd
670 */
671 doxygen_overloaded_function(template <...> void convolveImageWithMask)
672
673 template <class SrcIterator, class SrcAccessor,
674 class DestIterator, class DestAccessor,
675 class MaskIterator, class MaskAccessor,
676 class KernelIterator, class KernelAccessor>
677 inline void
678 convolveImageWithMask(SrcIterator src_ul, SrcIterator src_lr, SrcAccessor src_acc,
679 MaskIterator mul, MaskAccessor am,
680 DestIterator dest_ul, DestAccessor dest_acc,
681 KernelIterator ki, KernelAccessor ak,
682 Diff2D kul, Diff2D klr, BorderTreatmentMode border)
683 {
684 normalizedConvolveImage(src_ul, src_lr, src_acc,
685 mul, am,
686 dest_ul, dest_acc,
687 ki, ak, kul, klr, border);
688 }
689
690 template <class SrcIterator, class SrcAccessor,
691 class DestIterator, class DestAccessor,
692 class MaskIterator, class MaskAccessor,
693 class KernelIterator, class KernelAccessor>
694 inline
695 void convolveImageWithMask(
696 triple<SrcIterator, SrcIterator, SrcAccessor> src,
697 pair<MaskIterator, MaskAccessor> mask,
698 pair<DestIterator, DestAccessor> dest,
699 tuple5<KernelIterator, KernelAccessor, Diff2D, Diff2D,
700 BorderTreatmentMode> kernel)
701 {
702 normalizedConvolveImage(src.first, src.second, src.third,
703 mask.first, mask.second,
704 dest.first, dest.second,
705 kernel.first, kernel.second, kernel.third,
706 kernel.fourth, kernel.fifth);
707 }
708
709 //@}
710
711 /********************************************************/
712 /* */
713 /* Kernel2D */
714 /* */
715 /********************************************************/
716
717 /** \brief Generic 2 dimensional convolution kernel.
718
719 This kernel may be used for convolution of 2 dimensional signals.
720
721 Convolution functions access the kernel via an ImageIterator
722 which they get by calling \ref center(). This iterator
723 points to the center of the kernel. The kernel's size is given by its upperLeft()
724 (upperLeft().x <= 0, upperLeft().y <= 0)
725 and lowerRight() (lowerRight().x >= 0, lowerRight().y >= 0) methods.
726 The desired border treatment mode is returned by borderTreatment().
727
728 The different init functions create a kernel with the specified
729 properties. The requirements for the kernel's value_type depend
730 on the init function used. At least NumericTraits must be defined.
731
732 <b> Usage:</b>
733
734 <b>\#include</b> <vigra/stdconvolution.hxx><br>
735 Namespace: vigra
736
737 \code
738 MultiArray<2, float> src(w,h), dest(w,h);
739 ...
740
741 // define horizontal Sobel filter
742 vigra::Kernel2D<float> sobel;
743 sobel.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) = // upper left and lower right
744 0.125, 0.0, -0.125,
745 0.25, 0.0, -0.25,
746 0.125, 0.0, -0.125;
747
748 convolveImage(src, dest, sobel);
749 \endcode
750
751 <b> Required Interface:</b>
752
753 \code
754 value_type v = NumericTraits<value_type>::one();
755 \endcode
756
757 See also the init functions.
758 */
759 template <class ARITHTYPE = double>
760 class Kernel2D
761 {
762 public:
763 /** the kernel's value type
764 */
765 typedef ARITHTYPE value_type;
766
767 /** 2D random access iterator over the kernel's values
768 */
769 typedef typename BasicImage<value_type>::traverser Iterator;
770
771 /** const 2D random access iterator over the kernel's values
772 */
773 typedef typename BasicImage<value_type>::const_traverser ConstIterator;
774
775 /** the kernel's accessor
776 */
777 typedef typename BasicImage<value_type>::Accessor Accessor;
778
779 /** the kernel's const accessor
780 */
781 typedef typename BasicImage<value_type>::ConstAccessor ConstAccessor;
782
783 struct InitProxy
784 {
785 typedef typename
786 BasicImage<value_type>::ScanOrderIterator Iterator;
787
788 InitProxy(Iterator i, int count, value_type & norm)
789 : iter_(i), base_(i),
790 count_(count), sum_(count),
791 norm_(norm)
792 {}
793
794 ~InitProxy()
795 #ifndef _MSC_VER
796 throw(PreconditionViolation)
797 #elif _MSC_VER >= 1900
798 noexcept(false)
799 #endif
800 {
801 vigra_precondition(count_ == 1 || count_ == sum_,
802 "Kernel2D::initExplicitly(): "
803 "Too few init values.");
804 }
805
806 InitProxy & operator,(value_type const & v)
807 {
808 if(count_ == sum_) norm_ = *iter_;
809
810 --count_;
811 vigra_precondition(count_ > 0,
812 "Kernel2D::initExplicitly(): "
813 "Too many init values.");
814
815 norm_ += v;
816
817 ++iter_;
818 *iter_ = v;
819
820 return *this;
821 }
822
823 Iterator iter_, base_;
824 int count_, sum_;
825 value_type & norm_;
826 };
827
828 static value_type one() { return NumericTraits<value_type>::one(); }
829
830 /** Default constructor.
831 Creates a kernel of size 1x1 which would copy the signal
832 unchanged.
833 */
834 Kernel2D()
835 : kernel_(1, 1, one()),
836 left_(0, 0),
837 right_(0, 0),
838 norm_(one()),
839 border_treatment_(BORDER_TREATMENT_REFLECT)
840 {}
841
842 /** Copy constructor.
843 */
844 Kernel2D(Kernel2D const & k)
845 : kernel_(k.kernel_),
846 left_(k.left_),
847 right_(k.right_),
848 norm_(k.norm_),
849 border_treatment_(k.border_treatment_)
850 {}
851
852 /** Copy assignment.
853 */
854 Kernel2D & operator=(Kernel2D const & k)
855 {
856 if(this != &k)
857 {
858 kernel_ = k.kernel_;
859 left_ = k.left_;
860 right_ = k.right_;
861 norm_ = k.norm_;
862 border_treatment_ = k.border_treatment_;
863 }
864 return *this;
865 }
866
867 /** Initialization.
868 This initializes the kernel with the given constant. The norm becomes
869 v*width()*height().
870
871 Instead of a single value an initializer list of length width()*height()
872 can be used like this:
873
874 \code
875 vigra::Kernel2D<float> binom;
876
877 binom.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) =
878 0.0625, 0.125, 0.0625,
879 0.125, 0.25, 0.125,
880 0.0625, 0.125, 0.0625;
881 \endcode
882
883 In this case, the norm will be set to the sum of the init values.
884 An initializer list of wrong length will result in a run-time error.
885 */
886 InitProxy operator=(value_type const & v)
887 {
888 int size = (right_.x - left_.x + 1) *
889 (right_.y - left_.y + 1);
890 kernel_ = v;
891 norm_ = (double)size*v;
892
893 return InitProxy(kernel_.begin(), size, norm_);
894 }
895
896 /** Destructor.
897 */
898 ~Kernel2D()
899 {}
900
901 /** Init the 2D kernel as the cartesian product of two 1D kernels
902 of type \ref Kernel1D. The norm becomes the product of the two original
903 norms.
904
905 <b> Required Interface:</b>
906
907 The kernel's value_type must be a linear algebra.
908
909 \code
910 vigra::Kernel2D<...>::value_type v;
911 v = v * v;
912 \endcode
913 */
914 void initSeparable(Kernel1D<value_type> const & kx,
915 Kernel1D<value_type> const & ky)
916 {
917 left_ = Diff2D(kx.left(), ky.left());
918 right_ = Diff2D(kx.right(), ky.right());
919 int w = right_.x - left_.x + 1;
920 int h = right_.y - left_.y + 1;
921 kernel_.resize(w, h);
922
923 norm_ = kx.norm() * ky.norm();
924
925 typedef typename Kernel1D<value_type>::const_iterator KIter;
926 typename Kernel1D<value_type>::Accessor ka;
927
928 KIter kiy = ky.center() + left_.y;
929 Iterator iy = center() + left_;
930
931 for(int y=left_.y; y<=right_.y; ++y, ++kiy, ++iy.y)
932 {
933 KIter kix = kx.center() + left_.x;
934 Iterator ix = iy;
935 for(int x=left_.x; x<=right_.x; ++x, ++kix, ++ix.x)
936 {
937 *ix = ka(kix) * ka(kiy);
938 }
939 }
940 }
941
942 /** Init the 2D kernel as the cartesian product of two 1D kernels
943 given explicitly by iterators and sizes. The norm becomes the
944 sum of the resulting kernel values.
945
946 <b> Required Interface:</b>
947
948 The kernel's value_type must be a linear algebra.
949
950 \code
951 vigra::Kernel2D<...>::value_type v;
952 v = v * v;
953 v += v;
954 \endcode
955
956 <b> Preconditions:</b>
957
958 \code
959 xleft <= 0;
960 xright >= 0;
961 yleft <= 0;
962 yright >= 0;
963 \endcode
964 */
965 template <class KernelIterator>
966 void initSeparable(KernelIterator kxcenter, int xleft, int xright,
967 KernelIterator kycenter, int yleft, int yright)
968 {
969 vigra_precondition(xleft <= 0 && yleft <= 0,
970 "Kernel2D::initSeparable(): left borders must be <= 0.");
971 vigra_precondition(xright >= 0 && yright >= 0,
972 "Kernel2D::initSeparable(): right borders must be >= 0.");
973
974 left_ = Point2D(xleft, yleft);
975 right_ = Point2D(xright, yright);
976
977 int w = right_.x - left_.x + 1;
978 int h = right_.y - left_.y + 1;
979 kernel_.resize(w, h);
980
981 KernelIterator kiy = kycenter + left_.y;
982 Iterator iy = center() + left_;
983
984 for(int y=left_.y; y<=right_.y; ++y, ++kiy, ++iy.y)
985 {
986 KernelIterator kix = kxcenter + left_.x;
987 Iterator ix = iy;
988 for(int x=left_.x; x<=right_.x; ++x, ++kix, ++ix.x)
989 {
990 *ix = *kix * *kiy;
991 }
992 }
993
994 typename BasicImage<value_type>::iterator i = kernel_.begin();
995 typename BasicImage<value_type>::iterator iend = kernel_.end();
996 norm_ = *i;
997 ++i;
998
999 for(; i!= iend; ++i)
1000 {
1001 norm_ += *i;
1002 }
1003 }
1004
1005 /** Init as a 2D box filter with given radius.
1006 */
1007 void initAveraging(int radius)
1008 {
1009 Kernel1D<value_type> avg;
1010 avg.initAveraging(radius);
1011 return initSeparable(avg, avg);
1012 }
1013
1014 /** Init as a 2D Gaussian function with given standard deviation and norm.
1015 */
1016 void initGaussian(double std_dev, value_type norm)
1017 {
1018 Kernel1D<value_type> gauss;
1019 gauss.initGaussian(std_dev, norm);
1020 return initSeparable(gauss, gauss);
1021 }
1022
1023 /** Init as a 2D Gaussian function with given standard deviation and unit norm.
1024 */
1025 void initGaussian(double std_dev)
1026 {
1027 return initGaussian(std_dev, NumericTraits<value_type>::one());
1028 }
1029
1030 /** Init the 2D kernel as a circular averaging filter. The norm will be
1031 calculated as
1032 <TT>NumericTraits<value_type>::one() / (number of non-zero kernel values)</TT>.
1033 The kernel's value_type must be a linear space.
1034
1035 <b> Required Interface:</b>
1036
1037 \code
1038 value_type v = vigra::NumericTraits<value_type>::one();
1039
1040 double d;
1041 v = d * v;
1042 \endcode
1043
1044 <b> Precondition:</b>
1045
1046 \code
1047 radius > 0;
1048 \endcode
1049 */
1050 void initDisk(int radius)
1051 {
1052 vigra_precondition(radius > 0,
1053 "Kernel2D::initDisk(): radius must be > 0.");
1054
1055 left_ = Point2D(-radius, -radius);
1056 right_ = Point2D(radius, radius);
1057 int w = right_.x - left_.x + 1;
1058 int h = right_.y - left_.y + 1;
1059 kernel_.resize(w, h);
1060 norm_ = NumericTraits<value_type>::one();
1061
1062 kernel_ = NumericTraits<value_type>::zero();
1063 double count = 0.0;
1064
1065 Iterator k = center();
1066 double r2 = (double)radius*radius;
1067
1068 int i;
1069 for(i=0; i<= radius; ++i)
1070 {
1071 double r = (double) i - 0.5;
1072 int w = (int)(VIGRA_CSTD::sqrt(r2 - r*r) + 0.5);
1073 for(int j=-w; j<=w; ++j)
1074 {
1075 k(j, i) = NumericTraits<value_type>::one();
1076 k(j, -i) = NumericTraits<value_type>::one();
1077 count += (i != 0) ? 2.0 : 1.0;
1078 }
1079 }
1080
1081 count = 1.0 / count;
1082
1083 for(int y=-radius; y<=radius; ++y)
1084 {
1085 for(int x=-radius; x<=radius; ++x)
1086 {
1087 k(x,y) = count * k(x,y);
1088 }
1089 }
1090 }
1091
1092 /** Init the kernel by an explicit initializer list.
1093 The upper left and lower right corners (inclusive) of the kernel must be passed
1094 either as <tt>Shape2</tt> or <tt>Diff2D</tt> objects. A comma-separated initializer
1095 list for the kernel's weights is given after the assignment operator like this:
1096
1097 \code
1098 // define horizontal Sobel filter
1099 vigra::Kernel2D<float> sobel;
1100
1101 sobel.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) =
1102 0.125, 0.0, -0.125,
1103 0.25, 0.0, -0.25,
1104 0.125, 0.0, -0.125;
1105 \endcode
1106
1107 The norm is set to the sum of the initializer values. If the wrong number of
1108 values is given, a run-time error results. It is, however, possible to give
1109 just one initializer. This creates an averaging filter with the given constant:
1110
1111 \code
1112 vigra::Kernel2D<float> average3x3;
1113
1114 average3x3.initExplicitly(Shape2(-1,-1), Shape2(1,1)) = 1.0/9.0;
1115 \endcode
1116
1117 Here, the norm is set to value*width()*height().
1118
1119 <b> Preconditions:</b>
1120
1121 \code
1122 1. upperleft.x <= 0;
1123 2. upperleft.y <= 0;
1124 3. lowerright.x >= 0;
1125 4. lowerright.y >= 0;
1126 5. the number of values in the initializer list
1127 is 1 or equals the size of the kernel.
1128 \endcode
1129 */
1130 Kernel2D & initExplicitly(Shape2 const & upperleft, Shape2 const & lowerright)
1131 {
1132 vigra_precondition(upperleft[0] <= 0 && upperleft[1] <= 0,
1133 "Kernel2D::initExplicitly(): left borders must be <= 0.");
1134 vigra_precondition(lowerright[0] >= 0 && lowerright[1] >= 0,
1135 "Kernel2D::initExplicitly(): right borders must be >= 0.");
1136
1137 left_ = Point2D(upperleft[0], upperleft[1]);
1138 right_ = Point2D(lowerright[0], lowerright[1]);
1139
1140 int w = right_.x - left_.x + 1;
1141 int h = right_.y - left_.y + 1;
1142 kernel_.resize(w, h);
1143
1144 return *this;
1145 }
1146
1147 Kernel2D & initExplicitly(Diff2D const & upperleft, Diff2D const & lowerright)
1148 {
1149 return initExplicitly(Shape2(upperleft), Shape2(lowerright));
1150 }
1151
1152 /** Init the kernel by providing a BasicImage with the kernel values.
1153
1154 The kernel's origin is placed at the center of the given image.
1155 The norm is set to the sum of the image values.
1156
1157 <b> Preconditions:</b>
1158
1159 odd image width and height;
1160 */
1161 Kernel2D & initExplicitly(BasicImage<value_type> const & image)
1162 {
1163 vigra_precondition(image.width() % 2 != 0 && image.height() % 2 != 0,
1164 "Kernel2D::initExplicitly(): kernel sizes must be odd.");
1165
1166 left_ = Point2D((image.width() - 1) / -2, (image.height() - 1) / -2);
1167 right_ = Point2D((image.width() - 1) / 2, (image.height() - 1) / 2);
1168
1169 norm_ = 0;
1170 for (auto iter = image.begin(); iter != image.end(); ++iter)
1171 {
1172 norm_ += *iter;
1173 }
1174
1175 kernel_ = image;
1176
1177 return *this;
1178 }
1179
1180 /** Coordinates of the upper left corner of the kernel.
1181 */
1182 Point2D upperLeft() const { return left_; }
1183
1184 /** Coordinates of the lower right corner of the kernel.
1185 */
1186 Point2D lowerRight() const { return right_; }
1187
1188 /** Width of the kernel.
1189 */
1190 int width() const { return right_.x - left_.x + 1; }
1191
1192 /** Height of the kernel.
1193 */
1194 int height() const { return right_.y - left_.y + 1; }
1195
1196 /** ImageIterator that points to the center of the kernel (coordinate (0,0)).
1197 */
1198 Iterator center() { return kernel_.upperLeft() - left_; }
1199
1200 /** ImageIterator that points to the center of the kernel (coordinate (0,0)).
1201 */
1202 ConstIterator center() const { return kernel_.upperLeft() - left_; }
1203
1204 /** Access kernel entry at given position.
1205 */
1206 value_type & operator()(int x, int y)
1207 { return kernel_[Diff2D(x,y) - left_]; }
1208
1209 /** Read kernel entry at given position.
1210 */
1211 value_type operator()(int x, int y) const
1212 { return kernel_[Diff2D(x,y) - left_]; }
1213
1214 /** Access kernel entry at given position.
1215 */
1216 value_type & operator[](Diff2D const & d)
1217 { return kernel_[d - left_]; }
1218
1219 /** Read kernel entry at given position.
1220 */
1221 value_type operator[](Diff2D const & d) const
1222 { return kernel_[d - left_]; }
1223
1224 /** Norm of the kernel (i.e. sum of its elements).
1225 */
1226 value_type norm() const { return norm_; }
1227
1228 /** The kernels default accessor.
1229 */
1230 Accessor accessor() { return Accessor(); }
1231
1232 /** The kernels default const accessor.
1233 */
1234 ConstAccessor accessor() const { return ConstAccessor(); }
1235
1236 /** Normalize the kernel to the given value. (The norm is the sum of all kernel
1237 elements.) The kernel's value_type must be a division algebra or
1238 algebraic field.
1239
1240 <b> Required Interface:</b>
1241
1242 \code
1243 value_type v = vigra::NumericTraits<value_type>::one(); // if norm is not
1244 // given explicitly
1245
1246 v += v;
1247 v = v * v;
1248 v = v / v;
1249 \endcode
1250 */
1251 void normalize(value_type norm)
1252 {
1253 typename BasicImage<value_type>::iterator i = kernel_.begin();
1254 typename BasicImage<value_type>::iterator iend = kernel_.end();
1255 typename NumericTraits<value_type>::RealPromote sum = *i;
1256 ++i;
1257
1258 for(; i!= iend; ++i)
1259 {
1260 sum += *i;
1261 }
1262
1263 sum = norm / sum;
1264 i = kernel_.begin();
1265 for(; i != iend; ++i)
1266 {
1267 *i = *i * sum;
1268 }
1269
1270 norm_ = norm;
1271 }
1272
1273 /** Normalize the kernel to norm 1.
1274 */
1275 void normalize()
1276 {
1277 normalize(one());
1278 }
1279
1280 /** current border treatment mode
1281 */
1282 BorderTreatmentMode borderTreatment() const
1283 { return border_treatment_; }
1284
1285 /** Set border treatment mode.
1286 Only <TT>BORDER_TREATMENT_CLIP</TT> and <TT>BORDER_TREATMENT_AVOID</TT> are currently
1287 allowed.
1288 */
1289 void setBorderTreatment( BorderTreatmentMode new_mode)
1290 {
1291 vigra_precondition((new_mode == BORDER_TREATMENT_CLIP ||
1292 new_mode == BORDER_TREATMENT_AVOID ||
1293 new_mode == BORDER_TREATMENT_REFLECT ||
1294 new_mode == BORDER_TREATMENT_REPEAT ||
1295 new_mode == BORDER_TREATMENT_WRAP),
1296 "convolveImage():\n"
1297 " Border treatment must be one of follow treatments:\n"
1298 " - BORDER_TREATMENT_CLIP\n"
1299 " - BORDER_TREATMENT_AVOID\n"
1300 " - BORDER_TREATMENT_REFLECT\n"
1301 " - BORDER_TREATMENT_REPEAT\n"
1302 " - BORDER_TREATMENT_WRAP\n");
1303
1304 border_treatment_ = new_mode;
1305 }
1306
1307
1308 private:
1309 BasicImage<value_type> kernel_;
1310 Point2D left_, right_;
1311 value_type norm_;
1312 BorderTreatmentMode border_treatment_;
1313 };
1314
1315 /**************************************************************/
1316 /* */
1317 /* Argument object factories for Kernel2D */
1318 /* */
1319 /* (documentation: see vigra/convolution.hxx) */
1320 /* */
1321 /**************************************************************/
1322
1323 template <class KernelIterator, class KernelAccessor>
1324 inline
1325 tuple5<KernelIterator, KernelAccessor, Diff2D, Diff2D, BorderTreatmentMode>
1326 kernel2d(KernelIterator ik, KernelAccessor ak, Diff2D kul, Diff2D klr,
1327 BorderTreatmentMode border)
1328
1329 {
1330 return
1331 tuple5<KernelIterator, KernelAccessor, Diff2D, Diff2D, BorderTreatmentMode> (
1332 ik, ak, kul, klr, border);
1333 }
1334
1335 template <class T>
1336 inline
1337 tuple5<typename Kernel2D<T>::ConstIterator,
1338 typename Kernel2D<T>::ConstAccessor,
1339 Diff2D, Diff2D, BorderTreatmentMode>
1340 kernel2d(Kernel2D<T> const & k)
1341
1342 {
1343 return
1344 tuple5<typename Kernel2D<T>::ConstIterator,
1345 typename Kernel2D<T>::ConstAccessor,
1346 Diff2D, Diff2D, BorderTreatmentMode>(
1347 k.center(),
1348 k.accessor(),
1349 k.upperLeft(), k.lowerRight(),
1350 k.borderTreatment());
1351 }
1352
1353 template <class T>
1354 inline
1355 tuple5<typename Kernel2D<T>::ConstIterator,
1356 typename Kernel2D<T>::ConstAccessor,
1357 Diff2D, Diff2D, BorderTreatmentMode>
1358 kernel2d(Kernel2D<T> const & k, BorderTreatmentMode border)
1359
1360 {
1361 return
1362 tuple5<typename Kernel2D<T>::ConstIterator,
1363 typename Kernel2D<T>::ConstAccessor,
1364 Diff2D, Diff2D, BorderTreatmentMode>(
1365 k.center(),
1366 k.accessor(),
1367 k.upperLeft(), k.lowerRight(),
1368 border);
1369 }
1370
1371
1372 } // namespace vigra
1373
1374 #endif // VIGRA_STDCONVOLUTION_HXX
vigra::BasicImage::end
iterator end()
Definition: basicimage.hxx:974
vigra::BasicImage::begin
iterator begin()
Definition: basicimage.hxx:965
vigra::Kernel2D::operator=
Kernel2D & operator=(Kernel2D const &k)
Definition: stdconvolution.hxx:854
vigra::Kernel1D::norm
value_type norm() const
Definition: separableconvolution.hxx:2175
vigra::Kernel1D::initAveraging
void initAveraging(int radius, value_type norm)
Definition: separableconvolution.hxx:2484
vigra::Kernel2D::ConstAccessor
BasicImage< value_type >::ConstAccessor ConstAccessor
Definition: stdconvolution.hxx:781
vigra::Kernel1D
Generic 1 dimensional convolution kernel.
Definition: separableconvolution.hxx:52
vigra::Kernel2D::value_type
ARITHTYPE value_type
Definition: stdconvolution.hxx:765
vigra::Kernel2D::accessor
Accessor accessor()
Definition: stdconvolution.hxx:1230
vigra::Diff2D::y
int y
Definition: diff2d.hxx:392
vigra::convolveImage
void convolveImage(...)
Convolve an image with the given kernel(s).
vigra::Kernel1D::initGaussian
void initGaussian(double std_dev, value_type norm, double windowRatio=0.0)
Definition: separableconvolution.hxx:2253
vigra::Kernel2D::operator()
value_type operator()(int x, int y) const
Definition: stdconvolution.hxx:1211
vigra::Kernel2D::initSeparable
void initSeparable(KernelIterator kxcenter, int xleft, int xright, KernelIterator kycenter, int yleft, int yright)
Definition: stdconvolution.hxx:966
vigra::Kernel2D::borderTreatment
BorderTreatmentMode borderTreatment() const
Definition: stdconvolution.hxx:1282
vigra::Kernel2D::Kernel2D
Kernel2D()
Definition: stdconvolution.hxx:834
vigra::Diff2D::x
int x
Definition: diff2d.hxx:385
vigra::Kernel2D::lowerRight
Point2D lowerRight() const
Definition: stdconvolution.hxx:1186
vigra::Kernel2D::operator[]
value_type operator[](Diff2D const &d) const
Definition: stdconvolution.hxx:1221
vigra::Kernel2D::height
int height() const
Definition: stdconvolution.hxx:1194
vigra::Diff2D
Two dimensional difference vector.
Definition: diff2d.hxx:185
vigra::Kernel2D::Accessor
BasicImage< value_type >::Accessor Accessor
Definition: stdconvolution.hxx:777
vigra::Kernel2D::operator=
InitProxy operator=(value_type const &v)
Definition: stdconvolution.hxx:886
vigra::Kernel2D::center
ConstIterator center() const
Definition: stdconvolution.hxx:1202
vigra::Kernel2D::center
Iterator center()
Definition: stdconvolution.hxx:1198
vigra::BasicImage::height
std::ptrdiff_t height() const
Definition: basicimage.hxx:847
vigra::Kernel1D::left
int left() const
Definition: separableconvolution.hxx:2153
vigra::Kernel2D::initAveraging
void initAveraging(int radius)
Definition: stdconvolution.hxx:1007
vigra::Point2D
Two dimensional point or position.
Definition: diff2d.hxx:592
vigra::norm
FFTWComplex< R >::NormType norm(const FFTWComplex< R > &a)
norm (= magnitude)
Definition: fftw3.hxx:1037
vigra::Kernel2D::upperLeft
Point2D upperLeft() const
Definition: stdconvolution.hxx:1182
vigra::mul
void mul(FixedPoint< IntBits1, FracBits1 > l, FixedPoint< IntBits2, FracBits2 > r, FixedPoint< IntBits3, FracBits3 > &result)
multiplication with enforced result type.
Definition: fixedpoint.hxx:605
vigra::Kernel2D::normalize
void normalize()
Definition: stdconvolution.hxx:1275
vigra::Kernel2D::operator[]
value_type & operator[](Diff2D const &d)
Definition: stdconvolution.hxx:1216
vigra::sum
NumericTraits< V >::Promote sum(TinyVectorBase< V, SIZE, D1, D2 > const &l)
sum of the vector's elements
Definition: tinyvector.hxx:2073
vigra::Diff2D::rowIterator
row_iterator rowIterator() const
Definition: diff2d.hxx:431
vigra::Kernel2D::accessor
ConstAccessor accessor() const
Definition: stdconvolution.hxx:1234
vigra::normalizedConvolveImage
void normalizedConvolveImage(...)
Performs a 2-dimensional normalized convolution, i.e. convolution with a mask image.
vigra::Kernel2D::initDisk
void initDisk(int radius)
Definition: stdconvolution.hxx:1050
vigra::Kernel2D::normalize
void normalize(value_type norm)
Definition: stdconvolution.hxx:1251
vigra::Kernel2D::norm
value_type norm() const
Definition: stdconvolution.hxx:1226
vigra::doxygen_overloaded_function
doxygen_overloaded_function(template<...> void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays.
vigra::Kernel2D::ConstIterator
BasicImage< value_type >::const_traverser ConstIterator
Definition: stdconvolution.hxx:773
vigra::convolveImageWithMask
void convolveImageWithMask(...)
Deprecated name of 2-dimensional normalized convolution, i.e. convolution with a mask image...
vigra::Kernel2D::initExplicitly
Kernel2D & initExplicitly(BasicImage< value_type > const &image)
Definition: stdconvolution.hxx:1161
vigra::Kernel2D::initSeparable
void initSeparable(Kernel1D< value_type > const &kx, Kernel1D< value_type > const &ky)
Definition: stdconvolution.hxx:914
utilities.hxx
vigra::BasicImage
Fundamental class template for images.
Definition: basicimage.hxx:475
vigra::Kernel2D
Generic 2 dimensional convolution kernel.
Definition: stdconvolution.hxx:52
vigra::Kernel2D::initGaussian
void initGaussian(double std_dev, value_type norm)
Definition: stdconvolution.hxx:1016
vigra::Kernel2D::width
int width() const
Definition: stdconvolution.hxx:1190
vigra::abs
FFTWComplex< R >::NormType abs(const FFTWComplex< R > &a)
absolute value (= magnitude)
Definition: fftw3.hxx:1002
vigra::BasicImage::resize
void resize(std::ptrdiff_t width, std::ptrdiff_t height)
Definition: basicimage.hxx:778
vigra::Kernel1D::right
int right() const
Definition: separableconvolution.hxx:2157
vigra::Kernel2D::initGaussian
void initGaussian(double std_dev)
Definition: stdconvolution.hxx:1025
vigra::Kernel1D::const_iterator
InternalVector::const_iterator const_iterator
Definition: separableconvolution.hxx:1393
vigra::Kernel1D::center
iterator center()
Definition: separableconvolution.hxx:2123
vigra::Kernel2D::operator()
value_type & operator()(int x, int y)
Definition: stdconvolution.hxx:1206
vigra::Kernel2D::initExplicitly
Kernel2D & initExplicitly(Shape2 const &upperleft, Shape2 const &lowerright)
Definition: stdconvolution.hxx:1130
vigra::StandardAccessor
Encapsulate access to the values an iterator points to.
Definition: accessor.hxx:133
vigra::Kernel2D::~Kernel2D
~Kernel2D()
Definition: stdconvolution.hxx:898
vigra::BasicImage::width
std::ptrdiff_t width() const
Definition: basicimage.hxx:840
vigra::Kernel2D::setBorderTreatment
void setBorderTreatment(BorderTreatmentMode new_mode)
Definition: stdconvolution.hxx:1289
vigra::Kernel2D::Iterator
BasicImage< value_type >::traverser Iterator
Definition: stdconvolution.hxx:769
vigra::sqrt
SquareRootTraits< FixedPoint< IntBits, FracBits > >::SquareRootResult sqrt(FixedPoint< IntBits, FracBits > v)
square root.
Definition: fixedpoint.hxx:616
vigra::BasicImage::upperLeft
traverser upperLeft()
Definition: basicimage.hxx:925
vigra::Kernel2D::Kernel2D
Kernel2D(Kernel2D const &k)
Definition: stdconvolution.hxx:844

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