[ VIGRA Homepage | Function Index | Class Index | Namespaces | File List | Main Page ]
00001 /************************************************************************/ 00002 /* */ 00003 /* Copyright 1998-2004 by Ullrich Koethe */ 00004 /* Cognitive Systems Group, University of Hamburg, Germany */ 00005 /* */ 00006 /* This file is part of the VIGRA computer vision library. */ 00007 /* ( Version 1.6.0, Aug 13 2008 ) */ 00008 /* The VIGRA Website is */ 00009 /* http://kogs-www.informatik.uni-hamburg.de/~koethe/vigra/ */ 00010 /* Please direct questions, bug reports, and contributions to */ 00011 /* ullrich.koethe@iwr.uni-heidelberg.de or */ 00012 /* vigra@informatik.uni-hamburg.de */ 00013 /* */ 00014 /* Permission is hereby granted, free of charge, to any person */ 00015 /* obtaining a copy of this software and associated documentation */ 00016 /* files (the "Software"), to deal in the Software without */ 00017 /* restriction, including without limitation the rights to use, */ 00018 /* copy, modify, merge, publish, distribute, sublicense, and/or */ 00019 /* sell copies of the Software, and to permit persons to whom the */ 00020 /* Software is furnished to do so, subject to the following */ 00021 /* conditions: */ 00022 /* */ 00023 /* The above copyright notice and this permission notice shall be */ 00024 /* included in all copies or substantial portions of the */ 00025 /* Software. */ 00026 /* */ 00027 /* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND */ 00028 /* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES */ 00029 /* OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND */ 00030 /* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT */ 00031 /* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, */ 00032 /* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING */ 00033 /* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR */ 00034 /* OTHER DEALINGS IN THE SOFTWARE. */ 00035 /* */ 00036 /************************************************************************/ 00037 00038 #ifndef VIGRA_RESAMPLING_CONVOLUTION_HXX 00039 #define VIGRA_RESAMPLING_CONVOLUTION_HXX 00040 00041 #include <cmath> 00042 #include "stdimage.hxx" 00043 #include "array_vector.hxx" 00044 #include "rational.hxx" 00045 #include "functortraits.hxx" 00046 #include "functorexpression.hxx" 00047 #include "transformimage.hxx" 00048 #include "imagecontainer.hxx" 00049 00050 namespace vigra { 00051 00052 namespace resampling_detail 00053 { 00054 00055 struct MapTargetToSourceCoordinate 00056 { 00057 MapTargetToSourceCoordinate(Rational<int> const & samplingRatio, 00058 Rational<int> const & offset) 00059 : a(samplingRatio.denominator()*offset.denominator()), 00060 b(samplingRatio.numerator()*offset.numerator()), 00061 c(samplingRatio.numerator()*offset.denominator()) 00062 {} 00063 00064 // the following functions are more efficient realizations of: 00065 // rational_cast<T>(i / samplingRatio + offset); 00066 // we need efficiency because this may be called in the inner loop 00067 00068 int operator()(int i) const 00069 { 00070 return (i * a + b) / c; 00071 } 00072 00073 double toDouble(int i) const 00074 { 00075 return double(i * a + b) / c; 00076 } 00077 00078 Rational<int> toRational(int i) const 00079 { 00080 return Rational<int>(i * a + b, c); 00081 } 00082 00083 bool isExpand2() const 00084 { 00085 return a == 1 && b == 0 && c == 2; 00086 } 00087 00088 bool isReduce2() const 00089 { 00090 return a == 2 && b == 0 && c == 1; 00091 } 00092 00093 int a, b, c; 00094 }; 00095 00096 } // namespace resampling_detail 00097 00098 template <> 00099 class FunctorTraits<resampling_detail::MapTargetToSourceCoordinate> 00100 : public FunctorTraitsBase<resampling_detail::MapTargetToSourceCoordinate> 00101 { 00102 public: 00103 typedef VigraTrueType isUnaryFunctor; 00104 }; 00105 00106 template <class SrcIter, class SrcAcc, 00107 class DestIter, class DestAcc, 00108 class KernelArray> 00109 void 00110 resamplingExpandLine2(SrcIter s, SrcIter send, SrcAcc src, 00111 DestIter d, DestIter dend, DestAcc dest, 00112 KernelArray const & kernels) 00113 { 00114 typedef typename KernelArray::value_type Kernel; 00115 typedef typename KernelArray::const_reference KernelRef; 00116 typedef typename Kernel::const_iterator KernelIter; 00117 00118 typedef typename 00119 PromoteTraits<typename SrcAcc::value_type, typename Kernel::value_type>::Promote 00120 TmpType; 00121 00122 int wo = send - s; 00123 int wn = dend - d; 00124 int wo2 = 2*wo - 2; 00125 00126 int ileft = std::max(kernels[0].right(), kernels[1].right()); 00127 int iright = wo + std::min(kernels[0].left(), kernels[1].left()) - 1; 00128 for(int i = 0; i < wn; ++i, ++d) 00129 { 00130 int is = i / 2; 00131 KernelRef kernel = kernels[i & 1]; 00132 KernelIter k = kernel.center() + kernel.right(); 00133 TmpType sum = NumericTraits<TmpType>::zero(); 00134 if(is < ileft) 00135 { 00136 for(int m=is-kernel.right(); m <= is-kernel.left(); ++m, --k) 00137 { 00138 int mm = (m < 0) 00139 ? -m 00140 : m; 00141 sum += *k * src(s, mm); 00142 } 00143 } 00144 else if(is > iright) 00145 { 00146 for(int m=is-kernel.right(); m <= is-kernel.left(); ++m, --k) 00147 { 00148 int mm = (m >= wo) 00149 ? wo2 - m 00150 : m; 00151 sum += *k * src(s, mm); 00152 } 00153 } 00154 else 00155 { 00156 SrcIter ss = s + is - kernel.right(); 00157 for(int m = 0; m < kernel.size(); ++m, --k, ++ss) 00158 { 00159 sum += *k * src(ss); 00160 } 00161 } 00162 dest.set(sum, d); 00163 } 00164 } 00165 00166 template <class SrcIter, class SrcAcc, 00167 class DestIter, class DestAcc, 00168 class KernelArray> 00169 void 00170 resamplingReduceLine2(SrcIter s, SrcIter send, SrcAcc src, 00171 DestIter d, DestIter dend, DestAcc dest, 00172 KernelArray const & kernels) 00173 { 00174 typedef typename KernelArray::value_type Kernel; 00175 typedef typename KernelArray::const_reference KernelRef; 00176 typedef typename Kernel::const_iterator KernelIter; 00177 00178 KernelRef kernel = kernels[0]; 00179 KernelIter kbegin = kernel.center() + kernel.right(); 00180 00181 typedef typename 00182 PromoteTraits<typename SrcAcc::value_type, typename Kernel::value_type>::Promote 00183 TmpType; 00184 00185 int wo = send - s; 00186 int wn = dend - d; 00187 int wo2 = 2*wo - 2; 00188 00189 int ileft = kernel.right(); 00190 int iright = wo + kernel.left() - 1; 00191 for(int i = 0; i < wn; ++i, ++d) 00192 { 00193 int is = 2 * i; 00194 KernelIter k = kbegin; 00195 TmpType sum = NumericTraits<TmpType>::zero(); 00196 if(is < ileft) 00197 { 00198 for(int m=is-kernel.right(); m <= is-kernel.left(); ++m, --k) 00199 { 00200 int mm = (m < 0) 00201 ? -m 00202 : m; 00203 sum += *k * src(s, mm); 00204 } 00205 } 00206 else if(is > iright) 00207 { 00208 for(int m=is-kernel.right(); m <= is-kernel.left(); ++m, --k) 00209 { 00210 int mm = (m >= wo) 00211 ? wo2 - m 00212 : m; 00213 sum += *k * src(s, mm); 00214 } 00215 } 00216 else 00217 { 00218 SrcIter ss = s + is - kernel.right(); 00219 for(int m = 0; m < kernel.size(); ++m, --k, ++ss) 00220 { 00221 sum += *k * src(ss); 00222 } 00223 } 00224 dest.set(sum, d); 00225 } 00226 } 00227 00228 /** \addtogroup ResamplingConvolutionFilters Resampling Convolution Filters 00229 00230 These functions implement the convolution operation when the source and target images 00231 have different sizes. This is realized by accessing a continous kernel at the 00232 appropriate non-integer positions. The technique is, for example, described in 00233 D. Schumacher: <i>General Filtered Image Rescaling</i>, in: Graphics Gems III, 00234 Academic Press, 1992. 00235 */ 00236 //@{ 00237 00238 /********************************************************/ 00239 /* */ 00240 /* resamplingConvolveLine */ 00241 /* */ 00242 /********************************************************/ 00243 00244 /** \brief Performs a 1-dimensional resampling convolution of the source signal using the given 00245 set of kernels. 00246 00247 This function is mainly used internally: It is called for each dimension of a 00248 higher dimensional array in order to perform a separable resize operation. 00249 00250 <b> Declaration:</b> 00251 00252 <b>\#include</b> <<a href="resampling__convolution_8hxx-source.html">vigra/resampling_convolution.hxx</a>> 00253 00254 \code 00255 namespace vigra { 00256 template <class SrcIter, class SrcAcc, 00257 class DestIter, class DestAcc, 00258 class KernelArray, 00259 class Functor> 00260 void 00261 resamplingConvolveLine(SrcIter s, SrcIter send, SrcAcc src, 00262 DestIter d, DestIter dend, DestAcc dest, 00263 KernelArray const & kernels, 00264 Functor mapTargetToSourceCoordinate) 00265 } 00266 \endcode 00267 00268 */ 00269 doxygen_overloaded_function(template <...> void resamplingConvolveLine) 00270 00271 template <class SrcIter, class SrcAcc, 00272 class DestIter, class DestAcc, 00273 class KernelArray, 00274 class Functor> 00275 void 00276 resamplingConvolveLine(SrcIter s, SrcIter send, SrcAcc src, 00277 DestIter d, DestIter dend, DestAcc dest, 00278 KernelArray const & kernels, 00279 Functor mapTargetToSourceCoordinate) 00280 { 00281 if(mapTargetToSourceCoordinate.isExpand2()) 00282 { 00283 resamplingExpandLine2(s, send, src, d, dend, dest, kernels); 00284 return; 00285 } 00286 if(mapTargetToSourceCoordinate.isReduce2()) 00287 { 00288 resamplingReduceLine2(s, send, src, d, dend, dest, kernels); 00289 return; 00290 } 00291 00292 typedef typename 00293 NumericTraits<typename SrcAcc::value_type>::RealPromote 00294 TmpType; 00295 typedef typename KernelArray::value_type Kernel; 00296 typedef typename Kernel::const_iterator KernelIter; 00297 00298 int wo = send - s; 00299 int wn = dend - d; 00300 int wo2 = 2*wo - 2; 00301 00302 int i; 00303 typename KernelArray::const_iterator kernel = kernels.begin(); 00304 for(i=0; i<wn; ++i, ++d, ++kernel) 00305 { 00306 // use the kernels periodically 00307 if(kernel == kernels.end()) 00308 kernel = kernels.begin(); 00309 00310 // calculate current target point into source location 00311 int is = mapTargetToSourceCoordinate(i); 00312 00313 TmpType sum = NumericTraits<TmpType>::zero(); 00314 00315 int lbound = is - kernel->right(), 00316 hbound = is - kernel->left(); 00317 00318 KernelIter k = kernel->center() + kernel->right(); 00319 if(lbound < 0 || hbound >= wo) 00320 { 00321 vigra_precondition(-lbound < wo && wo2 - hbound >= 0, 00322 "resamplingConvolveLine(): kernel or offset larger than image."); 00323 for(int m=lbound; m <= hbound; ++m, --k) 00324 { 00325 int mm = (m < 0) ? 00326 -m : 00327 (m >= wo) ? 00328 wo2 - m : 00329 m; 00330 sum += *k * src(s, mm); 00331 } 00332 } 00333 else 00334 { 00335 SrcIter ss = s + lbound; 00336 SrcIter ssend = s + hbound; 00337 00338 for(; ss <= ssend; ++ss, --k) 00339 { 00340 sum += *k * src(ss); 00341 } 00342 } 00343 00344 dest.set(sum, d); 00345 } 00346 } 00347 00348 template <class Kernel, class MapCoordinate, class KernelArray> 00349 void 00350 createResamplingKernels(Kernel const & kernel, 00351 MapCoordinate const & mapCoordinate, KernelArray & kernels) 00352 { 00353 for(unsigned int idest = 0; idest < kernels.size(); ++idest) 00354 { 00355 int isrc = mapCoordinate(idest); 00356 double idsrc = mapCoordinate.toDouble(idest); 00357 double offset = idsrc - isrc; 00358 double radius = kernel.radius(); 00359 int left = int(ceil(-radius - offset)); 00360 int right = int(floor(radius - offset)); 00361 kernels[idest].initExplicitly(left, right); 00362 00363 double x = left + offset; 00364 for(int i = left; i <= right; ++i, ++x) 00365 kernels[idest][i] = kernel(x); 00366 kernels[idest].normalize(1.0, kernel.derivativeOrder(), offset); 00367 } 00368 } 00369 00370 /** \brief Apply a resampling filter in the x-direction. 00371 00372 This function implements a convolution operation in x-direction 00373 (i.e. applies a 1D filter to every row) where the width of the source 00374 and destination images differ. This is typically used to avoid aliasing if 00375 the image is scaled down, or to interpolate smoothly if the image is scaled up. 00376 The target coordinates are transformed into source coordinates by 00377 00378 \code 00379 xsource = (xtarget - offset) / samplingRatio 00380 \endcode 00381 00382 The <tt>samplingRatio</tt> and <tt>offset</tt> must be given as \ref vigra::Rational 00383 in order to avoid rounding errors in this transformation. It is required that for all 00384 pixels of the target image, <tt>xsource</tt> remains within the range of the source 00385 image (i.e. <tt>0 <= xsource <= sourceWidth-1</tt>. Since <tt>xsource</tt> is 00386 in general not an integer, the <tt>kernel</tt> must be a functor that can be accessed at 00387 arbitrary (<tt>double</tt>) coordinates. It must also provide a member function <tt>radius()</tt> 00388 which specifies the support (non-zero interval) of the kernel. VIGRA already 00389 provides a number of suitable functors, e.g. \ref vigra::Gaussian, \ref vigra::BSpline 00390 \ref vigra::CatmullRomSpline, and \ref vigra::CoscotFunction. The function 00391 \ref resizeImageSplineInterpolation() is implemented by means resamplingConvolveX() and 00392 resamplingConvolveY(). 00393 00394 <b> Declarations:</b> 00395 00396 pass arguments explicitly: 00397 \code 00398 namespace vigra { 00399 template <class SrcIter, class SrcAcc, 00400 class DestIter, class DestAcc, 00401 class Kernel> 00402 void 00403 resamplingConvolveX(SrcIter sul, SrcIter slr, SrcAcc src, 00404 DestIter dul, DestIter dlr, DestAcc dest, 00405 Kernel const & kernel, 00406 Rational<int> const & samplingRatio, Rational<int> const & offset); 00407 } 00408 \endcode 00409 00410 00411 use argument objects in conjunction with \ref ArgumentObjectFactories : 00412 \code 00413 namespace vigra { 00414 template <class SrcIter, class SrcAcc, 00415 class DestIter, class DestAcc, 00416 class Kernel> 00417 void 00418 resamplingConvolveX(triple<SrcIter, SrcIter, SrcAcc> src, 00419 triple<DestIter, DestIter, DestAcc> dest, 00420 Kernel const & kernel, 00421 Rational<int> const & samplingRatio, Rational<int> const & offset); 00422 } 00423 \endcode 00424 00425 <b> Usage:</b> 00426 00427 <b>\#include</b> <<a href="resampling__convolution_8hxx-source.html">vigra/resampling_convolution.hxx</a>> 00428 00429 00430 \code 00431 Rational<int> ratio(2), offset(0); 00432 00433 FImage src(w,h), 00434 dest(rational_cast<int>(ratio*w), h); 00435 00436 float sigma = 2.0; 00437 Gaussian<float> smooth(sigma); 00438 ... 00439 00440 // simpultaneously enlarge and smooth source image 00441 resamplingConvolveX(srcImageRange(src), destImageRange(dest), 00442 smooth, ratio, offset); 00443 \endcode 00444 00445 <b> Required Interface:</b> 00446 00447 \code 00448 Kernel kernel; 00449 int kernelRadius = kernel.radius(); 00450 double x = ...; // must be <= radius() 00451 double value = kernel(x); 00452 \endcode 00453 */ 00454 doxygen_overloaded_function(template <...> void resamplingConvolveX) 00455 00456 template <class SrcIter, class SrcAcc, 00457 class DestIter, class DestAcc, 00458 class Kernel> 00459 void 00460 resamplingConvolveX(SrcIter sul, SrcIter slr, SrcAcc src, 00461 DestIter dul, DestIter dlr, DestAcc dest, 00462 Kernel const & kernel, 00463 Rational<int> const & samplingRatio, Rational<int> const & offset) 00464 { 00465 int wold = slr.x - sul.x; 00466 int wnew = dlr.x - dul.x; 00467 00468 vigra_precondition(!samplingRatio.is_inf() && samplingRatio > 0, 00469 "resamplingConvolveX(): sampling ratio must be > 0 and < infinity"); 00470 vigra_precondition(!offset.is_inf(), 00471 "resamplingConvolveX(): offset must be < infinity"); 00472 00473 int period = lcm(samplingRatio.numerator(), samplingRatio.denominator()); 00474 resampling_detail::MapTargetToSourceCoordinate mapCoordinate(samplingRatio, offset); 00475 00476 ArrayVector<Kernel1D<double> > kernels(period); 00477 00478 createResamplingKernels(kernel, mapCoordinate, kernels); 00479 00480 for(; sul.y < slr.y; ++sul.y, ++dul.y) 00481 { 00482 typename SrcIter::row_iterator sr = sul.rowIterator(); 00483 typename DestIter::row_iterator dr = dul.rowIterator(); 00484 resamplingConvolveLine(sr, sr+wold, src, dr, dr+wnew, dest, 00485 kernels, mapCoordinate); 00486 } 00487 } 00488 00489 template <class SrcIter, class SrcAcc, 00490 class DestIter, class DestAcc, 00491 class Kernel> 00492 inline void 00493 resamplingConvolveX(triple<SrcIter, SrcIter, SrcAcc> src, 00494 triple<DestIter, DestIter, DestAcc> dest, 00495 Kernel const & kernel, 00496 Rational<int> const & samplingRatio, Rational<int> const & offset) 00497 { 00498 resamplingConvolveX(src.first, src.second, src.third, 00499 dest.first, dest.second, dest.third, 00500 kernel, samplingRatio, offset); 00501 } 00502 00503 /********************************************************/ 00504 /* */ 00505 /* resamplingConvolveY */ 00506 /* */ 00507 /********************************************************/ 00508 00509 /** \brief Apply a resampling filter in the y-direction. 00510 00511 This function implements a convolution operation in y-direction 00512 (i.e. applies a 1D filter to every column) where the height of the source 00513 and destination images differ. This is typically used to avoid aliasing if 00514 the image is scaled down, or to interpolate smoothly if the image is scaled up. 00515 The target coordinates are transformed into source coordinates by 00516 00517 \code 00518 ysource = (ytarget - offset) / samplingRatio 00519 \endcode 00520 00521 The <tt>samplingRatio</tt> and <tt>offset</tt> must be given as \ref vigra::Rational 00522 in order to avoid rounding errors in this transformation. It is required that for all 00523 pixels of the target image, <tt>ysource</tt> remains within the range of the source 00524 image (i.e. <tt>0 <= ysource <= sourceHeight-1</tt>. Since <tt>ysource</tt> is 00525 in general not an integer, the <tt>kernel</tt> must be a functor that can be accessed at 00526 arbitrary (<tt>double</tt>) coordinates. It must also provide a member function <tt>radius()</tt> 00527 which specifies the support (non-zero interval) of the kernel. VIGRA already 00528 provides a number of suitable functors, e.g. \ref vigra::Gaussian, \ref vigra::BSpline 00529 \ref vigra::CatmullRomSpline, and \ref vigra::CoscotFunction. The function 00530 \ref resizeImageSplineInterpolation() is implemented by means resamplingConvolveX() and 00531 resamplingConvolveY(). 00532 00533 <b> Declarations:</b> 00534 00535 pass arguments explicitly: 00536 \code 00537 namespace vigra { 00538 template <class SrcIter, class SrcAcc, 00539 class DestIter, class DestAcc, 00540 class Kernel> 00541 void 00542 resamplingConvolveY(SrcIter sul, SrcIter slr, SrcAcc src, 00543 DestIter dul, DestIter dlr, DestAcc dest, 00544 Kernel const & kernel, 00545 Rational<int> const & samplingRatio, Rational<int> const & offset); 00546 } 00547 \endcode 00548 00549 00550 use argument objects in conjunction with \ref ArgumentObjectFactories : 00551 \code 00552 namespace vigra { 00553 template <class SrcIter, class SrcAcc, 00554 class DestIter, class DestAcc, 00555 class Kernel> 00556 void 00557 resamplingConvolveY(triple<SrcIter, SrcIter, SrcAcc> src, 00558 triple<DestIter, DestIter, DestAcc> dest, 00559 Kernel const & kernel, 00560 Rational<int> const & samplingRatio, Rational<int> const & offset); 00561 } 00562 \endcode 00563 00564 <b> Usage:</b> 00565 00566 <b>\#include</b> <<a href="resampling__convolution_8hxx-source.html">vigra/resampling_convolution.hxx</a>> 00567 00568 00569 \code 00570 Rational<int> ratio(2), offset(0); 00571 00572 FImage src(w,h), 00573 dest(w, rational_cast<int>(ratio*h)); 00574 00575 float sigma = 2.0; 00576 Gaussian<float> smooth(sigma); 00577 ... 00578 00579 // simpultaneously enlarge and smooth source image 00580 resamplingConvolveY(srcImageRange(src), destImageRange(dest), 00581 smooth, ratio, offset); 00582 \endcode 00583 00584 <b> Required Interface:</b> 00585 00586 \code 00587 Kernel kernel; 00588 int kernelRadius = kernel.radius(); 00589 double y = ...; // must be <= radius() 00590 double value = kernel(y); 00591 \endcode 00592 */ 00593 doxygen_overloaded_function(template <...> void resamplingConvolveY) 00594 00595 template <class SrcIter, class SrcAcc, 00596 class DestIter, class DestAcc, 00597 class Kernel> 00598 void 00599 resamplingConvolveY(SrcIter sul, SrcIter slr, SrcAcc src, 00600 DestIter dul, DestIter dlr, DestAcc dest, 00601 Kernel const & kernel, 00602 Rational<int> const & samplingRatio, Rational<int> const & offset) 00603 { 00604 int hold = slr.y - sul.y; 00605 int hnew = dlr.y - dul.y; 00606 00607 vigra_precondition(!samplingRatio.is_inf() && samplingRatio > 0, 00608 "resamplingConvolveY(): sampling ratio must be > 0 and < infinity"); 00609 vigra_precondition(!offset.is_inf(), 00610 "resamplingConvolveY(): offset must be < infinity"); 00611 00612 int period = lcm(samplingRatio.numerator(), samplingRatio.denominator()); 00613 00614 resampling_detail::MapTargetToSourceCoordinate mapCoordinate(samplingRatio, offset); 00615 00616 ArrayVector<Kernel1D<double> > kernels(period); 00617 00618 createResamplingKernels(kernel, mapCoordinate, kernels); 00619 00620 for(; sul.x < slr.x; ++sul.x, ++dul.x) 00621 { 00622 typename SrcIter::column_iterator sc = sul.columnIterator(); 00623 typename DestIter::column_iterator dc = dul.columnIterator(); 00624 resamplingConvolveLine(sc, sc+hold, src, dc, dc+hnew, dest, 00625 kernels, mapCoordinate); 00626 } 00627 } 00628 00629 template <class SrcIter, class SrcAcc, 00630 class DestIter, class DestAcc, 00631 class Kernel> 00632 inline void 00633 resamplingConvolveY(triple<SrcIter, SrcIter, SrcAcc> src, 00634 triple<DestIter, DestIter, DestAcc> dest, 00635 Kernel const & kernel, 00636 Rational<int> const & samplingRatio, Rational<int> const & offset) 00637 { 00638 resamplingConvolveY(src.first, src.second, src.third, 00639 dest.first, dest.second, dest.third, 00640 kernel, samplingRatio, offset); 00641 } 00642 00643 /********************************************************/ 00644 /* */ 00645 /* resamplingConvolveImage */ 00646 /* */ 00647 /********************************************************/ 00648 00649 /** \brief Apply two separable resampling filters successively, the first in x-direction, 00650 the second in y-direction. 00651 00652 This function is a shorthand for the concatenation of a call to 00653 \ref resamplingConvolveX() and \ref resamplingConvolveY() 00654 with the given kernels. See there for detailed documentation. 00655 00656 <b> Declarations:</b> 00657 00658 pass arguments explicitly: 00659 \code 00660 namespace vigra { 00661 template <class SrcIterator, class SrcAccessor, 00662 class DestIterator, class DestAccessor, 00663 class KernelX, class KernelY> 00664 void resamplingConvolveImage(SrcIterator sul,SrcIterator slr, SrcAccessor src, 00665 DestIterator dul, DestIterator dlr, DestAccessor dest, 00666 KernelX const & kx, 00667 Rational<int> const & samplingRatioX, Rational<int> const & offsetX, 00668 KernelY const & ky, 00669 Rational<int> const & samplingRatioY, Rational<int> const & offsetY); 00670 } 00671 \endcode 00672 00673 00674 use argument objects in conjunction with \ref ArgumentObjectFactories : 00675 \code 00676 namespace vigra { 00677 template <class SrcIterator, class SrcAccessor, 00678 class DestIterator, class DestAccessor, 00679 class KernelX, class KernelY> 00680 void 00681 resamplingConvolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> src, 00682 triple<DestIterator, DestIterator, DestAccessor> dest, 00683 KernelX const & kx, 00684 Rational<int> const & samplingRatioX, Rational<int> const & offsetX, 00685 KernelY const & ky, 00686 Rational<int> const & samplingRatioY, Rational<int> const & offsetY); 00687 } 00688 \endcode 00689 00690 <b> Usage:</b> 00691 00692 <b>\#include</b> <<a href="resampling__convolution_8hxx-source.html">vigra/resampling_convolution.hxx</a>> 00693 00694 00695 \code 00696 Rational<int> xratio(2), yratio(3), offset(0); 00697 00698 FImage src(w,h), 00699 dest(rational_cast<int>(xratio*w), rational_cast<int>(yratio*h)); 00700 00701 float sigma = 2.0; 00702 Gaussian<float> smooth(sigma); 00703 ... 00704 00705 // simpultaneously enlarge and smooth source image 00706 resamplingConvolveImage(srcImageRange(src), destImageRange(dest), 00707 smooth, xratio, offset, 00708 smooth, yratio, offset); 00709 00710 \endcode 00711 00712 */ 00713 doxygen_overloaded_function(template <...> void resamplingConvolveImage) 00714 00715 template <class SrcIterator, class SrcAccessor, 00716 class DestIterator, class DestAccessor, 00717 class KernelX, class KernelY> 00718 void resamplingConvolveImage(SrcIterator sul,SrcIterator slr, SrcAccessor src, 00719 DestIterator dul, DestIterator dlr, DestAccessor dest, 00720 KernelX const & kx, 00721 Rational<int> const & samplingRatioX, Rational<int> const & offsetX, 00722 KernelY const & ky, 00723 Rational<int> const & samplingRatioY, Rational<int> const & offsetY) 00724 { 00725 typedef typename 00726 NumericTraits<typename SrcAccessor::value_type>::RealPromote 00727 TmpType; 00728 00729 BasicImage<TmpType> tmp(dlr.x - dul.x, slr.y - sul.y); 00730 00731 resamplingConvolveX(srcIterRange(sul, slr, src), 00732 destImageRange(tmp), 00733 kx, samplingRatioX, offsetX); 00734 resamplingConvolveY(srcImageRange(tmp), 00735 destIterRange(dul, dlr, dest), 00736 ky, samplingRatioY, offsetY); 00737 } 00738 00739 template <class SrcIterator, class SrcAccessor, 00740 class DestIterator, class DestAccessor, 00741 class KernelX, class KernelY> 00742 inline void 00743 resamplingConvolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> src, 00744 triple<DestIterator, DestIterator, DestAccessor> dest, 00745 KernelX const & kx, 00746 Rational<int> const & samplingRatioX, Rational<int> const & offsetX, 00747 KernelY const & ky, 00748 Rational<int> const & samplingRatioY, Rational<int> const & offsetY) 00749 { 00750 resamplingConvolveImage(src.first, src.second, src.third, 00751 dest.first, dest.second, dest.third, 00752 kx, samplingRatioX, offsetX, 00753 ky, samplingRatioY, offsetY); 00754 } 00755 00756 /** \brief Two-fold down-sampling for image pyramid construction. 00757 00758 Sorry, no \ref detailedDocumentation() available yet. 00759 00760 <b> Declarations:</b> 00761 00762 <b>\#include</b> <<a href="resampling__convolution_8hxx-source.html">vigra/resampling_convolution.hxx</a>><br> 00763 Namespace: vigra 00764 00765 pass arguments explicitly: 00766 \code 00767 namespace vigra { 00768 template <class SrcIterator, class SrcAccessor, 00769 class DestIterator, class DestAccessor> 00770 void pyramidReduceBurtFilter(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00771 DestIterator dul, DestIterator dlr, DestAccessor dest, 00772 double centerValue = 0.4); 00773 } 00774 \endcode 00775 00776 use argument objects in conjunction with \ref ArgumentObjectFactories : 00777 \code 00778 namespace vigra { 00779 template <class SrcIterator, class SrcAccessor, 00780 class DestIterator, class DestAccessor> 00781 void pyramidReduceBurtFilter(triple<SrcIterator, SrcIterator, SrcAccessor> src, 00782 triple<DestIterator, DestIterator, DestAccessor> dest, 00783 double centerValue = 0.4); 00784 } 00785 \endcode 00786 00787 use a \ref vigra::ImagePyramid : 00788 \code 00789 namespace vigra { 00790 template <class Image, class Alloc> 00791 void pyramidReduceBurtFilter(ImagePyramid<Image, Alloc> & pyramid, int fromLevel, int toLevel, 00792 double centerValue = 0.4); 00793 } 00794 \endcode 00795 */ 00796 doxygen_overloaded_function(template <...> void pyramidReduceBurtFilter) 00797 00798 template <class SrcIterator, class SrcAccessor, 00799 class DestIterator, class DestAccessor> 00800 void pyramidReduceBurtFilter(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00801 DestIterator dul, DestIterator dlr, DestAccessor dest, 00802 double centerValue = 0.4) 00803 { 00804 vigra_precondition(0.25 <= centerValue && centerValue <= 0.5, 00805 "pyramidReduceBurtFilter(): centerValue must be between 0.25 and 0.5."); 00806 00807 int wold = slr.x - sul.x; 00808 int wnew = dlr.x - dul.x; 00809 int hold = slr.y - sul.y; 00810 int hnew = dlr.y - dul.y; 00811 00812 Rational<int> samplingRatio(1,2), offset(0); 00813 resampling_detail::MapTargetToSourceCoordinate mapCoordinate(samplingRatio, offset); 00814 00815 ArrayVector<Kernel1D<double> > kernels(1); 00816 kernels[0].initExplicitly(-2, 2) = 0.25 - centerValue / 2.0, 0.25, centerValue, 0.25, 0.25 - centerValue / 2.0; 00817 00818 typedef typename 00819 NumericTraits<typename SrcAccessor::value_type>::RealPromote 00820 TmpType; 00821 typedef BasicImage<TmpType> TmpImage; 00822 typedef typename TmpImage::traverser TmpIterator; 00823 00824 BasicImage<TmpType> tmp(wnew, hold); 00825 00826 TmpIterator tul = tmp.upperLeft(); 00827 00828 for(; sul.y < slr.y; ++sul.y, ++tul.y) 00829 { 00830 typename SrcIterator::row_iterator sr = sul.rowIterator(); 00831 typename TmpIterator::row_iterator tr = tul.rowIterator(); 00832 // FIXME: replace with reduceLineBurtFilter() 00833 resamplingConvolveLine(sr, sr+wold, src, tr, tr+wnew, tmp.accessor(), 00834 kernels, mapCoordinate); 00835 } 00836 00837 tul = tmp.upperLeft(); 00838 00839 for(; dul.x < dlr.x; ++dul.x, ++tul.x) 00840 { 00841 typename DestIterator::column_iterator dc = dul.columnIterator(); 00842 typename TmpIterator::column_iterator tc = tul.columnIterator(); 00843 resamplingConvolveLine(tc, tc+hold, tmp.accessor(), dc, dc+hnew, dest, 00844 kernels, mapCoordinate); 00845 } 00846 } 00847 00848 template <class SrcIterator, class SrcAccessor, 00849 class DestIterator, class DestAccessor> 00850 inline 00851 void pyramidReduceBurtFilter(triple<SrcIterator, SrcIterator, SrcAccessor> src, 00852 triple<DestIterator, DestIterator, DestAccessor> dest, 00853 double centerValue = 0.4) 00854 { 00855 pyramidReduceBurtFilter(src.first, src.second, src.third, 00856 dest.first, dest.second, dest.third, centerValue); 00857 } 00858 00859 template <class Image, class Alloc> 00860 inline 00861 void pyramidReduceBurtFilter(ImagePyramid<Image, Alloc> & pyramid, int fromLevel, int toLevel, 00862 double centerValue = 0.4) 00863 { 00864 vigra_precondition(fromLevel < toLevel, 00865 "pyramidReduceBurtFilter(): fromLevel must be smaller than toLevel."); 00866 vigra_precondition(pyramid.lowestLevel() <= fromLevel && toLevel <= pyramid.highestLevel(), 00867 "pyramidReduceBurtFilter(): fromLevel and toLevel must be between the lowest and highest pyramid levels (inclusive)."); 00868 00869 for(int i=fromLevel+1; i <= toLevel; ++i) 00870 pyramidReduceBurtFilter(srcImageRange(pyramid[i-1]), destImageRange(pyramid[i]), centerValue); 00871 } 00872 00873 /** \brief Two-fold up-sampling for image pyramid reconstruction. 00874 00875 Sorry, no \ref detailedDocumentation() available yet. 00876 00877 <b> Declarations:</b> 00878 00879 <b>\#include</b> <<a href="resampling__convolution_8hxx-source.html">vigra/resampling_convolution.hxx</a>><br> 00880 Namespace: vigra 00881 00882 pass arguments explicitly: 00883 \code 00884 namespace vigra { 00885 template <class SrcIterator, class SrcAccessor, 00886 class DestIterator, class DestAccessor> 00887 void pyramidExpandBurtFilter(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00888 DestIterator dul, DestIterator dlr, DestAccessor dest, 00889 double centerValue = 0.4); 00890 } 00891 \endcode 00892 00893 00894 use argument objects in conjunction with \ref ArgumentObjectFactories : 00895 \code 00896 namespace vigra { 00897 template <class SrcIterator, class SrcAccessor, 00898 class DestIterator, class DestAccessor> 00899 void pyramidExpandBurtFilter(triple<SrcIterator, SrcIterator, SrcAccessor> src, 00900 triple<DestIterator, DestIterator, DestAccessor> dest, 00901 double centerValue = 0.4); 00902 } 00903 \endcode 00904 00905 use a \ref vigra::ImagePyramid : 00906 \code 00907 namespace vigra { 00908 template <class Image, class Alloc> 00909 void pyramidExpandBurtFilter(ImagePyramid<Image, Alloc> & pyramid, int fromLevel, int toLevel, 00910 double centerValue = 0.4); 00911 } 00912 \endcode 00913 */ 00914 doxygen_overloaded_function(template <...> void pyramidExpandBurtFilter) 00915 00916 template <class SrcIterator, class SrcAccessor, 00917 class DestIterator, class DestAccessor> 00918 void pyramidExpandBurtFilter(SrcIterator sul, SrcIterator slr, SrcAccessor src, 00919 DestIterator dul, DestIterator dlr, DestAccessor dest, 00920 double centerValue = 0.4) 00921 { 00922 vigra_precondition(0.25 <= centerValue && centerValue <= 0.5, 00923 "pyramidExpandBurtFilter(): centerValue must be between 0.25 and 0.5."); 00924 00925 int wold = slr.x - sul.x; 00926 int wnew = dlr.x - dul.x; 00927 int hold = slr.y - sul.y; 00928 int hnew = dlr.y - dul.y; 00929 00930 Rational<int> samplingRatio(2), offset(0); 00931 resampling_detail::MapTargetToSourceCoordinate mapCoordinate(samplingRatio, offset); 00932 00933 ArrayVector<Kernel1D<double> > kernels(2); 00934 kernels[0].initExplicitly(-1, 1) = 0.5 - centerValue, 2.0*centerValue, 0.5 - centerValue; 00935 kernels[1].initExplicitly(-1, 0) = 0.5, 0.5; 00936 00937 typedef typename 00938 NumericTraits<typename SrcAccessor::value_type>::RealPromote 00939 TmpType; 00940 typedef BasicImage<TmpType> TmpImage; 00941 typedef typename TmpImage::traverser TmpIterator; 00942 00943 BasicImage<TmpType> tmp(wnew, hold); 00944 00945 TmpIterator tul = tmp.upperLeft(); 00946 00947 for(; sul.y < slr.y; ++sul.y, ++tul.y) 00948 { 00949 typename SrcIterator::row_iterator sr = sul.rowIterator(); 00950 typename TmpIterator::row_iterator tr = tul.rowIterator(); 00951 // FIXME: replace with expandLineBurtFilter() 00952 resamplingConvolveLine(sr, sr+wold, src, tr, tr+wnew, tmp.accessor(), 00953 kernels, mapCoordinate); 00954 } 00955 00956 tul = tmp.upperLeft(); 00957 00958 for(; dul.x < dlr.x; ++dul.x, ++tul.x) 00959 { 00960 typename DestIterator::column_iterator dc = dul.columnIterator(); 00961 typename TmpIterator::column_iterator tc = tul.columnIterator(); 00962 resamplingConvolveLine(tc, tc+hold, tmp.accessor(), dc, dc+hnew, dest, 00963 kernels, mapCoordinate); 00964 } 00965 } 00966 00967 template <class SrcIterator, class SrcAccessor, 00968 class DestIterator, class DestAccessor> 00969 inline 00970 void pyramidExpandBurtFilter(triple<SrcIterator, SrcIterator, SrcAccessor> src, 00971 triple<DestIterator, DestIterator, DestAccessor> dest, 00972 double centerValue = 0.4) 00973 { 00974 pyramidExpandBurtFilter(src.first, src.second, src.third, 00975 dest.first, dest.second, dest.third, centerValue); 00976 } 00977 00978 00979 template <class Image, class Alloc> 00980 inline 00981 void pyramidExpandBurtFilter(ImagePyramid<Image, Alloc> & pyramid, int fromLevel, int toLevel, 00982 double centerValue = 0.4) 00983 { 00984 vigra_precondition(fromLevel > toLevel, 00985 "pyramidExpandBurtFilter(): fromLevel must be larger than toLevel."); 00986 vigra_precondition(pyramid.lowestLevel() <= toLevel && fromLevel <= pyramid.highestLevel(), 00987 "pyramidExpandBurtFilter(): fromLevel and toLevel must be between the lowest and highest pyramid levels (inclusive)."); 00988 00989 for(int i=fromLevel-1; i >= toLevel; --i) 00990 pyramidExpandBurtFilter(srcImageRange(pyramid[i+1]), destImageRange(pyramid[i]), centerValue); 00991 } 00992 00993 /** \brief Create a Laplacian pyramid. 00994 00995 Sorry, no \ref detailedDocumentation() available yet. 00996 00997 <b>\#include</b> <<a href="resampling__convolution_8hxx-source.html">vigra/resampling_convolution.hxx</a>><br> 00998 Namespace: vigra 00999 */ 01000 template <class Image, class Alloc> 01001 inline 01002 void pyramidReduceBurtLaplacian(ImagePyramid<Image, Alloc> & pyramid, int fromLevel, int toLevel, 01003 double centerValue = 0.4) 01004 { 01005 using namespace functor; 01006 01007 pyramidReduceBurtFilter(pyramid, fromLevel, toLevel, centerValue); 01008 for(int i=fromLevel; i < toLevel; ++i) 01009 { 01010 typename ImagePyramid<Image, Alloc>::value_type tmpImage(pyramid[i].size()); 01011 pyramidExpandBurtFilter(srcImageRange(pyramid[i+1]), destImageRange(tmpImage), centerValue); 01012 combineTwoImages(srcImageRange(tmpImage), srcImage(pyramid[i]), destImage(pyramid[i]), 01013 Arg1() - Arg2()); 01014 } 01015 } 01016 01017 /** \brief Reconstruct a Laplacian pyramid. 01018 01019 Sorry, no \ref detailedDocumentation() available yet. 01020 01021 <b>\#include</b> <<a href="resampling__convolution_8hxx-source.html">vigra/resampling_convolution.hxx</a>><br> 01022 Namespace: vigra 01023 */ 01024 template <class Image, class Alloc> 01025 inline 01026 void pyramidExpandBurtLaplacian(ImagePyramid<Image, Alloc> & pyramid, int fromLevel, int toLevel, 01027 double centerValue = 0.4) 01028 { 01029 using namespace functor; 01030 01031 vigra_precondition(fromLevel > toLevel, 01032 "pyramidExpandBurtLaplacian(): fromLevel must be larger than toLevel."); 01033 vigra_precondition(pyramid.lowestLevel() <= toLevel && fromLevel <= pyramid.highestLevel(), 01034 "pyramidExpandBurtLaplacian(): fromLevel and toLevel must be between the lowest and highest pyramid levels (inclusive)."); 01035 01036 for(int i=fromLevel-1; i >= toLevel; --i) 01037 { 01038 typename ImagePyramid<Image, Alloc>::value_type tmpImage(pyramid[i].size()); 01039 pyramidExpandBurtFilter(srcImageRange(pyramid[i+1]), destImageRange(tmpImage), centerValue); 01040 combineTwoImages(srcImageRange(tmpImage), srcImage(pyramid[i]), destImage(pyramid[i]), 01041 Arg1() - Arg2()); 01042 } 01043 } 01044 01045 //@} 01046 01047 } // namespace vigra 01048 01049 01050 #endif /* VIGRA_RESAMPLING_CONVOLUTION_HXX */
© Ullrich Köthe (ullrich.koethe@iwr.uni-heidelberg.de) |
html generated using doxygen and Python
|