36 #ifndef VIGRA_RESAMPLING_CONVOLUTION_HXX 
   37 #define VIGRA_RESAMPLING_CONVOLUTION_HXX 
   40 #include "stdimage.hxx" 
   41 #include "array_vector.hxx" 
   42 #include "rational.hxx" 
   43 #include "functortraits.hxx" 
   44 #include "functorexpression.hxx" 
   45 #include "transformimage.hxx" 
   46 #include "imagecontainer.hxx" 
   47 #include "multi_shape.hxx" 
   51 namespace resampling_detail
 
   54 struct MapTargetToSourceCoordinate
 
   56     MapTargetToSourceCoordinate(Rational<int> 
const & samplingRatio,
 
   57                                 Rational<int> 
const & offset)
 
   58     : a(samplingRatio.denominator()*offset.denominator()),
 
   59       b(samplingRatio.numerator()*offset.numerator()),
 
   60       c(samplingRatio.numerator()*offset.denominator())
 
   67     int operator()(
int i)
 const 
   69         return (i * a + b) / c;
 
   72     double toDouble(
int i)
 const 
   74         return double(i * a + b) / c;
 
   77     Rational<int> toRational(
int i)
 const 
   79         return Rational<int>(i * a + b, c);
 
   82     bool isExpand2()
 const 
   84         return a == 1 && b == 0 && c == 2;
 
   87     bool isReduce2()
 const 
   89         return a == 2 && b == 0 && c == 1;
 
   98 class FunctorTraits<resampling_detail::MapTargetToSourceCoordinate>
 
   99 : 
public FunctorTraitsBase<resampling_detail::MapTargetToSourceCoordinate>
 
  102     typedef VigraTrueType isUnaryFunctor;
 
  105 template <
class SrcIter, 
class SrcAcc,
 
  106           class DestIter, 
class DestAcc,
 
  109 resamplingExpandLine2(SrcIter s, SrcIter send, SrcAcc src,
 
  110                        DestIter d, DestIter dend, DestAcc dest,
 
  111                        KernelArray 
const & kernels)
 
  113     typedef typename KernelArray::value_type Kernel;
 
  114     typedef typename KernelArray::const_reference KernelRef;
 
  115     typedef typename Kernel::const_iterator KernelIter;
 
  118         PromoteTraits<typename SrcAcc::value_type, typename Kernel::value_type>::Promote
 
  125     int ileft = std::max(kernels[0].right(), kernels[1].right());
 
  126     int iright = wo + std::min(kernels[0].left(), kernels[1].left()) - 1;
 
  127     for(
int i = 0; i < wn; ++i, ++d)
 
  130         KernelRef kernel = kernels[i & 1];
 
  131         KernelIter k = kernel.center() + kernel.right();
 
  132         TmpType 
sum = NumericTraits<TmpType>::zero();
 
  135             for(
int m=is-kernel.right(); m <= is-kernel.left(); ++m, --k)
 
  140                 sum += *k * src(s, mm);
 
  145             for(
int m=is-kernel.right(); m <= is-kernel.left(); ++m, --k)
 
  150                 sum += *k * src(s, mm);
 
  155             SrcIter ss = s + is - kernel.right();
 
  156             for(
int m = 0; m < kernel.size(); ++m, --k, ++ss)
 
  165 template <
class SrcIter, 
class SrcAcc,
 
  166           class DestIter, 
