[ 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 #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  */
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  */
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  */
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  */
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  {
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  */
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  */
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  */
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
iterator end()
Definition: basicimage.hxx:974
iterator begin()
Definition: basicimage.hxx:965
Kernel2D & operator=(Kernel2D const &k)
Definition: stdconvolution.hxx:854
value_type norm() const
Definition: separableconvolution.hxx:2175
void initAveraging(int radius, value_type norm)
Definition: separableconvolution.hxx:2484
BasicImage< value_type >::ConstAccessor ConstAccessor
Definition: stdconvolution.hxx:781
Generic 1 dimensional convolution kernel.
Definition: separableconvolution.hxx:52
ARITHTYPE value_type
Definition: stdconvolution.hxx:765
Accessor accessor()
Definition: stdconvolution.hxx:1230
int y
Definition: diff2d.hxx:392
void convolveImage(...)
Convolve an image with the given kernel(s).
void initGaussian(double std_dev, value_type norm, double windowRatio=0.0)
Definition: separableconvolution.hxx:2253
value_type operator()(int x, int y) const
Definition: stdconvolution.hxx:1211
void initSeparable(KernelIterator kxcenter, int xleft, int xright, KernelIterator kycenter, int yleft, int yright)
Definition: stdconvolution.hxx:966
BorderTreatmentMode borderTreatment() const
Definition: stdconvolution.hxx:1282
Kernel2D()
Definition: stdconvolution.hxx:834
int x
Definition: diff2d.hxx:385
Point2D lowerRight() const
Definition: stdconvolution.hxx:1186
value_type operator[](Diff2D const &d) const
Definition: stdconvolution.hxx:1221
int height() const
Definition: stdconvolution.hxx:1194
Two dimensional difference vector.
Definition: diff2d.hxx:185
BasicImage< value_type >::Accessor Accessor
Definition: stdconvolution.hxx:777
InitProxy operator=(value_type const &v)
Definition: stdconvolution.hxx:886
ConstIterator center() const
Definition: stdconvolution.hxx:1202
Iterator center()
Definition: stdconvolution.hxx:1198
std::ptrdiff_t height() const
Definition: basicimage.hxx:847
int left() const
Definition: separableconvolution.hxx:2153
void initAveraging(int radius)
Definition: stdconvolution.hxx:1007
Two dimensional point or position.
Definition: diff2d.hxx:592
FFTWComplex< R >::NormType norm(const FFTWComplex< R > &a)
norm (= magnitude)
Definition: fftw3.hxx:1037
Point2D upperLeft() const
Definition: stdconvolution.hxx:1182
void mul(FixedPoint< IntBits1, FracBits1 > l, FixedPoint< IntBits2, FracBits2 > r, FixedPoint< IntBits3, FracBits3 > &result)
multiplication with enforced result type.
Definition: fixedpoint.hxx:605
void normalize()
Definition: stdconvolution.hxx:1275
value_type & operator[](Diff2D const &d)
Definition: stdconvolution.hxx:1216
NumericTraits< V >::Promote sum(TinyVectorBase< V, SIZE, D1, D2 > const &l)
sum of the vector's elements
Definition: tinyvector.hxx:2073
row_iterator rowIterator() const
Definition: diff2d.hxx:431
ConstAccessor accessor() const
Definition: stdconvolution.hxx:1234
void normalizedConvolveImage(...)
Performs a 2-dimensional normalized convolution, i.e. convolution with a mask image.
void initDisk(int radius)
Definition: stdconvolution.hxx:1050
void normalize(value_type norm)
Definition: stdconvolution.hxx:1251
value_type norm() const
Definition: stdconvolution.hxx:1226
doxygen_overloaded_function(template<...> void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays.
BasicImage< value_type >::const_traverser ConstIterator
Definition: stdconvolution.hxx:773
void convolveImageWithMask(...)
Deprecated name of 2-dimensional normalized convolution, i.e. convolution with a mask image...
Kernel2D & initExplicitly(BasicImage< value_type > const &image)
Definition: stdconvolution.hxx:1161
void initSeparable(Kernel1D< value_type > const &kx, Kernel1D< value_type > const &ky)
Definition: stdconvolution.hxx:914
Fundamental class template for images.
Definition: basicimage.hxx:475
Generic 2 dimensional convolution kernel.
Definition: stdconvolution.hxx:52
void initGaussian(double std_dev, value_type norm)
Definition: stdconvolution.hxx:1016
int width() const
Definition: stdconvolution.hxx:1190
FFTWComplex< R >::NormType abs(const FFTWComplex< R > &a)
absolute value (= magnitude)
Definition: fftw3.hxx:1002
void resize(std::ptrdiff_t width, std::ptrdiff_t height)
Definition: basicimage.hxx:778
int right() const
Definition: separableconvolution.hxx:2157
void initGaussian(double std_dev)
Definition: stdconvolution.hxx:1025
InternalVector::const_iterator const_iterator
Definition: separableconvolution.hxx:1393
iterator center()
Definition: separableconvolution.hxx:2123
value_type & operator()(int x, int y)
Definition: stdconvolution.hxx:1206
Kernel2D & initExplicitly(Shape2 const &upperleft, Shape2 const &lowerright)
Definition: stdconvolution.hxx:1130
Encapsulate access to the values an iterator points to.
Definition: accessor.hxx:133
~Kernel2D()
Definition: stdconvolution.hxx:898
std::ptrdiff_t width() const
Definition: basicimage.hxx:840
void setBorderTreatment(BorderTreatmentMode new_mode)
Definition: stdconvolution.hxx:1289
BasicImage< value_type >::traverser Iterator
Definition: stdconvolution.hxx:769
SquareRootTraits< FixedPoint< IntBits, FracBits > >::SquareRootResult sqrt(FixedPoint< IntBits, FracBits > v)
square root.
Definition: fixedpoint.hxx:616
traverser upperLeft()
Definition: basicimage.hxx:925
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.1 (Fri May 19 2017)