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

vigra/recursiveconvolution.hxx |

    00001 /************************************************************************/
    00002 /*                                                                      */
    00003 /*               Copyright 1998-2002 by Ullrich Koethe                  */
    00004 /*                                                                      */
    00005 /*    This file is part of the VIGRA computer vision library.           */
    00006 /*    The VIGRA Website is                                              */
    00007 /*        http://hci.iwr.uni-heidelberg.de/vigra/                       */
    00008 /*    Please direct questions, bug reports, and contributions to        */
    00009 /*        ullrich.koethe@iwr.uni-heidelberg.de    or                    */
    00010 /*        vigra@informatik.uni-hamburg.de                               */
    00011 /*                                                                      */
    00012 /*    Permission is hereby granted, free of charge, to any person       */
    00013 /*    obtaining a copy of this software and associated documentation    */
    00014 /*    files (the "Software"), to deal in the Software without           */
    00015 /*    restriction, including without limitation the rights to use,      */
    00016 /*    copy, modify, merge, publish, distribute, sublicense, and/or      */
    00017 /*    sell copies of the Software, and to permit persons to whom the    */
    00018 /*    Software is furnished to do so, subject to the following          */
    00019 /*    conditions:                                                       */
    00020 /*                                                                      */
    00021 /*    The above copyright notice and this permission notice shall be    */
    00022 /*    included in all copies or substantial portions of the             */
    00023 /*    Software.                                                         */
    00024 /*                                                                      */
    00025 /*    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND    */
    00026 /*    EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES   */
    00027 /*    OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND          */
    00028 /*    NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT       */
    00029 /*    HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,      */
    00030 /*    WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING      */
    00031 /*    FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR     */
    00032 /*    OTHER DEALINGS IN THE SOFTWARE.                                   */
    00033 /*                                                                      */
    00034 /************************************************************************/
    00035
    00036
    00037 #ifndef VIGRA_RECURSIVECONVOLUTION_HXX
    00038 #define VIGRA_RECURSIVECONVOLUTION_HXX
    00039
    00040 #include <cmath>
    00041 #include <vector>
    00042 #include "utilities.hxx"
    00043 #include "numerictraits.hxx"
    00044 #include "imageiteratoradapter.hxx"
    00045 #include "bordertreatment.hxx"
    00046 #include "array_vector.hxx"
    00047
    00048 namespace vigra {
    00049
    00050 /********************************************************/
    00051 /*                                                      */
    00052 /*         Recursive convolution functions              */
    00053 /*                                                      */
    00054 /********************************************************/
    00055
    00056 /** \addtogroup RecursiveConvolution Recursive convolution functions
    00057
    00058     First order recursive filters and their specialization for
    00059     the exponential filter and its derivatives (1D and separable 2D).
    00060     These filters are very fast, and the speed does not depend on the
    00061     filter size.
    00062 */
    00063 //@{
    00064
    00065 /********************************************************/
    00066 /*                                                      */
    00067 /*                   recursiveFilterLine                */
    00068 /*                                                      */
    00069 /********************************************************/
    00070
    00071 /** \brief Performs a 1-dimensional recursive convolution of the source signal.
    00072
    00073     The function performs a causal and an anti-causal first or second order
    00074     recursive filtering with the given filter parameter <TT>b1</TT> and
    00075     border treatment <TT>border</TT> (first order filter, <TT>b2 = 0</TT>) or parameters
    00076     <TT>b1, b2</TT> and <TT>BORDER_TREATMENT_REFLECT</TT> (second order filter). Thus,
    00077     the result is always a filtering with linear phase.
    00078     \f[
    00079         \begin{array}{rcl}
    00080         a_{i, causal} & = & source_i + b1 * a_{i-1, causal} + b2 * a_{i-2, causal} \\
    00081         a_{i, anticausal} & = & source_i + b1 * a_{i+1, anticausal} + b2 * a_{i+2, anticausal} \\
    00082         dest_i & = & \frac{1 - b1 - b2}{1 + b1 + b2}(a_{i, causal} + a_{i, anticausal} - source_i)
    00083         \end{array}
    00084     \f]
    00085
    00086     The signal's value_type (SrcAccessor::value_type) must be a
    00087     linear space over <TT>double</TT>,
    00088     i.e. addition of source values, multiplication with <TT>double</TT>,
    00089     and <TT>NumericTraits</TT> must be defined.
    00090
    00091     <b> Declaration:</b>
    00092
    00093     <b>First order recursive filter:</b>
    00094
    00095     \code
    00096     namespace vigra {
    00097         template <class SrcIterator, class SrcAccessor,
    00098               class DestIterator, class DestAccessor>
    00099         void recursiveFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
    00100                      DestIterator id, DestAccessor ad,
    00101                      double b1, BorderTreatmentMode border)
    00102     }
    00103     \endcode
    00104
    00105     <b>Second order recursive filter:</b>
    00106
    00107     \code
    00108     namespace vigra {
    00109         template <class SrcIterator, class SrcAccessor,
    00110               class DestIterator, class DestAccessor>
    00111         void recursiveFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
    00112                      DestIterator id, DestAccessor ad,
    00113                      double b1, double b2)
    00114     }
    00115     \endcode
    00116
    00117     <b> Usage:</b>
    00118
    00119     <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
    00120     Namespace: vigra
    00121
    00122
    00123     \code
    00124     vector<float> src, dest;
    00125     ...
    00126
    00127     vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
    00128
    00129
    00130     vigra::recursiveFilterLine(src.begin(), src.end(), FAccessor(),
    00131                                dest.begin(), FAccessor(),
    00132                                0.5, BORDER_TREATMENT_REFLECT);
    00133     \endcode
    00134
    00135     <b> Required Interface:</b>
    00136
    00137     \code
    00138     RandomAccessIterator is, isend;
    00139     RandomAccessIterator id;
    00140
    00141     SrcAccessor src_accessor;
    00142     DestAccessor dest_accessor;
    00143
    00144     NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is);
    00145     double d;
    00146
    00147     s = s + s;
    00148     s = d * s;
    00149
    00150     dest_accessor.set(
    00151         NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
    00152
    00153     \endcode
    00154
    00155     <b> Preconditions:</b>
    00156
    00157     \code
    00158     -1 < b  < 1
    00159     \endcode
    00160
    00161 */
    00162 doxygen_overloaded_function(template <...> void recursiveFilterLine)
    00163
    00164 template <class SrcIterator, class SrcAccessor,
    00165           class DestIterator, class DestAccessor>
    00166 void recursiveFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
    00167                          DestIterator id, DestAccessor ad, double b, BorderTreatmentMode border)
    00168 {
    00169     int w = isend - is;
    00170     SrcIterator istart = is;
    00171
    00172     int x;
    00173
    00174     vigra_precondition(-1.0 < b && b < 1.0,
    00175                  "recursiveFilterLine(): -1 < factor < 1 required.\n");
    00176
    00177     // trivial case: b == 0.0 is an identity filter => simply copy the data and return
    00178     if(b == 0.0)
    00179     {
    00180         for(; is != isend; ++is, ++id)
    00181         {
    00182             ad.set(as(is), id);
    00183         }
    00184         return;
    00185     }
    00186
    00187     double eps = 0.00001;
    00188     int kernelw = std::min(w-1, (int)(VIGRA_CSTD::log(eps)/VIGRA_CSTD::log(VIGRA_CSTD::fabs(b))));
    00189
    00190     typedef typename
    00191         NumericTraits<typename SrcAccessor::value_type>::RealPromote TempType;
    00192     typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
    00193     typedef typename DestTraits::RealPromote RealPromote;
    00194
    00195     // store result of causal filtering
    00196     std::vector<TempType> vline(w);
    00197     typename std::vector<TempType>::iterator line = vline.begin();
    00198
    00199     double norm = (1.0 - b) / (1.0 + b);
    00200
    00201     TempType old;
    00202
    00203     if(border == BORDER_TREATMENT_REPEAT ||
    00204        border == BORDER_TREATMENT_AVOID)
    00205     {
    00206          old = TempType((1.0 / (1.0 - b)) * as(is));
    00207     }
    00208     else if(border == BORDER_TREATMENT_REFLECT)
    00209     {
    00210         is += kernelw;
    00211         old = TempType((1.0 / (1.0 - b)) * as(is));
    00212         for(x = 0; x < kernelw; ++x, --is)
    00213             old = TempType(as(is) + b * old);
    00214     }
    00215     else if(border == BORDER_TREATMENT_WRAP)
    00216     {
    00217         is = isend - kernelw;
    00218         old = TempType((1.0 / (1.0 - b)) * as(is));
    00219         for(x = 0; x < kernelw; ++x, ++is)
    00220             old = TempType(as(is) + b * old);
    00221     }
    00222     else if(border == BORDER_TREATMENT_CLIP ||
    00223             border == BORDER_TREATMENT_ZEROPAD)
    00224     {
    00225         old = NumericTraits<TempType>::zero();
    00226     }
    00227     else
    00228     {
    00229         vigra_fail("recursiveFilterLine(): Unknown border treatment mode.\n");
    00230         old = NumericTraits<TempType>::zero(); // fix a stupid warning
    00231     }
    00232
    00233     // left side of filter
    00234     for(x=0, is = istart; x < w; ++x, ++is)
    00235     {
    00236         old = TempType(as(is) + b * old);
    00237         line[x] = old;
    00238     }
    00239
    00240     // right side of the filter
    00241     if(border == BORDER_TREATMENT_REPEAT ||
    00242        border == BORDER_TREATMENT_AVOID)
    00243     {
    00244         is = isend - 1;
    00245         old = TempType((1.0 / (1.0 - b)) * as(is));
    00246     }
    00247     else if(border == BORDER_TREATMENT_REFLECT)
    00248     {
    00249         old = line[w-2];
    00250     }
    00251     else if(border == BORDER_TREATMENT_WRAP)
    00252     {
    00253       is = istart + kernelw - 1;
    00254       old = TempType((1.0 / (1.0 - b)) * as(is));
    00255       for(x = 0; x < kernelw; ++x, --is)
    00256           old = TempType(as(is) + b * old);
    00257     }
    00258     else if(border == BORDER_TREATMENT_CLIP ||
    00259             border == BORDER_TREATMENT_ZEROPAD)
    00260     {
    00261         old = NumericTraits<TempType>::zero();
    00262     }
    00263
    00264     is = isend - 1;
    00265     id += w - 1;
    00266     if(border == BORDER_TREATMENT_CLIP)
    00267     {
    00268        // correction factors for b
    00269         double bright = b;
    00270         double bleft = VIGRA_CSTD::pow(b, w);
    00271
    00272         for(x=w-1; x>=0; --x, --is, --id)
    00273         {
    00274             TempType f = TempType(b * old);
    00275             old = as(is) + f;
    00276             double norm = (1.0 - b) / (1.0 + b - bleft - bright);
    00277             bleft /= b;
    00278             bright *= b;
    00279             ad.set(norm * (line[x] + f), id);
    00280         }
    00281     }
    00282     else if(border == BORDER_TREATMENT_AVOID)
    00283     {
    00284         for(x=w-1; x >= kernelw; --x, --is, --id)
    00285         {
    00286             TempType f = TempType(b * old);
    00287             old = as(is) + f;
    00288             if(x < w - kernelw)
    00289                 ad.set(DestTraits::fromRealPromote(RealPromote(norm * (line[x] + f))), id);
    00290         }
    00291     }
    00292     else
    00293     {
    00294         for(x=w-1; x>=0; --x, --is, --id)
    00295         {
    00296             TempType f = TempType(b * old);
    00297             old = as(is) + f;
    00298             ad.set(DestTraits::fromRealPromote(RealPromote(norm * (line[x] + f))), id);
    00299         }
    00300     }
    00301 }
    00302
    00303 /********************************************************/
    00304 /*                                                      */
    00305 /*            recursiveFilterLine (2nd order)           */
    00306 /*                                                      */
    00307 /********************************************************/
    00308
    00309 template <class SrcIterator, class SrcAccessor,
    00310           class DestIterator, class DestAccessor>
    00311 void recursiveFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
    00312                          DestIterator id, DestAccessor ad, double b1, double b2)
    00313 {
    00314     int w = isend - is;
    00315     int x;
    00316
    00317     typedef typename
    00318         NumericTraits<typename SrcAccessor::value_type>::RealPromote TempType;
    00319     typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
    00320
    00321     // speichert den Ergebnis der linkseitigen Filterung.
    00322     std::vector<TempType> vline(w+1);
    00323     typename std::vector<TempType>::iterator line = vline.begin();
    00324
    00325     double norm  = 1.0 - b1 - b2;
    00326     double norm1 = (1.0 - b1 - b2) / (1.0 + b1 + b2);
    00327     double norm2 = norm * norm;
    00328
    00329
    00330     // init left side of filter
    00331     int kernelw = std::min(w-1, std::max(8, (int)(1.0 / norm + 0.5)));
    00332     is += (kernelw - 2);
    00333     line[kernelw] = as(is);
    00334     line[kernelw-1] = as(is);
    00335     for(x = kernelw - 2; x > 0; --x, --is)
    00336     {
    00337         line[x] = detail::RequiresExplicitCast<TempType>::cast(as(is) + b1 * line[x+1] + b2 * line[x+2]);
    00338     }
    00339     line[0] = detail::RequiresExplicitCast<TempType>::cast(as(is) + b1 * line[1] + b2 * line[2]);
    00340     ++is;
    00341     line[1] = detail::RequiresExplicitCast<TempType>::cast(as(is) + b1 * line[0] + b2 * line[1]);
    00342     ++is;
    00343     for(x=2; x < w; ++x, ++is)
    00344     {
    00345         line[x] = detail::RequiresExplicitCast<TempType>::cast(as(is) + b1 * line[x-1] + b2 * line[x-2]);
    00346     }
    00347     line[w] = line[w-1];
    00348
    00349     line[w-1] = detail::RequiresExplicitCast<TempType>::cast(norm1 * (line[w-1] + b1 * line[w-2] + b2 * line[w-3]));
    00350     line[w-2] = detail::RequiresExplicitCast<TempType>::cast(norm1 * (line[w-2] + b1 * line[w] + b2 * line[w-2]));
    00351     id += w-1;
    00352     ad.set(line[w-1], id);
    00353     --id;
    00354     ad.set(line[w-2], id);
    00355     --id;
    00356     for(x=w-3; x>=0; --x, --id, --is)
    00357     {
    00358         line[x] = detail::RequiresExplicitCast<TempType>::cast(norm2 * line[x] + b1 * line[x+1] + b2 * line[x+2]);
    00359         ad.set(line[x], id);
    00360     }
    00361 }
    00362
    00363 /********************************************************/
    00364 /*                                                      */
    00365 /*              recursiveGaussianFilterLine             */
    00366 /*                                                      */
    00367 /********************************************************/
    00368
    00369 // AUTHOR: Sebastian Boppel
    00370
    00371 /** \brief Compute a 1-dimensional recursive approximation of Gaussian smoothing.
    00372
    00373     The function applies a causal and an anti-causal third order recursive filter
    00374     which optimally approximates the Gaussian filter, as proposed in
    00375
    00376     I. Young, L. van Vliet: <i>Recursive implementation of the Gaussian filter</i><br>
    00377     Signal Processing 44:139-151, 1995
    00378
    00379     The formulas for transforming the given scale parameter <tt>sigma</tt> into the actual filter coefficients
    00380     are taken from Luigi Rosa's Matlab implementation.
    00381
    00382     The signal's value_type (SrcAccessor::value_type) must be a
    00383     linear space over <TT>double</TT>, i.e. addition of source values, multiplication with <TT>double</TT>,
    00384     and <TT>NumericTraits</TT> must be defined.
    00385
    00386     <b> Declaration:</b>
    00387
    00388     \code
    00389     namespace vigra {
    00390         template <class SrcIterator, class SrcAccessor,
    00391                   class DestIterator, class DestAccessor>
    00392         void
    00393         recursiveGaussianFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
    00394                                     DestIterator id, DestAccessor ad,
    00395                                     double sigma);
    00396     }
    00397     \endcode
    00398
    00399     <b> Usage:</b>
    00400
    00401     <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
    00402     Namespace: vigra
    00403
    00404
    00405     \code
    00406     vector<float> src, dest;
    00407     ...
    00408
    00409     vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
    00410     double sigma = 2.5;
    00411
    00412     vigra::recursiveGaussianFilterLine(src.begin(), src.end(), FAccessor(),
    00413                                        dest.begin(), FAccessor(),
    00414                                        sigma);
    00415     \endcode
    00416
    00417     <b> Required Interface:</b>
    00418
    00419     \code
    00420     RandomAccessIterator is, isend;
    00421     RandomAccessIterator id;
    00422
    00423     SrcAccessor src_accessor;
    00424     DestAccessor dest_accessor;
    00425
    00426     NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is);
    00427     double d;
    00428
    00429     s = s + s;
    00430     s = d * s;
    00431
    00432     dest_accessor.set(
    00433         NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
    00434
    00435     \endcode
    00436
    00437     <b> Preconditions:</b>
    00438
    00439     \code
    00440     0 <= sigma (absolute values are used for negative sigma)
    00441     \endcode
    00442
    00443 */
    00444 doxygen_overloaded_function(template <...> void recursiveGaussianFilterLine)
    00445
    00446 template <class SrcIterator, class SrcAccessor,
    00447           class DestIterator, class DestAccessor>
    00448 void
    00449 recursiveGaussianFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
    00450                             DestIterator id, DestAccessor ad,
    00451                             double sigma)
    00452 {
    00453     //coefficients taken out Luigi Rosa's implementation for Matlab
    00454     double q = 1.31564 * (std::sqrt(1.0 + 0.490811 * sigma*sigma) - 1.0);
    00455     double qq = q*q;
    00456     double qqq = qq*q;
    00457     double b0 = 1.0/(1.57825 + 2.44413*q + 1.4281*qq + 0.422205*qqq);
    00458     double b1 = (2.44413*q + 2.85619*qq + 1.26661*qqq)*b0;
    00459     double b2 = (-1.4281*qq - 1.26661*qqq)*b0;
    00460     double b3 = 0.422205*qqq*b0;
    00461     double B = 1.0 - (b1 + b2 + b3);
    00462
    00463     int w = isend - is;
    00464     vigra_precondition(w >= 4,
    00465         "recursiveGaussianFilterLine(): line must have at least length 4.");
    00466
    00467     int kernelw = std::min(w-4, (int)(4.0*sigma));
    00468
    00469     int x;
    00470
    00471     typedef typename
    00472         NumericTraits<typename SrcAccessor::value_type>::RealPromote TempType;
    00473     typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
    00474
    00475     // speichert das Ergebnis der linkseitigen Filterung.
    00476     std::vector<TempType> yforward(w);
    00477
    00478     std::vector<TempType> ybackward(w, 0.0);
    00479
    00480     // initialise the filter for reflective boundary conditions
    00481     for(x=kernelw; x>=0; --x)
    00482     {
    00483         ybackward[x] = detail::RequiresExplicitCast<TempType>::cast(B*as(is, x) + (b1*ybackward[x+1]+b2*ybackward[x+2]+b3*ybackward[x+3]));
    00484     }
    00485
    00486     //from left to right - causal - forward
    00487     yforward[0] = detail::RequiresExplicitCast<TempType>::cast(B*as(is) + (b1*ybackward[1]+b2*ybackward[2]+b3*ybackward[3]));
    00488
    00489     ++is;
    00490     yforward[1] = detail::RequiresExplicitCast<TempType>::cast(B*as(is) + (b1*yforward[0]+b2*ybackward[1]+b3*ybackward[2]));
    00491
    00492     ++is;
    00493     yforward[2] = detail::RequiresExplicitCast<TempType>::cast(B*as(is) + (b1*yforward[1]+b2*yforward[0]+b3*ybackward[1]));
    00494
    00495     ++is;
    00496     for(x=3; x < w; ++x, ++is)
    00497     {
    00498         yforward[x] = detail::RequiresExplicitCast<TempType>::cast(B*as(is) + (b1*yforward[x-1]+b2*yforward[x-2]+b3*yforward[x-3]));
    00499     }
    00500
    00501     //from right to left - anticausal - backward
    00502     ybackward[w-1] = detail::RequiresExplicitCast<TempType>::cast(B*yforward[w-1] + (b1*yforward[w-2]+b2*yforward[w-3]+b3*yforward[w-4]));
    00503
    00504     ybackward[w-2] = detail::RequiresExplicitCast<TempType>::cast(B*yforward[w-2] + (b1*ybackward[w-1]+b2*yforward[w-2]+b3*yforward[w-3]));
    00505
    00506     ybackward[w-3] = detail::RequiresExplicitCast<TempType>::cast(B*yforward[w-3] + (b1*ybackward[w-2]+b2*ybackward[w-1]+b3*yforward[w-2]));
    00507
    00508     for(x=w-4; x>=0; --x)
    00509     {
    00510         ybackward[x] = detail::RequiresExplicitCast<TempType>::cast(B*yforward[x]+(b1*ybackward[x+1]+b2*ybackward[x+2]+b3*ybackward[x+3]));
    00511     }
    00512
    00513     // output
    00514     for(x=0; x < w; ++x, ++id)
    00515     {
    00516         ad.set(ybackward[x], id);
    00517     }
    00518 }
    00519
    00520
    00521 /********************************************************/
    00522 /*                                                      */
    00523 /*                    recursiveSmoothLine               */
    00524 /*                                                      */
    00525 /********************************************************/
    00526
    00527 /** \brief Convolves the image with a 1-dimensional exponential filter.
    00528
    00529     This function calls \ref recursiveFilterLine() with <TT>b = exp(-1.0/scale)</TT>
    00530     and <TT>border = BORDER_TREATMENT_REPEAT</TT>. See
    00531     \ref recursiveFilterLine() for more documentation.
    00532
    00533     <b> Declaration:</b>
    00534
    00535     \code
    00536     namespace vigra {
    00537         template <class SrcIterator, class SrcAccessor,
    00538               class DestIterator, class DestAccessor>
    00539         void recursiveSmoothLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
    00540                      DestIterator id, DestAccessor ad, double scale)
    00541     }
    00542     \endcode
    00543
    00544     <b> Usage:</b>
    00545
    00546     <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
    00547     Namespace: vigra
    00548
    00549
    00550     \code
    00551     vector<float> src, dest;
    00552     ...
    00553
    00554     vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
    00555
    00556
    00557     vigra::recursiveSmoothLine(src.begin(), src.end(), FAccessor(),
    00558                         dest.begin(), FAccessor(), 3.0);
    00559     \endcode
    00560
    00561     <b> Required Interface:</b>
    00562
    00563     \code
    00564     RandomAccessIterator is, isend;
    00565     RandomAccessIterator id;
    00566
    00567     SrcAccessor src_accessor;
    00568     DestAccessor dest_accessor;
    00569
    00570     NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is);
    00571     double d;
    00572
    00573     s = s + s;
    00574     s = d * s;
    00575
    00576     dest_accessor.set(
    00577         NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
    00578
    00579     \endcode
    00580
    00581     <b> Preconditions:</b>
    00582
    00583     \code
    00584     scale > 0
    00585     \endcode
    00586
    00587 */
    00588 doxygen_overloaded_function(template <...> void recursiveSmoothLine)
    00589
    00590 template <class SrcIterator, class SrcAccessor,
    00591           class DestIterator, class DestAccessor>
    00592 inline
    00593 void recursiveSmoothLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
    00594                          DestIterator id, DestAccessor ad, double scale)
    00595 {
    00596     vigra_precondition(scale >= 0,
    00597                  "recursiveSmoothLine(): scale must be >= 0.\n");
    00598
    00599     double b = (scale == 0.0) ?
    00600                     0.0 :
    00601                     VIGRA_CSTD::exp(-1.0/scale);
    00602
    00603     recursiveFilterLine(is, isend, as, id, ad, b, BORDER_TREATMENT_REPEAT);
    00604 }
    00605
    00606 /********************************************************/
    00607 /*                                                      */
    00608 /*             recursiveFirstDerivativeLine             */
    00609 /*                                                      */
    00610 /********************************************************/
    00611
    00612 /** \brief Performs a 1 dimensional recursive convolution of the source signal.
    00613
    00614     It uses the first derivative an exponential  <TT>d/dx exp(-abs(x)/scale)</TT> as
    00615     a kernel. The signal's value_type (SrcAccessor::value_type) must be a
    00616     linear space over <TT>double</TT>,
    00617     i.e. addition and subtraction of source values, multiplication with
    00618     <TT>double</TT>, and <TT>NumericTraits</TT> must be defined. Border
    00619     treatment is always <TT>BORDER_TREATMENT_REPEAT</TT>.
    00620
    00621     <b> Declaration:</b>
    00622
    00623     \code
    00624     namespace vigra {
    00625         template <class SrcIterator, class SrcAccessor,
    00626               class DestIterator, class DestAccessor>
    00627         void recursiveFirstDerivativeLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
    00628                      DestIterator id, DestAccessor ad, double scale)
    00629     }
    00630     \endcode
    00631
    00632     <b> Usage:</b>
    00633
    00634     <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
    00635     Namespace: vigra
    00636
    00637
    00638     \code
    00639     vector<float> src, dest;
    00640     ...
    00641
    00642     vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
    00643
    00644
    00645     vigra::recursiveFirstDerivativeLine(src.begin(), src.end(), FAccessor(),
    00646                         dest.begin(), FAccessor(), 3.0);
    00647     \endcode
    00648
    00649     <b> Required Interface:</b>
    00650
    00651     \code
    00652     RandomAccessIterator is, isend;
    00653     RandomAccessIterator id;
    00654
    00655     SrcAccessor src_accessor;
    00656     DestAccessor dest_accessor;
    00657
    00658     NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is);
    00659     double d;
    00660
    00661     s = s + s;
    00662     s = -s;
    00663     s = d * s;
    00664
    00665     dest_accessor.set(
    00666         NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
    00667
    00668     \endcode
    00669
    00670     <b> Preconditions:</b>
    00671
    00672     \code
    00673     scale > 0
    00674     \endcode
    00675
    00676 */
    00677 doxygen_overloaded_function(template <...> void recursiveFirstDerivativeLine)
    00678
    00679 template <class SrcIterator, class SrcAccessor,
    00680           class DestIterator, class DestAccessor>
    00681 void recursiveFirstDerivativeLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
    00682                          DestIterator id, DestAccessor ad, double scale)
    00683 {
    00684     vigra_precondition(scale > 0,
    00685                  "recursiveFirstDerivativeLine(): scale must be > 0.\n");
    00686
    00687     int w = isend -is;
    00688
    00689     int x;
    00690
    00691     typedef typename
    00692         NumericTraits<typename SrcAccessor::value_type>::RealPromote
    00693     TempType;
    00694     typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
    00695
    00696     std::vector<TempType> vline(w);
    00697     typename std::vector<TempType>::iterator line = vline.begin();
    00698
    00699     double b = VIGRA_CSTD::exp(-1.0/scale);
    00700     double norm = (1.0 - b) * (1.0 - b) / 2.0 / b;
    00701     TempType old = (1.0 / (1.0 - b)) * as(is);
    00702
    00703     // left side of filter
    00704     for(x=0; x<w; ++x, ++is)
    00705     {
    00706         old = as(is) + b * old;
    00707         line[x] = -old;
    00708     }
    00709
    00710     // right side of the filter
    00711     --is;
    00712     old = (1.0 / (1.0 - b)) * as(is);
    00713     id += w;
    00714     ++is;
    00715
    00716     for(x=w-1; x>=0; --x)
    00717     {
    00718         --is;
    00719         --id;
    00720
    00721         old = as(is) + b * old;
    00722
    00723         ad.set(DestTraits::fromRealPromote(norm * (line[x] + old)), id);
    00724     }
    00725 }
    00726
    00727 /********************************************************/
    00728 /*                                                      */
    00729 /*            recursiveSecondDerivativeLine             */
    00730 /*                                                      */
    00731 /********************************************************/
    00732
    00733 /** \brief Performs a 1 dimensional recursive convolution of the source signal.
    00734
    00735     It uses the second derivative an exponential  <TT>d2/dx2 exp(-abs(x)/scale)</TT> as
    00736     a kernel. The signal's value_type (SrcAccessor::value_type) must be a
    00737     linear space over <TT>double</TT>,
    00738     i.e. addition and subtraction of source values, multiplication with
    00739     <TT>double</TT>, and <TT>NumericTraits</TT> must be defined. Border
    00740     treatment is always <TT>BORDER_TREATMENT_REPEAT</TT>.
    00741
    00742     <b> Declaration:</b>
    00743
    00744     \code
    00745     namespace vigra {
    00746         template <class SrcIterator, class SrcAccessor,
    00747               class DestIterator, class DestAccessor>
    00748         void recursiveSecondDerivativeLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
    00749                      DestIterator id, DestAccessor ad, double scale)
    00750     }
    00751     \endcode
    00752
    00753     <b> Usage:</b>
    00754
    00755     <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
    00756     Namespace: vigra
    00757
    00758
    00759     \code
    00760     vector<float> src, dest;
    00761     ...
    00762
    00763     vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
    00764
    00765
    00766     vigra::recursiveSecondDerivativeLine(src.begin(), src.end(), FAccessor(),
    00767                         dest.begin(), FAccessor(), 3.0);
    00768     \endcode
    00769
    00770     <b> Required Interface:</b>
    00771
    00772     \code
    00773     RandomAccessIterator is, isend;
    00774     RandomAccessIterator id;
    00775
    00776     SrcAccessor src_accessor;
    00777     DestAccessor dest_accessor;
    00778
    00779     NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is);
    00780     double d;
    00781
    00782     s = s + s;
    00783     s = s - s;
    00784     s = d * s;
    00785
    00786     dest_accessor.set(
    00787         NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
    00788
    00789     \endcode
    00790
    00791     <b> Preconditions:</b>
    00792
    00793     \code
    00794     scale > 0
    00795     \endcode
    00796
    00797 */
    00798 doxygen_overloaded_function(template <...> void recursiveSecondDerivativeLine)
    00799
    00800 template <class SrcIterator, class SrcAccessor,
    00801           class DestIterator, class DestAccessor>
    00802 void recursiveSecondDerivativeLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
    00803                          DestIterator id, DestAccessor ad, double scale)
    00804 {
    00805     vigra_precondition(scale > 0,
    00806                  "recursiveSecondDerivativeLine(): scale must be > 0.\n");
    00807
    00808     int w = isend -is;
    00809
    00810     int x;
    00811
    00812     typedef typename
    00813         NumericTraits<typename SrcAccessor::value_type>::RealPromote
    00814     TempType;
    00815     typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
    00816
    00817     std::vector<TempType> vline(w);
    00818     typename std::vector<TempType>::iterator line = vline.begin();
    00819
    00820     double b = VIGRA_CSTD::exp(-1.0/scale);
    00821     double a = -2.0 / (1.0 - b);
    00822     double norm = (1.0 - b) * (1.0 - b) * (1.0 - b) / (1.0 + b);
    00823     TempType old = detail::RequiresExplicitCast<TempType>::cast((1.0 / (1.0 - b)) * as(is));
    00824
    00825     // left side of filter
    00826     for(x=0; x<w; ++x, ++is)
    00827     {
    00828         line[x] = old;
    00829         old = detail::RequiresExplicitCast<TempType>::cast(as(is) + b * old);
    00830     }
    00831
    00832     // right side of the filter
    00833     --is;
    00834     old = detail::RequiresExplicitCast<TempType>::cast((1.0 / (1.0 - b)) * as(is));
    00835     id += w;
    00836     ++is;
    00837
    00838     for(x=w-1; x>=0; --x)
    00839     {
    00840         --is;
    00841         --id;
    00842
    00843         TempType f = detail::RequiresExplicitCast<TempType>::cast(old + a * as(is));
    00844         old = detail::RequiresExplicitCast<TempType>::cast(as(is) + b * old);
    00845         ad.set(DestTraits::fromRealPromote(detail::RequiresExplicitCast<TempType>::cast(norm * (line[x] + f))), id);
    00846     }
    00847 }
    00848
    00849 /********************************************************/
    00850 /*                                                      */
    00851 /*                   recursiveFilterX                   */
    00852 /*                                                      */
    00853 /********************************************************/
    00854
    00855 /** \brief Performs 1 dimensional recursive filtering (1st and 2nd order) in x direction.
    00856
    00857     It calls \ref recursiveFilterLine() for every row of the
    00858     image. See \ref recursiveFilterLine() for more information about
    00859     required interfaces and vigra_preconditions.
    00860
    00861     <b> Declarations:</b>
    00862
    00863     pass arguments explicitly:
    00864     \code
    00865     namespace vigra {
    00866         // first order filter
    00867         template <class SrcImageIterator, class SrcAccessor,
    00868                   class DestImageIterator, class DestAccessor>
    00869         void recursiveFilterX(SrcImageIterator supperleft,
    00870                                SrcImageIterator slowerright, SrcAccessor as,
    00871                                DestImageIterator dupperleft, DestAccessor ad,
    00872                                double b, BorderTreatmentMode border);
    00873
    00874         // second order filter
    00875         template <class SrcImageIterator, class SrcAccessor,
    00876                   class DestImageIterator, class DestAccessor>
    00877         void recursiveFilterX(SrcImageIterator supperleft,
    00878                                SrcImageIterator slowerright, SrcAccessor as,
    00879                                DestImageIterator dupperleft, DestAccessor ad,
    00880                                double b1, double b2);
    00881     }
    00882     \endcode
    00883
    00884
    00885     use argument objects in conjunction with \ref ArgumentObjectFactories :
    00886     \code
    00887     namespace vigra {
    00888         // first order filter
    00889         template <class SrcImageIterator, class SrcAccessor,
    00890                   class DestImageIterator, class DestAccessor>
    00891         void recursiveFilterX(
    00892                     triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    00893                     pair<DestImageIterator, DestAccessor> dest,
    00894                     double b, BorderTreatmentMode border);
    00895
    00896         // second order filter
    00897         template <class SrcImageIterator, class SrcAccessor,
    00898                   class DestImageIterator, class DestAccessor>
    00899         void recursiveFilterX(
    00900                     triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    00901                     pair<DestImageIterator, DestAccessor> dest,
    00902                     double b1, double b2);
    00903             }
    00904     \endcode
    00905
    00906     <b> Usage:</b>
    00907
    00908     <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
    00909     Namespace: vigra
    00910
    00911     \code
    00912     vigra::FImage src(w,h), dest(w,h);
    00913     ...
    00914
    00915     vigra::recursiveSmoothX(srcImageRange(src), destImage(dest),
    00916            0.5, BORDER_TREATMENT_REFLECT);
    00917
    00918     \endcode
    00919
    00920 */
    00921 doxygen_overloaded_function(template <...> void recursiveFilterX)
    00922
    00923 template <class SrcImageIterator, class SrcAccessor,
    00924           class DestImageIterator, class DestAccessor>
    00925 void recursiveFilterX(SrcImageIterator supperleft,
    00926                        SrcImageIterator slowerright, SrcAccessor as,
    00927                        DestImageIterator dupperleft, DestAccessor ad,
    00928                        double b, BorderTreatmentMode border)
    00929 {
    00930     int w = slowerright.x - supperleft.x;
    00931     int h = slowerright.y - supperleft.y;
    00932
    00933     int y;
    00934
    00935     for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
    00936     {
    00937         typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
    00938         typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
    00939
    00940         recursiveFilterLine(rs, rs+w, as,
    00941                              rd, ad,
    00942                              b, border);
    00943     }
    00944 }
    00945
    00946 template <class SrcImageIterator, class SrcAccessor,
    00947           class DestImageIterator, class DestAccessor>
    00948 inline void recursiveFilterX(
    00949             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    00950             pair<DestImageIterator, DestAccessor> dest,
    00951             double b, BorderTreatmentMode border)
    00952 {
    00953     recursiveFilterX(src.first, src.second, src.third,
    00954                       dest.first, dest.second, b, border);
    00955 }
    00956
    00957 /********************************************************/
    00958 /*                                                      */
    00959 /*            recursiveFilterX (2nd order)              */
    00960 /*                                                      */
    00961 /********************************************************/
    00962
    00963 template <class SrcImageIterator, class SrcAccessor,
    00964           class DestImageIterator, class DestAccessor>
    00965 void recursiveFilterX(SrcImageIterator supperleft,
    00966                        SrcImageIterator slowerright, SrcAccessor as,
    00967                        DestImageIterator dupperleft, DestAccessor ad,
    00968                        double b1, double b2)
    00969 {
    00970     int w = slowerright.x - supperleft.x;
    00971     int h = slowerright.y - supperleft.y;
    00972
    00973     int y;
    00974
    00975     for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
    00976     {
    00977         typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
    00978         typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
    00979
    00980         recursiveFilterLine(rs, rs+w, as,
    00981                              rd, ad,
    00982                              b1, b2);
    00983     }
    00984 }
    00985
    00986 template <class SrcImageIterator, class SrcAccessor,
    00987           class DestImageIterator, class DestAccessor>
    00988 inline void recursiveFilterX(
    00989             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    00990             pair<DestImageIterator, DestAccessor> dest,
    00991                        double b1, double b2)
    00992 {
    00993     recursiveFilterX(src.first, src.second, src.third,
    00994                       dest.first, dest.second, b1, b2);
    00995 }
    00996
    00997
    00998
    00999 /********************************************************/
    01000 /*                                                      */
    01001 /*               recursiveGaussianFilterX               */
    01002 /*                                                      */
    01003 /********************************************************/
    01004
    01005 // AUTHOR: Sebastian Boppel
    01006
    01007 /** \brief Compute 1 dimensional recursive approximation of Gaussian smoothing in y direction.
    01008
    01009     It calls \ref recursiveGaussianFilterLine() for every column of the
    01010     image. See \ref recursiveGaussianFilterLine() for more information about
    01011     required interfaces and vigra_preconditions.
    01012
    01013     <b> Declarations:</b>
    01014
    01015     pass arguments explicitly:
    01016     \code
    01017     namespace vigra {
    01018         template <class SrcImageIterator, class SrcAccessor,
    01019                   class DestImageIterator, class DestAccessor>
    01020         void
    01021         recursiveGaussianFilterX(SrcImageIterator supperleft, SrcImageIterator slowerright, SrcAccessor as,
    01022                                  DestImageIterator dupperleft, DestAccessor ad,
    01023                                  double sigma);
    01024     }
    01025     \endcode
    01026
    01027
    01028     use argument objects in conjunction with \ref ArgumentObjectFactories :
    01029     \code
    01030     namespace vigra {
    01031         template <class SrcImageIterator, class SrcAccessor,
    01032                   class DestImageIterator, class DestAccessor>
    01033         void
    01034         recursiveGaussianFilterX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    01035                                  pair<DestImageIterator, DestAccessor> dest,
    01036                                  double sigma);
    01037     }
    01038     \endcode
    01039
    01040     <b> Usage:</b>
    01041
    01042     <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
    01043     Namespace: vigra
    01044
    01045     \code
    01046     vigra::FImage src(w,h), dest(w,h);
    01047     ...
    01048
    01049     vigra::recursiveGaussianFilterX(srcImageRange(src), destImage(dest), 3.0);
    01050
    01051     \endcode
    01052
    01053 */
    01054 doxygen_overloaded_function(template <...> void recursiveGaussianFilterX)
    01055
    01056 template <class SrcImageIterator, class SrcAccessor,
    01057           class DestImageIterator, class DestAccessor>
    01058 void
    01059 recursiveGaussianFilterX(SrcImageIterator supperleft, SrcImageIterator slowerright, SrcAccessor as,
    01060                          DestImageIterator dupperleft, DestAccessor ad,
    01061                          double sigma)
    01062 {
    01063     int w = slowerright.x - supperleft.x;
    01064     int h = slowerright.y - supperleft.y;
    01065
    01066     int y;
    01067
    01068     for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
    01069     {
    01070         typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
    01071         typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
    01072
    01073         recursiveGaussianFilterLine(rs, rs+w, as,
    01074                                     rd, ad,
    01075                                     sigma);
    01076     }
    01077 }
    01078
    01079 template <class SrcImageIterator, class SrcAccessor,
    01080           class DestImageIterator, class DestAccessor>
    01081 inline void
    01082 recursiveGaussianFilterX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    01083                          pair<DestImageIterator, DestAccessor> dest,
    01084                          double sigma)
    01085 {
    01086     recursiveGaussianFilterX(src.first, src.second, src.third,
    01087                              dest.first, dest.second, sigma);
    01088 }
    01089
    01090
    01091 /********************************************************/
    01092 /*                                                      */
    01093 /*                    recursiveSmoothX                  */
    01094 /*                                                      */
    01095 /********************************************************/
    01096
    01097 /** \brief Performs 1 dimensional recursive smoothing in x direction.
    01098
    01099     It calls \ref recursiveSmoothLine() for every row of the
    01100     image. See \ref recursiveSmoothLine() for more information about
    01101     required interfaces and vigra_preconditions.
    01102
    01103     <b> Declarations:</b>
    01104
    01105     pass arguments explicitly:
    01106     \code
    01107     namespace vigra {
    01108         template <class SrcImageIterator, class SrcAccessor,
    01109               class DestImageIterator, class DestAccessor>
    01110         void recursiveSmoothX(SrcImageIterator supperleft,
    01111                   SrcImageIterator slowerright, SrcAccessor as,
    01112                   DestImageIterator dupperleft, DestAccessor ad,
    01113                   double scale)
    01114     }
    01115     \endcode
    01116
    01117
    01118     use argument objects in conjunction with \ref ArgumentObjectFactories :
    01119     \code
    01120     namespace vigra {
    01121         template <class SrcImageIterator, class SrcAccessor,
    01122               class DestImageIterator, class DestAccessor>
    01123         void recursiveSmoothX(
    01124             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    01125             pair<DestImageIterator, DestAccessor> dest,
    01126             double scale)
    01127     }
    01128     \endcode
    01129
    01130     <b> Usage:</b>
    01131
    01132     <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
    01133     Namespace: vigra
    01134
    01135     \code
    01136     vigra::FImage src(w,h), dest(w,h);
    01137     ...
    01138
    01139     vigra::recursiveSmoothX(srcImageRange(src), destImage(dest), 3.0);
    01140
    01141     \endcode
    01142
    01143 */
    01144 doxygen_overloaded_function(template <...> void recursiveSmoothX)
    01145
    01146 template <class SrcImageIterator, class SrcAccessor,
    01147           class DestImageIterator, class DestAccessor>
    01148 void recursiveSmoothX(SrcImageIterator supperleft,
    01149                       SrcImageIterator slowerright, SrcAccessor as,
    01150                       DestImageIterator dupperleft, DestAccessor ad,
    01151                       double scale)
    01152 {
    01153     int w = slowerright.x - supperleft.x;
    01154     int h = slowerright.y - supperleft.y;
    01155
    01156     int y;
    01157
    01158     for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
    01159     {
    01160         typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
    01161         typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
    01162
    01163         recursiveSmoothLine(rs, rs+w, as,
    01164                             rd, ad,
    01165                             scale);
    01166     }
    01167 }
    01168
    01169 template <class SrcImageIterator, class SrcAccessor,
    01170           class DestImageIterator, class DestAccessor>
    01171 inline void recursiveSmoothX(
    01172             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    01173             pair<DestImageIterator, DestAccessor> dest,
    01174         double scale)
    01175 {
    01176     recursiveSmoothX(src.first, src.second, src.third,
    01177                      dest. first, dest.second, scale);
    01178 }
    01179
    01180 /********************************************************/
    01181 /*                                                      */
    01182 /*                     recursiveFilterY                 */
    01183 /*                                                      */
    01184 /********************************************************/
    01185
    01186 /** \brief Performs 1 dimensional recursive filtering (1st and 2nd order) in y direction.
    01187
    01188     It calls \ref recursiveFilterLine() for every column of the
    01189     image. See \ref recursiveFilterLine() for more information about
    01190     required interfaces and vigra_preconditions.
    01191
    01192     <b> Declarations:</b>
    01193
    01194     pass arguments explicitly:
    01195     \code
    01196     namespace vigra {
    01197         // first order filter
    01198         template <class SrcImageIterator, class SrcAccessor,
    01199                   class DestImageIterator, class DestAccessor>
    01200         void recursiveFilterY(SrcImageIterator supperleft,
    01201                                SrcImageIterator slowerright, SrcAccessor as,
    01202                                DestImageIterator dupperleft, DestAccessor ad,
    01203                                double b, BorderTreatmentMode border);
    01204
    01205         // second order filter
    01206         template <class SrcImageIterator, class SrcAccessor,
    01207                   class DestImageIterator, class DestAccessor>
    01208         void recursiveFilterY(SrcImageIterator supperleft,
    01209                                SrcImageIterator slowerright, SrcAccessor as,
    01210                                DestImageIterator dupperleft, DestAccessor ad,
    01211                                double b1, double b2);
    01212     }
    01213     \endcode
    01214
    01215
    01216     use argument objects in conjunction with \ref ArgumentObjectFactories :
    01217     \code
    01218     namespace vigra {
    01219         // first order filter
    01220         template <class SrcImageIterator, class SrcAccessor,
    01221                   class DestImageIterator, class DestAccessor>
    01222         void recursiveFilterY(
    01223                     triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    01224                     pair<DestImageIterator, DestAccessor> dest,
    01225                     double b, BorderTreatmentMode border);
    01226
    01227         // second order filter
    01228         template <class SrcImageIterator, class SrcAccessor,
    01229                   class DestImageIterator, class DestAccessor>
    01230         void recursiveFilterY(
    01231                     triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    01232                     pair<DestImageIterator, DestAccessor> dest,
    01233                     double b1, double b2);
    01234             }
    01235     \endcode
    01236
    01237     <b> Usage:</b>
    01238
    01239     <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
    01240     Namespace: vigra
    01241
    01242     \code
    01243     vigra::FImage src(w,h), dest(w,h);
    01244     ...
    01245
    01246     vigra::recursiveFilterY(srcImageRange(src), destImage(dest), -0.6, -0.06);
    01247
    01248     \endcode
    01249
    01250 */
    01251 doxygen_overloaded_function(template <...> void recursiveFilterY)
    01252
    01253 template <class SrcImageIterator, class SrcAccessor,
    01254           class DestImageIterator, class DestAccessor>
    01255 void recursiveFilterY(SrcImageIterator supperleft,
    01256                        SrcImageIterator slowerright, SrcAccessor as,
    01257                        DestImageIterator dupperleft, DestAccessor ad,
    01258                        double b, BorderTreatmentMode border)
    01259 {
    01260     int w = slowerright.x - supperleft.x;
    01261     int h = slowerright.y - supperleft.y;
    01262
    01263     int x;
    01264
    01265     for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
    01266     {
    01267         typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
    01268         typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
    01269
    01270         recursiveFilterLine(cs, cs+h, as,
    01271                             cd, ad,
    01272                             b, border);
    01273     }
    01274 }
    01275
    01276 template <class SrcImageIterator, class SrcAccessor,
    01277           class DestImageIterator, class DestAccessor>
    01278 inline void recursiveFilterY(
    01279             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    01280             pair<DestImageIterator, DestAccessor> dest,
    01281             double b, BorderTreatmentMode border)
    01282 {
    01283     recursiveFilterY(src.first, src.second, src.third,
    01284                       dest.first, dest.second, b, border);
    01285 }
    01286
    01287 /********************************************************/
    01288 /*                                                      */
    01289 /*            recursiveFilterY (2nd order)              */
    01290 /*                                                      */
    01291 /********************************************************/
    01292
    01293 template <class SrcImageIterator, class SrcAccessor,
    01294           class DestImageIterator, class DestAccessor>
    01295 void recursiveFilterY(SrcImageIterator supperleft,
    01296                        SrcImageIterator slowerright, SrcAccessor as,
    01297                        DestImageIterator dupperleft, DestAccessor ad,
    01298                        double b1, double b2)
    01299 {
    01300     int w = slowerright.x - supperleft.x;
    01301     int h = slowerright.y - supperleft.y;
    01302
    01303     int x;
    01304
    01305     for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
    01306     {
    01307         typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
    01308         typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
    01309
    01310         recursiveFilterLine(cs, cs+h, as,
    01311                             cd, ad,
    01312                             b1, b2);
    01313     }
    01314 }
    01315
    01316 template <class SrcImageIterator, class SrcAccessor,
    01317           class DestImageIterator, class DestAccessor>
    01318 inline void recursiveFilterY(
    01319             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    01320             pair<DestImageIterator, DestAccessor> dest,
    01321                        double b1, double b2)
    01322 {
    01323     recursiveFilterY(src.first, src.second, src.third,
    01324                       dest.first, dest.second, b1, b2);
    01325 }
    01326
    01327
    01328 /********************************************************/
    01329 /*                                                      */
    01330 /*               recursiveGaussianFilterY               */
    01331 /*                                                      */
    01332 /********************************************************/
    01333
    01334 // AUTHOR: Sebastian Boppel
    01335
    01336 /** \brief Compute 1 dimensional recursive approximation of Gaussian smoothing in y direction.
    01337
    01338     It calls \ref recursiveGaussianFilterLine() for every column of the
    01339     image. See \ref recursiveGaussianFilterLine() for more information about
    01340     required interfaces and vigra_preconditions.
    01341
    01342     <b> Declarations:</b>
    01343
    01344     pass arguments explicitly:
    01345     \code
    01346     namespace vigra {
    01347         template <class SrcImageIterator, class SrcAccessor,
    01348                   class DestImageIterator, class DestAccessor>
    01349         void
    01350         recursiveGaussianFilterY(SrcImageIterator supperleft, SrcImageIterator slowerright, SrcAccessor as,
    01351                                  DestImageIterator dupperleft, DestAccessor ad,
    01352                                  double sigma);
    01353     }
    01354     \endcode
    01355
    01356
    01357     use argument objects in conjunction with \ref ArgumentObjectFactories :
    01358     \code
    01359     namespace vigra {
    01360         template <class SrcImageIterator, class SrcAccessor,
    01361                   class DestImageIterator, class DestAccessor>
    01362         void
    01363         recursiveGaussianFilterY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    01364                                  pair<DestImageIterator, DestAccessor> dest,
    01365                                  double sigma);
    01366     }
    01367     \endcode
    01368
    01369     <b> Usage:</b>
    01370
    01371     <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
    01372     Namespace: vigra
    01373
    01374     \code
    01375     vigra::FImage src(w,h), dest(w,h);
    01376     ...
    01377
    01378     vigra::recursiveGaussianFilterY(srcImageRange(src), destImage(dest), 3.0);
    01379
    01380     \endcode
    01381
    01382 */
    01383 doxygen_overloaded_function(template <...> void recursiveGaussianFilterY)
    01384
    01385 template <class SrcImageIterator, class SrcAccessor,
    01386           class DestImageIterator, class DestAccessor>
    01387 void
    01388 recursiveGaussianFilterY(SrcImageIterator supperleft, SrcImageIterator slowerright, SrcAccessor as,
    01389                          DestImageIterator dupperleft, DestAccessor ad,
    01390                          double sigma)
    01391 {
    01392     int w = slowerright.x - supperleft.x;
    01393     int h = slowerright.y - supperleft.y;
    01394
    01395     int x;
    01396
    01397     for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
    01398     {
    01399         typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
    01400         typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
    01401
    01402         recursiveGaussianFilterLine(cs, cs+h, as,
    01403                                     cd, ad,
    01404                                     sigma);
    01405     }
    01406 }
    01407
    01408 template <class SrcImageIterator, class SrcAccessor,
    01409           class DestImageIterator, class DestAccessor>
    01410 inline void
    01411 recursiveGaussianFilterY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    01412                          pair<DestImageIterator, DestAccessor> dest,
    01413                          double sigma)
    01414 {
    01415     recursiveGaussianFilterY(src.first, src.second, src.third,
    01416                              dest.first, dest.second, sigma);
    01417 }
    01418
    01419
    01420 /********************************************************/
    01421 /*                                                      */
    01422 /*                     recursiveSmoothY                 */
    01423 /*                                                      */
    01424 /********************************************************/
    01425
    01426 /** \brief Performs 1 dimensional recursive smoothing in y direction.
    01427
    01428     It calls \ref recursiveSmoothLine() for every column of the
    01429     image. See \ref recursiveSmoothLine() for more information about
    01430     required interfaces and vigra_preconditions.
    01431
    01432     <b> Declarations:</b>
    01433
    01434     pass arguments explicitly:
    01435     \code
    01436     namespace vigra {
    01437         template <class SrcImageIterator, class SrcAccessor,
    01438               class DestImageIterator, class DestAccessor>
    01439         void recursiveSmoothY(SrcImageIterator supperleft,
    01440                   SrcImageIterator slowerright, SrcAccessor as,
    01441                   DestImageIterator dupperleft, DestAccessor ad,
    01442                   double scale)
    01443     }
    01444     \endcode
    01445
    01446
    01447     use argument objects in conjunction with \ref ArgumentObjectFactories :
    01448     \code
    01449     namespace vigra {
    01450         template <class SrcImageIterator, class SrcAccessor,
    01451               class DestImageIterator, class DestAccessor>
    01452         void recursiveSmoothY(
    01453             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    01454             pair<DestImageIterator, DestAccessor> dest,
    01455             double scale)
    01456     }
    01457     \endcode
    01458
    01459     <b> Usage:</b>
    01460
    01461     <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
    01462     Namespace: vigra
    01463
    01464     \code
    01465     vigra::FImage src(w,h), dest(w,h);
    01466     ...
    01467
    01468     vigra::recursiveSmoothY(srcImageRange(src), destImage(dest), 3.0);
    01469
    01470     \endcode
    01471
    01472 */
    01473 doxygen_overloaded_function(template <...> void recursiveSmoothY)
    01474
    01475 template <class SrcImageIterator, class SrcAccessor,
    01476           class DestImageIterator, class DestAccessor>
    01477 void recursiveSmoothY(SrcImageIterator supperleft,
    01478                       SrcImageIterator slowerright, SrcAccessor as,
    01479                       DestImageIterator dupperleft, DestAccessor ad,
    01480               double scale)
    01481 {
    01482     int w = slowerright.x - supperleft.x;
    01483     int h = slowerright.y - supperleft.y;
    01484
    01485     int x;
    01486
    01487     for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
    01488     {
    01489         typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
    01490         typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
    01491
    01492         recursiveSmoothLine(cs, cs+h, as,
    01493                             cd, ad,
    01494                             scale);
    01495     }
    01496 }
    01497
    01498 template <class SrcImageIterator, class SrcAccessor,
    01499           class DestImageIterator, class DestAccessor>
    01500 inline void recursiveSmoothY(
    01501             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    01502             pair<DestImageIterator, DestAccessor> dest,
    01503             double scale)
    01504 {
    01505     recursiveSmoothY(src.first, src.second, src.third,
    01506                      dest. first, dest.second, scale);
    01507 }
    01508
    01509 /********************************************************/
    01510 /*                                                      */
    01511 /*              recursiveFirstDerivativeX               */
    01512 /*                                                      */
    01513 /********************************************************/
    01514
    01515 /** \brief Recursively calculates the 1 dimensional first derivative in x
    01516     direction.
    01517
    01518     It calls \ref recursiveFirstDerivativeLine() for every
    01519     row of the image. See \ref recursiveFirstDerivativeLine() for more
    01520     information about required interfaces and vigra_preconditions.
    01521
    01522     <b> Declarations:</b>
    01523
    01524     pass arguments explicitly:
    01525     \code
    01526     namespace vigra {
    01527         template <class SrcImageIterator, class SrcAccessor,
    01528               class DestImageIterator, class DestAccessor>
    01529         void recursiveFirstDerivativeX(SrcImageIterator supperleft,
    01530                   SrcImageIterator slowerright, SrcAccessor as,
    01531                   DestImageIterator dupperleft, DestAccessor ad,
    01532                   double scale)
    01533     }
    01534     \endcode
    01535
    01536
    01537     use argument objects in conjunction with \ref ArgumentObjectFactories :
    01538     \code
    01539     namespace vigra {
    01540         template <class SrcImageIterator, class SrcAccessor,
    01541               class DestImageIterator, class DestAccessor>
    01542         void recursiveFirstDerivativeX(
    01543             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    01544             pair<DestImageIterator, DestAccessor> dest,
    01545             double scale)
    01546     }
    01547     \endcode
    01548
    01549     <b> Usage:</b>
    01550
    01551     <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
    01552     Namespace: vigra
    01553
    01554     \code
    01555     vigra::FImage src(w,h), dest(w,h);
    01556     ...
    01557
    01558     vigra::recursiveFirstDerivativeX(srcImageRange(src), destImage(dest), 3.0);
    01559
    01560     \endcode
    01561
    01562 */
    01563 doxygen_overloaded_function(template <...> void recursiveFirstDerivativeX)
    01564
    01565 template <class SrcImageIterator, class SrcAccessor,
    01566           class DestImageIterator, class DestAccessor>
    01567 void recursiveFirstDerivativeX(SrcImageIterator supperleft,
    01568                       SrcImageIterator slowerright, SrcAccessor as,
    01569                       DestImageIterator dupperleft, DestAccessor ad,
    01570               double scale)
    01571 {
    01572     int w = slowerright.x - supperleft.x;
    01573     int h = slowerright.y - supperleft.y;
    01574
    01575     int y;
    01576
    01577     for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
    01578     {
    01579         typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
    01580         typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
    01581
    01582         recursiveFirstDerivativeLine(rs, rs+w, as,
    01583                                      rd, ad,
    01584                                      scale);
    01585     }
    01586 }
    01587
    01588 template <class SrcImageIterator, class SrcAccessor,
    01589           class DestImageIterator, class DestAccessor>
    01590 inline void recursiveFirstDerivativeX(
    01591             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    01592             pair<DestImageIterator, DestAccessor> dest,
    01593         double scale)
    01594 {
    01595     recursiveFirstDerivativeX(src.first, src.second, src.third,
    01596                           dest. first, dest.second, scale);
    01597 }
    01598
    01599 /********************************************************/
    01600 /*                                                      */
    01601 /*              recursiveFirstDerivativeY               */
    01602 /*                                                      */
    01603 /********************************************************/
    01604
    01605 /** \brief Recursively calculates the 1 dimensional first derivative in y
    01606     direction.
    01607
    01608     It calls \ref recursiveFirstDerivativeLine() for every
    01609     column of the image. See \ref recursiveFirstDerivativeLine() for more
    01610     information about required interfaces and vigra_preconditions.
    01611
    01612     <b> Declarations:</b>
    01613
    01614     pass arguments explicitly:
    01615     \code
    01616     namespace vigra {
    01617         template <class SrcImageIterator, class SrcAccessor,
    01618               class DestImageIterator, class DestAccessor>
    01619         void recursiveFirstDerivativeY(SrcImageIterator supperleft,
    01620                   SrcImageIterator slowerright, SrcAccessor as,
    01621                   DestImageIterator dupperleft, DestAccessor ad,
    01622                   double scale)
    01623     }
    01624     \endcode
    01625
    01626
    01627     use argument objects in conjunction with \ref ArgumentObjectFactories :
    01628     \code
    01629     namespace vigra {
    01630         template <class SrcImageIterator, class SrcAccessor,
    01631               class DestImageIterator, class DestAccessor>
    01632         void recursiveFirstDerivativeY(
    01633             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    01634             pair<DestImageIterator, DestAccessor> dest,
    01635             double scale)
    01636     }
    01637     \endcode
    01638
    01639     <b> Usage:</b>
    01640
    01641     <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
    01642     Namespace: vigra
    01643
    01644     \code
    01645     vigra::FImage src(w,h), dest(w,h);
    01646     ...
    01647
    01648     vigra::recursiveFirstDerivativeY(srcImageRange(src), destImage(dest), 3.0);
    01649
    01650     \endcode
    01651
    01652 */
    01653 doxygen_overloaded_function(template <...> void recursiveFirstDerivativeY)
    01654
    01655 template <class SrcImageIterator, class SrcAccessor,
    01656           class DestImageIterator, class DestAccessor>
    01657 void recursiveFirstDerivativeY(SrcImageIterator supperleft,
    01658                       SrcImageIterator slowerright, SrcAccessor as,
    01659                       DestImageIterator dupperleft, DestAccessor ad,
    01660               double scale)
    01661 {
    01662     int w = slowerright.x - supperleft.x;
    01663     int h = slowerright.y - supperleft.y;
    01664
    01665     int x;
    01666
    01667     for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
    01668     {
    01669         typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
    01670         typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
    01671
    01672         recursiveFirstDerivativeLine(cs, cs+h, as,
    01673                                      cd, ad,
    01674                                      scale);
    01675     }
    01676 }
    01677
    01678 template <class SrcImageIterator, class SrcAccessor,
    01679           class DestImageIterator, class DestAccessor>
    01680 inline void recursiveFirstDerivativeY(
    01681             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    01682             pair<DestImageIterator, DestAccessor> dest,
    01683         double scale)
    01684 {
    01685     recursiveFirstDerivativeY(src.first, src.second, src.third,
    01686                           dest. first, dest.second, scale);
    01687 }
    01688
    01689 /********************************************************/
    01690 /*                                                      */
    01691 /*             recursiveSecondDerivativeX               */
    01692 /*                                                      */
    01693 /********************************************************/
    01694
    01695 /** \brief Recursively calculates the 1 dimensional second derivative in x
    01696     direction.
    01697
    01698     It calls \ref recursiveSecondDerivativeLine() for every
    01699     row of the image. See \ref recursiveSecondDerivativeLine() for more
    01700     information about required interfaces and vigra_preconditions.
    01701
    01702     <b> Declarations:</b>
    01703
    01704     pass arguments explicitly:
    01705     \code
    01706     namespace vigra {
    01707         template <class SrcImageIterator, class SrcAccessor,
    01708               class DestImageIterator, class DestAccessor>
    01709         void recursiveSecondDerivativeX(SrcImageIterator supperleft,
    01710                   SrcImageIterator slowerright, SrcAccessor as,
    01711                   DestImageIterator dupperleft, DestAccessor ad,
    01712                   double scale)
    01713     }
    01714     \endcode
    01715
    01716
    01717     use argument objects in conjunction with \ref ArgumentObjectFactories :
    01718     \code
    01719     namespace vigra {
    01720         template <class SrcImageIterator, class SrcAccessor,
    01721               class DestImageIterator, class DestAccessor>
    01722         void recursiveSecondDerivativeX(
    01723             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    01724             pair<DestImageIterator, DestAccessor> dest,
    01725             double scale)
    01726     }
    01727     \endcode
    01728
    01729     <b> Usage:</b>
    01730
    01731     <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
    01732     Namespace: vigra
    01733
    01734     \code
    01735     vigra::FImage src(w,h), dest(w,h);
    01736     ...
    01737
    01738     vigra::recursiveSecondDerivativeX(srcImageRange(src), destImage(dest), 3.0);
    01739
    01740     \endcode
    01741
    01742 */
    01743 doxygen_overloaded_function(template <...> void recursiveSecondDerivativeX)
    01744
    01745 template <class SrcImageIterator, class SrcAccessor,
    01746           class DestImageIterator, class DestAccessor>
    01747 void recursiveSecondDerivativeX(SrcImageIterator supperleft,
    01748                       SrcImageIterator slowerright, SrcAccessor as,
    01749                       DestImageIterator dupperleft, DestAccessor ad,
    01750               double scale)
    01751 {
    01752     int w = slowerright.x - supperleft.x;
    01753     int h = slowerright.y - supperleft.y;
    01754
    01755     int y;
    01756
    01757     for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
    01758     {
    01759         typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
    01760         typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
    01761
    01762         recursiveSecondDerivativeLine(rs, rs+w, as,
    01763                                       rd, ad,
    01764                                       scale);
    01765     }
    01766 }
    01767
    01768 template <class SrcImageIterator, class SrcAccessor,
    01769           class DestImageIterator, class DestAccessor>
    01770 inline void recursiveSecondDerivativeX(
    01771             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    01772             pair<DestImageIterator, DestAccessor> dest,
    01773         double scale)
    01774 {
    01775     recursiveSecondDerivativeX(src.first, src.second, src.third,
    01776                           dest. first, dest.second, scale);
    01777 }
    01778
    01779 /********************************************************/
    01780 /*                                                      */
    01781 /*             recursiveSecondDerivativeY               */
    01782 /*                                                      */
    01783 /********************************************************/
    01784
    01785 /** \brief Recursively calculates the 1 dimensional second derivative in y
    01786     direction.
    01787
    01788     It calls \ref recursiveSecondDerivativeLine() for every
    01789     column of the image. See \ref recursiveSecondDerivativeLine() for more
    01790     information about required interfaces and vigra_preconditions.
    01791
    01792     <b> Declarations:</b>
    01793
    01794     pass arguments explicitly:
    01795     \code
    01796     namespace vigra {
    01797         template <class SrcImageIterator, class SrcAccessor,
    01798               class DestImageIterator, class DestAccessor>
    01799         void recursiveSecondDerivativeY(SrcImageIterator supperleft,
    01800                   SrcImageIterator slowerright, SrcAccessor as,
    01801                   DestImageIterator dupperleft, DestAccessor ad,
    01802                   double scale)
    01803     }
    01804     \endcode
    01805
    01806
    01807     use argument objects in conjunction with \ref ArgumentObjectFactories :
    01808     \code
    01809     namespace vigra {
    01810         template <class SrcImageIterator, class SrcAccessor,
    01811               class DestImageIterator, class DestAccessor>
    01812         void recursiveSecondDerivativeY(
    01813             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    01814             pair<DestImageIterator, DestAccessor> dest,
    01815             double scale)
    01816     }
    01817     \endcode
    01818
    01819     <b> Usage:</b>
    01820
    01821     <b>\#include</b> <vigra/recursiveconvolution.hxx><br>
    01822     Namespace: vigra
    01823
    01824     \code
    01825     vigra::FImage src(w,h), dest(w,h);
    01826     ...
    01827
    01828     vigra::recursiveSecondDerivativeY(srcImageRange(src), destImage(dest), 3.0);
    01829
    01830     \endcode
    01831
    01832 */
    01833 doxygen_overloaded_function(template <...> void recursiveSecondDerivativeY)
    01834
    01835 template <class SrcImageIterator, class SrcAccessor,
    01836           class DestImageIterator, class DestAccessor>
    01837 void recursiveSecondDerivativeY(SrcImageIterator supperleft,
    01838                       SrcImageIterator slowerright, SrcAccessor as,
    01839                       DestImageIterator dupperleft, DestAccessor ad,
    01840               double scale)
    01841 {
    01842     int w = slowerright.x - supperleft.x;
    01843     int h = slowerright.y - supperleft.y;
    01844
    01845     int x;
    01846
    01847     for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
    01848     {
    01849         typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
    01850         typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
    01851
    01852         recursiveSecondDerivativeLine(cs, cs+h, as,
    01853                                       cd, ad,
    01854                                       scale);
    01855     }
    01856 }
    01857
    01858 template <class SrcImageIterator, class SrcAccessor,
    01859           class DestImageIterator, class DestAccessor>
    01860 inline void recursiveSecondDerivativeY(
    01861             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
    01862             pair<DestImageIterator, DestAccessor> dest,
    01863         double scale)
    01864 {
    01865     recursiveSecondDerivativeY(src.first, src.second, src.third,
    01866                           dest. first, dest.second, scale);
    01867 }
    01868
    01869
    01870 //@}
    01871
    01872 } // namespace vigra
    01873
    01874 #endif // VIGRA_RECURSIVECONVOLUTION_HXX

© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de) Heidelberg Collaboratory for Image Processing, University of Heidelberg, Germany | html generated using doxygen and Python vigra 1.9.0 (Tue Nov 6 2012)