class DestAcc,
 
  169 resamplingReduceLine2(SrcIter s, SrcIter send, SrcAcc src,
 
  170                        DestIter d, DestIter dend, DestAcc dest,
 
  171                        KernelArray 
const & kernels)
 
  173     typedef typename KernelArray::value_type Kernel;
 
  174     typedef typename KernelArray::const_reference KernelRef;
 
  175     typedef typename Kernel::const_iterator KernelIter;
 
  177     KernelRef kernel = kernels[0];
 
  178     KernelIter kbegin = kernel.center() + kernel.right();
 
  181         PromoteTraits<typename SrcAcc::value_type, typename Kernel::value_type>::Promote
 
  188     int ileft = kernel.right();
 
  189     int iright = wo + kernel.left() - 1;
 
  190     for(
int i = 0; i < wn; ++i, ++d)
 
  193         KernelIter k = kbegin;
 
  194         TmpType sum = NumericTraits<TmpType>::zero();
 
  197             for(
int m=is-kernel.right(); m <= is-kernel.left(); ++m, --k)
 
  202                 sum += *k * src(s, mm);
 
  207             for(
int m=is-kernel.right(); m <= is-kernel.left(); ++m, --k)
 
  212                 sum += *k * src(s, mm);
 
  217             SrcIter ss = s + is - kernel.right();
 
  218             for(
int m = 0; m < kernel.size(); ++m, --k, ++ss)
 
  271 template <
class SrcIter, 
class SrcAcc,
 
  272           class DestIter, 
class DestAcc,
 
  277                        DestIter d, DestIter dend, DestAcc dest,
 
  278                        KernelArray 
const & kernels,
 
  279                        Functor mapTargetToSourceCoordinate)
 
  281     if(mapTargetToSourceCoordinate.isExpand2())
 
  283         resamplingExpandLine2(s, send, src, d, dend, dest, kernels);
 
  286     if(mapTargetToSourceCoordinate.isReduce2())
 
  288         resamplingReduceLine2(s, send, src, d, dend, dest, kernels);
 
  293         NumericTraits<typename SrcAcc::value_type>::RealPromote
 
  295     typedef typename KernelArray::value_type Kernel;
 
  296     typedef typename Kernel::const_iterator KernelIter;
 
  303     typename KernelArray::const_iterator kernel = kernels.begin();
 
  304     for(i=0; i<wn; ++i, ++d, ++kernel)
 
  307         if(kernel == kernels.end())
 
  308             kernel = kernels.begin();
 
  311         int is = mapTargetToSourceCoordinate(i);
 
  313         TmpType sum = NumericTraits<TmpType>::zero();
 
  315         int lbound = is - kernel->right(),
 
  316             hbound = is - kernel->left();
 
  318         KernelIter k = kernel->center() + kernel->right();
 
  319         if(lbound < 0 || hbound >= wo)
 
  321             vigra_precondition(-lbound < wo && wo2 - hbound >= 0,
 
  322                 "resamplingConvolveLine(): kernel or offset larger than image.");
 
  323             for(
int m=lbound; m <= hbound; ++m, --k)
 
  330                 sum = TmpType(sum + *k * src(s, mm));
 
  335             SrcIter ss = s + lbound;
 
  336             SrcIter ssend = s + hbound;
 
  338             for(; ss <= ssend; ++ss, --k)
 
  340                 sum = TmpType(sum + *k * src(ss));
 
  348 template <
class Kernel, 
class MapCoordinate, 
class KernelArray>
 
  350 createResamplingKernels(Kernel 
const & kernel,
 
  351              MapCoordinate 
const & mapCoordinate, KernelArray & kernels)
 
  353     for(
unsigned int idest = 0; idest < kernels.size(); ++idest)
 
  355         int isrc = mapCoordinate(idest);
 
  356         double idsrc = mapCoordinate.toDouble(idest);
 
  357         double offset = idsrc - isrc;
 
  358         double radius = kernel.radius();
 
  359         int left = std::min(0, 
int(
ceil(-radius - offset)));
 
  360         int right = std::max(0, 
int(
floor(radius - offset)));
 
  361         kernels[idest].initExplicitly(left, right);
 
  363         double x = left + offset;
 
  364         for(
int i = left; i <= right; ++i, ++x)
 
  365             kernels[idest][i] = kernel(x);
 
  366         kernels[idest].normalize(1.0, kernel.derivativeOrder(), offset);
 
  485 template <
class SrcIter, 
class SrcAcc,
 
  486           class DestIter, 
class DestAcc,
 
  490                     DestIter dul, DestIter dlr, DestAcc dest,
 
  491                     Kernel 
const & kernel,
 
  492                     Rational<int> 
