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