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

vigra/recursiveconvolution-merge.hxx VIGRA

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> <<a href="recursiveconvolution_8hxx-source.html">vigra/recursiveconvolution.hxx</a>><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     if(b == 0.0)
00178     {
00179         for(; is != isend; ++is, ++id)
00180         {
00181             ad.set(as(is), id);
00182         }
00183         return;
00184     }
00185 
00186     double eps = 0.00001;
00187     int kernelw = std::min(w-1, (int)(VIGRA_CSTD::log(eps)/VIGRA_CSTD::log(VIGRA_CSTD::fabs(b))));
00188     
00189     typedef typename
00190         NumericTraits<typename SrcAccessor::value_type>::RealPromote TempType;
00191     typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
00192     typedef typename DestTraits::RealPromote RealPromote;
00193     
00194     // store result of causal filtering
00195     std::vector<TempType> vline(w);
00196     typename std::vector<TempType>::iterator line = vline.begin();
00197     
00198     double norm = (1.0 - b) / (1.0 + b);
00199 
00200     TempType old;
00201     
00202     if(border == BORDER_TREATMENT_REPEAT ||
00203        border == BORDER_TREATMENT_AVOID)
00204     {
00205          old = TempType((1.0 / (1.0 - b)) * as(is));
00206     }
00207     else if(border == BORDER_TREATMENT_REFLECT)
00208     {
00209         is += kernelw;
00210         old = TempType((1.0 / (1.0 - b)) * as(is));
00211         for(x = 0; x < kernelw; ++x, --is)
00212             old = TempType(as(is) + b * old);
00213     }
00214     else if(border == BORDER_TREATMENT_WRAP)
00215     {
00216         is = isend - kernelw; 
00217         old = TempType((1.0 / (1.0 - b)) * as(is));
00218         for(x = 0; x < kernelw; ++x, ++is)
00219             old = TempType(as(is) + b * old);
00220     }
00221     else if(border == BORDER_TREATMENT_CLIP)
00222     {
00223         old = NumericTraits<TempType>::zero();
00224     }
00225     else
00226         vigra_fail("recursiveFilterLine(): Unknown border treatment mode.\n");
00227 
00228     // left side of filter
00229     for(x=0, is = istart; x < w; ++x, ++is)
00230     {
00231         old = TempType(as(is) + b * old);
00232         line[x] = old;
00233     }
00234 
00235     // right side of the filter
00236     if(border == BORDER_TREATMENT_REPEAT ||
00237        border == BORDER_TREATMENT_AVOID)
00238     {
00239         is = isend - 1;
00240         old = TempType((1.0 / (1.0 - b)) * as(is));
00241     }
00242     else if(border == BORDER_TREATMENT_REFLECT)
00243     {
00244         old = line[w-2];
00245     }
00246     else if(border == BORDER_TREATMENT_WRAP)
00247     {
00248       is = istart + kernelw - 1;
00249       old = TempType((1.0 / (1.0 - b)) * as(is));
00250       for(x = 0; x < kernelw; ++x, --is)
00251           old = TempType(as(is) + b * old);
00252     }
00253     else if(border == BORDER_TREATMENT_CLIP)
00254     {
00255         old = NumericTraits<TempType>::zero();
00256     }
00257     
00258     is = isend - 1;
00259     id += w - 1;
00260     if(border == BORDER_TREATMENT_CLIP)
00261     {    
00262        // correction factors for b
00263         double bright = b;
00264         double bleft = VIGRA_CSTD::pow(b, w);
00265 
00266         for(x=w-1; x>=0; --x, --is, --id)
00267         {    
00268             TempType f = TempType(b * old);
00269             old = as(is) + f;
00270             double norm = (1.0 - b) / (1.0 + b - bleft - bright);
00271             bleft /= b;
00272             bright *= b;
00273             ad.set(norm * (line[x] + f), id);
00274         }
00275     }
00276     else if(border == BORDER_TREATMENT_AVOID)
00277     {
00278         for(x=w-1; x >= kernelw; --x, --is, --id)
00279         {    
00280             TempType f = TempType(b * old);
00281             old = as(is) + f;
00282             if(x < w - kernelw)
00283                 ad.set(DestTraits::fromRealPromote(RealPromote(norm * (line[x] + f))), id);
00284         }
00285     }
00286     else
00287     {
00288         for(x=w-1; x>=0; --x, --is, --id)
00289         {    
00290             TempType f = TempType(b * old);
00291             old = as(is) + f;
00292             ad.set(DestTraits::fromRealPromote(RealPromote(norm * (line[x] + f))), id);
00293         }
00294     }
00295 }
00296             
00297 /********************************************************/
00298 /*                                                      */
00299 /*            recursiveFilterLine (2nd order)           */
00300 /*                                                      */
00301 /********************************************************/
00302 
00303 template <class SrcIterator, class SrcAccessor,
00304           class DestIterator, class DestAccessor>
00305 void recursiveFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
00306                          DestIterator id, DestAccessor ad, double b1, double b2)
00307 {
00308     int w = isend - is;
00309     SrcIterator istart = is;
00310     
00311     int x;
00312     
00313     typedef typename
00314         NumericTraits<typename SrcAccessor::value_type>::RealPromote TempType;
00315     typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
00316     
00317     // speichert den Ergebnis der linkseitigen Filterung.
00318     std::vector<TempType> vline(w+1);
00319     typename std::vector<TempType>::iterator line = vline.begin();
00320     
00321     double norm  = 1.0 - b1 - b2;
00322     double norm1 = (1.0 - b1 - b2) / (1.0 + b1 + b2);
00323     double norm2 = norm * norm;
00324     
00325 
00326     // init left side of filter
00327     int kernelw = std::min(w-1, std::max(8, (int)(1.0 / norm + 0.5)));  
00328     is += (kernelw - 2);
00329     line[kernelw] = as(is);
00330     line[kernelw-1] = as(is);
00331     for(x = kernelw - 2; x > 0; --x, --is)
00332     {
00333         line[x] = detail::RequiresExplicitCast<TempType>::cast(as(is) + b1 * line[x+1] + b2 * line[x+2]);
00334     }
00335     line[0] = detail::RequiresExplicitCast<TempType>::cast(as(is) + b1 * line[1] + b2 * line[2]);
00336     ++is;
00337     line[1] = detail::RequiresExplicitCast<TempType>::cast(as(is) + b1 * line[0] + b2 * line[1]);
00338     ++is;
00339     for(x=2; x < w; ++x, ++is)
00340     {
00341         line[x] = detail::RequiresExplicitCast<TempType>::cast(as(is) + b1 * line[x-1] + b2 * line[x-2]);
00342     }
00343     line[w] = line[w-1];
00344 
00345     line[w-1] = detail::RequiresExplicitCast<TempType>::cast(norm1 * (line[w-1] + b1 * line[w-2] + b2 * line[w-3]));
00346     line[w-2] = detail::RequiresExplicitCast<TempType>::cast(norm1 * (line[w-2] + b1 * line[w] + b2 * line[w-2]));
00347     id += w-1;
00348     ad.set(line[w-1], id);
00349     --id;
00350     ad.set(line[w-2], id);
00351     --id;
00352     for(x=w-3; x>=0; --x, --id, --is)
00353     {    
00354         line[x] = detail::RequiresExplicitCast<TempType>::cast(norm2 * line[x] + b1 * line[x+1] + b2 * line[x+2]);
00355         ad.set(line[x], id);
00356     }
00357 }
00358             
00359 /********************************************************/
00360 /*                                                      */
00361 /*              recursiveGaussianFilterLine             */
00362 /*                                                      */
00363 /********************************************************/
00364 
00365 // AUTHOR: Sebastian Boppel
00366 
00367 /** \brief Compute a 1-dimensional recursive approximation of Gaussian smoothing.
00368 
00369     The function applies a causal and an anti-causal third order recursive filter 
00370     which optimally approximates the Gaussian filter, as proposed in
00371     
00372     I. Young, L. van Vliet: <it>Recursive implementation of the Gaussian filter</it><br>
00373     Signal Processing 44:139-151, 1995
00374     
00375     The formulas for transforming the given scale parameter <tt>sigma</tt> into the actual filter coefficients
00376     are taken from Luigi Rosa's Matlab implementation.
00377    
00378     The signal's value_type (SrcAccessor::value_type) must be a
00379     linear space over <TT>double</TT>, i.e. addition of source values, multiplication with <TT>double</TT>,
00380     and <TT>NumericTraits</TT> must be defined.     
00381     
00382     <b> Declaration:</b>
00383     
00384     \code
00385     namespace vigra {
00386         template <class SrcIterator, class SrcAccessor,
00387                   class DestIterator, class DestAccessor>
00388         void 
00389         recursiveGaussianFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
00390                                     DestIterator id, DestAccessor ad, 
00391                                     double sigma);
00392     }
00393     \endcode
00394     
00395     <b> Usage:</b>
00396     
00397     <b>\#include</b> <<a href="recursiveconvolution_8hxx-source.html">vigra/recursiveconvolution.hxx</a>><br>
00398     Namespace: vigra
00399     
00400     
00401     \code
00402     vector<float> src, dest;    
00403     ...
00404     
00405     vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
00406     double sigma = 2.5;
00407     
00408     vigra::recursiveGaussianFilterLine(src.begin(), src.end(), FAccessor(), 
00409                                        dest.begin(), FAccessor(), 
00410                                        sigma);
00411     \endcode
00412 
00413     <b> Required Interface:</b>
00414     
00415     \code
00416     RandomAccessIterator is, isend;
00417     RandomAccessIterator id;
00418     
00419     SrcAccessor src_accessor;
00420     DestAccessor dest_accessor;
00421     
00422     NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is);
00423     double d;
00424     
00425     s = s + s;
00426     s = d * s;
00427 
00428     dest_accessor.set(
00429         NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
00430 
00431     \endcode
00432 
00433     <b> Preconditions:</b>
00434     
00435     \code
00436     0 <= sigma (absolute values are taken for negative sigma)
00437     \endcode
00438 
00439 */
00440 doxygen_overloaded_function(template <...> void recursiveGaussianFilterLine)
00441 
00442 template <class SrcIterator, class SrcAccessor,
00443           class DestIterator, class DestAccessor>
00444 void 
00445 recursiveGaussianFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
00446                             DestIterator id, DestAccessor ad, 
00447                             double sigma)
00448 {
00449     //coefficients taken out Luigi Rosa's implementation for Matlab
00450     double q = 1.31564 * (std::sqrt(1.0 + 0.490811 * sigma*sigma) - 1.0);
00451     double qq = q*q;
00452     double qqq = qq*q;
00453     double b0 = 1.0/(1.57825 + 2.44413*q + 1.4281*qq + 0.422205*qqq);
00454     double b1 = (2.44413*q + 2.85619*qq + 1.26661*qqq)*b0;
00455     double b2 = (-1.4281*qq - 1.26661*qqq)*b0;
00456     double b3 = 0.422205*qqq*b0;
00457     double B = 1.0 - (b1 + b2 + b3);
00458 
00459     /*
00460     Formulas out of Vliets paper; either copy mistake or not correct in the paper
00461     double q = 0.98711*sigma-0.96330; //This is just for sigma >2.5
00462     
00463     
00464     double b0 = 1.57825 + (2.44413*q) + (1.4281*VIGRA_CSTD::pow(2.0, q)) + (0.422205*VIGRA_CSTD::pow(3.0, q));
00465     double b1 = (2.44413*q) + (2.85619*VIGRA_CSTD::pow(2.0, q)) + (1.26661*VIGRA_CSTD::pow(3.0, q));
00466     double b2 = -((1.4281*VIGRA_CSTD::pow(2.0, q)) + (1.26661*VIGRA_CSTD::pow(3.0, q)));
00467     double b3 = 0.422205*VIGRA_CSTD::pow(3.0, q);
00468     
00469     double B = 1 - ((b1 + b2 +b3)/b0);
00470     */
00471     
00472     int w = isend - is;
00473  
00474     int x;
00475     
00476     typedef typename
00477         NumericTraits<typename SrcAccessor::value_type>::RealPromote TempType;
00478     typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
00479     
00480     // speichert das Ergebnis der linkseitigen Filterung.
00481     std::vector<TempType> vyforward(w+1);
00482     typename std::vector<TempType>::iterator yforward = vyforward.begin();
00483     std::vector<TempType> vybackward(w+1);
00484     typename std::vector<TempType>::iterator ybackward = vybackward.begin();
00485 
00486     //from left to right - causal - forward
00487     yforward[0] = B*as(is);
00488 
00489     ++is;    
00490     yforward[1] = B*as(is) + (b1*yforward[0]);
00491 
00492     ++is;
00493     yforward[2] = B*as(is) + (b1*yforward[1]+b2*yforward[0]);
00494 
00495     for(x=3; x < w; ++x)
00496     {
00497         ++is;
00498         yforward[x] = B*as(is) + (b1*yforward[x-1]+b2*yforward[x-2]+b3*yforward[x-3]);
00499     }
00500 
00501     
00502     //from right to left - anticausal - backward
00503     ybackward[w] = B*yforward[w];
00504         
00505     ybackward[w-1] = B*yforward[w-1]+(b1*ybackward[w]);
00506     
00507     ybackward[w-2] = B*yforward[w-2]+(b1*ybackward[w-1]+b2*ybackward[w]);
00508   
00509     
00510     for(x=w-3; x>=0; --x)
00511     {
00512        ybackward[x] = B*yforward[x]+(b1*ybackward[x+1]+b2*ybackward[x+2]+b3*ybackward[x+3]);
00513     }
00514 
00515     // output
00516     for(x=0; x < w; ++x, ++id)
00517     {
00518         ad.set(ybackward[x], id);
00519     }
00520 }
00521 
00522 // AUTHOR: Sebastian Boppel
00523 // adaptive version of the above algorithm (i.e. the coefficients may change in every pixel)
00524 // theoretical properties of this version are unclear
00525 template <class SrcIterator, class SrcAccessor,
00526           class DestIterator, class DestAccessor>
00527 void 
00528 recursiveGaussianFilterLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
00529                             DestIterator id, DestAccessor ad,  
00530                             ArrayVector<double> const &b1,  ArrayVector<double> const &b2,  
00531                             ArrayVector<double> const &b3, ArrayVector<double> const &B)
00532 {
00533 
00534     int w = isend - is;
00535     SrcIterator istart = is;
00536     
00537     int x;
00538     
00539     typedef typename
00540         NumericTraits<typename SrcAccessor::value_type>::RealPromote TempType;
00541     typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
00542     
00543     // speichert den Ergebnis der linkseitigen Filterung.
00544     std::vector<TempType> vyforward(w+1);
00545     typename std::vector<TempType>::iterator yforward = vyforward.begin();
00546     std::vector<TempType> vybackward(w+1);
00547     typename std::vector<TempType>::iterator ybackward = vybackward.begin();
00548 
00549     //from left to right - causal - forward
00550     yforward[0] = B[0]*as(is);
00551 
00552     ++is;    
00553     yforward[1] = B[1]*as(is) + (b1[1]*yforward[0]);
00554 
00555     ++is;
00556     yforward[2] = B[2]*as(is) + (b1[2]*yforward[1]+b2[2]*yforward[0]);
00557 
00558     ++is;
00559     for(x=3; x <= w; ++x, ++is)
00560     {
00561         yforward[x] = B[x]*as(is) + (b1[x]*yforward[x-1]+b2[x]*yforward[x-2]+b3[x]*yforward[x-3]);
00562     }
00563 
00564     x= w;
00565     //from right to left - anticausal - backward
00566     ybackward[w] = B[x]*yforward[w];
00567 
00568     
00569     ybackward[w-1] = B[x]*yforward[w-1]+(b1[x]*ybackward[w]);
00570 
00571     
00572     ybackward[w-2] = B[x]*yforward[w-2]+(b1[x]*ybackward[w-1]+b2[x]*ybackward[w]);
00573 
00574 
00575 
00576     for(x=w-3; x>=0; --x)
00577     {
00578        ybackward[x] = B[x]*yforward[x]+(b1[x]*ybackward[x+1]+b2[x]*ybackward[x+2]+b3[x]*ybackward[x+3]);
00579     }
00580 
00581     // output
00582     for(x=0; x <= w; ++x, ++id)
00583     {
00584         ad.set(ybackward[x], id);
00585     }
00586 }
00587 
00588             
00589 /********************************************************/
00590 /*                                                      */
00591 /*                    recursiveSmoothLine               */
00592 /*                                                      */
00593 /********************************************************/
00594 
00595 /** \brief Convolves the image with a 1-dimensional exponential filter.
00596 
00597     This function calls \ref recursiveFilterLine() with <TT>b = exp(-1.0/scale)</TT>
00598     and <TT>border = BORDER_TREATMENT_REPEAT</TT>. See 
00599     \ref recursiveFilterLine() for more documentation.
00600     
00601     <b> Declaration:</b>
00602     
00603     \code
00604     namespace vigra {
00605         template <class SrcIterator, class SrcAccessor,
00606               class DestIterator, class DestAccessor>
00607         void recursiveSmoothLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
00608                      DestIterator id, DestAccessor ad, double scale)
00609     }
00610     \endcode
00611     
00612     <b> Usage:</b>
00613     
00614     <b>\#include</b> <<a href="recursiveconvolution_8hxx-source.html">vigra/recursiveconvolution.hxx</a>><br>
00615     Namespace: vigra
00616     
00617     
00618     \code
00619     vector<float> src, dest;    
00620     ...
00621     
00622     vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
00623     
00624     
00625     vigra::recursiveSmoothLine(src.begin(), src.end(), FAccessor(), 
00626                         dest.begin(), FAccessor(), 3.0);
00627     \endcode
00628 
00629     <b> Required Interface:</b>
00630     
00631     \code
00632     RandomAccessIterator is, isend;
00633     RandomAccessIterator id;
00634     
00635     SrcAccessor src_accessor;
00636     DestAccessor dest_accessor;
00637     
00638     NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is);
00639     double d;
00640     
00641     s = s + s;
00642     s = d * s;
00643 
00644     dest_accessor.set(
00645         NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
00646 
00647     \endcode
00648 
00649     <b> Preconditions:</b>
00650     
00651     \code
00652     scale > 0
00653     \endcode
00654 
00655 */
00656 doxygen_overloaded_function(template <...> void recursiveSmoothLine)
00657 
00658 template <class SrcIterator, class SrcAccessor,
00659           class DestIterator, class DestAccessor>
00660 inline 
00661 void recursiveSmoothLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
00662                          DestIterator id, DestAccessor ad, double scale)
00663 {
00664     vigra_precondition(scale >= 0,
00665                  "recursiveSmoothLine(): scale must be >= 0.\n");
00666                  
00667     double b = (scale == 0.0) ? 
00668                     0.0 :
00669                     VIGRA_CSTD::exp(-1.0/scale);
00670     
00671     recursiveFilterLine(is, isend, as, id, ad, b, BORDER_TREATMENT_REPEAT);
00672 }
00673             
00674 /********************************************************/
00675 /*                                                      */
00676 /*             recursiveFirstDerivativeLine             */
00677 /*                                                      */
00678 /********************************************************/
00679 
00680 /** \brief Performs a 1 dimensional recursive convolution of the source signal.
00681 
00682     It uses the first derivative an exponential  <TT>d/dx exp(-abs(x)/scale)</TT> as 
00683     a kernel. The signal's value_type (SrcAccessor::value_type) must be a
00684     linear space over <TT>double</TT>,
00685     i.e. addition and subtraction of source values, multiplication with 
00686     <TT>double</TT>, and <TT>NumericTraits</TT> must be defined. Border 
00687     treatment is always <TT>BORDER_TREATMENT_REPEAT</TT>.
00688     
00689     <b> Declaration:</b>
00690     
00691     \code
00692     namespace vigra {
00693         template <class SrcIterator, class SrcAccessor,
00694               class DestIterator, class DestAccessor>
00695         void recursiveFirstDerivativeLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
00696                      DestIterator id, DestAccessor ad, double scale)
00697     }
00698     \endcode
00699     
00700     <b> Usage:</b>
00701     
00702     <b>\#include</b> <<a href="recursiveconvolution_8hxx-source.html">vigra/recursiveconvolution.hxx</a>><br>
00703     Namespace: vigra
00704     
00705     
00706     \code
00707     vector<float> src, dest;    
00708     ...
00709     
00710     vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
00711     
00712     
00713     vigra::recursiveFirstDerivativeLine(src.begin(), src.end(), FAccessor(), 
00714                         dest.begin(), FAccessor(), 3.0);
00715     \endcode
00716 
00717     <b> Required Interface:</b>
00718     
00719     \code
00720     RandomAccessIterator is, isend;
00721     RandomAccessIterator id;
00722     
00723     SrcAccessor src_accessor;
00724     DestAccessor dest_accessor;
00725     
00726     NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is);
00727     double d;
00728     
00729     s = s + s;
00730     s = -s;
00731     s = d * s;
00732 
00733     dest_accessor.set(
00734         NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
00735 
00736     \endcode
00737 
00738     <b> Preconditions:</b>
00739     
00740     \code
00741     scale > 0
00742     \endcode
00743 
00744 */
00745 doxygen_overloaded_function(template <...> void recursiveFirstDerivativeLine)
00746 
00747 template <class SrcIterator, class SrcAccessor,
00748           class DestIterator, class DestAccessor>
00749 void recursiveFirstDerivativeLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
00750                          DestIterator id, DestAccessor ad, double scale)
00751 {
00752     vigra_precondition(scale > 0,
00753                  "recursiveFirstDerivativeLine(): scale must be > 0.\n");
00754 
00755     int w = isend -is;
00756     
00757     int x;
00758     
00759     typedef typename
00760         NumericTraits<typename SrcAccessor::value_type>::RealPromote 
00761     TempType;
00762     typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
00763 
00764     std::vector<TempType> vline(w);
00765     typename std::vector<TempType>::iterator line = vline.begin();
00766     
00767     double b = VIGRA_CSTD::exp(-1.0/scale);
00768     double norm = (1.0 - b) * (1.0 - b) / 2.0 / b;
00769     TempType old = (1.0 / (1.0 - b)) * as(is);
00770 
00771     // left side of filter
00772     for(x=0; x<w; ++x, ++is)
00773     {
00774         old = as(is) + b * old;
00775         line[x] = -old;
00776     }
00777     
00778     // right side of the filter
00779     --is;
00780     old = (1.0 / (1.0 - b)) * as(is);
00781     id += w;
00782     ++is;
00783     
00784     for(x=w-1; x>=0; --x)
00785     {    
00786         --is;
00787         --id;
00788 
00789         old = as(is) + b * old;
00790 
00791         ad.set(DestTraits::fromRealPromote(norm * (line[x] + old)), id);
00792     }
00793 }
00794             
00795 /********************************************************/
00796 /*                                                      */
00797 /*            recursiveSecondDerivativeLine             */
00798 /*                                                      */
00799 /********************************************************/
00800 
00801 /** \brief Performs a 1 dimensional recursive convolution of the source signal.
00802 
00803     It uses the second derivative an exponential  <TT>d2/dx2 exp(-abs(x)/scale)</TT> as 
00804     a kernel. The signal's value_type (SrcAccessor::value_type) must be a
00805     linear space over <TT>double</TT>,
00806     i.e. addition and subtraction of source values, multiplication with 
00807     <TT>double</TT>, and <TT>NumericTraits</TT> must be defined. Border 
00808     treatment is always <TT>BORDER_TREATMENT_REPEAT</TT>.
00809     
00810     <b> Declaration:</b>
00811     
00812     \code
00813     namespace vigra {
00814         template <class SrcIterator, class SrcAccessor,
00815               class DestIterator, class DestAccessor>
00816         void recursiveSecondDerivativeLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
00817                      DestIterator id, DestAccessor ad, double scale)
00818     }
00819     \endcode
00820     
00821     <b> Usage:</b>
00822     
00823     <b>\#include</b> <<a href="recursiveconvolution_8hxx-source.html">vigra/recursiveconvolution.hxx</a>><br>
00824     Namespace: vigra
00825     
00826     
00827     \code
00828     vector<float> src, dest;    
00829     ...
00830     
00831     vigra::DefaultAccessor<vector<float>::iterator, float> FAccessor;
00832     
00833     
00834     vigra::recursiveSecondDerivativeLine(src.begin(), src.end(), FAccessor(), 
00835                         dest.begin(), FAccessor(), 3.0);
00836     \endcode
00837 
00838     <b> Required Interface:</b>
00839     
00840     \code
00841     RandomAccessIterator is, isend;
00842     RandomAccessIterator id;
00843     
00844     SrcAccessor src_accessor;
00845     DestAccessor dest_accessor;
00846     
00847     NumericTraits<SrcAccessor::value_type>::RealPromote s = src_accessor(is);
00848     double d;
00849     
00850     s = s + s;
00851     s = s - s;
00852     s = d * s;
00853 
00854     dest_accessor.set(
00855         NumericTraits<DestAccessor::value_type>::fromRealPromote(s), id);
00856 
00857     \endcode
00858 
00859     <b> Preconditions:</b>
00860     
00861     \code
00862     scale > 0
00863     \endcode
00864 
00865 */
00866 doxygen_overloaded_function(template <...> void recursiveSecondDerivativeLine)
00867 
00868 template <class SrcIterator, class SrcAccessor,
00869           class DestIterator, class DestAccessor>
00870 void recursiveSecondDerivativeLine(SrcIterator is, SrcIterator isend, SrcAccessor as,
00871                          DestIterator id, DestAccessor ad, double scale)
00872 {
00873     vigra_precondition(scale > 0,
00874                  "recursiveSecondDerivativeLine(): scale must be > 0.\n");
00875 
00876     int w = isend -is;
00877     
00878     int x;
00879     
00880     typedef typename
00881         NumericTraits<typename SrcAccessor::value_type>::RealPromote 
00882     TempType;
00883     typedef NumericTraits<typename DestAccessor::value_type> DestTraits;
00884     
00885     std::vector<TempType> vline(w);
00886     typename std::vector<TempType>::iterator line = vline.begin();
00887         
00888     double b = VIGRA_CSTD::exp(-1.0/scale);
00889     double a = -2.0 / (1.0 - b);
00890     double norm = (1.0 - b) * (1.0 - b) * (1.0 - b) / (1.0 + b);
00891     TempType old = detail::RequiresExplicitCast<TempType>::cast((1.0 / (1.0 - b)) * as(is));
00892 
00893     // left side of filter
00894     for(x=0; x<w; ++x, ++is)
00895     {
00896         line[x] = old;
00897         old = detail::RequiresExplicitCast<TempType>::cast(as(is) + b * old);
00898     }
00899     
00900     // right side of the filter
00901     --is;
00902     old = detail::RequiresExplicitCast<TempType>::cast((1.0 / (1.0 - b)) * as(is));
00903     id += w;
00904     ++is;
00905     
00906     for(x=w-1; x>=0; --x)
00907     {    
00908         --is;
00909         --id;
00910 
00911         TempType f = detail::RequiresExplicitCast<TempType>::cast(old + a * as(is));
00912         old = detail::RequiresExplicitCast<TempType>::cast(as(is) + b * old);
00913         ad.set(DestTraits::fromRealPromote(detail::RequiresExplicitCast<TempType>::cast(norm * (line[x] + f))), id);
00914     }
00915 }
00916             
00917 /********************************************************/
00918 /*                                                      */
00919 /*                   recursiveFilterX                   */
00920 /*                                                      */
00921 /********************************************************/
00922 
00923 /** \brief Performs 1 dimensional recursive filtering (1st and 2nd order) in x direction.
00924 
00925     It calls \ref recursiveFilterLine() for every row of the
00926     image. See \ref recursiveFilterLine() for more information about 
00927     required interfaces and vigra_preconditions.
00928     
00929     <b> Declarations:</b>
00930     
00931     pass arguments explicitly:
00932     \code
00933     namespace vigra {
00934         // first order filter
00935         template <class SrcImageIterator, class SrcAccessor,
00936                   class DestImageIterator, class DestAccessor>
00937         void recursiveFilterX(SrcImageIterator supperleft, 
00938                                SrcImageIterator slowerright, SrcAccessor as,
00939                                DestImageIterator dupperleft, DestAccessor ad, 
00940                                double b, BorderTreatmentMode border);
00941 
00942         // second order filter
00943         template <class SrcImageIterator, class SrcAccessor,
00944                   class DestImageIterator, class DestAccessor>
00945         void recursiveFilterX(SrcImageIterator supperleft, 
00946                                SrcImageIterator slowerright, SrcAccessor as,
00947                                DestImageIterator dupperleft, DestAccessor ad, 
00948                                double b1, double b2);
00949     }
00950     \endcode
00951     
00952     
00953     use argument objects in conjunction with \ref ArgumentObjectFactories :
00954     \code
00955     namespace vigra {
00956         // first order filter
00957         template <class SrcImageIterator, class SrcAccessor,
00958                   class DestImageIterator, class DestAccessor>
00959         void recursiveFilterX(
00960                     triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
00961                     pair<DestImageIterator, DestAccessor> dest, 
00962                     double b, BorderTreatmentMode border);
00963 
00964         // second order filter
00965         template <class SrcImageIterator, class SrcAccessor,
00966                   class DestImageIterator, class DestAccessor>
00967         void recursiveFilterX(
00968                     triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
00969                     pair<DestImageIterator, DestAccessor> dest, 
00970                     double b1, double b2);
00971             }
00972     \endcode
00973     
00974     <b> Usage:</b>
00975     
00976     <b>\#include</b> <<a href="recursiveconvolution_8hxx-source.html">vigra/recursiveconvolution.hxx</a>><br>
00977     Namespace: vigra
00978     
00979     \code
00980     vigra::FImage src(w,h), dest(w,h);    
00981     ...
00982     
00983     vigra::recursiveSmoothX(srcImageRange(src), destImage(dest), 
00984            0.5, BORDER_TREATMENT_REFLECT);
00985     
00986     \endcode
00987 
00988 */
00989 doxygen_overloaded_function(template <...> void recursiveFilterX)
00990 
00991 template <class SrcImageIterator, class SrcAccessor,
00992           class DestImageIterator, class DestAccessor>
00993 void recursiveFilterX(SrcImageIterator supperleft, 
00994                        SrcImageIterator slowerright, SrcAccessor as,
00995                        DestImageIterator dupperleft, DestAccessor ad, 
00996                        double b, BorderTreatmentMode border)
00997 {
00998     int w = slowerright.x - supperleft.x;
00999     int h = slowerright.y - supperleft.y;
01000     
01001     int y;
01002     
01003     for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
01004     {
01005         typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
01006         typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
01007 
01008         recursiveFilterLine(rs, rs+w, as, 
01009                              rd, ad, 
01010                              b, border);
01011     }
01012 }
01013             
01014 template <class SrcImageIterator, class SrcAccessor,
01015           class DestImageIterator, class DestAccessor>
01016 inline void recursiveFilterX(
01017             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
01018             pair<DestImageIterator, DestAccessor> dest, 
01019             double b, BorderTreatmentMode border)
01020 {
01021     recursiveFilterX(src.first, src.second, src.third,
01022                       dest.first, dest.second, b, border);
01023 }
01024 
01025 /********************************************************/
01026 /*                                                      */
01027 /*            recursiveFilterX (2nd order)              */
01028 /*                                                      */
01029 /********************************************************/
01030 
01031 template <class SrcImageIterator, class SrcAccessor,
01032           class DestImageIterator, class DestAccessor>
01033 void recursiveFilterX(SrcImageIterator supperleft, 
01034                        SrcImageIterator slowerright, SrcAccessor as,
01035                        DestImageIterator dupperleft, DestAccessor ad, 
01036                        double b1, double b2)
01037 {
01038     int w = slowerright.x - supperleft.x;
01039     int h = slowerright.y - supperleft.y;
01040     
01041     int y;
01042     
01043     for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
01044     {
01045         typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
01046         typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
01047 
01048         recursiveFilterLine(rs, rs+w, as, 
01049                              rd, ad, 
01050                              b1, b2);
01051     }
01052 }
01053 
01054 template <class SrcImageIterator, class SrcAccessor,
01055           class DestImageIterator, class DestAccessor>
01056 inline void recursiveFilterX(
01057             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
01058             pair<DestImageIterator, DestAccessor> dest, 
01059                        double b1, double b2)
01060 {
01061     recursiveFilterX(src.first, src.second, src.third,
01062                       dest.first, dest.second, b1, b2);
01063 }
01064             
01065 
01066 
01067 /********************************************************/
01068 /*                                                      */
01069 /*               recursiveGaussianFilterX               */
01070 /*                                                      */
01071 /********************************************************/
01072 
01073 // AUTHOR: Sebastian Boppel
01074 
01075 /** \brief Compute 1 dimensional recursive approximation of Gaussian smoothing in y direction.
01076 
01077     It calls \ref recursiveGaussianFilterLine() for every column of the
01078     image. See \ref recursiveGaussianFilterLine() for more information about 
01079     required interfaces and vigra_preconditions.
01080     
01081     <b> Declarations:</b>
01082     
01083     pass arguments explicitly:
01084     \code
01085     namespace vigra {
01086         template <class SrcImageIterator, class SrcAccessor,
01087                   class DestImageIterator, class DestAccessor>
01088         void 
01089         recursiveGaussianFilterX(SrcImageIterator supperleft, SrcImageIterator slowerright, SrcAccessor as,
01090                                  DestImageIterator dupperleft, DestAccessor ad, 
01091                                  double sigma);
01092     }
01093     \endcode
01094     
01095     
01096     use argument objects in conjunction with \ref ArgumentObjectFactories :
01097     \code
01098     namespace vigra {
01099         template <class SrcImageIterator, class SrcAccessor,
01100                   class DestImageIterator, class DestAccessor>
01101         void 
01102         recursiveGaussianFilterX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
01103                                  pair<DestImageIterator, DestAccessor> dest, 
01104                                  double sigma);
01105     }
01106     \endcode
01107     
01108     <b> Usage:</b>
01109     
01110     <b>\#include</b> <<a href="recursiveconvolution_8hxx-source.html">vigra/recursiveconvolution.hxx</a>><br>
01111     Namespace: vigra
01112     
01113     \code
01114     vigra::FImage src(w,h), dest(w,h);    
01115     ...
01116     
01117     vigra::recursiveGaussianFilterX(srcImageRange(src), destImage(dest), 3.0);
01118     
01119     \endcode
01120 
01121 */
01122 doxygen_overloaded_function(template <...> void recursiveGaussianFilterX)
01123 
01124 template <class SrcImageIterator, class SrcAccessor,
01125           class DestImageIterator, class DestAccessor>
01126 void 
01127 recursiveGaussianFilterX(SrcImageIterator supperleft, SrcImageIterator slowerright, SrcAccessor as,
01128                          DestImageIterator dupperleft, DestAccessor ad, 
01129                          double sigma)
01130 {
01131     int w = slowerright.x - supperleft.x;
01132     int h = slowerright.y - supperleft.y;
01133     
01134     int y;
01135     
01136     for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
01137     {
01138         typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
01139         typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
01140 
01141         recursiveGaussianFilterLine(rs, rs+w, as, 
01142                                     rd, ad, 
01143                                     sigma);
01144     }
01145 }
01146 
01147 template <class SrcImageIterator, class SrcAccessor,
01148           class DestImageIterator, class DestAccessor>
01149 inline void 
01150 recursiveGaussianFilterX(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
01151                          pair<DestImageIterator, DestAccessor> dest, 
01152                          double sigma)
01153 {
01154     recursiveGaussianFilterX(src.first, src.second, src.third,
01155                              dest.first, dest.second, sigma);
01156 }
01157 
01158 // adaptive version of the above algorithm, i.e. different sigmas for every pixel,
01159 // theoretical properties of this version are unclear
01160 template <class SrcImageIterator, class SrcAccessor,
01161           class DestImageIterator, class DestAccessor>
01162 void 
01163 recursiveGaussianFilterX(SrcImageIterator supperleft, SrcImageIterator slowerright, SrcAccessor as,
01164                          DestImageIterator dupperleft, DestAccessor ad, 
01165                          double *sigma)
01166 {
01167     int w = slowerright.x - supperleft.x;
01168     int x;
01169 
01170     double q;
01171     double qq;
01172     double qqq;
01173     double b0;
01174     ArrayVector<double> b1(w);
01175     ArrayVector<double> b2(w);
01176     ArrayVector<double> b3(w);
01177     ArrayVector<double> B(w);
01178 
01179     for(x=0; x<w; ++x)
01180     {
01181         //coefficients taken out Luigi Rosa's implementation for Matlab
01182         q= 1.31564 * (sqrt(1 + 0.490811 * (sigma[x])* (sigma[x])) - 1);
01183         qq = q*q;
01184         qqq = qq*q;
01185         b0 = 1.0/(1.57825 + 2.44413*q + 1.4281*qq + 0.422205*qqq);
01186         b1[x] = (2.44413*q + 2.85619*qq + 1.26661*qqq)*b0;
01187         b2[x] = (-1.4281*qq - 1.26661*qqq)*b0;
01188         b3[x] = (0.422205*qqq) * (b0);
01189         B[x] = 1.0 - (b1[x] + b2[x] + b3[x]);
01190     }
01191  
01192 
01193     int h = slowerright.y - supperleft.y;
01194     int y;
01195     for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
01196     {        
01197         typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
01198         typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
01199         recursiveGaussianFilterLine(rs, rs+w, as, rd, ad, b1, b2, b3, B );
01200     }
01201 }
01202 
01203 template <class SrcImageIterator, class SrcAccessor,
01204           class DestImageIterator, class DestAccessor>
01205 inline void 
01206 recursiveGaussianFilterX(
01207             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
01208             pair<DestImageIterator, DestAccessor> dest, 
01209             double *sigma)
01210 {
01211     recursiveGaussianFilterX(src.first, src.second, src.third,
01212                              dest.first, dest.second, sigma);
01213 }
01214             
01215 /********************************************************/
01216 /*                                                      */
01217 /*                    recursiveSmoothX                  */
01218 /*                                                      */
01219 /********************************************************/
01220 
01221 /** \brief Performs 1 dimensional recursive smoothing in x direction.
01222 
01223     It calls \ref recursiveSmoothLine() for every row of the
01224     image. See \ref recursiveSmoothLine() for more information about 
01225     required interfaces and vigra_preconditions.
01226     
01227     <b> Declarations:</b>
01228     
01229     pass arguments explicitly:
01230     \code
01231     namespace vigra {
01232         template <class SrcImageIterator, class SrcAccessor,
01233               class DestImageIterator, class DestAccessor>
01234         void recursiveSmoothX(SrcImageIterator supperleft, 
01235                   SrcImageIterator slowerright, SrcAccessor as,
01236                   DestImageIterator dupperleft, DestAccessor ad, 
01237                   double scale)
01238     }
01239     \endcode
01240     
01241     
01242     use argument objects in conjunction with \ref ArgumentObjectFactories :
01243     \code
01244     namespace vigra {
01245         template <class SrcImageIterator, class SrcAccessor,
01246               class DestImageIterator, class DestAccessor>
01247         void recursiveSmoothX(
01248             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
01249             pair<DestImageIterator, DestAccessor> dest, 
01250             double scale)
01251     }
01252     \endcode
01253     
01254     <b> Usage:</b>
01255     
01256     <b>\#include</b> <<a href="recursiveconvolution_8hxx-source.html">vigra/recursiveconvolution.hxx</a>><br>
01257     Namespace: vigra
01258     
01259     \code
01260     vigra::FImage src(w,h), dest(w,h);    
01261     ...
01262     
01263     vigra::recursiveSmoothX(srcImageRange(src), destImage(dest), 3.0);
01264     
01265     \endcode
01266 
01267 */
01268 doxygen_overloaded_function(template <...> void recursiveSmoothX)
01269 
01270 template <class SrcImageIterator, class SrcAccessor,
01271           class DestImageIterator, class DestAccessor>
01272 void recursiveSmoothX(SrcImageIterator supperleft, 
01273                       SrcImageIterator slowerright, SrcAccessor as,
01274                       DestImageIterator dupperleft, DestAccessor ad, 
01275                       double scale)
01276 {
01277     int w = slowerright.x - supperleft.x;
01278     int h = slowerright.y - supperleft.y;
01279     
01280     int y;
01281     
01282     for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
01283     {
01284         typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
01285         typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
01286 
01287         recursiveSmoothLine(rs, rs+w, as, 
01288                             rd, ad, 
01289                             scale);
01290     }
01291 }
01292             
01293 template <class SrcImageIterator, class SrcAccessor,
01294           class DestImageIterator, class DestAccessor>
01295 inline void recursiveSmoothX(
01296             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
01297             pair<DestImageIterator, DestAccessor> dest, 
01298         double scale)
01299 {
01300     recursiveSmoothX(src.first, src.second, src.third,
01301                      dest. first, dest.second, scale);
01302 }
01303             
01304 /********************************************************/
01305 /*                                                      */
01306 /*                     recursiveFilterY                 */
01307 /*                                                      */
01308 /********************************************************/
01309 
01310 /** \brief Performs 1 dimensional recursive filtering (1st and 2nd order) in y direction.
01311 
01312     It calls \ref recursiveFilterLine() for every column of the
01313     image. See \ref recursiveFilterLine() for more information about 
01314     required interfaces and vigra_preconditions.
01315     
01316     <b> Declarations:</b>
01317     
01318     pass arguments explicitly:
01319     \code
01320     namespace vigra {
01321         // first order filter
01322         template <class SrcImageIterator, class SrcAccessor,
01323                   class DestImageIterator, class DestAccessor>
01324         void recursiveFilterY(SrcImageIterator supperleft, 
01325                                SrcImageIterator slowerright, SrcAccessor as,
01326                                DestImageIterator dupperleft, DestAccessor ad, 
01327                                double b, BorderTreatmentMode border);
01328 
01329         // second order filter
01330         template <class SrcImageIterator, class SrcAccessor,
01331                   class DestImageIterator, class DestAccessor>
01332         void recursiveFilterY(SrcImageIterator supperleft, 
01333                                SrcImageIterator slowerright, SrcAccessor as,
01334                                DestImageIterator dupperleft, DestAccessor ad, 
01335                                double b1, double b2);
01336     }
01337     \endcode
01338     
01339     
01340     use argument objects in conjunction with \ref ArgumentObjectFactories :
01341     \code
01342     namespace vigra {
01343         // first order filter
01344         template <class SrcImageIterator, class SrcAccessor,
01345                   class DestImageIterator, class DestAccessor>
01346         void recursiveFilterY(
01347                     triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
01348                     pair<DestImageIterator, DestAccessor> dest, 
01349                     double b, BorderTreatmentMode border);
01350 
01351         // second order filter
01352         template <class SrcImageIterator, class SrcAccessor,
01353                   class DestImageIterator, class DestAccessor>
01354         void recursiveFilterY(
01355                     triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
01356                     pair<DestImageIterator, DestAccessor> dest, 
01357                     double b1, double b2);
01358             }
01359     \endcode
01360     
01361     <b> Usage:</b>
01362     
01363     <b>\#include</b> <<a href="recursiveconvolution_8hxx-source.html">vigra/recursiveconvolution.hxx</a>><br>
01364     Namespace: vigra
01365     
01366     \code
01367     vigra::FImage src(w,h), dest(w,h);    
01368     ...
01369     
01370     vigra::recursiveFilterY(srcImageRange(src), destImage(dest), -0.6, -0.06);
01371     
01372     \endcode
01373 
01374 */
01375 doxygen_overloaded_function(template <...> void recursiveFilterY)
01376 
01377 template <class SrcImageIterator, class SrcAccessor,
01378           class DestImageIterator, class DestAccessor>
01379 void recursiveFilterY(SrcImageIterator supperleft, 
01380                        SrcImageIterator slowerright, SrcAccessor as,
01381                        DestImageIterator dupperleft, DestAccessor ad, 
01382                        double b, BorderTreatmentMode border)
01383 {
01384     int w = slowerright.x - supperleft.x;
01385     int h = slowerright.y - supperleft.y;
01386     
01387     int x;
01388     
01389     for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
01390     {
01391         typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
01392         typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
01393 
01394         recursiveFilterLine(cs, cs+h, as, 
01395                             cd, ad, 
01396                             b, border);
01397     }
01398 }
01399             
01400 template <class SrcImageIterator, class SrcAccessor,
01401           class DestImageIterator, class DestAccessor>
01402 inline void recursiveFilterY(
01403             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
01404             pair<DestImageIterator, DestAccessor> dest, 
01405             double b, BorderTreatmentMode border)
01406 {
01407     recursiveFilterY(src.first, src.second, src.third,
01408                       dest.first, dest.second, b, border);
01409 }
01410 
01411 /********************************************************/
01412 /*                                                      */
01413 /*            recursiveFilterY (2nd order)              */
01414 /*                                                      */
01415 /********************************************************/
01416 
01417 template <class SrcImageIterator, class SrcAccessor,
01418           class DestImageIterator, class DestAccessor>
01419 void recursiveFilterY(SrcImageIterator supperleft, 
01420                        SrcImageIterator slowerright, SrcAccessor as,
01421                        DestImageIterator dupperleft, DestAccessor ad, 
01422                        double b1, double b2)
01423 {
01424     int w = slowerright.x - supperleft.x;
01425     int h = slowerright.y - supperleft.y;
01426     
01427     int x;
01428     
01429     for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
01430     {
01431         typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
01432         typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
01433 
01434         recursiveFilterLine(cs, cs+h, as, 
01435                             cd, ad, 
01436                             b1, b2);
01437     }
01438 }
01439 
01440 template <class SrcImageIterator, class SrcAccessor,
01441           class DestImageIterator, class DestAccessor>
01442 inline void recursiveFilterY(
01443             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
01444             pair<DestImageIterator, DestAccessor> dest, 
01445                        double b1, double b2)
01446 {
01447     recursiveFilterY(src.first, src.second, src.third,
01448                       dest.first, dest.second, b1, b2);
01449 }
01450             
01451 
01452 /********************************************************/
01453 /*                                                      */
01454 /*               recursiveGaussianFilterY               */
01455 /*                                                      */
01456 /********************************************************/
01457 
01458 // AUTHOR: Sebastian Boppel
01459 
01460 /** \brief Compute 1 dimensional recursive approximation of Gaussian smoothing in y direction.
01461 
01462     It calls \ref recursiveGaussianFilterLine() for every column of the
01463     image. See \ref recursiveGaussianFilterLine() for more information about 
01464     required interfaces and vigra_preconditions.
01465     
01466     <b> Declarations:</b>
01467     
01468     pass arguments explicitly:
01469     \code
01470     namespace vigra {
01471         template <class SrcImageIterator, class SrcAccessor,
01472                   class DestImageIterator, class DestAccessor>
01473         void 
01474         recursiveGaussianFilterY(SrcImageIterator supperleft, SrcImageIterator slowerright, SrcAccessor as,
01475                                  DestImageIterator dupperleft, DestAccessor ad, 
01476                                  double sigma);
01477     }
01478     \endcode
01479     
01480     
01481     use argument objects in conjunction with \ref ArgumentObjectFactories :
01482     \code
01483     namespace vigra {
01484         template <class SrcImageIterator, class SrcAccessor,
01485                   class DestImageIterator, class DestAccessor>
01486         void 
01487         recursiveGaussianFilterY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
01488                                  pair<DestImageIterator, DestAccessor> dest, 
01489                                  double sigma);
01490     }
01491     \endcode
01492     
01493     <b> Usage:</b>
01494     
01495     <b>\#include</b> <<a href="recursiveconvolution_8hxx-source.html">vigra/recursiveconvolution.hxx</a>><br>
01496     Namespace: vigra
01497     
01498     \code
01499     vigra::FImage src(w,h), dest(w,h);    
01500     ...
01501     
01502     vigra::recursiveGaussianFilterY(srcImageRange(src), destImage(dest), 3.0);
01503     
01504     \endcode
01505 
01506 */
01507 doxygen_overloaded_function(template <...> void recursiveGaussianFilterY)
01508 
01509 template <class SrcImageIterator, class SrcAccessor,
01510           class DestImageIterator, class DestAccessor>
01511 void 
01512 recursiveGaussianFilterY(SrcImageIterator supperleft, SrcImageIterator slowerright, SrcAccessor as,
01513                          DestImageIterator dupperleft, DestAccessor ad, 
01514                          double sigma)
01515 {
01516     int w = slowerright.x - supperleft.x;
01517     int h = slowerright.y - supperleft.y;
01518     
01519     int x;
01520     
01521     for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
01522     {
01523         typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
01524         typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
01525 
01526         recursiveGaussianFilterLine(cs, cs+h, as, 
01527                                     cd, ad, 
01528                                     sigma);
01529     } 
01530 }
01531 
01532 template <class SrcImageIterator, class SrcAccessor,
01533           class DestImageIterator, class DestAccessor>
01534 inline void 
01535 recursiveGaussianFilterY(triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
01536                          pair<DestImageIterator, DestAccessor> dest, 
01537                          double sigma)
01538 {
01539     recursiveGaussianFilterY(src.first, src.second, src.third,
01540                              dest.first, dest.second, sigma);
01541 }
01542 
01543 
01544 /********************************************************/
01545 /*                                                      */
01546 /*                     recursiveSmoothY                 */
01547 /*                                                      */
01548 /********************************************************/
01549 
01550 /** \brief Performs 1 dimensional recursive smoothing in y direction.
01551 
01552     It calls \ref recursiveSmoothLine() for every column of the
01553     image. See \ref recursiveSmoothLine() for more information about 
01554     required interfaces and vigra_preconditions.
01555     
01556     <b> Declarations:</b>
01557     
01558     pass arguments explicitly:
01559     \code
01560     namespace vigra {
01561         template <class SrcImageIterator, class SrcAccessor,
01562               class DestImageIterator, class DestAccessor>
01563         void recursiveSmoothY(SrcImageIterator supperleft, 
01564                   SrcImageIterator slowerright, SrcAccessor as,
01565                   DestImageIterator dupperleft, DestAccessor ad, 
01566                   double scale)
01567     }
01568     \endcode
01569     
01570     
01571     use argument objects in conjunction with \ref ArgumentObjectFactories :
01572     \code
01573     namespace vigra {
01574         template <class SrcImageIterator, class SrcAccessor,
01575               class DestImageIterator, class DestAccessor>
01576         void recursiveSmoothY(
01577             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
01578             pair<DestImageIterator, DestAccessor> dest, 
01579             double scale)
01580     }
01581     \endcode
01582     
01583     <b> Usage:</b>
01584     
01585     <b>\#include</b> <<a href="recursiveconvolution_8hxx-source.html">vigra/recursiveconvolution.hxx</a>><br>
01586     Namespace: vigra
01587     
01588     \code
01589     vigra::FImage src(w,h), dest(w,h);    
01590     ...
01591     
01592     vigra::recursiveSmoothY(srcImageRange(src), destImage(dest), 3.0);
01593     
01594     \endcode
01595 
01596 */
01597 doxygen_overloaded_function(template <...> void recursiveSmoothY)
01598 
01599 template <class SrcImageIterator, class SrcAccessor,
01600           class DestImageIterator, class DestAccessor>
01601 void recursiveSmoothY(SrcImageIterator supperleft, 
01602                       SrcImageIterator slowerright, SrcAccessor as,
01603                       DestImageIterator dupperleft, DestAccessor ad, 
01604               double scale)
01605 {
01606     int w = slowerright.x - supperleft.x;
01607     int h = slowerright.y - supperleft.y;
01608     
01609     int x;
01610     
01611     for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
01612     {
01613         typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
01614         typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
01615 
01616         recursiveSmoothLine(cs, cs+h, as, 
01617                             cd, ad, 
01618                             scale);
01619     }
01620 }
01621             
01622 template <class SrcImageIterator, class SrcAccessor,
01623           class DestImageIterator, class DestAccessor>
01624 inline void recursiveSmoothY(
01625             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
01626             pair<DestImageIterator, DestAccessor> dest, 
01627             double scale)
01628 {
01629     recursiveSmoothY(src.first, src.second, src.third,
01630                      dest. first, dest.second, scale);
01631 }
01632             
01633 /********************************************************/
01634 /*                                                      */
01635 /*              recursiveFirstDerivativeX               */
01636 /*                                                      */
01637 /********************************************************/
01638 
01639 /** \brief Recursively calculates the 1 dimensional first derivative in x 
01640     direction.
01641     
01642     It calls \ref recursiveFirstDerivativeLine() for every 
01643     row of the image. See \ref recursiveFirstDerivativeLine() for more 
01644     information about required interfaces and vigra_preconditions.
01645     
01646     <b> Declarations:</b>
01647     
01648     pass arguments explicitly:
01649     \code
01650     namespace vigra {
01651         template <class SrcImageIterator, class SrcAccessor,
01652               class DestImageIterator, class DestAccessor>
01653         void recursiveFirstDerivativeX(SrcImageIterator supperleft, 
01654                   SrcImageIterator slowerright, SrcAccessor as,
01655                   DestImageIterator dupperleft, DestAccessor ad, 
01656                   double scale)
01657     }
01658     \endcode
01659     
01660     
01661     use argument objects in conjunction with \ref ArgumentObjectFactories :
01662     \code
01663     namespace vigra {
01664         template <class SrcImageIterator, class SrcAccessor,
01665               class DestImageIterator, class DestAccessor>
01666         void recursiveFirstDerivativeX(
01667             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
01668             pair<DestImageIterator, DestAccessor> dest, 
01669             double scale)
01670     }
01671     \endcode
01672     
01673     <b> Usage:</b>
01674     
01675     <b>\#include</b> <<a href="recursiveconvolution_8hxx-source.html">vigra/recursiveconvolution.hxx</a>><br>
01676     Namespace: vigra
01677     
01678     \code
01679     vigra::FImage src(w,h), dest(w,h);    
01680     ...
01681     
01682     vigra::recursiveFirstDerivativeX(srcImageRange(src), destImage(dest), 3.0);
01683     
01684     \endcode
01685 
01686 */
01687 doxygen_overloaded_function(template <...> void recursiveFirstDerivativeX)
01688 
01689 template <class SrcImageIterator, class SrcAccessor,
01690           class DestImageIterator, class DestAccessor>
01691 void recursiveFirstDerivativeX(SrcImageIterator supperleft, 
01692                       SrcImageIterator slowerright, SrcAccessor as,
01693                       DestImageIterator dupperleft, DestAccessor ad, 
01694               double scale)
01695 {
01696     int w = slowerright.x - supperleft.x;
01697     int h = slowerright.y - supperleft.y;
01698     
01699     int y;
01700     
01701     for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
01702     {
01703         typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
01704         typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
01705 
01706         recursiveFirstDerivativeLine(rs, rs+w, as, 
01707                                      rd, ad, 
01708                                      scale);
01709     }
01710 }
01711             
01712 template <class SrcImageIterator, class SrcAccessor,
01713           class DestImageIterator, class DestAccessor>
01714 inline void recursiveFirstDerivativeX(
01715             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
01716             pair<DestImageIterator, DestAccessor> dest, 
01717         double scale)
01718 {
01719     recursiveFirstDerivativeX(src.first, src.second, src.third,
01720                           dest. first, dest.second, scale);
01721 }
01722             
01723 /********************************************************/
01724 /*                                                      */
01725 /*              recursiveFirstDerivativeY               */
01726 /*                                                      */
01727 /********************************************************/
01728 
01729 /** \brief Recursively calculates the 1 dimensional first derivative in y 
01730     direction.
01731     
01732     It calls \ref recursiveFirstDerivativeLine() for every 
01733     column of the image. See \ref recursiveFirstDerivativeLine() for more 
01734     information about required interfaces and vigra_preconditions.
01735     
01736     <b> Declarations:</b>
01737     
01738     pass arguments explicitly:
01739     \code
01740     namespace vigra {
01741         template <class SrcImageIterator, class SrcAccessor,
01742               class DestImageIterator, class DestAccessor>
01743         void recursiveFirstDerivativeY(SrcImageIterator supperleft, 
01744                   SrcImageIterator slowerright, SrcAccessor as,
01745                   DestImageIterator dupperleft, DestAccessor ad, 
01746                   double scale)
01747     }
01748     \endcode
01749     
01750     
01751     use argument objects in conjunction with \ref ArgumentObjectFactories :
01752     \code
01753     namespace vigra {
01754         template <class SrcImageIterator, class SrcAccessor,
01755               class DestImageIterator, class DestAccessor>
01756         void recursiveFirstDerivativeY(
01757             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
01758             pair<DestImageIterator, DestAccessor> dest, 
01759             double scale)
01760     }
01761     \endcode
01762     
01763     <b> Usage:</b>
01764     
01765     <b>\#include</b> <<a href="recursiveconvolution_8hxx-source.html">vigra/recursiveconvolution.hxx</a>><br>
01766     Namespace: vigra
01767     
01768     \code
01769     vigra::FImage src(w,h), dest(w,h);    
01770     ...
01771     
01772     vigra::recursiveFirstDerivativeY(srcImageRange(src), destImage(dest), 3.0);
01773     
01774     \endcode
01775 
01776 */
01777 doxygen_overloaded_function(template <...> void recursiveFirstDerivativeY)
01778 
01779 template <class SrcImageIterator, class SrcAccessor,
01780           class DestImageIterator, class DestAccessor>
01781 void recursiveFirstDerivativeY(SrcImageIterator supperleft, 
01782                       SrcImageIterator slowerright, SrcAccessor as,
01783                       DestImageIterator dupperleft, DestAccessor ad, 
01784               double scale)
01785 {
01786     int w = slowerright.x - supperleft.x;
01787     int h = slowerright.y - supperleft.y;
01788     
01789     int x;
01790     
01791     for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
01792     {
01793         typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
01794         typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
01795 
01796         recursiveFirstDerivativeLine(cs, cs+h, as, 
01797                                      cd, ad, 
01798                                      scale);
01799     }
01800 }
01801             
01802 template <class SrcImageIterator, class SrcAccessor,
01803           class DestImageIterator, class DestAccessor>
01804 inline void recursiveFirstDerivativeY(
01805             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
01806             pair<DestImageIterator, DestAccessor> dest, 
01807         double scale)
01808 {
01809     recursiveFirstDerivativeY(src.first, src.second, src.third,
01810                           dest. first, dest.second, scale);
01811 }
01812             
01813 /********************************************************/
01814 /*                                                      */
01815 /*             recursiveSecondDerivativeX               */
01816 /*                                                      */
01817 /********************************************************/
01818 
01819 /** \brief Recursively calculates the 1 dimensional second derivative in x 
01820     direction.
01821     
01822     It calls \ref recursiveSecondDerivativeLine() for every 
01823     row of the image. See \ref recursiveSecondDerivativeLine() for more 
01824     information about required interfaces and vigra_preconditions.
01825     
01826     <b> Declarations:</b>
01827     
01828     pass arguments explicitly:
01829     \code
01830     namespace vigra {
01831         template <class SrcImageIterator, class SrcAccessor,
01832               class DestImageIterator, class DestAccessor>
01833         void recursiveSecondDerivativeX(SrcImageIterator supperleft, 
01834                   SrcImageIterator slowerright, SrcAccessor as,
01835                   DestImageIterator dupperleft, DestAccessor ad, 
01836                   double scale)
01837     }
01838     \endcode
01839     
01840     
01841     use argument objects in conjunction with \ref ArgumentObjectFactories :
01842     \code
01843     namespace vigra {
01844         template <class SrcImageIterator, class SrcAccessor,
01845               class DestImageIterator, class DestAccessor>
01846         void recursiveSecondDerivativeX(
01847             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
01848             pair<DestImageIterator, DestAccessor> dest, 
01849             double scale)
01850     }
01851     \endcode
01852     
01853     <b> Usage:</b>
01854     
01855     <b>\#include</b> <<a href="recursiveconvolution_8hxx-source.html">vigra/recursiveconvolution.hxx</a>><br>
01856     Namespace: vigra
01857     
01858     \code
01859     vigra::FImage src(w,h), dest(w,h);    
01860     ...
01861     
01862     vigra::recursiveSecondDerivativeX(srcImageRange(src), destImage(dest), 3.0);
01863     
01864     \endcode
01865 
01866 */
01867 doxygen_overloaded_function(template <...> void recursiveSecondDerivativeX)
01868 
01869 template <class SrcImageIterator, class SrcAccessor,
01870           class DestImageIterator, class DestAccessor>
01871 void recursiveSecondDerivativeX(SrcImageIterator supperleft, 
01872                       SrcImageIterator slowerright, SrcAccessor as,
01873                       DestImageIterator dupperleft, DestAccessor ad, 
01874               double scale)
01875 {
01876     int w = slowerright.x - supperleft.x;
01877     int h = slowerright.y - supperleft.y;
01878     
01879     int y;
01880     
01881     for(y=0; y<h; ++y, ++supperleft.y, ++dupperleft.y)
01882     {
01883         typename SrcImageIterator::row_iterator rs = supperleft.rowIterator();
01884         typename DestImageIterator::row_iterator rd = dupperleft.rowIterator();
01885 
01886         recursiveSecondDerivativeLine(rs, rs+w, as, 
01887                                       rd, ad, 
01888                                       scale);
01889     }
01890 }
01891             
01892 template <class SrcImageIterator, class SrcAccessor,
01893           class DestImageIterator, class DestAccessor>
01894 inline void recursiveSecondDerivativeX(
01895             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
01896             pair<DestImageIterator, DestAccessor> dest, 
01897         double scale)
01898 {
01899     recursiveSecondDerivativeX(src.first, src.second, src.third,
01900                           dest. first, dest.second, scale);
01901 }
01902             
01903 /********************************************************/
01904 /*                                                      */
01905 /*             recursiveSecondDerivativeY               */
01906 /*                                                      */
01907 /********************************************************/
01908 
01909 /** \brief Recursively calculates the 1 dimensional second derivative in y 
01910     direction.
01911     
01912     It calls \ref recursiveSecondDerivativeLine() for every 
01913     column of the image. See \ref recursiveSecondDerivativeLine() for more 
01914     information about required interfaces and vigra_preconditions.
01915     
01916     <b> Declarations:</b>
01917     
01918     pass arguments explicitly:
01919     \code
01920     namespace vigra {
01921         template <class SrcImageIterator, class SrcAccessor,
01922               class DestImageIterator, class DestAccessor>
01923         void recursiveSecondDerivativeY(SrcImageIterator supperleft, 
01924                   SrcImageIterator slowerright, SrcAccessor as,
01925                   DestImageIterator dupperleft, DestAccessor ad, 
01926                   double scale)
01927     }
01928     \endcode
01929     
01930     
01931     use argument objects in conjunction with \ref ArgumentObjectFactories :
01932     \code
01933     namespace vigra {
01934         template <class SrcImageIterator, class SrcAccessor,
01935               class DestImageIterator, class DestAccessor>
01936         void recursiveSecondDerivativeY(
01937             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
01938             pair<DestImageIterator, DestAccessor> dest, 
01939             double scale)
01940     }
01941     \endcode
01942     
01943     <b> Usage:</b>
01944     
01945     <b>\#include</b> <<a href="recursiveconvolution_8hxx-source.html">vigra/recursiveconvolution.hxx</a>><br>
01946     Namespace: vigra
01947     
01948     \code
01949     vigra::FImage src(w,h), dest(w,h);    
01950     ...
01951     
01952     vigra::recursiveSecondDerivativeY(srcImageRange(src), destImage(dest), 3.0);
01953     
01954     \endcode
01955 
01956 */
01957 doxygen_overloaded_function(template <...> void recursiveSecondDerivativeY)
01958 
01959 template <class SrcImageIterator, class SrcAccessor,
01960           class DestImageIterator, class DestAccessor>
01961 void recursiveSecondDerivativeY(SrcImageIterator supperleft, 
01962                       SrcImageIterator slowerright, SrcAccessor as,
01963                       DestImageIterator dupperleft, DestAccessor ad, 
01964               double scale)
01965 {
01966     int w = slowerright.x - supperleft.x;
01967     int h = slowerright.y - supperleft.y;
01968     
01969     int x;
01970     
01971     for(x=0; x<w; ++x, ++supperleft.x, ++dupperleft.x)
01972     {
01973         typename SrcImageIterator::column_iterator cs = supperleft.columnIterator();
01974         typename DestImageIterator::column_iterator cd = dupperleft.columnIterator();
01975 
01976         recursiveSecondDerivativeLine(cs, cs+h, as, 
01977                                       cd, ad, 
01978                                       scale);
01979     }
01980 }
01981             
01982 template <class SrcImageIterator, class SrcAccessor,
01983           class DestImageIterator, class DestAccessor>
01984 inline void recursiveSecondDerivativeY(
01985             triple<SrcImageIterator, SrcImageIterator, SrcAccessor> src,
01986             pair<DestImageIterator, DestAccessor> dest, 
01987         double scale)
01988 {
01989     recursiveSecondDerivativeY(src.first, src.second, src.third,
01990                           dest. first, dest.second, scale);
01991 }
01992             
01993             
01994 //@}
01995 
01996 } // namespace vigra
01997 
01998 #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.7.1 (9 Jul 2010)