const & samplingRatio, Rational<int> 
const & offset)
 
  494     int wold = slr.x - sul.x;
 
  495     int wnew = dlr.x - dul.x;
 
  497     vigra_precondition(!samplingRatio.is_inf() && samplingRatio > 0,
 
  498                 "resamplingConvolveX(): sampling ratio must be > 0 and < infinity");
 
  499     vigra_precondition(!offset.is_inf(),
 
  500                 "resamplingConvolveX(): offset must be < infinity");
 
  502     int period = 
lcm(samplingRatio.numerator(), samplingRatio.denominator());
 
  503     resampling_detail::MapTargetToSourceCoordinate mapCoordinate(samplingRatio, offset);
 
  505     ArrayVector<Kernel1D<double> > kernels(period);
 
  507     createResamplingKernels(kernel, mapCoordinate, kernels);
 
  509     for(; sul.y < slr.y; ++sul.y, ++dul.y)
 
  511         typename SrcIter::row_iterator sr = sul.rowIterator();
 
  512         typename DestIter::row_iterator dr = dul.rowIterator();
 
  514                                kernels, mapCoordinate);
 
  518 template <
class SrcIter, 
class SrcAcc,
 
  519           class DestIter, 
class DestAcc,
 
  523                     triple<DestIter, DestIter, DestAcc> dest,
 
  524                     Kernel 
const & kernel,
 
  525                     Rational<int> 
const & samplingRatio, Rational<int> 
const & offset)
 
  528                         dest.first, dest.second, dest.third,
 
  529                         kernel, samplingRatio, offset);
 
  532 template <
class T1, 
class S1,
 
  537                     MultiArrayView<2, T2, S2> dest,
 
  538                     Kernel 
const & kernel,
 
  539                     Rational<int> 
const & samplingRatio, Rational<int> 
const & offset)
 
  542                         destImageRange(dest),
 
  543                         kernel, samplingRatio, offset);
 
  667 template <
class SrcIter, 
class SrcAcc,
 
  668           class DestIter, 
class DestAcc,
 
  672                     DestIter dul, DestIter dlr, DestAcc dest,
 
  673                     Kernel 
const & kernel,
 
  674                     Rational<int> 
const & samplingRatio, Rational<int> 
const & offset)
 
  676     int hold = slr.y - sul.y;
 
  677     int hnew = dlr.y - dul.y;
 
  679     vigra_precondition(!samplingRatio.is_inf() && samplingRatio > 0,
 
  680                 "resamplingConvolveY(): sampling ratio must be > 0 and < infinity");
 
  681     vigra_precondition(!offset.is_inf(),
 
  682                 "resamplingConvolveY(): offset must be < infinity");
 
  684     int period = 
lcm(samplingRatio.numerator(), samplingRatio.denominator());
 
  686     resampling_detail::MapTargetToSourceCoordinate mapCoordinate(samplingRatio, offset);
 
  688     ArrayVector<Kernel1D<double> > kernels(period);
 
  690     createResamplingKernels(kernel, mapCoordinate, kernels);
 
  692     for(; sul.x < slr.x; ++sul.x, ++dul.x)
 
  694         typename SrcIter::column_iterator sc = sul.columnIterator();
 
  695         typename DestIter::column_iterator dc = dul.columnIterator();
 
  697                                kernels, mapCoordinate);
 
  701 template <
class SrcIter, 
class SrcAccessor,
 
  702           class DestIter, 
class DestAccessor,
 
  706                     triple<DestIter, DestIter, DestAccessor> dest,
 
  707                     Kernel 
const & kernel,
 
  708                     Rational<int> 
const & samplingRatio, Rational<int> 
const & offset)
 
  711                         dest.first, dest.second, dest.third,
 
  712                         kernel, samplingRatio, offset);
 
  715 template <
class T1, 
class S1,
 
  720                     MultiArrayView<2, T2, S2> dest,
 
  721                     Kernel 
const & kernel,
 
  722                     Rational<int> 
