[ VIGRA Homepage | Class Index | Function Index | File Index | Main Page ]
![]() |
vigra/resampling_convolution.hxx | ![]() |
---|
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.5.0, Dec 07 2006 ) */ 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 /* koethe@informatik.uni-hamburg.de or */ 00012 /* vigra@kogs1.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 00047 namespace vigra { 00048 00049 namespace resampling_detail 00050 { 00051 00052 struct MapTargetToSourceCoordinate 00053 { 00054 MapTargetToSourceCoordinate(Rational<int> const & samplingRatio, 00055 Rational<int> const & offset) 00056 : a(samplingRatio.denominator()*offset.denominator()), 00057 b(samplingRatio.numerator()*offset.numerator()), 00058 c(samplingRatio.numerator()*offset.denominator()) 00059 {} 00060 00061 // the following funcions are more efficient realizations of: 00062 // rational_cast<T>(i / samplingRatio + offset); 00063 // we need efficiency because this may be called in the inner loop 00064 00065 int operator()(int i) const 00066 { 00067 return (i * a + b) / c; 00068 } 00069 00070 double toDouble(int i) const 00071 { 00072 return double(i * a + b) / c; 00073 } 00074 00075 Rational<int> toRational(int i) const 00076 { 00077 return Rational<int>(i * a + b, c); 00078 } 00079 00080 int a, b, c; 00081 }; 00082 00083 } // namespace resampling_detail 00084 00085 template <> 00086 class FunctorTraits<resampling_detail::MapTargetToSourceCoordinate> 00087 : public FunctorTraitsBase<resampling_detail::MapTargetToSourceCoordinate> 00088 { 00089 public: 00090 typedef VigraTrueType isUnaryFunctor; 00091 }; 00092 00093 template <class SrcIter, class SrcAcc, 00094 class DestIter, class DestAcc, 00095 class KernelArray, 00096 class Functor> 00097 void 00098 resamplingConvolveLine(SrcIter s, SrcIter send, SrcAcc src, 00099 DestIter d, DestIter dend, DestAcc dest, 00100 KernelArray const & kernels, 00101 Functor mapTargetToSourceCoordinate) 00102 { 00103 typedef typename 00104 NumericTraits<typename SrcAcc::value_type>::RealPromote 00105 TmpType; 00106 typedef typename KernelArray::value_type Kernel; 00107 typedef typename Kernel::const_iterator KernelIter; 00108 00109 int wo = send - s; 00110 int wn = dend - d; 00111 int wo2 = 2*wo - 2; 00112 00113 int i; 00114 typename KernelArray::const_iterator kernel = kernels.begin(); 00115 for(i=0; i<wn; ++i, ++d, ++kernel) 00116 { 00117 // use the kernels periodically 00118 if(kernel == kernels.end()) 00119 kernel = kernels.begin(); 00120 00121 // calculate current target point into source location 00122 int is = mapTargetToSourceCoordinate(i); 00123 00124 TmpType sum = NumericTraits<TmpType>::zero(); 00125 00126 int lbound = is - kernel->right(), 00127 hbound = is - kernel->left(); 00128 00129 KernelIter k = kernel->center() + kernel->right(); 00130 if(lbound < 0 || hbound >= wo) 00131 { 00132 vigra_precondition(-lbound < wo && wo2 - hbound >= 0, 00133 "resamplingConvolveLine(): kernel or offset larger than image."); 00134 for(int m=lbound; m <= hbound; ++m, --k) 00135 { 00136 int mm = (m < 0) ? 00137 -m : 00138 (m >= wo) ? 00139 wo2 - m : 00140 m; 00141 sum += *k * src(s, mm); 00142 } 00143 } 00144 else 00145 { 00146 SrcIter ss = s + lbound; 00147 SrcIter ssend = s + hbound; 00148 00149 for(; ss <= ssend; ++ss, --k) 00150 { 00151 sum += *k * src(ss); 00152 } 00153 } 00154 00155 dest.set(sum, d); 00156 } 00157 } 00158 00159 template <class Kernel, class MapCoordinate, class KernelArray> 00160 void 00161 createResamplingKernels(Kernel const & kernel, 00162 MapCoordinate const & mapCoordinate, KernelArray & kernels) 00163 { 00164 for(unsigned int idest = 0; idest < kernels.size(); ++idest) 00165 { 00166 int isrc = mapCoordinate(idest); 00167 double idsrc = mapCoordinate.toDouble(idest); 00168 double offset = idsrc - isrc; 00169 double radius = kernel.radius(); 00170 int left = int(ceil(-radius - offset)); 00171 int right = int(floor(radius - offset)); 00172 kernels[idest].initExplicitly(left, right); 00173 00174 double x = left + offset; 00175 for(int i = left; i <= right; ++i, ++x) 00176 kernels[idest][i] = kernel(x); 00177 kernels[idest].normalize(1.0, kernel.derivativeOrder(), offset); 00178 } 00179 } 00180 00181 /** \addtogroup ResamplingConvolutionFilters Resampling Convolution Filters 00182 00183 These functions implement the convolution operation when the source and target images 00184 have different sizes. This is realized by accessing a continous kernel at the 00185 appropriate non-integer positions. The technique is, for example, described in 00186 D. Schumacher: <i>General Filtered Image Rescaling</i>, in: Graphics Gems III, 00187 Academic Press, 1992. 00188 */ 00189 //@{ 00190 00191 /********************************************************/ 00192 /* */ 00193 /* resamplingConvolveX */ 00194 /* */ 00195 /********************************************************/ 00196 00197 /** \brief Apply a resampling filter in the x-direction. 00198 00199 This function implements a convolution operation in x-direction 00200 (i.e. applies a 1D filter to every row) where the width of the source 00201 and destination images differ. This is typically used to avoid aliasing if 00202 the image is scaled down, or to interpolate smoothly if the image is scaled up. 00203 The target coordinates are transformed into source coordinates by 00204 00205 \code 00206 xsource = (xtarget - offset) / samplingRatio 00207 \endcode 00208 00209 The <tt>samplingRatio</tt> and <tt>offset</tt> must be given as \ref vigra::Rational 00210 in order to avoid rounding errors in this transformation. It is required that for all 00211 pixels of the target image, <tt>xsource</tt> remains within the range of the source 00212 image (i.e. <tt>0 <= xsource <= sourceWidth-1</tt>. Since <tt>xsource</tt> is 00213 in general not an integer, the <tt>kernel</tt> must be a functor that can be accessed at 00214 arbitrary (<tt>double</tt>) coordinates. It must also provide a member function <tt>radius()</tt> 00215 which specifies the support (non-zero interval) of the kernel. VIGRA already 00216 provides a number of suitable functors, e.g. \ref vigra::Gaussian, \ref vigra::BSpline 00217 \ref vigra::CatmullRomSpline, and \ref vigra::CoscotFunction. The function 00218 \ref resizeImageSplineInterpolation() is implemented by means resamplingConvolveX() and 00219 resamplingConvolveY(). 00220 00221 <b> Declarations:</b> 00222 00223 pass arguments explicitly: 00224 \code 00225 namespace vigra { 00226 template <class SrcIter, class SrcAcc, 00227 class DestIter, class DestAcc, 00228 class Kernel> 00229 void 00230 resamplingConvolveX(SrcIter sul, SrcIter slr, SrcAcc src, 00231 DestIter dul, DestIter dlr, DestAcc dest, 00232 Kernel const & kernel, 00233 Rational<int> const & samplingRatio, Rational<int> const & offset); 00234 } 00235 \endcode 00236 00237 00238 use argument objects in conjunction with \ref ArgumentObjectFactories: 00239 \code 00240 namespace vigra { 00241 template <class SrcIter, class SrcAcc, 00242 class DestIter, class DestAcc, 00243 class Kernel> 00244 void 00245 resamplingConvolveX(triple<SrcIter, SrcIter, SrcAcc> src, 00246 triple<DestIter, DestIter, DestAcc> dest, 00247 Kernel const & kernel, 00248 Rational<int> const & samplingRatio, Rational<int> const & offset); 00249 } 00250 \endcode 00251 00252 <b> Usage:</b> 00253 00254 <b>\#include</b> "<a href="resampling__convolution_8hxx-source.html">vigra/resampling_convolution.hxx</a>" 00255 00256 00257 \code 00258 Rational<int> ratio(2), offset(0); 00259 00260 FImage src(w,h), 00261 dest(rational_cast<int>(ratio*w), h); 00262 00263 float sigma = 2.0; 00264 Gaussian<float> smooth(sigma); 00265 ... 00266 00267 // simpultaneously enlarge and smooth source image 00268 resamplingConvolveX(srcImageRange(src), destImageRange(dest), 00269 smooth, ratio, offset); 00270 \endcode 00271 00272 <b> Required Interface:</b> 00273 00274 \code 00275 Kernel kernel; 00276 int kernelRadius = kernel.radius(); 00277 double x = ...; // must be <= radius() 00278 double value = kernel(x); 00279 \endcode 00280 */ 00281 template <class SrcIter, class SrcAcc, 00282 class DestIter, class DestAcc, 00283 class Kernel> 00284 void 00285 resamplingConvolveX(SrcIter sul, SrcIter slr, SrcAcc src, 00286 DestIter dul, DestIter dlr, DestAcc dest, 00287 Kernel const & kernel, 00288 Rational<int> const & samplingRatio, Rational<int> const & offset) 00289 { 00290 int wold = slr.x - sul.x; 00291 int wnew = dlr.x - dul.x; 00292 00293 vigra_precondition(!samplingRatio.is_inf() && samplingRatio > 0, 00294 "resamplingConvolveX(): sampling ratio must be > 0 and < infinity"); 00295 vigra_precondition(!offset.is_inf(), 00296 "resamplingConvolveX(): offset must be < infinity"); 00297 00298 int period = lcm(samplingRatio.numerator(), samplingRatio.denominator()); 00299 resampling_detail::MapTargetToSourceCoordinate mapCoordinate(samplingRatio, offset); 00300 00301 ArrayVector<Kernel1D<double> > kernels(period); 00302 00303 createResamplingKernels(kernel, mapCoordinate, kernels); 00304 00305 for(; sul.y < slr.y; ++sul.y, ++dul.y) 00306 { 00307 typename SrcIter::row_iterator sr = sul.rowIterator(); 00308 typename DestIter::row_iterator dr = dul.rowIterator(); 00309 resamplingConvolveLine(sr, sr+wold, src, dr, dr+wnew, dest, 00310 kernels, mapCoordinate); 00311 } 00312 } 00313 00314 template <class SrcIter, class SrcAcc, 00315 class DestIter, class DestAcc, 00316 class Kernel> 00317 inline void 00318 resamplingConvolveX(triple<SrcIter, SrcIter, SrcAcc> src, 00319 triple<DestIter, DestIter, DestAcc> dest, 00320 Kernel const & kernel, 00321 Rational<int> const & samplingRatio, Rational<int> const & offset) 00322 { 00323 resamplingConvolveX(src.first, src.second, src.third, 00324 dest.first, dest.second, dest.third, 00325 kernel, samplingRatio, offset); 00326 } 00327 00328 /********************************************************/ 00329 /* */ 00330 /* resamplingConvolveY */ 00331 /* */ 00332 /********************************************************/ 00333 00334 /** \brief Apply a resampling filter in the y-direction. 00335 00336 This function implements a convolution operation in y-direction 00337 (i.e. applies a 1D filter to every column) where the height of the source 00338 and destination images differ. This is typically used to avoid aliasing if 00339 the image is scaled down, or to interpolate smoothly if the image is scaled up. 00340 The target coordinates are transformed into source coordinates by 00341 00342 \code 00343 ysource = (ytarget - offset) / samplingRatio 00344 \endcode 00345 00346 The <tt>samplingRatio</tt> and <tt>offset</tt> must be given as \ref vigra::Rational 00347 in order to avoid rounding errors in this transformation. It is required that for all 00348 pixels of the target image, <tt>ysource</tt> remains within the range of the source 00349 image (i.e. <tt>0 <= ysource <= sourceHeight-1</tt>. Since <tt>ysource</tt> is 00350 in general not an integer, the <tt>kernel</tt> must be a functor that can be accessed at 00351 arbitrary (<tt>double</tt>) coordinates. It must also provide a member function <tt>radius()</tt> 00352 which specifies the support (non-zero interval) of the kernel. VIGRA already 00353 provides a number of suitable functors, e.g. \ref vigra::Gaussian, \ref vigra::BSpline 00354 \ref vigra::CatmullRomSpline, and \ref vigra::CoscotFunction. The function 00355 \ref resizeImageSplineInterpolation() is implemented by means resamplingConvolveX() and 00356 resamplingConvolveY(). 00357 00358 <b> Declarations:</b> 00359 00360 pass arguments explicitly: 00361 \code 00362 namespace vigra { 00363 template <class SrcIter, class SrcAcc, 00364 class DestIter, class DestAcc, 00365 class Kernel> 00366 void 00367 resamplingConvolveY(SrcIter sul, SrcIter slr, SrcAcc src, 00368 DestIter dul, DestIter dlr, DestAcc dest, 00369 Kernel const & kernel, 00370 Rational<int> const & samplingRatio, Rational<int> const & offset); 00371 } 00372 \endcode 00373 00374 00375 use argument objects in conjunction with \ref ArgumentObjectFactories: 00376 \code 00377 namespace vigra { 00378 template <class SrcIter, class SrcAcc, 00379 class DestIter, class DestAcc, 00380 class Kernel> 00381 void 00382 resamplingConvolveY(triple<SrcIter, SrcIter, SrcAcc> src, 00383 triple<DestIter, DestIter, DestAcc> dest, 00384 Kernel const & kernel, 00385 Rational<int> const & samplingRatio, Rational<int> const & offset); 00386 } 00387 \endcode 00388 00389 <b> Usage:</b> 00390 00391 <b>\#include</b> "<a href="resampling__convolution_8hxx-source.html">vigra/resampling_convolution.hxx</a>" 00392 00393 00394 \code 00395 Rational<int> ratio(2), offset(0); 00396 00397 FImage src(w,h), 00398 dest(w, rational_cast<int>(ratio*h)); 00399 00400 float sigma = 2.0; 00401 Gaussian<float> smooth(sigma); 00402 ... 00403 00404 // simpultaneously enlarge and smooth source image 00405 resamplingConvolveY(srcImageRange(src), destImageRange(dest), 00406 smooth, ratio, offset); 00407 \endcode 00408 00409 <b> Required Interface:</b> 00410 00411 \code 00412 Kernel kernel; 00413 int kernelRadius = kernel.radius(); 00414 double y = ...; // must be <= radius() 00415 double value = kernel(y); 00416 \endcode 00417 */ 00418 template <class SrcIter, class SrcAcc, 00419 class DestIter, class DestAcc, 00420 class Kernel> 00421 void 00422 resamplingConvolveY(SrcIter sul, SrcIter slr, SrcAcc src, 00423 DestIter dul, DestIter dlr, DestAcc dest, 00424 Kernel const & kernel, 00425 Rational<int> const & samplingRatio, Rational<int> const & offset) 00426 { 00427 int hold = slr.y - sul.y; 00428 int hnew = dlr.y - dul.y; 00429 00430 vigra_precondition(!samplingRatio.is_inf() && samplingRatio > 0, 00431 "resamplingConvolveY(): sampling ratio must be > 0 and < infinity"); 00432 vigra_precondition(!offset.is_inf(), 00433 "resamplingConvolveY(): offset must be < infinity"); 00434 00435 int period = lcm(samplingRatio.numerator(), samplingRatio.denominator()); 00436 00437 resampling_detail::MapTargetToSourceCoordinate mapCoordinate(samplingRatio, offset); 00438 00439 ArrayVector<Kernel1D<double> > kernels(period); 00440 00441 createResamplingKernels(kernel, mapCoordinate, kernels); 00442 00443 for(; sul.x < slr.x; ++sul.x, ++dul.x) 00444 { 00445 typename SrcIter::column_iterator sc = sul.columnIterator(); 00446 typename DestIter::column_iterator dc = dul.columnIterator(); 00447 resamplingConvolveLine(sc, sc+hold, src, dc, dc+hnew, dest, 00448 kernels, mapCoordinate); 00449 } 00450 } 00451 00452 template <class SrcIter, class SrcAcc, 00453 class DestIter, class DestAcc, 00454 class Kernel> 00455 inline void 00456 resamplingConvolveY(triple<SrcIter, SrcIter, SrcAcc> src, 00457 triple<DestIter, DestIter, DestAcc> dest, 00458 Kernel const & kernel, 00459 Rational<int> const & samplingRatio, Rational<int> const & offset) 00460 { 00461 resamplingConvolveY(src.first, src.second, src.third, 00462 dest.first, dest.second, dest.third, 00463 kernel, samplingRatio, offset); 00464 } 00465 00466 /********************************************************/ 00467 /* */ 00468 /* resamplingConvolveImage */ 00469 /* */ 00470 /********************************************************/ 00471 00472 /** \brief Apply two separable resampling filters successively, the first in x-direction, 00473 the second in y-direction. 00474 00475 This function is a shorthand for the concatenation of a call to 00476 \link ResamplingConvolutionFilters#resamplingConvolveX resamplingConvolveX\endlink() 00477 and \link ResamplingConvolutionFilters#resamplingConvolveY resamplingConvolveY\endlink() 00478 with the given kernels. See there for detailed documentation. 00479 00480 <b> Declarations:</b> 00481 00482 pass arguments explicitly: 00483 \code 00484 namespace vigra { 00485 template <class SrcIterator, class SrcAccessor, 00486 class DestIterator, class DestAccessor, 00487 class KernelX, class KernelY> 00488 void resamplingConvolveImage(SrcIterator sul,SrcIterator slr, SrcAccessor src, 00489 DestIterator dul, DestIterator dlr, DestAccessor dest, 00490 KernelX const & kx, 00491 Rational<int> const & samplingRatioX, Rational<int> const & offsetX, 00492 KernelY const & ky, 00493 Rational<int> const & samplingRatioY, Rational<int> const & offsetY); 00494 } 00495 \endcode 00496 00497 00498 use argument objects in conjunction with \ref ArgumentObjectFactories: 00499 \code 00500 namespace vigra { 00501 template <class SrcIterator, class SrcAccessor, 00502 class DestIterator, class DestAccessor, 00503 class KernelX, class KernelY> 00504 void 00505 resamplingConvolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> src, 00506 triple<DestIterator, DestIterator, DestAccessor> dest, 00507 KernelX const & kx, 00508 Rational<int> const & samplingRatioX, Rational<int> const & offsetX, 00509 KernelY const & ky, 00510 Rational<int> const & samplingRatioY, Rational<int> const & offsetY); 00511 } 00512 \endcode 00513 00514 <b> Usage:</b> 00515 00516 <b>\#include</b> "<a href="resampling__convolution_8hxx-source.html">vigra/resampling_convolution.hxx</a>" 00517 00518 00519 \code 00520 Rational<int> xratio(2), yratio(3), offset(0); 00521 00522 FImage src(w,h), 00523 dest(rational_cast<int>(xratio*w), rational_cast<int>(yratio*h)); 00524 00525 float sigma = 2.0; 00526 Gaussian<float> smooth(sigma); 00527 ... 00528 00529 // simpultaneously enlarge and smooth source image 00530 resamplingConvolveImage(srcImageRange(src), destImageRange(dest), 00531 smooth, xratio, offset, 00532 smooth, yratio, offset); 00533 00534 \endcode 00535 00536 */ 00537 template <class SrcIterator, class SrcAccessor, 00538 class DestIterator, class DestAccessor, 00539 class KernelX, class KernelY> 00540 void resamplingConvolveImage(SrcIterator sul,SrcIterator slr, SrcAccessor src, 00541 DestIterator dul, DestIterator dlr, DestAccessor dest, 00542 KernelX const & kx, 00543 Rational<int> const & samplingRatioX, Rational<int> const & offsetX, 00544 KernelY const & ky, 00545 Rational<int> const & samplingRatioY, Rational<int> const & offsetY) 00546 { 00547 typedef typename 00548 NumericTraits<typename SrcAccessor::value_type>::RealPromote 00549 TmpType; 00550 00551 BasicImage<TmpType> tmp(dlr.x - dul.x, slr.y - sul.y); 00552 00553 resamplingConvolveX(srcIterRange(sul, slr, src), 00554 destImageRange(tmp), 00555 kx, samplingRatioX, offsetX); 00556 resamplingConvolveY(srcImageRange(tmp), 00557 destIterRange(dul, dlr, dest), 00558 ky, samplingRatioY, offsetY); 00559 } 00560 00561 template <class SrcIterator, class SrcAccessor, 00562 class DestIterator, class DestAccessor, 00563 class KernelX, class KernelY> 00564 inline void 00565 resamplingConvolveImage(triple<SrcIterator, SrcIterator, SrcAccessor> src, 00566 triple<DestIterator, DestIterator, DestAccessor> dest, 00567 KernelX const & kx, 00568 Rational<int> const & samplingRatioX, Rational<int> const & offsetX, 00569 KernelY const & ky, 00570 Rational<int> const & samplingRatioY, Rational<int> const & offsetY) 00571 { 00572 resamplingConvolveImage(src.first, src.second, src.third, 00573 dest.first, dest.second, dest.third, 00574 kx, samplingRatioX, offsetX, 00575 ky, samplingRatioY, offsetY); 00576 } 00577 00578 } // namespace vigra 00579 00580 00581 #endif /* VIGRA_RESAMPLING_CONVOLUTION_HXX */
© Ullrich Köthe (koethe@informatik.uni-hamburg.de) |
html generated using doxygen and Python
|