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

stdconvolution.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_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 */
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 */
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
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  */
770 
771  /** const 2D random access iterator over the kernel's values
772  */
774 
775  /** the kernel's accessor
776  */
778 
779  /** the kernel's const accessor
780  */
782 
783  struct InitProxy
784  {
785  typedef typename
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  noexcept(false)
796  {
797  vigra_precondition(count_ == 1 || count_ == sum_,
798  "Kernel2D::initExplicitly(): "
799  "Too few init values.");
800  }
801 
802  InitProxy & operator,(value_type const & v)
803  {
804  if(count_ == sum_) norm_ = *iter_;
805 
806  --count_;
807  vigra_precondition(count_ > 0,
808  "Kernel2D::initExplicitly(): "
809  "Too many init values.");
810 
811  norm_ += v;
812 
813  ++iter_;
814  *iter_ = v;
815 
816  return *this;
817  }
818 
819  Iterator iter_, base_;
820  int count_, sum_;
821  value_type & norm_;
822  };
823 
824  static value_type one() { return NumericTraits<value_type>::one(); }
825 
826  /** Default constructor.
827  Creates a kernel of size 1x1 which would copy the signal
828  unchanged.
829  */
831  : kernel_(1, 1, one()),
832  left_(0, 0),
833  right_(0, 0),
834  norm_(one()),
835  border_treatment_(BORDER_TREATMENT_REFLECT)
836  {}
837 
838  /** Copy constructor.
839  */
840  Kernel2D(Kernel2D const & k)
841  : kernel_(k.kernel_),
842  left_(k.left_),
843  right_(k.right_),
844  norm_(k.norm_),
845  border_treatment_(k.border_treatment_)
846  {}
847 
848  /** Copy assignment.
849  */
851  {
852  if(this != &k)
853  {
854  kernel_ = k.kernel_;
855  left_ = k.left_;
856  right_ = k.right_;
857  norm_ = k.norm_;
858  border_treatment_ = k.border_treatment_;
859  }
860  return *this;
861  }
862 
863  /** Initialization.
864  This initializes the kernel with the given constant. The norm becomes
865  v*width()*height().
866 
867  Instead of a single value an initializer list of length width()*height()
868  can be used like this:
869 
870  \code
871  vigra::Kernel2D<float> binom;
872 
873  binom.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) =
874  0.0625, 0.125, 0.0625,
875  0.125, 0.25, 0.125,
876  0.0625, 0.125, 0.0625;
877  \endcode
878 
879  In this case, the norm will be set to the sum of the init values.
880  An initializer list of wrong length will result in a run-time error.
881  */
882  InitProxy operator=(value_type const & v)
883  {
884  int size = (right_.x - left_.x + 1) *
885  (right_.y - left_.y + 1);
886  kernel_ = v;
887  norm_ = (double)size*v;
888 
889  return InitProxy(kernel_.begin(), size, norm_);
890  }
891 
892  /** Destructor.
893  */
895  {}
896 
897  /** Init the 2D kernel as the cartesian product of two 1D kernels
898  of type \ref Kernel1D. The norm becomes the product of the two original
899  norms.
900 
901  <b> Required Interface:</b>
902 
903  The kernel's value_type must be a linear algebra.
904 
905  \code
906  vigra::Kernel2D<...>::value_type v;
907  v = v * v;
908  \endcode
909  */
911  Kernel1D<value_type> const & ky)
912  {
913  left_ = Diff2D(kx.left(), ky.left());
914  right_ = Diff2D(kx.right(), ky.right());
915  int w = right_.x - left_.x + 1;
916  int h = right_.y - left_.y + 1;
917  kernel_.resize(w, h);
918 
919  norm_ = kx.norm() * ky.norm();
920 
921  typedef typename Kernel1D<value_type>::const_iterator KIter;
922  typename Kernel1D<value_type>::Accessor ka;
923 
924  KIter kiy = ky.center() + left_.y;
925  Iterator iy = center() + left_;
926 
927  for(int y=left_.y; y<=right_.y; ++y, ++kiy, ++iy.y)
928  {
929  KIter kix = kx.center() + left_.x;
930  Iterator ix = iy;
931  for(int x=left_.x; x<=right_.x; ++x, ++kix, ++ix.x)
932  {
933  *ix = ka(kix) * ka(kiy);
934  }
935  }
936  }
937 
938  /** Init the 2D kernel as the cartesian product of two 1D kernels
939  given explicitly by iterators and sizes. The norm becomes the
940  sum of the resulting kernel values.
941 
942  <b> Required Interface:</b>
943 
944  The kernel's value_type must be a linear algebra.
945 
946  \code
947  vigra::Kernel2D<...>::value_type v;
948  v = v * v;
949  v += v;
950  \endcode
951 
952  <b> Preconditions:</b>
953 
954  \code
955  xleft <= 0;
956  xright >= 0;
957  yleft <= 0;
958  yright >= 0;
959  \endcode
960  */
961  template <class KernelIterator>
962  void initSeparable(KernelIterator kxcenter, int xleft, int xright,
963  KernelIterator kycenter, int yleft, int yright)
964  {
965  vigra_precondition(xleft <= 0 && yleft <= 0,
966  "Kernel2D::initSeparable(): left borders must be <= 0.");
967  vigra_precondition(xright >= 0 && yright >= 0,
968  "Kernel2D::initSeparable(): right borders must be >= 0.");
969 
970  left_ = Point2D(xleft, yleft);
971  right_ = Point2D(xright, yright);
972 
973  int w = right_.x - left_.x + 1;
974  int h = right_.y - left_.y + 1;
975  kernel_.resize(w, h);
976 
977  KernelIterator kiy = kycenter + left_.y;
978  Iterator iy = center() + left_;
979 
980  for(int y=left_.y; y<=right_.y; ++y, ++kiy, ++iy.y)
981  {
982  KernelIterator kix = kxcenter + left_.x;
983  Iterator ix = iy;
984  for(int x=left_.x; x<=right_.x; ++x, ++kix, ++ix.x)
985  {
986  *ix = *kix * *kiy;
987  }
988  }
989 
990  typename BasicImage<value_type>::iterator i = kernel_.begin();
991  typename BasicImage<value_type>::iterator iend = kernel_.end();
992  norm_ = *i;
993  ++i;
994 
995  for(; i!= iend; ++i)
996  {
997  norm_ += *i;
998  }
999  }
1000 
1001  /** Init as a 2D box filter with given radius.
1002  */
1003  void initAveraging(int radius)
1004  {
1006  avg.initAveraging(radius);
1007  return initSeparable(avg, avg);
1008  }
1009 
1010  /** Init as a 2D Gaussian function with given standard deviation and norm.
1011  */
1012  void initGaussian(double std_dev, value_type norm)
1013  {
1014  Kernel1D<value_type> gauss;
1015  gauss.initGaussian(std_dev, norm);
1016  return initSeparable(gauss, gauss);
1017  }
1018 
1019  /** Init as a 2D Gaussian function with given standard deviation and unit norm.
1020  */
1021  void initGaussian(double std_dev)
1022  {
1023  return initGaussian(std_dev, NumericTraits<value_type>::one());
1024  }
1025 
1026  /** Init the 2D kernel as a circular averaging filter. The norm will be
1027  calculated as
1028  <TT>NumericTraits<value_type>::one() / (number of non-zero kernel values)</TT>.
1029  The kernel's value_type must be a linear space.
1030 
1031  <b> Required Interface:</b>
1032 
1033  \code
1034  value_type v = vigra::NumericTraits<value_type>::one();
1035 
1036  double d;
1037  v = d * v;
1038  \endcode
1039 
1040  <b> Precondition:</b>
1041 
1042  \code
1043  radius > 0;
1044  \endcode
1045  */
1046  void initDisk(int radius)
1047  {
1048  vigra_precondition(radius > 0,
1049  "Kernel2D::initDisk(): radius must be > 0.");
1050 
1051  left_ = Point2D(-radius, -radius);
1052  right_ = Point2D(radius, radius);
1053  int w = right_.x - left_.x + 1;
1054  int h = right_.y - left_.y + 1;
1055  kernel_.resize(w, h);
1056  norm_ = NumericTraits<value_type>::one();
1057 
1058  kernel_ = NumericTraits<value_type>::zero();
1059  double count = 0.0;
1060 
1061  Iterator k = center();
1062  double r2 = (double)radius*radius;
1063 
1064  int i;
1065  for(i=0; i<= radius; ++i)
1066  {
1067  double r = (double) i - 0.5;
1068  int w = (int)(VIGRA_CSTD::sqrt(r2 - r*r) + 0.5);
1069  for(int j=-w; j<=w; ++j)
1070  {
1071  k(j, i) = NumericTraits<value_type>::one();
1072  k(j, -i) = NumericTraits<value_type>::one();
1073  count += (i != 0) ? 2.0 : 1.0;
1074  }
1075  }
1076 
1077  count = 1.0 / count;
1078 
1079  for(int y=-radius; y<=radius; ++y)
1080  {
1081  for(int x=-radius; x<=radius; ++x)
1082  {
1083  k(x,y) = count * k(x,y);
1084  }
1085  }
1086  }
1087 
1088  /** Init the kernel by an explicit initializer list.
1089  The upper left and lower right corners (inclusive) of the kernel must be passed
1090  either as <tt>Shape2</tt> or <tt>Diff2D</tt> objects. A comma-separated initializer
1091  list for the kernel's weights is given after the assignment operator like this:
1092 
1093  \code
1094  // define horizontal Sobel filter
1095  vigra::Kernel2D<float> sobel;
1096 
1097  sobel.initExplicitly(Diff2D(-1,-1), Diff2D(1,1)) =
1098  0.125, 0.0, -0.125,
1099  0.25, 0.0, -0.25,
1100  0.125, 0.0, -0.125;
1101  \endcode
1102 
1103  The norm is set to the sum of the initializer values. If the wrong number of
1104  values is given, a run-time error results. It is, however, possible to give
1105  just one initializer. This creates an averaging filter with the given constant:
1106 
1107  \code
1108  vigra::Kernel2D<float> average3x3;
1109 
1110  average3x3.initExplicitly(Shape2(-1,-1), Shape2(1,1)) = 1.0/9.0;
1111  \endcode
1112 
1113  Here, the norm is set to value*width()*height().
1114 
1115  <b> Preconditions:</b>
1116 
1117  \code
1118  1. upperleft.x <= 0;
1119  2. upperleft.y <= 0;
1120  3. lowerright.x >= 0;
1121  4. lowerright.y >= 0;
1122  5. the number of values in the initializer list
1123  is 1 or equals the size of the kernel.
1124  \endcode
1125  */
1126  Kernel2D & initExplicitly(Shape2 const & upperleft, Shape2 const & lowerright)
1127  {
1128  vigra_precondition(upperleft[0] <= 0 && upperleft[1] <= 0,
1129  "Kernel2D::initExplicitly(): left borders must be <= 0.");
1130  vigra_precondition(lowerright[0] >= 0 && lowerright[1] >= 0,
1131  "Kernel2D::initExplicitly(): right borders must be >= 0.");
1132 
1133  left_ = Point2D(upperleft[0], upperleft[1]);
1134  right_ = Point2D(lowerright[0], lowerright[1]);
1135 
1136  int w = right_.x - left_.x + 1;
1137  int h = right_.y - left_.y + 1;
1138  kernel_.resize(w, h);
1139 
1140  return *this;
1141  }
1142 
1143  Kernel2D & initExplicitly(Diff2D const & upperleft, Diff2D const & lowerright)
1144  {
1145  return initExplicitly(Shape2(upperleft), Shape2(lowerright));
1146  }
1147 
1148  /** Init the kernel by providing a BasicImage with the kernel values.
1149 
1150  The kernel's origin is placed at the center of the given image.
1151  The norm is set to the sum of the image values.
1152 
1153  <b> Preconditions:</b>
1154 
1155  odd image width and height;
1156  */
1158  {
1159  vigra_precondition(image.width() % 2 != 0 && image.height() % 2 != 0,
1160  "Kernel2D::initExplicitly(): kernel sizes must be odd.");
1161 
1162  left_ = Point2D((image.width() - 1) / -2, (image.height() - 1) / -2);
1163  right_ = Point2D((image.width() - 1) / 2, (image.height() - 1) / 2);
1164 
1165  norm_ = 0;
1166  for (auto iter = image.begin(); iter != image.end(); ++iter)
1167  {
1168  norm_ += *iter;
1169  }
1170 
1171  kernel_ = image;
1172 
1173  return *this;
1174  }
1175 
1176  /** Coordinates of the upper left corner of the kernel.
1177  */
1178  Point2D upperLeft() const { return left_; }
1179 
1180  /** Coordinates of the lower right corner of the kernel.
1181  */
1182  Point2D lowerRight() const { return right_; }
1183 
1184  /** Width of the kernel.
1185  */
1186  int width() const { return right_.x - left_.x + 1; }
1187 
1188  /** Height of the kernel.
1189  */
1190  int height() const { return right_.y - left_.y + 1; }
1191 
1192  /** ImageIterator that points to the center of the kernel (coordinate (0,0)).
1193  */
1194  Iterator center() { return kernel_.upperLeft() - left_; }
1195 
1196  /** ImageIterator that points to the center of the kernel (coordinate (0,0)).
1197  */
1198  ConstIterator center() const { return kernel_.upperLeft() - left_; }
1199 
1200  /** Access kernel entry at given position.
1201  */
1202  value_type & operator()(int x, int y)
1203  { return kernel_[Diff2D(x,y) - left_]; }
1204 
1205  /** Read kernel entry at given position.
1206  */
1207  value_type operator()(int x, int y) const
1208  { return kernel_[Diff2D(x,y) - left_]; }
1209 
1210  /** Access kernel entry at given position.
1211  */
1213  { return kernel_[d - left_]; }
1214 
1215  /** Read kernel entry at given position.
1216  */
1217  value_type operator[](Diff2D const & d) const
1218  { return kernel_[d - left_]; }
1219 
1220  /** Norm of the kernel (i.e. sum of its elements).
1221  */
1222  value_type norm() const { return norm_; }
1223 
1224  /** The kernels default accessor.
1225  */
1226  Accessor accessor() { return Accessor(); }
1227 
1228  /** The kernels default const accessor.
1229  */
1230  ConstAccessor accessor() const { return ConstAccessor(); }
1231 
1232  /** Normalize the kernel to the given value. (The norm is the sum of all kernel
1233  elements.) The kernel's value_type must be a division algebra or
1234  algebraic field.
1235 
1236  <b> Required Interface:</b>
1237 
1238  \code
1239  value_type v = vigra::NumericTraits<value_type>::one(); // if norm is not
1240  // given explicitly
1241 
1242  v += v;
1243  v = v * v;
1244  v = v / v;
1245  \endcode
1246  */
1248  {
1249  typename BasicImage<value_type>::iterator i = kernel_.begin();
1250  typename BasicImage<value_type>::iterator iend = kernel_.end();
1251  typename NumericTraits<value_type>::RealPromote sum = *i;
1252  ++i;
1253 
1254  for(; i!= iend; ++i)
1255  {
1256  sum += *i;
1257  }
1258 
1259  sum = norm / sum;
1260  i = kernel_.begin();
1261  for(; i != iend; ++i)
1262  {
1263  *i = *i * sum;
1264  }
1265 
1266  norm_ = norm;
1267  }
1268 
1269  /** Normalize the kernel to norm 1.
1270  */
1271  void normalize()
1272  {
1273  normalize(one());
1274  }
1275 
1276  /** current border treatment mode
1277  */
1278  BorderTreatmentMode borderTreatment() const
1279  { return border_treatment_; }
1280 
1281  /** Set border treatment mode.
1282  Only <TT>BORDER_TREATMENT_CLIP</TT> and <TT>BORDER_TREATMENT_AVOID</TT> are currently
1283  allowed.
1284  */
1285  void setBorderTreatment( BorderTreatmentMode new_mode)
1286  {
1287  vigra_precondition((new_mode == BORDER_TREATMENT_CLIP ||
1288  new_mode == BORDER_TREATMENT_AVOID ||
1289  new_mode == BORDER_TREATMENT_REFLECT ||
1290  new_mode == BORDER_TREATMENT_REPEAT ||
1291  new_mode == BORDER_TREATMENT_WRAP),
1292  "convolveImage():\n"
1293  " Border treatment must be one of follow treatments:\n"
1294  " - BORDER_TREATMENT_CLIP\n"
1295  " - BORDER_TREATMENT_AVOID\n"
1296  " - BORDER_TREATMENT_REFLECT\n"
1297  " - BORDER_TREATMENT_REPEAT\n"
1298  " - BORDER_TREATMENT_WRAP\n");
1299 
1300  border_treatment_ = new_mode;
1301  }
1302 
1303 
1304 private:
1305  BasicImage<value_type> kernel_;
1306  Point2D left_, right_;
1307  value_type norm_;
1308  BorderTreatmentMode border_treatment_;
1309 };
1310 
1311 /**************************************************************/
1312 /* */
1313 /* Argument object factories for Kernel2D */
1314 /* */
1315 /* (documentation: see vigra/convolution.hxx) */
1316 /* */
1317 /**************************************************************/
1318 
1319 template <class KernelIterator, class KernelAccessor>
1320 inline
1321 tuple5<KernelIterator, KernelAccessor, Diff2D, Diff2D, BorderTreatmentMode>
1322 kernel2d(KernelIterator ik, KernelAccessor ak, Diff2D kul, Diff2D klr,
1323  BorderTreatmentMode border)
1324 
1325 {
1326  return
1327  tuple5<KernelIterator, KernelAccessor, Diff2D, Diff2D, BorderTreatmentMode> (
1328  ik, ak, kul, klr, border);
1329 }
1330 
1331 template <class T>
1332 inline
1333 tuple5<typename Kernel2D<T>::ConstIterator,
1334  typename Kernel2D<T>::ConstAccessor,
1335  Diff2D, Diff2D, BorderTreatmentMode>
1336 kernel2d(Kernel2D<T> const & k)
1337 
1338 {
1339  return
1340  tuple5<typename Kernel2D<T>::ConstIterator,
1341  typename Kernel2D<T>::ConstAccessor,
1342  Diff2D, Diff2D, BorderTreatmentMode>(
1343  k.center(),
1344  k.accessor(),
1345  k.upperLeft(), k.lowerRight(),
1346  k.borderTreatment());
1347 }
1348 
1349 template <class T>
1350 inline
1351 tuple5<typename Kernel2D<T>::ConstIterator,
1352  typename Kernel2D<T>::ConstAccessor,
1353  Diff2D, Diff2D, BorderTreatmentMode>
1354 kernel2d(Kernel2D<T> const & k, BorderTreatmentMode border)
1355 
1356 {
1357  return
1358  tuple5<typename Kernel2D<T>::ConstIterator,
1359  typename Kernel2D<T>::ConstAccessor,
1360  Diff2D, Diff2D, BorderTreatmentMode>(
1361  k.center(),
1362  k.accessor(),
1363  k.upperLeft(), k.lowerRight(),
1364  border);
1365 }
1366 
1367 
1368 } // namespace vigra
1369 
1370 #endif // VIGRA_STDCONVOLUTION_HXX
Fundamental class template for images.
Definition: basicimage.hxx:476
std::ptrdiff_t height() const
Definition: basicimage.hxx:847
void resize(std::ptrdiff_t width, std::ptrdiff_t height)
Definition: basicimage.hxx:778
std::ptrdiff_t width() const
Definition: basicimage.hxx:840
iterator end()
Definition: basicimage.hxx:974
iterator begin()
Definition: basicimage.hxx:965
traverser upperLeft()
Definition: basicimage.hxx:925
Two dimensional difference vector.
Definition: diff2d.hxx:186
int y
Definition: diff2d.hxx:392
int x
Definition: diff2d.hxx:385
Generic 1 dimensional convolution kernel.
Definition: separableconvolution.hxx:1367
int right() const
Definition: separableconvolution.hxx:2153
value_type norm() const
Definition: separableconvolution.hxx:2171
void initGaussian(double std_dev, value_type norm, double windowRatio=0.0)
Definition: separableconvolution.hxx:2249
InternalVector::const_iterator const_iterator
Definition: separableconvolution.hxx:1393
void initAveraging(int radius, value_type norm)
Definition: separableconvolution.hxx:2480
int left() const
Definition: separableconvolution.hxx:2149
iterator center()
Definition: separableconvolution.hxx:2119
Generic 2 dimensional convolution kernel.
Definition: stdconvolution.hxx:761
BasicImage< value_type >::ConstAccessor ConstAccessor
Definition: stdconvolution.hxx:781
void initGaussian(double std_dev, value_type norm)
Definition: stdconvolution.hxx:1012
Kernel2D & operator=(Kernel2D const &k)
Definition: stdconvolution.hxx:850
Kernel2D & initExplicitly(BasicImage< value_type > const &image)
Definition: stdconvolution.hxx:1157
value_type norm() const
Definition: stdconvolution.hxx:1222
value_type operator[](Diff2D const &d) const
Definition: stdconvolution.hxx:1217
InitProxy operator=(value_type const &v)
Definition: stdconvolution.hxx:882
void initSeparable(KernelIterator kxcenter, int xleft, int xright, KernelIterator kycenter, int yleft, int yright)
Definition: stdconvolution.hxx:962
BorderTreatmentMode borderTreatment() const
Definition: stdconvolution.hxx:1278
Point2D upperLeft() const
Definition: stdconvolution.hxx:1178
ConstIterator center() const
Definition: stdconvolution.hxx:1198
void setBorderTreatment(BorderTreatmentMode new_mode)
Definition: stdconvolution.hxx:1285
ConstAccessor accessor() const
Definition: stdconvolution.hxx:1230
void initSeparable(Kernel1D< value_type > const &kx, Kernel1D< value_type > const &ky)
Definition: stdconvolution.hxx:910
Point2D lowerRight() const
Definition: stdconvolution.hxx:1182
~Kernel2D()
Definition: stdconvolution.hxx:894
value_type & operator()(int x, int y)
Definition: stdconvolution.hxx:1202
BasicImage< value_type >::traverser Iterator
Definition: stdconvolution.hxx:769
Kernel2D(Kernel2D const &k)
Definition: stdconvolution.hxx:840
void initAveraging(int radius)
Definition: stdconvolution.hxx:1003
Iterator center()
Definition: stdconvolution.hxx:1194
BasicImage< value_type >::const_traverser ConstIterator
Definition: stdconvolution.hxx:773
void initDisk(int radius)
Definition: stdconvolution.hxx:1046
value_type operator()(int x, int y) const
Definition: stdconvolution.hxx:1207
ARITHTYPE value_type
Definition: stdconvolution.hxx:765
void normalize(value_type norm)
Definition: stdconvolution.hxx:1247
Kernel2D & initExplicitly(Shape2 const &upperleft, Shape2 const &lowerright)
Definition: stdconvolution.hxx:1126
void initGaussian(double std_dev)
Definition: stdconvolution.hxx:1021
Accessor accessor()
Definition: stdconvolution.hxx:1226
value_type & operator[](Diff2D const &d)
Definition: stdconvolution.hxx:1212
void normalize()
Definition: stdconvolution.hxx:1271
int height() const
Definition: stdconvolution.hxx:1190
int width() const
Definition: stdconvolution.hxx:1186
BasicImage< value_type >::Accessor Accessor
Definition: stdconvolution.hxx:777
Kernel2D()
Definition: stdconvolution.hxx:830
Two dimensional point or position.
Definition: diff2d.hxx:593
Encapsulate access to the values an iterator points to.
Definition: accessor.hxx:134
NumericTraits< V >::Promote sum(TinyVectorBase< V, SIZE, D1, D2 > const &l)
sum of the vector's elements
Definition: tinyvector.hxx:2073
FFTWComplex< R >::NormType norm(const FFTWComplex< R > &a)
norm (= magnitude)
Definition: fftw3.hxx:1037
void normalizedConvolveImage(...)
Performs a 2-dimensional normalized convolution, i.e. convolution with a mask image.
FFTWComplex< R >::NormType abs(const FFTWComplex< R > &a)
absolute value (= magnitude)
Definition: fftw3.hxx:1002
void mul(FixedPoint< IntBits1, FracBits1 > l, FixedPoint< IntBits2, FracBits2 > r, FixedPoint< IntBits3, FracBits3 > &result)
multiplication with enforced result type.
Definition: fixedpoint.hxx:605
void convolveImage(...)
Convolve an image with the given kernel(s).
doxygen_overloaded_function(template<... > void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays.
void convolveImageWithMask(...)
Deprecated name of 2-dimensional normalized convolution, i.e. convolution with a mask image.

© 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