const & samplingRatio, Rational<int> 
const & offset)
 
  725                         destImageRange(dest),
 
  726                         kernel, samplingRatio, offset);
 
  815 template <
class SrcIterator, 
class SrcAccessor,
 
  816           class DestIterator, 
class DestAccessor,
 
  817           class KernelX, 
class KernelY>
 
  819                    DestIterator dul, DestIterator dlr, DestAccessor dest,
 
  821                    Rational<int> 
const & samplingRatioX, Rational<int> 
const & offsetX,
 
  823                    Rational<int> 
const & samplingRatioY, Rational<int> 
const & offsetY)
 
  826         NumericTraits<typename SrcAccessor::value_type>::RealPromote
 
  829     BasicImage<TmpType> tmp(dlr.x - dul.x, slr.y - sul.y);
 
  833                         kx, samplingRatioX, offsetX);
 
  835                         destIterRange(dul, dlr, dest),
 
  836                         ky, samplingRatioY, offsetY);
 
  839 template <
class SrcIterator, 
class SrcAccessor,
 
  840           class DestIterator, 
class DestAccessor,
 
  841           class KernelX, 
class KernelY>
 
  844                         triple<DestIterator, DestIterator, DestAccessor> dest,
 
  846                         Rational<int> 
const & samplingRatioX, Rational<int> 
const & offsetX,
 
  848                         Rational<int> 
const & samplingRatioY, Rational<int> 
const & offsetY)
 
  851                             dest.first, dest.second, dest.third,
 
  852                             kx, samplingRatioX, offsetX,
 
  853                             ky, samplingRatioY, offsetY);
 
  856 template <
class T1, 
class S1,
 
  858           class KernelX, 
class KernelY>
 
  861                         MultiArrayView<2, T2, S2> dest,
 
  863                         Rational<int> 
const & samplingRatioX, Rational<int> 
const & offsetX,
 
  865                         Rational<int> 
const & samplingRatioY, Rational<int> 
const & offsetY)
 
  868                             destImageRange(dest),
 
  869                             kx, samplingRatioX, offsetX,
 
  870                             ky, samplingRatioY, offsetY);
 
  945 template <
class SrcIterator, 
class SrcAccessor,
 
  946           class DestIterator, 
class DestAccessor>
 
  948                              DestIterator dul, DestIterator dlr, DestAccessor dest,
 
  949                              double centerValue = 0.4)
 
  951     vigra_precondition(0.25 <= centerValue && centerValue <= 0.5,
 
  952              "pyramidReduceBurtFilter(): centerValue must be between 0.25 and 0.5.");
 
  954     int wold = slr.x - sul.x;
 
  955     int wnew = dlr.x - dul.x;
 
  956     int hold = slr.y - sul.y;
 
  957     int hnew = dlr.y - dul.y;
 
  959     vigra_precondition(wnew == (wold + 1) / 2 && hnew == (hold + 1) / 2,
 
  960        "pyramidReduceBurtFilter(): destSize = ceil(srcSize / 2) required.");
 
  962     Rational<int> samplingRatio(1,2), offset(0);
 
  963     resampling_detail::MapTargetToSourceCoordinate mapCoordinate(samplingRatio, offset);
 
  965     ArrayVector<Kernel1D<double> > kernels(1);
 
  966     kernels[0].initExplicitly(-2, 2) = 0.25 - centerValue / 2.0, 0.25, centerValue, 0.25, 0.25 - centerValue / 2.0;
 
  969         NumericTraits<typename SrcAccessor::value_type>::RealPromote
 
  971     typedef BasicImage<TmpType> TmpImage;
 
  972     typedef typename TmpImage::traverser TmpIterator;
 
  974     BasicImage<TmpType> tmp(wnew, hold);
 
  976     TmpIterator tul = tmp.upperLeft();
 
  978     for(; sul.y < slr.y; ++sul.y, ++tul.y)
 
  980         typename SrcIterator::row_iterator sr = sul.rowIterator();
 
  981         typename TmpIterator::row_iterator tr = tul.rowIterator();
 
  984                                kernels, mapCoordinate);
 
  987     tul  = tmp.upperLeft();
 
  989     for(; dul.x < dlr.x; ++dul.x, ++tul.x)
 
  991         typename DestIterator::column_iterator dc = dul.columnIterator();
 
  992         typename TmpIterator::column_iterator tc = tul.columnIterator();
 
  994                                kernels, mapCoordinate);
 
  998 template <
