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

recursiveconvolution.hxx
1/************************************************************************/
2/* */
3/* Copyright 1998-2002 by Ullrich Koethe */
4/* */
5/* This file is part of the VIGRA computer vision library. */
6/* The VIGRA Website is */
7/* http://hci.iwr.uni-heidelberg.de/vigra/ */
8/* Please direct questions, bug reports, and contributions to */
9/* ullrich.koethe@iwr.uni-heidelberg.de or */
10/* vigra@informatik.uni-hamburg.de */
11/* */
12/* Permission is hereby granted, free of charge, to any person */
13/* obtaining a copy of this software and associated documentation */
14/* files (the "Software"), to deal in the Software without */
15/* restriction, including without limitation the rights to use, */
16/* copy, modify, merge, publish, distribute, sublicense, and/or */
17/* sell copies of the Software, and to permit persons to whom the */
18/* Software is furnished to do so, subject to the following */
19/* conditions: */
20/* */
21/* The above copyright notice and this permission notice shall be */
22/* included in all copies or substantial portions of the */
23/* Software. */
24/* */
25/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */
26/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */
27/* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */
28/* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */
29/* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */
30/* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */
31/* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */
32/* OTHER DEALINGS IN THE SOFTWARE. */
33/* */
34/************************************************************************/
35
36
37#ifndef VIGRA_RECURSIVECONVOLUTION_HXX
38#define VIGRA_RECURSIVECONVOLUTION_HXX
39
40#include <cmath>
41#include <vector>
42#include "utilities.hxx"
43#include "numerictraits.hxx"
44#include "imageiteratoradapter.hxx"
45#include "bordertreatment.hxx"
46#include "array_vector.hxx"
47#include "multi_shape.hxx"
48
49namespace vigra {
50
51/********************************************************/
52/* */
53/* Recursive convolution functions */
54/* */
55/********************************************************/
56
57/** \addtogroup RecursiveConvolution Recursive convolution functions
58
59 First order recursive filters and their specialization for
60 the exponential filter and its derivatives (1D and separable 2D).
61 These filters are very fast, and the speed does not depend on the
62 filter size.
63*/
64//@{
65
66/********************************************************/
67/* */
68/* recursiveFilterLine */
69/* */
70/********************************************************/
71
72/** \brief Performs a 1-dimensional recursive convolution of the source signal.
73
74 The function performs a causal and an anti-causal first or second order
75 recursive filtering with the given filter parameter <TT>b1</TT> and
76 border treatment <TT>border</TT> (first order filter, <TT>b2 = 0</TT>) or parameters
77 <TT>b1, b2</TT> and <TT>BORDER_TREATMENT_REFLECT</TT> (second order filter). Thus,
78 the result is always a filtering with linear phase.
79 \f[
80 \begin{array}{rcl}
81 a_{i, causal} & = & source_i + b1 * a_{i-1, causal} + b2 * a_{i-2, causal} \\
82 a_{i, anticausal} & = & source_i + b1 * a_{i+1, anticausal} + b2 * a_{i+2, anticausal} \\
83 dest_i & = & \frac{1 - b1 - b2}{1 + b1 + b2}(a_{i, causal} + a_{i, anticausal} - source_i)
84 \end{array}
85 \f]
86
87 The signal's value_type (SrcAccessor::value_type) must be a
88 linear space over <TT>double</TT>,
89 i.e. addition of source values, multiplication with <TT>double</TT>,
90 and <TT>NumericTraits</TT> must be defined.
91
92 <b> Declaration:</b>
93
94 <b>First order recursive filter:</b>
95
96 \code
97 namespace vigra {
98 template <class SrcIterator, class SrcAccessor,
99 class DestIterator, class DestAccessor>
100 void recursiveFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
101 DestIterator id, DestAccessor ad,
102 double b1, BorderTreatmentMode border)
103 }
104 \endcode
105
106 <b>Second order recursive filter:</b>
107
108 \code
109 namespace vigra {
110 template <class SrcIterator, class SrcAccessor,
111 class DestIterator, class DestAccessor>
112 void recursiveFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
113 DestIterator id, DestAccessor ad,
114 double b1, double b2)
115 }
116 \endcode
117
118 <b> Usage:</b>
119
120 <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
121 Namespace: vigra
122
123
124 \code
125 vector<float> src, dest;
126 ...
127
128 DefaultAccessor<vector<float>::iterator, float> FAccessor;
129
130
131 recursiveFilterLine(src.begin(), src.end(), FAccessor(),
132 dest.begin(), FAccessor(),
133 0.5, BORDER_TREATMENT_REFLECT);
134 \endcode
135
136 <b> Required Interface:</b>
137
138 \code
139 RandomAccessIterator is, isend;
140 RandomAccessIterator id;
141
142 SrcAccessor src_accessor;
143 DestAccessor dest_accessor;
144
145 NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is);
146 double d;
147
148 s = s + s;
149 s = d * s;
150
151 dest_accessor.set(
152 NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
153 \endcode
154
155 <b> Preconditions:</b>
156
157 \code
158 -1 < b < 1
159 \endcode
160
161*/
163
164template <class SrcIterator, class SrcAccessor,
165 class DestIterator, class DestAccessor>
166void recursiveFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
167 DestIterator id, DestAccessor ad, double b, BorderTreatmentMode border)
168{
169 int w = isend - is;
170 SrcIterator istart = is;
171
172 int x;
173
174 vigra_precondition(-1.0 < b && b < 1.0,
175 "recursiveFilterLine(): -1 < factor < 1 required.\n");
176
177 // trivial case: b == 0.0 is an identity filter => simply copy the data and return
178 if(b == 0.0)
179 {
180 for(; is != isend; ++is, ++id)
181 {
182 ad.set(as(is), id);
183 }
184 return;
185 }
186
187 double eps = 0.00001;
188 int kernelw = std::min(w-1, (int)(VIGRA_CSTD::log(eps)/VIGRA_CSTD::log(VIGRA_CSTD::fabs(b))));
189
190 typedef typename
191 NumericTraits<typename SrcAccessor::value_type>::RealPromote TempType;
192 typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
193 typedef typename DestTraits::RealPromote RealPromote;
194
195 // store result of causal filtering
196 std::vector<TempType> vline(w);
197 typename std::vector<TempType>::iterator line = vline.begin();
198
199 double norm = (1.0 - b) / (1.0 + b);
200
201 TempType old;
202
203 if(border == BORDER_TREATMENT_REPEAT ||
204 border == BORDER_TREATMENT_AVOID)
205 {
206 old = TempType((1.0 / (1.0 - b)) * as(is));
207 }
208 else if(border == BORDER_TREATMENT_REFLECT)
209 {
210 is += kernelw;
211 old = TempType((1.0 / (1.0 - b)) * as(is));
212 for(x = 0; x < kernelw; ++x, --is)
213 old = TempType(as(is) + b * old);
214 }
215 else if(border == BORDER_TREATMENT_WRAP)
216 {
217 is = isend - kernelw;
218 old = TempType((1.0 / (1.0 - b)) * as(is));
219 for(x = 0; x < kernelw; ++x, ++is)
220 old = TempType(as(is) + b * old);
221 }
222 else if(border == BORDER_TREATMENT_CLIP ||
223 border == BORDER_TREATMENT_ZEROPAD)
224 {
225 old = NumericTraits<TempType>::zero();
226 }
227 else
228 {
229 vigra_fail("recursiveFilterLine(): Unknown border treatment mode.\n");
230 old = NumericTraits<TempType>::zero(); // fix a stupid warning
231 }
232
233 // left side of filter
234 for(x=0, is = istart; x < w; ++x, ++is)
235 {
236 old = TempType(as(is) + b * old);
237 line[x] = old;
238 }
239
240 // right side of the filter
241 if(border == BORDER_TREATMENT_REPEAT ||
242 border == BORDER_TREATMENT_AVOID)
243 {
244 is = isend - 1;
245 old = TempType((1.0 / (1.0 - b)) * as(is));
246 }
247 else if(border == BORDER_TREATMENT_REFLECT)
248 {
249 old = line[w-2];
250 }
251 else if(border == BORDER_TREATMENT_WRAP)
252 {
253 is = istart + kernelw - 1;
254 old = TempType((1.0 / (1.0 - b)) * as(is));
255 for(x = 0; x < kernelw; ++x, --is)
256 old = TempType(as(is) + b * old);
257 }
258 else if(border == BORDER_TREATMENT_CLIP ||
259 border == BORDER_TREATMENT_ZEROPAD)
260 {
261 old = NumericTraits<TempType>::zero();
262 }
263
264 is = isend - 1;
265 id += w - 1;
266 if(border == BORDER_TREATMENT_CLIP)
267 {
268 // correction factors for b
269 double bright = b;
270 double bleft = VIGRA_CSTD::pow(b, w);
271
272 for(x=w-1; x>=0; --x, --is, --id)
273 {
274 TempType f = TempType(b * old);
275 old = as(is) + f;
276 norm = (1.0 - b) / (1.0 + b - bleft - bright);
277 bleft /= b;
278 bright *= b;
279 ad.set(norm * (line[x] + f), id);
280 }
281 }
282 else if(border == BORDER_TREATMENT_AVOID)
283 {
284 for(x=w-1; x >= kernelw; --x, --is, --id)
285 {
286 TempType f = TempType(b * old);
287 old = as(is) + f;
288 if(x < w - kernelw)
289 ad.set(DestTraits::fromRealPromote(RealPromote(norm * (line[x] + f))), id);
290 }
291 }
292 else
293 {
294 for(x=w-1; x>=0; --x, --is, --id)
295 {
296 TempType f = TempType(b * old);
297 old = as(is) + f;
298 ad.set(DestTraits::fromRealPromote(RealPromote(norm * (line[x] + f))), id);
299 }
300 }
301}
302
303/********************************************************/
304/* */
305/* recursiveFilterLine (2nd order) */
306/* */
307/********************************************************/
308
309template <class SrcIterator, class SrcAccessor,
310 class DestIterator, class DestAccessor>
311void recursiveFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
312 DestIterator id, DestAccessor ad, double b1, double b2)
313{
314 int w = isend - is;
315 int x;
316
317 typedef typename
318 NumericTraits<typename SrcAccessor::value_type>::RealPromote TempType;
319
320 // speichert den Ergebnis der linkseitigen Filterung.
321 std::vector<TempType> vline(w+1);
322 typename std::vector<TempType>::iterator line = vline.begin();
323
324 double norm = 1.0 - b1 - b2;
325 double norm1 = (1.0 - b1 - b2) / (1.0 + b1 + b2);
326 double norm2 = norm * norm;
327
328
329 // init left side of filter
330 int kernelw = std::min(w-1, std::max(8, (int)(1.0 / norm + 0.5)));
331 is += (kernelw - 2);
332 line[kernelw] = as(is);
333 line[kernelw-1] = as(is);
334 for(x = kernelw - 2; x > 0; --x, --is)
335 {
336 line[x] = detail::RequiresExplicitCast<TempType>::cast(as(is) + b1 * line[x+1] + b2 * line[x+2]);
337 }
338 line[0] = detail::RequiresExplicitCast<TempType>::cast(as(is) + b1 * line[1] + b2 * line[2]);
339 ++is;
340 line[1] = detail::RequiresExplicitCast<TempType>::cast(as(is) + b1 * line[0] + b2 * line[1]);
341 ++is;
342 for(x=2; x < w; ++x, ++is)
343 {
344 line[x] = detail::RequiresExplicitCast<TempType>::cast(as(is) + b1 * line[x-1] + b2 * line[x-2]);
345 }
346 line[w] = line[w-1];
347
348 line[w-1] = detail::RequiresExplicitCast<TempType>::cast(norm1 * (line[w-1] + b1 * line[w-2] + b2 * line[w-3]));
349 line[w-2] = detail::RequiresExplicitCast<TempType>::cast(norm1 * (line[w-2] + b1 * line[w] + b2 * line[w-2]));
350 id += w-1;
351 ad.set(line[w-1], id);
352 --id;
353 ad.set(line[w-2], id);
354 --id;
355 for(x=w-3; x>=0; --x, --id, --is)
356 {
357 line[x] = detail::RequiresExplicitCast<TempType>::cast(norm2 * line[x] + b1 * line[x+1] + b2 * line[x+2]);
358 ad.set(line[x], id);
359 }
360}
361
362/********************************************************/
363/* */
364/* recursiveGaussianFilterLine */
365/* */
366/********************************************************/
367
368// AUTHOR: Sebastian Boppel
369
370/** \brief Compute a 1-dimensional recursive approximation of Gaussian smoothing.
371
372 The function applies a causal and an anti-causal third order recursive filter
373 which optimally approximates the Gaussian filter, as proposed in
374
375 I. Young, L. van Vliet: <i>Recursive implementation of the Gaussian filter</i><br>
376 Signal Processing 44:139-151, 1995
377
378 The formulas for transforming the given scale parameter <tt>sigma</tt> into the actual filter coefficients
379 are taken from Luigi Rosa's Matlab implementation.
380
381 The signal's value_type (SrcAccessor::value_type) must be a
382 linear space over <TT>double</TT>, i.e. addition of source values, multiplication with <TT>double</TT>,
383 and <TT>NumericTraits</TT> must be defined.
384
385 <b> Declaration:</b>
386
387 \code
388 namespace vigra {
389 template <class SrcIterator, class SrcAccessor,
390 class DestIterator, class DestAccessor>
391 void
392 recursiveGaussianFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
393 DestIterator id, DestAccessor ad,
394 double sigma);
395 }
396 \endcode
397
398 <b> Usage:</b>
399
400 <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
401 Namespace: vigra
402
403
404 \code
405 vector<float> src, dest;
406 ...
407
408 vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
409 double sigma = 2.5;
410
411 vigra::recursiveGaussianFilterLine(src.begin(), src.end(), FAccessor(),
412 dest.begin(), FAccessor(),
413 sigma);
414 \endcode
415
416 <b> Required Interface:</b>
417
418 \code
419 RandomAccessIterator is, isend;
420 RandomAccessIterator id;
421
422 SrcAccessor src_accessor;
423 DestAccessor dest_accessor;
424
425 NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is);
426 double d;
427
428 s = s + s;
429 s = d * s;
430
431 dest_accessor.set(
432 NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
433 \endcode
434
435 <b> Preconditions:</b>
436
437 \code
438 0 <= sigma (absolute values are used for negative sigma)
439 \endcode
440
441*/
443
444template <class SrcIterator, class SrcAccessor,
445 class DestIterator, class DestAccessor>
446void
447recursiveGaussianFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
448 DestIterator id, DestAccessor ad,
449 double sigma)
450{
451 //coefficients taken out Luigi Rosa's implementation for Matlab
452 double q = 1.31564 * (std::sqrt(1.0 + 0.490811 * sigma*sigma) - 1.0);
453 double qq = q*q;
454 double qqq = qq*q;
455 double b0 = 1.0/(1.57825 + 2.44413*q + 1.4281*qq + 0.422205*qqq);
456 double b1 = (2.44413*q + 2.85619*qq + 1.26661*qqq)*b0;
457 double b2 = (-1.4281*qq - 1.26661*qqq)*b0;
458 double b3 = 0.422205*qqq*b0;
459 double B = 1.0 - (b1 + b2 + b3);
460
461 int w = isend - is;
462 vigra_precondition(w >= 4,
463 "recursiveGaussianFilterLine(): line must have at least length 4.");
464
465 int kernelw = std::min(w-4, (int)(4.0*sigma));
466
467 int x;
468
469 typedef typename
470 NumericTraits<typename SrcAccessor::value_type>::RealPromote TempType;
471
472 // speichert das Ergebnis der linkseitigen Filterung.
473 std::vector<TempType> yforward(w);
474
475 std::vector<TempType> ybackward(w, 0.0);
476
477 // initialise the filter for reflective boundary conditions
478 for(x=kernelw; x>=0; --x)
479 {
480 ybackward[x] = detail::RequiresExplicitCast<TempType>::cast(B*as(is, x) + (b1*ybackward[x+1]+b2*ybackward[x+2]+b3*ybackward[x+3]));
481 }
482
483 //from left to right - causal - forward
484 yforward[0] = detail::RequiresExplicitCast<TempType>::cast(B*as(is) + (b1*ybackward[1]+b2*ybackward[2]+b3*ybackward[3]));
485
486 ++is;
487 yforward[1] = detail::RequiresExplicitCast<TempType>::cast(B*as(is) + (b1*yforward[0]+b2*ybackward[1]+b3*ybackward[2]));
488
489 ++is;
490 yforward[2] = detail::RequiresExplicitCast<TempType>::cast(B*as(is) + (b1*yforward[1]+b2*yforward[0]+b3*ybackward[1]));
491
492 ++is;
493 for(x=3; x < w; ++x, ++is)
494 {
495 yforward[x] = detail::RequiresExplicitCast<TempType>::cast(B*as(is) + (b1*yforward[x-1]+b2*yforward[x-2]+b3*yforward[x-3]));
496 }
497
498 //from right to left - anticausal - backward
499 ybackward[w-1] = detail::RequiresExplicitCast<TempType>::cast(B*yforward[w-1] + (b1*yforward[w-2]+b2*yforward[w-3]+b3*yforward[w-4]));
500
501 ybackward[w-2] = detail::RequiresExplicitCast<TempType>::cast(B*yforward[w-2] + (b1*ybackward[w-1]+b2*yforward[w-2]+b3*yforward[w-3]));
502
503 ybackward[w-3] = detail::RequiresExplicitCast<TempType>::cast(B*yforward[w-3] + (b1*ybackward[w-2]+b2*ybackward[w-1]+b3*yforward[w-2]));
504
505 for(x=w-4; x>=0; --x)
506 {
507 ybackward[x] = detail::RequiresExplicitCast<TempType>::cast(B*yforward[x]+(b1*ybackward[x+1]+b2*ybackward[x+2]+b3*ybackward[x+3]));
508 }
509
510 // output
511 for(x=0; x < w; ++x, ++id)
512 {
513 ad.set(ybackward[x], id);
514 }
515}
516
517
518/********************************************************/
519/* */
520/* recursiveSmoothLine */
521/* */
522/********************************************************/
523
524/** \brief Convolves the image with a 1-dimensional exponential filter.
525
526 This function calls \ref recursiveFilterLine() with <TT>b = exp(-1.0/scale)</TT>
527 and <TT>border = BORDER_TREATMENT_REPEAT</TT>. See
528 \ref recursiveFilterLine() for more documentation.
529
530 <b> Declaration:</b>
531
532 \code
533 namespace vigra {
534 template <class SrcIterator, class SrcAccessor,
535 class DestIterator, class DestAccessor>
536 void recursiveSmoothLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
537 DestIterator id, DestAccessor ad, double scale)
538 }
539 \endcode
540
541 <b> Usage:</b>
542
543 <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
544 Namespace: vigra
545
546
547 \code
548 vector<float> src, dest;
549 ...
550
551 vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
552
553
554 vigra::recursiveSmoothLine(src.begin(), src.end(), FAccessor(),
555 dest.begin(), FAccessor(), 3.0);
556 \endcode
557
558 <b> Required Interface:</b>
559
560 \code
561 RandomAccessIterator is, isend;
562 RandomAccessIterator id;
563
564 SrcAccessor src_accessor;
565 DestAccessor dest_accessor;
566
567 NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is);
568 double d;
569
570 s = s + s;
571 s = d * s;
572
573 dest_accessor.set(
574 NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
575 \endcode
576
577 <b> Preconditions:</b>
578
579 \code
580 scale > 0
581 \endcode
582
583*/
585
586template <class SrcIterator, class SrcAccessor,
587 class DestIterator, class DestAccessor>
588inline
589void recursiveSmoothLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
590 DestIterator id, DestAccessor ad, double scale)
591{
592 vigra_precondition(scale >= 0,
593 "recursiveSmoothLine(): scale must be >= 0.\n");
594
595 double b = (scale == 0.0) ?
596 0.0 :
597 VIGRA_CSTD::exp(-1.0/scale);
598
599 recursiveFilterLine(is, isend, as, id, ad, b, BORDER_TREATMENT_REPEAT);
600}
601
602/********************************************************/
603/* */
604/* recursiveFirstDerivativeLine */
605/* */
606/********************************************************/
607
608/** \brief Performs a 1 dimensional recursive convolution of the source signal.
609
610 It uses the first derivative an exponential <TT>d/dx exp(-abs(x)/scale)</TT> as
611 a kernel. The signal's value_type (SrcAccessor::value_type) must be a
612 linear space over <TT>double</TT>,
613 i.e. addition and subtraction of source values, multiplication with
614 <TT>double</TT>, and <TT>NumericTraits</TT> must be defined. Border
615 treatment is always <TT>BORDER_TREATMENT_REPEAT</TT>.
616
617 <b> Declaration:</b>
618
619 \code
620 namespace vigra {
621 template <class SrcIterator, class SrcAccessor,
622 class DestIterator, class DestAccessor>
623 void recursiveFirstDerivativeLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
624 DestIterator id, DestAccessor ad, double scale)
625 }
626 \endcode
627
628 <b> Usage:</b>
629
630 <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
631 Namespace: vigra
632
633
634 \code
635 vector<float> src, dest;
636 ...
637
638 vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
639
640
641 vigra::recursiveFirstDerivativeLine(src.begin(), src.end(), FAccessor(),
642 dest.begin(), FAccessor(), 3.0);
643 \endcode
644
645 <b> Required Interface:</b>
646
647 \code
648 RandomAccessIterator is, isend;
649 RandomAccessIterator id;
650
651 SrcAccessor src_accessor;
652 DestAccessor dest_accessor;
653
654 NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is);
655 double d;
656
657 s = s + s;
658 s = -s;
659 s = d * s;
660
661 dest_accessor.set(
662 NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
663 \endcode
664
665 <b> Preconditions:</b>
666
667 \code
668 scale > 0
669 \endcode
670
671*/
673
674template <class SrcIterator, class SrcAccessor,
675 class DestIterator, class DestAccessor>
676void recursiveFirstDerivativeLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
677 DestIterator id, DestAccessor ad, double scale)
678{
679 vigra_precondition(scale > 0,
680 "recursiveFirstDerivativeLine(): scale must be > 0.\n");
681
682 int w = isend -is;
683
684 int x;
685
686 typedef typename
687 NumericTraits<typename SrcAccessor::value_type>::RealPromote
688 TempType;
689 typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
690
691 std::vector<TempType> vline(w);
692 typename std::vector<TempType>::iterator line = vline.begin();
693
694 double b = VIGRA_CSTD::exp(-1.0/scale);
695 double norm = (1.0 - b) * (1.0 - b) / 2.0 / b;
696 TempType old = (1.0 / (1.0 - b)) * as(is);
697
698 // left side of filter
699 for(x=0; x<w; ++x, ++is)
700 {
701 old = as(is) + b * old;
702 line[x] = -old;
703 }
704
705 // right side of the filter
706 --is;
707 old = (1.0 / (1.0 - b)) * as(is);
708 id += w;
709 ++is;
710
711 for(x=w-1; x>=0; --x)
712 {
713 --is;
714 --id;
715
716 old = as(is) + b * old;
717
718 ad.set(DestTraits::fromRealPromote(norm * (line[x] + old)), id);
719 }
720}
721
722/********************************************************/
723/* */
724/* recursiveSecondDerivativeLine */
725/* */
726/********************************************************/
727
728/** \brief Performs a 1 dimensional recursive convolution of the source signal.
729
730 It uses the second derivative an exponential <TT>d2/dx2 exp(-abs(x)/scale)</TT> as
731 a kernel. The signal's value_type (SrcAccessor::value_type) must be a
732 linear space over <TT>double</TT>,
733 i.e. addition and subtraction of source values, multiplication with
734 <TT>double</TT>, and <TT>NumericTraits</TT> must be defined. Border
735 treatment is always <TT>BORDER_TREATMENT_REPEAT</TT>.
736
737 <b> Declaration:</b>
738
739 \code
740 namespace vigra {
741 template <class SrcIterator, class SrcAccessor,
742 class DestIterator, class DestAccessor>
743 void recursiveSecondDerivativeLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
744 DestIterator id, DestAccessor ad, double scale)
745 }
746 \endcode
747
748 <b> Usage:</b>
749
750 <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
751 Namespace: vigra
752
753
754 \code
755 vector<float> src, dest;
756 ...
757
758 vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
759
760
761 vigra::recursiveSecondDerivativeLine(src.begin(), src.end(), FAccessor(),
762 dest.begin(), FAccessor(), 3.0);
763 \endcode
764
765 <b> Required Interface:</b>
766
767 \code
768 RandomAccessIterator is, isend;
769 RandomAccessIterator id;
770
771 SrcAccessor src_accessor;
772 DestAccessor dest_accessor;
773
774 NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is);
775 double d;
776
777 s = s + s;
778 s = s - s;
779 s = d * s;
780
781 dest_accessor.set(
782 NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
783 \endcode
784
785 <b> Preconditions:</b>
786
787 \code
788 scale > 0
789 \endcode
790
791*/
793
794template <class SrcIterator, class SrcAccessor,
795 class DestIterator, class DestAccessor>
796void recursiveSecondDerivativeLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
797 DestIterator id, DestAccessor ad, double scale)
798{
799 vigra_precondition(scale > 0,
800 "recursiveSecondDerivativeLine(): scale must be > 0.\n");
801
802 int w = isend -is;
803
804 int x;
805
806 typedef typename
807 NumericTraits<typename SrcAccessor::value_type>::RealPromote
808 TempType;
809 typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
810
811 std::vector<TempType> vline(w);
812 typename std::vector<TempType>::iterator line = vline.begin();
813
814 double b = VIGRA_CSTD::exp(-1.0/scale);
815 double a = -2.0 / (1.0 - b);
816 double norm = (1.0 - b) * (1.0 - b) * (1.0 - b) / (1.0 + b);
817 TempType old = detail::RequiresExplicitCast<TempType>::cast((1.0 / (1.0 - b)) * as(is));
818
819 // left side of filter
820 for(x=0; x<w; ++x, ++is)
821 {
822 line[x] = old;
823 old = detail::RequiresExplicitCast<TempType>::cast(as(is) + b * old);
824 }
825
826 // right side of the filter
827 --is;
828 old = detail::RequiresExplicitCast<TempType>::cast((1.0 / (1.0 - b)) * as(is));
829 id += w;
830 ++is;
831
832 for(x=w-1; x>=0; --x)
833 {
834 --is;
835 --id;
836
837 TempType f = detail::RequiresExplicitCast<TempType>::cast(old + a * as(is));
838 old = detail::RequiresExplicitCast<TempType>::cast(as(is) + b * old);
839 ad.set(DestTraits::fromRealPromote(detail::RequiresExplicitCast<TempType>::cast(norm * (line[x] + f))), id);
840 }
841}
842
843/********************************************************/
844/* */
845/* recursiveFilterX */
846/* */
847/********************************************************/
848
849/** \brief Performs 1 dimensional recursive filtering (1st and 2nd order) in x direction.
850
851 It calls \ref recursiveFilterLine() for every row of the
852 image. See \ref recursiveFilterLine() for more information about
853 required interfaces and vigra_preconditions.
854
855 <b> Declarations:</b>
856
857 pass 2D array views:
858 \code
859 namespace vigra {
860 // first order filter
861 template <class T1, class S1,
862 class T2, class S2>
863 void
864 recursiveFilterX(MultiArrayView<2, T1, S1> const & src,
865 MultiArrayView<2, T2, S2> dest,
866 double b, BorderTreatmentMode border);
867
868 // second order filter
869 template <class T1, class S1,
870 class T2, class S2>
871 void
872 recursiveFilterX(MultiArrayView<2, T1, S1> const & src,
873 MultiArrayView<2, T2, S2> dest,
874 double b1, double b2);
875 }
876 \endcode
877
878 \deprecatedAPI{recursiveFilterX}
879 pass \ref ImageIterators and \ref DataAccessors :
880 \code
881 namespace vigra {
882 // first order filter
883 template <class SrcImageIterator, class SrcAccessor,
884 class DestImageIterator, class DestAccessor>
885 void recursiveFilterX(SrcImageIterator supperleft,
886 SrcImageIterator slowerright, SrcAccessor as,
887 DestImageIterator dupperleft, DestAccessor ad,
888 double b, BorderTreatmentMode border);
889
890 // second order filter
891 template <class SrcImageIterator, class SrcAccessor,
892 class DestImageIterator, class DestAccessor>
893 void recursiveFilterX(SrcImageIterator supperleft,
894 SrcImageIterator slowerright, SrcAccessor as,
895 DestImageIterator dupperleft, DestAccessor ad,
896 double b1, double b2);
897 }
898 \endcode
899 use argument objects in conjunction with \ref ArgumentObjectFactories :
900 \code
901 namespace vigra {
902 // first order filter
903 template <class SrcImageIterator, class SrcAccessor,
904 class DestImageIterator, class DestAccessor>
905 void recursiveFilterX(
906 triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
907 pair<DestImageIterator, DestAccessor> dest,
908 double b, BorderTreatmentMode border);
909
910 // second order filter
911 template <class SrcImageIterator, class SrcAccessor,
912 class DestImageIterator, class DestAccessor>
913 void recursiveFilterX(
914 triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
915 pair<DestImageIterator, DestAccessor> dest,
916 double b1, double b2);
917 }
918 \endcode
919 \deprecatedEnd
920
921 <b> Usage:</b>
922
923 <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
924 Namespace: vigra
925
926 \code
927 MultiArray<2, float> src(w,h), dest(w,h);
928 ...
929
930 // apply a first-order filter to the x-axis
931 recursiveFilterX(src, dest, 0.5, BORDER_TREATMENT_REFLECT);
932 \endcode
933
934 \deprecatedUsage{recursiveFilterX}
935 \code
936 vigra::FImage src(w,h), dest(w,h);
937 ...
938
939 vigra::recursiveFilterX(srcImageRange(src), destImage(dest),
940 0.5, BORDER_TREATMENT_REFLECT);
941 \endcode
942 \deprecatedEnd
943*/
945
946template <class SrcImageIterator, class SrcAccessor,
947 class DestImageIterator, class DestAccessor>
948void recursiveFilterX(SrcImageIterator supperleft,
949 SrcImageIterator slowerright, SrcAccessor as,
950 DestImageIterator dupperleft, DestAccessor ad,
951 double b, BorderTreatmentMode border)
952{
953 int w = slowerright.x - supperleft.x;
954 int h = slowerright.y - supperleft.y;
955
956 int y;
957
958 for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
959 {
960 typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
961 typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
962
963 recursiveFilterLine(rs, rs+w, as,
964 rd, ad,
965 b, border);
966 }
967}
968
969template <class SrcImageIterator, class SrcAccessor,
970 class DestImageIterator, class DestAccessor>
971inline void
972recursiveFilterX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
973 pair<DestImageIterator, DestAccessor> dest,
974 double b, BorderTreatmentMode border)
975{
976 recursiveFilterX(src.first, src.second, src.third,
977 dest.first, dest.second, b, border);
978}
979
980template <class T1, class S1,
981 class T2, class S2>
982inline void
983recursiveFilterX(MultiArrayView<2, T1, S1> const & src,
984 MultiArrayView<2, T2, S2> dest,
985 double b, BorderTreatmentMode border)
986{
987 vigra_precondition(src.shape() == dest.shape(),
988 "recursiveFilterX(): shape mismatch between input and output.");
989 recursiveFilterX(srcImageRange(src),
990 destImage(dest), b, border);
991}
992
993/********************************************************/
994/* */
995/* recursiveFilterX (2nd order) */
996/* */
997/********************************************************/
998
999template <class SrcImageIterator, class SrcAccessor,
1000 class DestImageIterator, class DestAccessor>
1001void recursiveFilterX(SrcImageIterator supperleft,
1002 SrcImageIterator slowerright, SrcAccessor as,
1003 DestImageIterator dupperleft, DestAccessor ad,
1004 double b1, double b2)
1005{
1006 int w = slowerright.x - supperleft.x;
1007 int h = slowerright.y - supperleft.y;
1008
1009 int y;
1010
1011 for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
1012 {
1013 typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
1014 typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
1015
1016 recursiveFilterLine(rs, rs+w, as,
1017 rd, ad,
1018 b1, b2);
1019 }
1020}
1021
1022template <class SrcImageIterator, class SrcAccessor,
1023 class DestImageIterator, class DestAccessor>
1024inline void
1025recursiveFilterX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1026 pair<DestImageIterator, DestAccessor> dest,
1027 double b1, double b2)
1028{
1029 recursiveFilterX(src.first, src.second, src.third,
1030 dest.first, dest.second, b1, b2);
1031}
1032
1033template <class T1, class S1,
1034 class T2, class S2>
1035inline void
1036recursiveFilterX(MultiArrayView<2, T1, S1> const & src,
1037 MultiArrayView<2, T2, S2> dest,
1038 double b1, double b2)
1039{
1040 vigra_precondition(src.shape() == dest.shape(),
1041 "recursiveFilterX(): shape mismatch between input and output.");
1042 recursiveFilterX(srcImageRange(src),
1043 destImage(dest), b1, b2);
1044}
1045
1046/********************************************************/
1047/* */
1048/* recursiveGaussianFilterX */
1049/* */
1050/********************************************************/
1051
1052// AUTHOR: Sebastian Boppel
1053
1054/** \brief Compute 1 dimensional recursive approximation of Gaussian smoothing in y direction.
1055
1056 It calls \ref recursiveGaussianFilterLine() for every column of the
1057 image. See \ref recursiveGaussianFilterLine() for more information about
1058 required interfaces and vigra_preconditions.
1059
1060 <b> Declarations:</b>
1061
1062 pass 2D array views:
1063 \code
1064 namespace vigra {
1065 template <class T1, class S1,
1066 class T2, class S2>
1067 void
1068 recursiveGaussianFilterX(MultiArrayView<2, T1, S1> const & src,
1069 MultiArrayView<2, T2, S2> dest,
1070 double sigma);
1071 }
1072 \endcode
1073
1074 \deprecatedAPI{recursiveGaussianFilterX}
1075 pass \ref ImageIterators and \ref DataAccessors :
1076 \code
1077 namespace vigra {
1078 template <class SrcImageIterator, class SrcAccessor,
1079 class DestImageIterator, class DestAccessor>
1080 void
1081 recursiveGaussianFilterX(SrcImageIterator supperleft, SrcImageIterator slowerright, SrcAccessor as,
1082 DestImageIterator dupperleft, DestAccessor ad,
1083 double sigma);
1084 }
1085 \endcode
1086 use argument objects in conjunction with \ref ArgumentObjectFactories :
1087 \code
1088 namespace vigra {
1089 template <class SrcImageIterator, class SrcAccessor,
1090 class DestImageIterator, class DestAccessor>
1091 void
1092 recursiveGaussianFilterX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1093 pair<DestImageIterator, DestAccessor> dest,
1094 double sigma);
1095 }
1096 \endcode
1097 \deprecatedEnd
1098
1099 <b> Usage:</b>
1100
1101 <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
1102 Namespace: vigra
1103
1104 \code
1105 MultiArray<2, float> src(w,h), dest(w,h);
1106 ...
1107
1108 recursiveGaussianFilterX(src, dest, 3.0);
1109 \endcode
1110
1111 \deprecatedUsage{recursiveGaussianFilterX}
1112 \code
1113 vigra::FImage src(w,h), dest(w,h);
1114 ...
1115
1116 vigra::recursiveGaussianFilterX(srcImageRange(src), destImage(dest), 3.0);
1117 \endcode
1118 \deprecatedEnd
1119*/
1121
1122template <class SrcImageIterator, class SrcAccessor,
1123 class DestImageIterator, class DestAccessor>
1124void
1125recursiveGaussianFilterX(SrcImageIterator supperleft, SrcImageIterator slowerright, SrcAccessor as,
1126 DestImageIterator dupperleft, DestAccessor ad,
1127 double sigma)
1128{
1129 int w = slowerright.x - supperleft.x;
1130 int h = slowerright.y - supperleft.y;
1131
1132 int y;
1133
1134 for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
1135 {
1136 typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
1137 typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
1138
1139 recursiveGaussianFilterLine(rs, rs+w, as,
1140 rd, ad,
1141 sigma);
1142 }
1143}
1144
1145template <class SrcImageIterator, class SrcAccessor,
1146 class DestImageIterator, class DestAccessor>
1147inline void
1148recursiveGaussianFilterX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1149 pair<DestImageIterator, DestAccessor> dest,
1150 double sigma)
1151{
1152 recursiveGaussianFilterX(src.first, src.second, src.third,
1153 dest.first, dest.second, sigma);
1154}
1155
1156template <class T1, class S1,
1157 class T2, class S2>
1158inline void
1159recursiveGaussianFilterX(MultiArrayView<2, T1, S1> const & src,
1160 MultiArrayView<2, T2, S2> dest,
1161 double sigma)
1162{
1163 vigra_precondition(src.shape() == dest.shape(),
1164 "recursiveGaussianFilterX(): shape mismatch between input and output.");
1165 recursiveGaussianFilterX(srcImageRange(src),
1166 destImage(dest), sigma);
1167}
1168
1169/********************************************************/
1170/* */
1171/* recursiveSmoothX */
1172/* */
1173/********************************************************/
1174
1175/** \brief Performs 1 dimensional recursive smoothing in x direction.
1176
1177 It calls \ref recursiveSmoothLine() for every row of the
1178 image. See \ref recursiveSmoothLine() for more information about
1179 required interfaces and vigra_preconditions.
1180
1181 <b> Declarations:</b>
1182
1183 pass 2D array views:
1184 \code
1185 namespace vigra {
1186 template <class T1, class S1,
1187 class T2, class S2>
1188 void
1189 recursiveSmoothX(MultiArrayView<2, T1, S1> const & src,
1190 MultiArrayView<2, T2, S2> dest,
1191 double scale);
1192 }
1193 \endcode
1194
1195 \deprecatedAPI{recursiveSmoothX}
1196 pass \ref ImageIterators and \ref DataAccessors :
1197 \code
1198 namespace vigra {
1199 template <class SrcImageIterator, class SrcAccessor,
1200 class DestImageIterator, class DestAccessor>
1201 void recursiveSmoothX(SrcImageIterator supperleft,
1202 SrcImageIterator slowerright, SrcAccessor as,
1203 DestImageIterator dupperleft, DestAccessor ad,
1204 double scale)
1205 }
1206 \endcode
1207 use argument objects in conjunction with \ref ArgumentObjectFactories :
1208 \code
1209 namespace vigra {
1210 template <class SrcImageIterator, class SrcAccessor,
1211 class DestImageIterator, class DestAccessor>
1212 void recursiveSmoothX(
1213 triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1214 pair<DestImageIterator, DestAccessor> dest,
1215 double scale)
1216 }
1217 \endcode
1218 \deprecatedEnd
1219
1220 <b> Usage:</b>
1221
1222 <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
1223 Namespace: vigra
1224
1225 \code
1226 MultiArray<2, float> src(w,h), dest(w,h);
1227 ...
1228
1229 recursiveSmoothX(src, dest, 3.0);
1230 \endcode
1231
1232 \deprecatedUsage{recursiveGaussianFilterX}
1233 \code
1234 vigra::FImage src(w,h), dest(w,h);
1235 ...
1236
1237 vigra::recursiveSmoothX(srcImageRange(src), destImage(dest), 3.0);
1238 \endcode
1239 \deprecatedEnd
1240*/
1242
1243template <class SrcImageIterator, class SrcAccessor,
1244 class DestImageIterator, class DestAccessor>
1245void recursiveSmoothX(SrcImageIterator supperleft,
1246 SrcImageIterator slowerright, SrcAccessor as,
1247 DestImageIterator dupperleft, DestAccessor ad,
1248 double scale)
1249{
1250 int w = slowerright.x - supperleft.x;
1251 int h = slowerright.y - supperleft.y;
1252
1253 int y;
1254
1255 for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
1256 {
1257 typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
1258 typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
1259
1260 recursiveSmoothLine(rs, rs+w, as,
1261 rd, ad,
1262 scale);
1263 }
1264}
1265
1266template <class SrcImageIterator, class SrcAccessor,
1267 class DestImageIterator, class DestAccessor>
1268inline void
1269recursiveSmoothX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1270 pair<DestImageIterator, DestAccessor> dest,
1271 double scale)
1272{
1273 recursiveSmoothX(src.first, src.second, src.third,
1274 dest.first, dest.second, scale);
1275}
1276
1277template <class T1, class S1,
1278 class T2, class S2>
1279inline void
1280recursiveSmoothX(MultiArrayView<2, T1, S1> const & src,
1281 MultiArrayView<2, T2, S2> dest,
1282 double scale)
1283{
1284 vigra_precondition(src.shape() == dest.shape(),
1285 "recursiveSmoothX(): shape mismatch between input and output.");
1286 recursiveSmoothX(srcImageRange(src),
1287 destImage(dest), scale);
1288}
1289
1290/********************************************************/
1291/* */
1292/* recursiveFilterY */
1293/* */
1294/********************************************************/
1295
1296/** \brief Performs 1 dimensional recursive filtering (1st and 2nd order) in y direction.
1297
1298 It calls \ref recursiveFilterLine() for every column of the
1299 image. See \ref recursiveFilterLine() for more information about
1300 required interfaces and vigra_preconditions.
1301
1302 <b> Declarations:</b>
1303
1304 pass 2D array views:
1305 \code
1306 namespace vigra {
1307 // first order filter
1308 template <class T1, class S1,
1309 class T2, class S2>
1310 void
1311 recursiveFilterY(MultiArrayView<2, T1, S1> const & src,
1312 MultiArrayView<2, T2, S2> dest,
1313 double b, BorderTreatmentMode border);
1314
1315 // second order filter
1316 template <class T1, class S1,
1317 class T2, class S2>
1318 void
1319 recursiveFilterY(MultiArrayView<2, T1, S1> const & src,
1320 MultiArrayView<2, T2, S2> dest,
1321 double b1, double b2);
1322 }
1323 \endcode
1324
1325 \deprecatedAPI{recursiveFilterY}
1326 pass \ref ImageIterators and \ref DataAccessors :
1327 \code
1328 namespace vigra {
1329 // first order filter
1330 template <class SrcImageIterator, class SrcAccessor,
1331 class DestImageIterator, class DestAccessor>
1332 void recursiveFilterY(SrcImageIterator supperleft,
1333 SrcImageIterator slowerright, SrcAccessor as,
1334 DestImageIterator dupperleft, DestAccessor ad,
1335 double b, BorderTreatmentMode border);
1336
1337 // second order filter
1338 template <class SrcImageIterator, class SrcAccessor,
1339 class DestImageIterator, class DestAccessor>
1340 void recursiveFilterY(SrcImageIterator supperleft,
1341 SrcImageIterator slowerright, SrcAccessor as,
1342 DestImageIterator dupperleft, DestAccessor ad,
1343 double b1, double b2);
1344 }
1345 \endcode
1346 use argument objects in conjunction with \ref ArgumentObjectFactories :
1347 \code
1348 namespace vigra {
1349 // first order filter
1350 template <class SrcImageIterator, class SrcAccessor,
1351 class DestImageIterator, class DestAccessor>
1352 void recursiveFilterY(
1353 triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1354 pair<DestImageIterator, DestAccessor> dest,
1355 double b, BorderTreatmentMode border);
1356
1357 // second order filter
1358 template <class SrcImageIterator, class SrcAccessor,
1359 class DestImageIterator, class DestAccessor>
1360 void recursiveFilterY(
1361 triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1362 pair<DestImageIterator, DestAccessor> dest,
1363 double b1, double b2);
1364 }
1365 \endcode
1366 \deprecatedEnd
1367
1368 <b> Usage:</b>
1369
1370 <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
1371 Namespace: vigra
1372
1373 \code
1374 MultiArray<2, float> src(w,h), dest(w,h);
1375 ...
1376
1377 // apply a second-order filter to the y-axis
1378 recursiveFilterY(src, dest, -0.6, -0.06);
1379 \endcode
1380
1381 \deprecatedUsage{recursiveFilterY}
1382 \code
1383 vigra::FImage src(w,h), dest(w,h);
1384 ...
1385
1386 vigra::recursiveFilterY(srcImageRange(src), destImage(dest), -0.6, -0.06);
1387 \endcode
1388 \deprecatedEnd
1389*/
1391
1392template <class SrcImageIterator, class SrcAccessor,
1393 class DestImageIterator, class DestAccessor>
1394void recursiveFilterY(SrcImageIterator supperleft,
1395 SrcImageIterator slowerright, SrcAccessor as,
1396 DestImageIterator dupperleft, DestAccessor ad,
1397 double b, BorderTreatmentMode border)
1398{
1399 int w = slowerright.x - supperleft.x;
1400 int h = slowerright.y - supperleft.y;
1401
1402 int x;
1403
1404 for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
1405 {
1406 typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
1407 typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
1408
1409 recursiveFilterLine(cs, cs+h, as,
1410 cd, ad,
1411 b, border);
1412 }
1413}
1414
1415template <class SrcImageIterator, class SrcAccessor,
1416 class DestImageIterator, class DestAccessor>
1417inline void
1418recursiveFilterY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1419 pair<DestImageIterator, DestAccessor> dest,
1420 double b, BorderTreatmentMode border)
1421{
1422 recursiveFilterY(src.first, src.second, src.third,
1423 dest.first, dest.second, b, border);
1424}
1425
1426template <class T1, class S1,
1427 class T2, class S2>
1428inline void
1429recursiveFilterY(MultiArrayView<2, T1, S1> const & src,
1430 MultiArrayView<2, T2, S2> dest,
1431 double b, BorderTreatmentMode border)
1432{
1433 vigra_precondition(src.shape() == dest.shape(),
1434 "recursiveFilterY(): shape mismatch between input and output.");
1435 recursiveFilterY(srcImageRange(src),
1436 destImage(dest), b, border);
1437}
1438
1439/********************************************************/
1440/* */
1441/* recursiveFilterY (2nd order) */
1442/* */
1443/********************************************************/
1444
1445template <class SrcImageIterator, class SrcAccessor,
1446 class DestImageIterator, class DestAccessor>
1447void recursiveFilterY(SrcImageIterator supperleft,
1448 SrcImageIterator slowerright, SrcAccessor as,
1449 DestImageIterator dupperleft, DestAccessor ad,
1450 double b1, double b2)
1451{
1452 int w = slowerright.x - supperleft.x;
1453 int h = slowerright.y - supperleft.y;
1454
1455 int x;
1456
1457 for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
1458 {
1459 typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
1460 typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
1461
1462 recursiveFilterLine(cs, cs+h, as,
1463 cd, ad,
1464 b1, b2);
1465 }
1466}
1467
1468template <class SrcImageIterator, class SrcAccessor,
1469 class DestImageIterator, class DestAccessor>
1470inline void
1471recursiveFilterY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1472 pair<DestImageIterator, DestAccessor> dest,
1473 double b1, double b2)
1474{
1475 recursiveFilterY(src.first, src.second, src.third,
1476 dest.first, dest.second, b1, b2);
1477}
1478
1479template <class T1, class S1,
1480 class T2, class S2>
1481inline void
1482recursiveFilterY(MultiArrayView<2, T1, S1> const & src,
1483 MultiArrayView<2, T2, S2> dest,
1484 double b1, double b2)
1485{
1486 vigra_precondition(src.shape() == dest.shape(),
1487 "recursiveFilterY(): shape mismatch between input and output.");
1488 recursiveFilterY(srcImageRange(src),
1489 destImage(dest), b1, b2);
1490}
1491
1492/********************************************************/
1493/* */
1494/* recursiveGaussianFilterY */
1495/* */
1496/********************************************************/
1497
1498// AUTHOR: Sebastian Boppel
1499
1500/** \brief Compute 1 dimensional recursive approximation of Gaussian smoothing in y direction.
1501
1502 It calls \ref recursiveGaussianFilterLine() for every column of the
1503 image. See \ref recursiveGaussianFilterLine() for more information about
1504 required interfaces and vigra_preconditions.
1505
1506 <b> Declarations:</b>
1507
1508 pass 2D array views:
1509 \code
1510 namespace vigra {
1511 template <class T1, class S1,
1512 class T2, class S2>
1513 void
1514 recursiveGaussianFilterY(MultiArrayView<2, T1, S1> const & src,
1515 MultiArrayView<2, T2, S2> dest,
1516 double sigma);
1517 }
1518 \endcode
1519
1520 \deprecatedAPI{recursiveGaussianFilterY}
1521 pass \ref ImageIterators and \ref DataAccessors :
1522 \code
1523 namespace vigra {
1524 template <class SrcImageIterator, class SrcAccessor,
1525 class DestImageIterator, class DestAccessor>
1526 void
1527 recursiveGaussianFilterY(SrcImageIterator supperleft, SrcImageIterator slowerright, SrcAccessor as,
1528 DestImageIterator dupperleft, DestAccessor ad,
1529 double sigma);
1530 }
1531 \endcode
1532 use argument objects in conjunction with \ref ArgumentObjectFactories :
1533 \code
1534 namespace vigra {
1535 template <class SrcImageIterator, class SrcAccessor,
1536 class DestImageIterator, class DestAccessor>
1537 void
1538 recursiveGaussianFilterY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1539 pair<DestImageIterator, DestAccessor> dest,
1540 double sigma);
1541 }
1542 \endcode
1543 \deprecatedEnd
1544
1545 <b> Usage:</b>
1546
1547 <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
1548 Namespace: vigra
1549
1550 \code
1551 MultiArray<2, float> src(w,h), dest(w,h);
1552 ...
1553
1554 recursiveGaussianFilterY(src, dest, 3.0);
1555 \endcode
1556
1557 \deprecatedUsage{recursiveGaussianFilterY}
1558 \code
1559 vigra::FImage src(w,h), dest(w,h);
1560 ...
1561
1562 vigra::recursiveGaussianFilterY(srcImageRange(src), destImage(dest), 3.0);
1563 \endcode
1564 \deprecatedEnd
1565*/
1567
1568template <class SrcImageIterator, class SrcAccessor,
1569 class DestImageIterator, class DestAccessor>
1570void
1571recursiveGaussianFilterY(SrcImageIterator supperleft, SrcImageIterator slowerright, SrcAccessor as,
1572 DestImageIterator dupperleft, DestAccessor ad,
1573 double sigma)
1574{
1575 int w = slowerright.x - supperleft.x;
1576 int h = slowerright.y - supperleft.y;
1577
1578 int x;
1579
1580 for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
1581 {
1582 typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
1583 typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
1584
1585 recursiveGaussianFilterLine(cs, cs+h, as,
1586 cd, ad,
1587 sigma);
1588 }
1589}
1590
1591template <class SrcImageIterator, class SrcAccessor,
1592 class DestImageIterator, class DestAccessor>
1593inline void
1594recursiveGaussianFilterY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1595 pair<DestImageIterator, DestAccessor> dest,
1596 double sigma)
1597{
1598 recursiveGaussianFilterY(src.first, src.second, src.third,
1599 dest.first, dest.second, sigma);
1600}
1601
1602template <class T1, class S1,
1603 class T2, class S2>
1604inline void
1605recursiveGaussianFilterY(MultiArrayView<2, T1, S1> const & src,
1606 MultiArrayView<2, T2, S2> dest,
1607 double sigma)
1608{
1609 vigra_precondition(src.shape() == dest.shape(),
1610 "recursiveGaussianFilterY(): shape mismatch between input and output.");
1611 recursiveGaussianFilterY(srcImageRange(src),
1612 destImage(dest), sigma);
1613}
1614
1615
1616/********************************************************/
1617/* */
1618/* recursiveSmoothY */
1619/* */
1620/********************************************************/
1621
1622/** \brief Performs 1 dimensional recursive smoothing in y direction.
1623
1624 It calls \ref recursiveSmoothLine() for every column of the
1625 image. See \ref recursiveSmoothLine() for more information about
1626 required interfaces and vigra_preconditions.
1627
1628 <b> Declarations:</b>
1629
1630 pass 2D array views:
1631 \code
1632 namespace vigra {
1633 template <class T1, class S1,
1634 class T2, class S2>
1635 void
1636 recursiveSmoothY(MultiArrayView<2, T1, S1> const & src,
1637 MultiArrayView<2, T2, S2> dest,
1638 double scale);
1639 }
1640 \endcode
1641
1642 \deprecatedAPI{recursiveSmoothY}
1643 pass \ref ImageIterators and \ref DataAccessors :
1644 \code
1645 namespace vigra {
1646 template <class SrcImageIterator, class SrcAccessor,
1647 class DestImageIterator, class DestAccessor>
1648 void recursiveSmoothY(SrcImageIterator supperleft,
1649 SrcImageIterator slowerright, SrcAccessor as,
1650 DestImageIterator dupperleft, DestAccessor ad,
1651 double scale)
1652 }
1653 \endcode
1654 use argument objects in conjunction with \ref ArgumentObjectFactories :
1655 \code
1656 namespace vigra {
1657 template <class SrcImageIterator, class SrcAccessor,
1658 class DestImageIterator, class DestAccessor>
1659 void recursiveSmoothY(
1660 triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1661 pair<DestImageIterator, DestAccessor> dest,
1662 double scale)
1663 }
1664 \endcode
1665 \deprecatedEnd
1666
1667 <b> Usage:</b>
1668
1669 <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
1670 Namespace: vigra
1671
1672 \code
1673 MultiArray<2, float> src(w,h), dest(w,h);
1674 ...
1675
1676 recursiveSmoothY(src, dest, 3.0);
1677 \endcode
1678
1679 \deprecatedUsage{recursiveSmoothY}
1680 \code
1681 vigra::FImage src(w,h), dest(w,h);
1682 ...
1683
1684 vigra::recursiveSmoothY(srcImageRange(src), destImage(dest), 3.0);
1685 \endcode
1686 \deprecatedEnd
1687*/
1689
1690template <class SrcImageIterator, class SrcAccessor,
1691 class DestImageIterator, class DestAccessor>
1692void recursiveSmoothY(SrcImageIterator supperleft,
1693 SrcImageIterator slowerright, SrcAccessor as,
1694 DestImageIterator dupperleft, DestAccessor ad,
1695 double scale)
1696{
1697 int w = slowerright.x - supperleft.x;
1698 int h = slowerright.y - supperleft.y;
1699
1700 int x;
1701
1702 for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
1703 {
1704 typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
1705 typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
1706
1707 recursiveSmoothLine(cs, cs+h, as,
1708 cd, ad,
1709 scale);
1710 }
1711}
1712
1713template <class SrcImageIterator, class SrcAccessor,
1714 class DestImageIterator, class DestAccessor>
1715inline void
1716recursiveSmoothY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1717 pair<DestImageIterator, DestAccessor> dest,
1718 double scale)
1719{
1720 recursiveSmoothY(src.first, src.second, src.third,
1721 dest.first, dest.second, scale);
1722}
1723
1724template <class T1, class S1,
1725 class T2, class S2>
1726inline void
1727recursiveSmoothY(MultiArrayView<2, T1, S1> const & src,
1728 MultiArrayView<2, T2, S2> dest,
1729 double scale)
1730{
1731 vigra_precondition(src.shape() == dest.shape(),
1732 "recursiveSmoothY(): shape mismatch between input and output.");
1733 recursiveSmoothY(srcImageRange(src),
1734 destImage(dest), scale);
1735}
1736
1737/********************************************************/
1738/* */
1739/* recursiveFirstDerivativeX */
1740/* */
1741/********************************************************/
1742
1743/** \brief Recursively calculates the 1 dimensional first derivative in x
1744 direction.
1745
1746 It calls \ref recursiveFirstDerivativeLine() for every
1747 row of the image. See \ref recursiveFirstDerivativeLine() for more
1748 information about required interfaces and vigra_preconditions.
1749
1750 <b> Declarations:</b>
1751
1752 pass 2D array views:
1753 \code
1754 namespace vigra {
1755 template <class T1, class S1,
1756 class T2, class S2>
1757 void
1758 recursiveFirstDerivativeX(MultiArrayView<2, T1, S1> const & src,
1759 MultiArrayView<2, T2, S2> dest,
1760 double scale);
1761 }
1762 \endcode
1763
1764 \deprecatedAPI{recursiveFirstDerivativeX}
1765 pass \ref ImageIterators and \ref DataAccessors :
1766 \code
1767 namespace vigra {
1768 template <class SrcImageIterator, class SrcAccessor,
1769 class DestImageIterator, class DestAccessor>
1770 void recursiveFirstDerivativeX(SrcImageIterator supperleft,
1771 SrcImageIterator slowerright, SrcAccessor as,
1772 DestImageIterator dupperleft, DestAccessor ad,
1773 double scale)
1774 }
1775 \endcode
1776 use argument objects in conjunction with \ref ArgumentObjectFactories :
1777 \code
1778 namespace vigra {
1779 template <class SrcImageIterator, class SrcAccessor,
1780 class DestImageIterator, class DestAccessor>
1781 void recursiveFirstDerivativeX(
1782 triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1783 pair<DestImageIterator, DestAccessor> dest,
1784 double scale)
1785 }
1786 \endcode
1787 \deprecatedEnd
1788
1789 <b> Usage:</b>
1790
1791 <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
1792 Namespace: vigra
1793
1794 \code
1795 MultiArray<2, float> src(w,h), dest(w,h);
1796 ...
1797
1798 recursiveFirstDerivativeX(src, dest, 3.0);
1799 \endcode
1800
1801 \deprecatedUsage{recursiveFirstDerivativeX}
1802 \code
1803 vigra::FImage src(w,h), dest(w,h);
1804 ...
1805
1806 vigra::recursiveFirstDerivativeX(srcImageRange(src), destImage(dest), 3.0);
1807 \endcode
1808 \deprecatedEnd
1809*/
1811
1812template <class SrcImageIterator, class SrcAccessor,
1813 class DestImageIterator, class DestAccessor>
1814void recursiveFirstDerivativeX(SrcImageIterator supperleft,
1815 SrcImageIterator slowerright, SrcAccessor as,
1816 DestImageIterator dupperleft, DestAccessor ad,
1817 double scale)
1818{
1819 int w = slowerright.x - supperleft.x;
1820 int h = slowerright.y - supperleft.y;
1821
1822 int y;
1823
1824 for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
1825 {
1826 typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
1827 typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
1828
1829 recursiveFirstDerivativeLine(rs, rs+w, as,
1830 rd, ad,
1831 scale);
1832 }
1833}
1834
1835template <class SrcImageIterator, class SrcAccessor,
1836 class DestImageIterator, class DestAccessor>
1837inline void
1838recursiveFirstDerivativeX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1839 pair<DestImageIterator, DestAccessor> dest,
1840 double scale)
1841{
1842 recursiveFirstDerivativeX(src.first, src.second, src.third,
1843 dest.first, dest.second, scale);
1844}
1845
1846template <class T1, class S1,
1847 class T2, class S2>
1848inline void
1849recursiveFirstDerivativeX(MultiArrayView<2, T1, S1> const & src,
1850 MultiArrayView<2, T2, S2> dest,
1851 double scale)
1852{
1853 vigra_precondition(src.shape() == dest.shape(),
1854 "recursiveFirstDerivativeX(): shape mismatch between input and output.");
1855 recursiveFirstDerivativeX(srcImageRange(src),
1856 destImage(dest), scale);
1857}
1858
1859/********************************************************/
1860/* */
1861/* recursiveFirstDerivativeY */
1862/* */
1863/********************************************************/
1864
1865/** \brief Recursively calculates the 1 dimensional first derivative in y
1866 direction.
1867
1868 It calls \ref recursiveFirstDerivativeLine() for every
1869 column of the image. See \ref recursiveFirstDerivativeLine() for more
1870 information about required interfaces and vigra_preconditions.
1871
1872 <b> Declarations:</b>
1873
1874 pass 2D array views:
1875 \code
1876 namespace vigra {
1877 template <class T1, class S1,
1878 class T2, class S2>
1879 void
1880 recursiveFirstDerivativeY(MultiArrayView<2, T1, S1> const & src,
1881 MultiArrayView<2, T2, S2> dest,
1882 double scale);
1883 }
1884 \endcode
1885
1886 \deprecatedAPI{recursiveFirstDerivativeY}
1887 pass \ref ImageIterators and \ref DataAccessors :
1888 \code
1889 namespace vigra {
1890 template <class SrcImageIterator, class SrcAccessor,
1891 class DestImageIterator, class DestAccessor>
1892 void recursiveFirstDerivativeY(SrcImageIterator supperleft,
1893 SrcImageIterator slowerright, SrcAccessor as,
1894 DestImageIterator dupperleft, DestAccessor ad,
1895 double scale)
1896 }
1897 \endcode
1898 use argument objects in conjunction with \ref ArgumentObjectFactories :
1899 \code
1900 namespace vigra {
1901 template <class SrcImageIterator, class SrcAccessor,
1902 class DestImageIterator, class DestAccessor>
1903 void recursiveFirstDerivativeY(
1904 triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1905 pair<DestImageIterator, DestAccessor> dest,
1906 double scale)
1907 }
1908 \endcode
1909 \deprecatedEnd
1910
1911 <b> Usage:</b>
1912
1913 <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
1914 Namespace: vigra
1915
1916 \code
1917 MultiArray<2, float> src(w,h), dest(w,h);
1918 ...
1919
1920 recursiveFirstDerivativeY(src, dest, 3.0);
1921 \endcode
1922
1923 \deprecatedUsage{recursiveFirstDerivativeY}
1924 \code
1925 vigra::FImage src(w,h), dest(w,h);
1926 ...
1927
1928 vigra::recursiveFirstDerivativeY(srcImageRange(src), destImage(dest), 3.0);
1929 \endcode
1930 \deprecatedEnd
1931*/
1933
1934template <class SrcImageIterator, class SrcAccessor,
1935 class DestImageIterator, class DestAccessor>
1936void recursiveFirstDerivativeY(SrcImageIterator supperleft,
1937 SrcImageIterator slowerright, SrcAccessor as,
1938 DestImageIterator dupperleft, DestAccessor ad,
1939 double scale)
1940{
1941 int w = slowerright.x - supperleft.x;
1942 int h = slowerright.y - supperleft.y;
1943
1944 int x;
1945
1946 for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
1947 {
1948 typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
1949 typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
1950
1951 recursiveFirstDerivativeLine(cs, cs+h, as,
1952 cd, ad,
1953 scale);
1954 }
1955}
1956
1957template <class SrcImageIterator, class SrcAccessor,
1958 class DestImageIterator, class DestAccessor>
1959inline void
1960recursiveFirstDerivativeY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
1961 pair<DestImageIterator, DestAccessor> dest,
1962 double scale)
1963{
1964 recursiveFirstDerivativeY(src.first, src.second, src.third,
1965 dest.first, dest.second, scale);
1966}
1967
1968template <class T1, class S1,
1969 class T2, class S2>
1970inline void
1971recursiveFirstDerivativeY(MultiArrayView<2, T1, S1> const & src,
1972 MultiArrayView<2, T2, S2> dest,
1973 double scale)
1974{
1975 vigra_precondition(src.shape() == dest.shape(),
1976 "recursiveFirstDerivativeY(): shape mismatch between input and output.");
1977 recursiveFirstDerivativeY(srcImageRange(src),
1978 destImage(dest), scale);
1979}
1980
1981/********************************************************/
1982/* */
1983/* recursiveSecondDerivativeX */
1984/* */
1985/********************************************************/
1986
1987/** \brief Recursively calculates the 1 dimensional second derivative in x
1988 direction.
1989
1990 It calls \ref recursiveSecondDerivativeLine() for every
1991 row of the image. See \ref recursiveSecondDerivativeLine() for more
1992 information about required interfaces and vigra_preconditions.
1993
1994 <b> Declarations:</b>
1995
1996 pass 2D array views:
1997 \code
1998 namespace vigra {
1999 template <class T1, class S1,
2000 class T2, class S2>
2001 void
2002 recursiveSecondDerivativeX(MultiArrayView<2, T1, S1> const & src,
2003 MultiArrayView<2, T2, S2> dest,
2004 double scale);
2005 }
2006 \endcode
2007
2008 \deprecatedAPI{recursiveSecondDerivativeX}
2009 pass \ref ImageIterators and \ref DataAccessors :
2010 \code
2011 namespace vigra {
2012 template <class SrcImageIterator, class SrcAccessor,
2013 class DestImageIterator, class DestAccessor>
2014 void recursiveSecondDerivativeX(SrcImageIterator supperleft,
2015 SrcImageIterator slowerright, SrcAccessor as,
2016 DestImageIterator dupperleft, DestAccessor ad,
2017 double scale)
2018 }
2019 \endcode
2020 use argument objects in conjunction with \ref ArgumentObjectFactories :
2021 \code
2022 namespace vigra {
2023 template <class SrcImageIterator, class SrcAccessor,
2024 class DestImageIterator, class DestAccessor>
2025 void recursiveSecondDerivativeX(
2026 triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
2027 pair<DestImageIterator, DestAccessor> dest,
2028 double scale)
2029 }
2030 \endcode
2031 \deprecatedEnd
2032
2033 <b> Usage:</b>
2034
2035 <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
2036 Namespace: vigra
2037
2038 \code
2039 MultiArray<2, float> src(w,h), dest(w,h);
2040 ...
2041
2042 recursiveSecondDerivativeX(src, dest, 3.0);
2043 \endcode
2044
2045 \deprecatedUsage{recursiveSecondDerivativeX}
2046 \code
2047 vigra::FImage src(w,h), dest(w,h);
2048 ...
2049
2050 vigra::recursiveSecondDerivativeX(srcImageRange(src), destImage(dest), 3.0);
2051 \endcode
2052 \deprecatedEnd
2053*/
2055
2056template <class SrcImageIterator, class SrcAccessor,
2057 class DestImageIterator, class DestAccessor>
2058void recursiveSecondDerivativeX(SrcImageIterator supperleft,
2059 SrcImageIterator slowerright, SrcAccessor as,
2060 DestImageIterator dupperleft, DestAccessor ad,
2061 double scale)
2062{
2063 int w = slowerright.x - supperleft.x;
2064 int h = slowerright.y - supperleft.y;
2065
2066 int y;
2067
2068 for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
2069 {
2070 typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
2071 typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
2072
2073 recursiveSecondDerivativeLine(rs, rs+w, as,
2074 rd, ad,
2075 scale);
2076 }
2077}
2078
2079template <class SrcImageIterator, class SrcAccessor,
2080 class DestImageIterator, class DestAccessor>
2081inline void
2082recursiveSecondDerivativeX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
2083 pair<DestImageIterator, DestAccessor> dest,
2084 double scale)
2085{
2086 recursiveSecondDerivativeX(src.first, src.second, src.third,
2087 dest.first, dest.second, scale);
2088}
2089
2090template <class T1, class S1,
2091 class T2, class S2>
2092inline void
2093recursiveSecondDerivativeX(MultiArrayView<2, T1, S1> const & src,
2094 MultiArrayView<2, T2, S2> dest,
2095 double scale)
2096{
2097 vigra_precondition(src.shape() == dest.shape(),
2098 "recursiveSecondDerivativeX(): shape mismatch between input and output.");
2099 recursiveSecondDerivativeX(srcImageRange(src),
2100 destImage(dest), scale);
2101}
2102
2103/********************************************************/
2104/* */
2105/* recursiveSecondDerivativeY */
2106/* */
2107/********************************************************/
2108
2109/** \brief Recursively calculates the 1 dimensional second derivative in y
2110 direction.
2111
2112 It calls \ref recursiveSecondDerivativeLine() for every
2113 column of the image. See \ref recursiveSecondDerivativeLine() for more
2114 information about required interfaces and vigra_preconditions.
2115
2116 <b> Declarations:</b>
2117
2118 pass 2D array views:
2119 \code
2120 namespace vigra {
2121 template <class T1, class S1,
2122 class T2, class S2>
2123 void
2124 recursiveSecondDerivativeY(MultiArrayView<2, T1, S1> const & src,
2125 MultiArrayView<2, T2, S2> dest,
2126 double scale);
2127 }
2128 \endcode
2129
2130 \deprecatedAPI{recursiveSecondDerivativeY}
2131 pass \ref ImageIterators and \ref DataAccessors :
2132 \code
2133 namespace vigra {
2134 template <class SrcImageIterator, class SrcAccessor,
2135 class DestImageIterator, class DestAccessor>
2136 void recursiveSecondDerivativeY(SrcImageIterator supperleft,
2137 SrcImageIterator slowerright, SrcAccessor as,
2138 DestImageIterator dupperleft, DestAccessor ad,
2139 double scale)
2140 }
2141 \endcode
2142 use argument objects in conjunction with \ref ArgumentObjectFactories :
2143 \code
2144 namespace vigra {
2145 template <class SrcImageIterator, class SrcAccessor,
2146 class DestImageIterator, class DestAccessor>
2147 void recursiveSecondDerivativeY(
2148 triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
2149 pair<DestImageIterator, DestAccessor> dest,
2150 double scale)
2151 }
2152 \endcode
2153 \deprecatedEnd
2154
2155 <b> Usage:</b>
2156
2157 <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
2158 Namespace: vigra
2159
2160 \code
2161 MultiArray<2, float> src(w,h), dest(w,h);
2162 ...
2163
2164 recursiveSecondDerivativeY(src, dest, 3.0);
2165 \endcode
2166
2167 \deprecatedUsage{recursiveSecondDerivativeY}
2168 \code
2169 vigra::FImage src(w,h), dest(w,h);
2170 ...
2171
2172 vigra::recursiveSecondDerivativeY(srcImageRange(src), destImage(dest), 3.0);
2173 \endcode
2174 \deprecatedEnd
2175*/
2177
2178template <class SrcImageIterator, class SrcAccessor,
2179 class DestImageIterator, class DestAccessor>
2180void recursiveSecondDerivativeY(SrcImageIterator supperleft,
2181 SrcImageIterator slowerright, SrcAccessor as,
2182 DestImageIterator dupperleft, DestAccessor ad,
2183 double scale)
2184{
2185 int w = slowerright.x - supperleft.x;
2186 int h = slowerright.y - supperleft.y;
2187
2188 int x;
2189
2190 for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
2191 {
2192 typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
2193 typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
2194
2195 recursiveSecondDerivativeLine(cs, cs+h, as,
2196 cd, ad,
2197 scale);
2198 }
2199}
2200
2201template <class SrcImageIterator, class SrcAccessor,
2202 class DestImageIterator, class DestAccessor>
2203inline void
2204recursiveSecondDerivativeY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
2205 pair<DestImageIterator, DestAccessor> dest,
2206 double scale)
2207{
2208 recursiveSecondDerivativeY(src.first, src.second, src.third,
2209 dest.first, dest.second, scale);
2210}
2211
2212template <class T1, class S1,
2213 class T2, class S2>
2214inline void
2215recursiveSecondDerivativeY(MultiArrayView<2, T1, S1> const & src,
2216 MultiArrayView<2, T2, S2> dest,
2217 double scale)
2218{
2219 vigra_precondition(src.shape() == dest.shape(),
2220 "recursiveSecondDerivativeY(): shape mismatch between input and output.");
2221 recursiveSecondDerivativeY(srcImageRange(src),
2222 destImage(dest), scale);
2223}
2224
2225//@}
2226
2227} // namespace vigra
2228
2229#endif // VIGRA_RECURSIVECONVOLUTION_HXX
void recursiveSmoothX(...)
Performs 1 dimensional recursive smoothing in x direction.
void recursiveFirstDerivativeY(...)
Recursively calculates the 1 dimensional first derivative in y direction.
void recursiveGaussianFilterY(...)
Compute 1 dimensional recursive approximation of Gaussian smoothing in y direction.
void recursiveSmoothY(...)
Performs 1 dimensional recursive smoothing in y direction.
void recursiveGaussianFilterX(...)
Compute 1 dimensional recursive approximation of Gaussian smoothing in y direction.
FFTWComplex< R >::NormType norm(const FFTWComplex< R > &a)
norm (= magnitude)
Definition: fftw3.hxx:1037
void recursiveGaussianFilterLine(...)
Compute a 1-dimensional recursive approximation of Gaussian smoothing.
void recursiveFilterY(...)
Performs 1 dimensional recursive filtering (1st and 2nd order) in y direction.
void recursiveSecondDerivativeLine(...)
Performs a 1 dimensional recursive convolution of the source signal.
doxygen_overloaded_function(template<... > void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays.
void recursiveFirstDerivativeLine(...)
Performs a 1 dimensional recursive convolution of the source signal.
void recursiveFilterX(...)
Performs 1 dimensional recursive filtering (1st and 2nd order) in x direction.
void recursiveSmoothLine(...)
Convolves the image with a 1-dimensional exponential filter.
void recursiveFirstDerivativeX(...)
Recursively calculates the 1 dimensional first derivative in x direction.
void recursiveSecondDerivativeX(...)
Recursively calculates the 1 dimensional second derivative in x direction.
void recursiveFilterLine(...)
Performs a 1-dimensional recursive convolution of the source signal.
void recursiveSecondDerivativeY(...)
Recursively calculates the 1 dimensional second derivative in y direction.

© 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