class SrcIterator, 
class SrcAccessor,
 
  999           class DestIterator, 
class DestAccessor>
 
 1002                              triple<DestIterator, DestIterator, DestAccessor> dest,
 
 1003                              double centerValue = 0.4)
 
 1006                             dest.first, dest.second, dest.third, centerValue);
 
 1009 template <
class Image, 
class Alloc>
 
 1012                              int fromLevel, 
int toLevel,
 
 1013                              double centerValue = 0.4)
 
 1015     vigra_precondition(fromLevel  < toLevel,
 
 1016        "pyramidReduceBurtFilter(): fromLevel must be smaller than toLevel.");
 
 1017     vigra_precondition(pyramid.lowestLevel() <= fromLevel && toLevel <= pyramid.highestLevel(),
 
 1018        "pyramidReduceBurtFilter(): fromLevel and toLevel must be between the lowest and highest pyramid levels (inclusive).");
 
 1020     for(
int i=fromLevel+1; i <= toLevel; ++i)
 
 1099 template <
class SrcIterator, 
class SrcAccessor,
 
 1100           class DestIterator, 
class DestAccessor>
 
 1102                              DestIterator dul, DestIterator dlr, DestAccessor dest,
 
 1103                              double centerValue = 0.4)
 
 1105     vigra_precondition(0.25 <= centerValue && centerValue <= 0.5,
 
 1106              "pyramidExpandBurtFilter(): centerValue must be between 0.25 and 0.5.");
 
 1108     int wold = slr.x - sul.x;
 
 1109     int wnew = dlr.x - dul.x;
 
 1110     int hold = slr.y - sul.y;
 
 1111     int hnew = dlr.y - dul.y;
 
 1113     vigra_precondition(wold == (wnew + 1) / 2 && hold == (hnew + 1) / 2,
 
 1114        "pyramidExpandBurtFilter(): oldSize = ceil(newSize / 2) required.");
 
 1116     Rational<int> samplingRatio(2), offset(0);
 
 1117     resampling_detail::MapTargetToSourceCoordinate mapCoordinate(samplingRatio, offset);
 
 1119     ArrayVector<Kernel1D<double> > kernels(2);
 
 1120     kernels[0].initExplicitly(-1, 1) = 0.5 - centerValue, 2.0*centerValue, 0.5 - centerValue;
 
 1121     kernels[1].initExplicitly(-1, 0) = 0.5, 0.5;
 
 1124         NumericTraits<typename SrcAccessor::value_type>::RealPromote
 
 1126     typedef BasicImage<TmpType> TmpImage;
 
 1127     typedef typename TmpImage::traverser TmpIterator;
 
 1129     BasicImage<TmpType> tmp(wnew, hold);
 
 1131     TmpIterator tul = tmp.upperLeft();
 
 1133     for(; sul.y < slr.y; ++sul.y, ++tul.y)
 
 1135         typename SrcIterator::row_iterator sr = sul.rowIterator();
 
 1136         typename TmpIterator::row_iterator tr = tul.rowIterator();
 
 1139                                kernels, mapCoordinate);
 
 1142     tul  = tmp.upperLeft();
 
 1144     for(; dul.x < dlr.x; ++dul.x, ++tul.x)
 
 1146         typename DestIterator::column_iterator dc = dul.columnIterator();
 
 1147         typename TmpIterator::column_iterator tc = tul.columnIterator();
 
 1149                                kernels, mapCoordinate);
 
 1153 template <
class SrcIterator, 
class SrcAccessor,
 
 1154           class DestIterator, 
class DestAccessor>
 
 1157                              triple<DestIterator, DestIterator, DestAccessor> dest,
 
 1158                              double centerValue = 0.4)
 
 1161                             dest.first, dest.second, dest.third, centerValue);
 
 1165 template <
class Image, 
class Alloc>
 
 1168                              double centerValue = 0.4)
 
 1170     vigra_precondition(fromLevel  > toLevel,
 
 1171        "pyramidExpandBurtFilter(): fromLevel must be larger than toLevel.");
 
 1172     vigra_precondition(pyramid.lowestLevel() <= toLevel && fromLevel <= pyramid.highestLevel(),
 
 1173        "pyramidExpandBurtFilter(): fromLevel and toLevel must be between the lowest and highest pyramid levels (inclusive).");
 
 1175     for(
int i=fromLevel-1; i >= toLevel; --i)
 
 1195 template <
class Image, 
class Alloc>
 
 1198                            int fromLevel, 
int toLevel,
 
 1199                            double centerValue = 0.4)
 
 1201     using namespace functor;
 
 1204     for(
int i=fromLevel; i < toLevel; ++i)
 
 1208         combineTwoImages(srcImageRange(tmpImage), srcImage(pyramid[i]), destImage(pyramid[i]),
 
 1228 template <
class Image, 
class Alloc>
 
 1231                            int fromLevel, 
int toLevel,
 
 1232                            double centerValue = 0.4)
 
 1234     using namespace functor;
 
 1236     vigra_precondition(fromLevel  > toLevel,
 
 1237        "pyramidExpandBurtLaplacian(): fromLevel must be larger than toLevel.");
 
 1239        "pyramidExpandBurtLaplacian(): fromLevel and toLevel must be between the lowest and highest pyramid levels (inclusive).");
 
 1241     for(
int i=fromLevel-1; i >= toLevel; --i)
 
 1245         combineTwoImages(srcImageRange(tmpImage), srcImage(pyramid[i]), destImage(pyramid[i]),
 
void resamplingConvolveX(...)
Apply a resampling filter in the x-direction. 
void pyramidExpandBurtFilter(...)
Two-fold up-sampling for image pyramid reconstruction. 
ImageType value_type
Definition: imagecontainer.hxx:479
void pyramidExpandBurtLaplacian(ImagePyramid< Image, Alloc > &pyramid, int fromLevel, int toLevel, double centerValue=0.4)
Reconstruct a Laplacian pyramid. 
Definition: resampling_convolution.hxx:1230
NumericTraits< V >::Promote sum(TinyVectorBase< V, SIZE, D1, D2 > const &l)
sum of the vector's elements 
Definition: tinyvector.hxx:2073
void resamplingConvolveImage(...)
Apply two separable resampling filters successively, the first in x-direction, the second in y-direct...
IntType lcm(IntType n, IntType m)
Definition: rational.hxx:122
void combineTwoImages(...)
Combine two source images into destination image. 
doxygen_overloaded_function(template<...> void separableConvolveBlockwise) template< unsigned int N
Separated convolution on ChunkedArrays. 
void pyramidReduceBurtFilter(...)
Two-fold down-sampling for image pyramid construction. 
int highestLevel() const 
Definition: imagecontainer.hxx:576
void resamplingConvolveY(...)
Apply a resampling filter in the y-direction. 
int lowestLevel() const 
Definition: imagecontainer.hxx:569
void pyramidReduceBurtLaplacian(ImagePyramid< Image, Alloc > &pyramid, int fromLevel, int toLevel, double centerValue=0.4)
Create a Laplacian pyramid. 
Definition: resampling_convolution.hxx:1197
int ceil(FixedPoint< IntBits, FracBits > v)
rounding up. 
Definition: fixedpoint.hxx:675
void resamplingConvolveLine(...)
Performs a 1-dimensional resampling convolution of the source signal using the given set of kernels...
Class template for logarithmically tapering image pyramids. 
Definition: imagecontainer.hxx:468
int floor(FixedPoint< IntBits, FracBits > v)
rounding down. 
Definition: fixedpoint.hxx:667