37 #ifndef VIGRA_RESIZEIMAGE_HXX
38 #define VIGRA_RESIZEIMAGE_HXX
41 #include "utilities.hxx"
42 #include "numerictraits.hxx"
43 #include "stdimage.hxx"
44 #include "recursiveconvolution.hxx"
45 #include "separableconvolution.hxx"
46 #include "resampling_convolution.hxx"
47 #include "splines.hxx"
160 template <
class SrcIterator,
class SrcAccessor,
161 class DestIterator,
class DestAccessor>
163 resizeLineNoInterpolation(SrcIterator i1, SrcIterator iend, SrcAccessor as,
164 DestIterator
id, DestIterator idend, DestAccessor ad)
166 int wold = iend - i1;
167 int wnew = idend - id;
175 double dx = (double)(wold - 1) / (wnew - 1);
177 for(;
id != idend; ++id, x += dx)
180 ad.set(as(i1, ix),
id);
266 template <
class SrcIterator,
class SrcAccessor,
267 class DestIterator,
class DestAccessor>
270 DestIterator
id, DestIterator idend, DestAccessor da)
272 int w = iend.x - is.x;
273 int h = iend.y - is.y;
275 int wnew = idend.x -
id.x;
276 int hnew = idend.y -
id.y;
278 vigra_precondition((w > 1) && (h > 1),
279 "resizeImageNoInterpolation(): "
280 "Source image too small.\n");
281 vigra_precondition((wnew > 1) && (hnew > 1),
282 "resizeImageNoInterpolation(): "
283 "Destination image too small.\n");
285 typedef BasicImage<typename SrcAccessor::value_type> TmpImage;
286 typedef typename TmpImage::traverser TmpImageIterator;
288 TmpImage tmp(w, hnew);
290 TmpImageIterator yt = tmp.upperLeft();
292 for(
int x=0; x<w; ++x, ++is.x, ++yt.x)
294 typename SrcIterator::column_iterator c1 = is.columnIterator();
295 typename TmpImageIterator::column_iterator ct = yt.columnIterator();
297 resizeLineNoInterpolation(c1, c1 + h, sa, ct, ct + hnew, tmp.accessor());
300 yt = tmp.upperLeft();
302 for(
int y=0; y < hnew; ++y, ++yt.y, ++
id.y)
304 typename DestIterator::row_iterator rd =
id.rowIterator();
305 typename TmpImageIterator::row_iterator rt = yt.rowIterator();
307 resizeLineNoInterpolation(rt, rt + w, tmp.accessor(), rd, rd + wnew, da);
311 template <
class SrcIterator,
class SrcAccessor,
312 class DestIterator,
class DestAccessor>
316 triple<DestIterator, DestIterator, DestAccessor> dest)
319 dest.first, dest.second, dest.third);
328 template <
class SrcIterator,
class SrcAccessor,
329 class DestIterator,
class DestAccessor>
331 resizeLineLinearInterpolation(SrcIterator i1, SrcIterator iend, SrcAccessor as,
332 DestIterator
id, DestIterator idend, DestAccessor ad)
334 int wold = iend - i1;
335 int wnew = idend - id;
337 if((wold <= 1) || (wnew <= 1))
return;
340 NumericTraits<typename DestAccessor::value_type> DestTraits;
341 typedef typename DestTraits::RealPromote RealPromote;
343 ad.set(DestTraits::fromRealPromote(as(i1)),
id);
347 ad.set(DestTraits::fromRealPromote(as(iend)), idend);
349 double dx = (double)(wold - 1) / (wnew - 1);
352 for(;
id != idend; ++id, x += dx)
362 ad.set(DestTraits::fromRealPromote(RealPromote(x1 * as(i1) + x * as(i1, 1))),
id);
461 template <
class SrcIterator,
class SrcAccessor,
462 class DestIterator,
class DestAccessor>
465 DestIterator
id, DestIterator idend, DestAccessor da)
467 int w = iend.x - is.x;
468 int h = iend.y - is.y;
470 int wnew = idend.x -
id.x;
471 int hnew = idend.y -
id.y;
473 vigra_precondition((w > 1) && (h > 1),
474 "resizeImageLinearInterpolation(): "
475 "Source image too small.\n");
476 vigra_precondition((wnew > 1) && (hnew > 1),
477 "resizeImageLinearInterpolation(): "
478 "Destination image too small.\n");
480 double const scale = 2.0;
482 typedef typename SrcAccessor::value_type SRCVT;
483 typedef typename NumericTraits<SRCVT>::RealPromote TMPTYPE;
484 typedef BasicImage<TMPTYPE> TmpImage;
485 typedef typename TmpImage::traverser TmpImageIterator;
487 BasicImage<TMPTYPE> tmp(w, hnew);
488 BasicImage<TMPTYPE> line((h > w) ? h : w, 1);
492 typename BasicImage<TMPTYPE>::Iterator yt = tmp.upperLeft();
493 typename TmpImageIterator::row_iterator lt = line.upperLeft().rowIterator();
495 for(x=0; x<w; ++x, ++is.x, ++yt.x)
497 typename SrcIterator::column_iterator c1 = is.columnIterator();
498 typename TmpImageIterator::column_iterator ct = yt.columnIterator();
503 lt, line.accessor(), (double)h/hnew/scale);
505 resizeLineLinearInterpolation(lt, lt + h, line.accessor(),
506 ct, ct + hnew, tmp.accessor());
510 resizeLineLinearInterpolation(c1, c1 + h, sa,
511 ct, ct + hnew, tmp.accessor());
515 yt = tmp.upperLeft();
517 for(y=0; y < hnew; ++y, ++yt.y, ++
id.y)
519 typename DestIterator::row_iterator rd =
id.rowIterator();
520 typename TmpImageIterator::row_iterator rt = yt.rowIterator();
525 lt, line.accessor(), (double)w/wnew/scale);
527 resizeLineLinearInterpolation(lt, lt + w, line.accessor(),
532 resizeLineLinearInterpolation(rt, rt + w, tmp.accessor(),
538 template <
class SrcIterator,
class SrcAccessor,
539 class DestIterator,
class DestAccessor>
543 triple<DestIterator, DestIterator, DestAccessor> dest)
546 dest.first, dest.second, dest.third);
665 template <
class SrcIterator,
class SrcAccessor,
666 class DestIterator,
class DestAccessor,
670 SrcIterator src_iter, SrcIterator src_iter_end, SrcAccessor src_acc,
671 DestIterator dest_iter, DestIterator dest_iter_end, DestAccessor dest_acc,
672 SPLINE
const & spline)
675 int width_old = src_iter_end.x - src_iter.x;
676 int height_old = src_iter_end.y - src_iter.y;
678 int width_new = dest_iter_end.x - dest_iter.x;
679 int height_new = dest_iter_end.y - dest_iter.y;
681 vigra_precondition((width_old > 1) && (height_old > 1),
682 "resizeImageSplineInterpolation(): "
683 "Source image too small.\n");
685 vigra_precondition((width_new > 1) && (height_new > 1),
686 "resizeImageSplineInterpolation(): "
687 "Destination image too small.\n");
689 Rational<int> xratio(width_new - 1, width_old - 1);
690 Rational<int> yratio(height_new - 1, height_old - 1);
691 Rational<int> offset(0);
692 resampling_detail::MapTargetToSourceCoordinate xmapCoordinate(xratio, offset);
693 resampling_detail::MapTargetToSourceCoordinate ymapCoordinate(yratio, offset);
694 int xperiod =
lcm(xratio.numerator(), xratio.denominator());
695 int yperiod =
lcm(yratio.numerator(), yratio.denominator());
697 double const scale = 2.0;
699 typedef typename SrcAccessor::value_type SRCVT;
700 typedef typename NumericTraits<SRCVT>::RealPromote TMPTYPE;
701 typedef BasicImage<TMPTYPE> TmpImage;
702 typedef typename TmpImage::traverser TmpImageIterator;
704 BasicImage<TMPTYPE> tmp(width_old, height_new);
706 BasicImage<TMPTYPE> line((height_old > width_old) ? height_old : width_old, 1);
707 typename BasicImage<TMPTYPE>::Accessor tmp_acc = tmp.accessor();
708 ArrayVector<double>
const & prefilterCoeffs = spline.prefilterCoefficients();
712 ArrayVector<Kernel1D<double> > kernels(yperiod);
713 createResamplingKernels(spline, ymapCoordinate, kernels);
715 typename BasicImage<TMPTYPE>::Iterator y_tmp = tmp.upperLeft();
716 typename TmpImageIterator::row_iterator line_tmp = line.upperLeft().rowIterator();
718 for(x=0; x<width_old; ++x, ++src_iter.x, ++y_tmp.x)
721 typename SrcIterator::column_iterator c_src = src_iter.columnIterator();
722 typename TmpImageIterator::column_iterator c_tmp = y_tmp.columnIterator();
724 if(prefilterCoeffs.size() == 0)
726 if(height_new >= height_old)
729 c_tmp, c_tmp + height_new, tmp_acc,
730 kernels, ymapCoordinate);
735 line_tmp, line.accessor(), (double)height_old/height_new/scale);
737 c_tmp, c_tmp + height_new, tmp_acc,
738 kernels, ymapCoordinate);
744 line_tmp, line.accessor(),
745 prefilterCoeffs[0], BORDER_TREATMENT_REFLECT);
746 for(
unsigned int b = 1; b < prefilterCoeffs.size(); ++b)
749 line_tmp, line.accessor(),
750 prefilterCoeffs[b], BORDER_TREATMENT_REFLECT);
752 if(height_new < height_old)
755 line_tmp, line.accessor(), (double)height_old/height_new/scale);
758 c_tmp, c_tmp + height_new, tmp_acc,
759 kernels, ymapCoordinate);
763 y_tmp = tmp.upperLeft();
765 kernels.resize(xperiod);
766 createResamplingKernels(spline, xmapCoordinate, kernels);
768 for(y=0; y < height_new; ++y, ++y_tmp.y, ++dest_iter.y)
770 typename DestIterator::row_iterator r_dest = dest_iter.rowIterator();
771 typename TmpImageIterator::row_iterator r_tmp = y_tmp.rowIterator();
773 if(prefilterCoeffs.size() == 0)
775 if(width_new >= width_old)
778 r_dest, r_dest + width_new, dest_acc,
779 kernels, xmapCoordinate);
784 line_tmp, line.accessor(), (double)width_old/width_new/scale);
786 r_dest, r_dest + width_new, dest_acc,
787 kernels, xmapCoordinate);
793 line_tmp, line.accessor(),
794 prefilterCoeffs[0], BORDER_TREATMENT_REFLECT);
795 for(
unsigned int b = 1; b < prefilterCoeffs.size(); ++b)
798 line_tmp, line.accessor(),
799 prefilterCoeffs[b], BORDER_TREATMENT_REFLECT);
801 if(width_new < width_old)
804 line_tmp, line.accessor(), (double)width_old/width_new/scale);
807 r_dest, r_dest + width_new, dest_acc,
808 kernels, xmapCoordinate);
813 template <
class SrcIterator,
class SrcAccessor,
814 class DestIterator,
class DestAccessor,
819 triple<DestIterator, DestIterator, DestAccessor> dest,
820 SPLINE
const & spline)
823 dest.first, dest.second, dest.third, spline);
826 template <
class SrcIterator,
class SrcAccessor,
827 class DestIterator,
class DestAccessor>
830 DestIterator
id, DestIterator idend, DestAccessor da)
835 template <
class SrcIterator,
class SrcAccessor,
836 class DestIterator,
class DestAccessor>
840 triple<DestIterator, DestIterator, DestAccessor> dest)
843 dest.first, dest.second, dest.third);
891 template <
class SrcIterator,
class SrcAccessor,
892 class DestIterator,
class DestAccessor>
895 DestIterator dest_iter, DestIterator dest_iter_end, DestAccessor dest_acc)
898 CatmullRomSpline<double>());
901 template <
class SrcIterator,
class SrcAccessor,
902 class DestIterator,
class DestAccessor>
906 triple<DestIterator, DestIterator, DestAccessor> dest)
909 dest.first, dest.second, dest.third);
930 template <
class SrcIterator,
class SrcAccessor,
931 class DestIterator,
class DestAccessor>
933 resizeImageCubicInterpolation(SrcIterator src_iter, SrcIterator src_iter_end, SrcAccessor src_acc,
934 DestIterator dest_iter, DestIterator dest_iter_end, DestAccessor dest_acc)
937 BSpline<3, double>());
940 template <
class SrcIterator,
class SrcAccessor,
941 class DestIterator,
class DestAccessor>
944 resizeImageCubicInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
945 triple<DestIterator, DestIterator, DestAccessor> dest)
947 resizeImageCubicInterpolation(src.first, src.second, src.third,
948 dest.first, dest.second, dest.third);
997 template <
class SrcIterator,
class SrcAccessor,
998 class DestIterator,
class DestAccessor>
1001 DestIterator dest_iter, DestIterator dest_iter_end, DestAccessor dest_acc)
1004 CoscotFunction<double>());
1007 template <
class SrcIterator,
class SrcAccessor,
1008 class DestIterator,
class DestAccessor>
1012 triple<DestIterator, DestIterator, DestAccessor> dest)
1015 dest.first, dest.second, dest.third);
1019 #if 0 // old version of the spline interpolation algorithm
1028 template <
class SrcIterator,
class SrcAccessor,
class VALUETYPE>
1030 resizeCalculateSplineCoefficients(SrcIterator i1, SrcIterator iend,
1031 SrcAccessor a, VALUETYPE * i2)
1037 VALUETYPE zero = NumericTraits<VALUETYPE>::zero();
1038 VALUETYPE two = 2.0 * NumericTraits<VALUETYPE>::one();
1039 VALUETYPE half = 0.5 * NumericTraits<VALUETYPE>::one();
1044 std::vector<VALUETYPE> vec(n);
1045 typename std::vector<VALUETYPE>::iterator u = vec.begin();
1049 for(++i1, ++i2, ++u, --iend; i1 != iend; ++i1, ++i2, ++u)
1051 VALUETYPE p = 0.5 * i2[-1] + two;
1053 *u = 3.0 *(a(i1,1) - 2.0 * a(i1) + a(i1, -1)) - 0.5 * u[-1] / p;
1058 for(--i2, --u; u != vec; --u, --i2)
1060 *i2 = *i2 * i2[1] + *u;
1070 template <
class SrcIterator,
class SrcAccessor,
1071 class DoubleIterator,
class TempIterator,
class DestIterator>
1073 resizeImageInternalSplineGradient(SrcIterator in, SrcIterator inend, SrcAccessor sa,
1074 DoubleIterator tmp, TempIterator r, DestIterator
id)
1080 typedef typename SrcAccessor::value_type SRCVT;
1081 typedef typename NumericTraits<SRCVT>::RealPromote TMPTYPE;
1084 SrcIterator xs = in;
1085 TMPTYPE p0 = -11.0/6.0 * sa(xs); ++xs;
1086 p0 += 3.0 * sa(xs); ++xs;
1087 p0 += -1.5 * sa(xs); ++xs;
1088 p0 += 1.0/3.0 * sa(xs);
1091 TMPTYPE pw = 11.0/6.0 * sa(xs); --xs;
1092 pw += -3.0 * sa(xs); --xs;
1093 pw += 1.5 * sa(xs); --xs;
1094 pw += -1.0/3.0 * sa(xs);
1097 SrcIterator xs1 = in;
1099 for(x=1; x<w-1; ++x, ++xs, ++xs1)
1101 r[x] = 3.0 * (sa(xs) - sa(xs1));
1111 id[1] = 0.25 * r[1];
1113 for(x=2; x<w-1; ++x)
1116 q = 1.0 / (4.0 - q);
1117 id[x] = q * (r[x] -
id[x-1]);
1120 for(x=w-3; x>=1; --x)
1122 id[x] -= tmp[x+1]*
id[x+1];
1132 template <
class SrcIterator,
class SrcAccessor,
1133 class DestIterator,
class DestAccessor>
1135 resizeImageInternalSplineInterpolation(SrcIterator is, SrcIterator iend, SrcAccessor sa,
1136 DestIterator
id, DestIterator idend, DestAccessor da)
1138 int w = iend.x - is.x;
1139 int h = iend.y - is.y;
1141 int wnew = idend.x -
id.x;
1142 int hnew = idend.y -
id.y;
1144 typedef typename SrcAccessor::value_type SRCVT;
1145 typedef typename NumericTraits<SRCVT>::RealPromote TMPTYPE;
1146 typedef typename BasicImage<TMPTYPE>::Iterator TMPITER;
1148 NumericTraits<typename DestAccessor::value_type> DestTraits;
1150 BasicImage<TMPTYPE> dx(w,h);
1151 BasicImage<TMPTYPE> dy(w,h);
1152 BasicImage<TMPTYPE> dxy(w,h);
1153 BasicImage<TMPTYPE> W(4,4), W1(4,4);
1154 std::vector<TMPTYPE> R(w > h ? w : h);
1155 std::vector<double> tmp(w > h ? w : h);
1157 typename BasicImage<TMPTYPE>::Accessor ta;
1159 SrcIterator in = is;
1161 TMPITER idx = dx.upperLeft();
1162 TMPITER idy = dy.upperLeft();
1163 TMPITER idxy = dxy.upperLeft();
1164 typename std::vector<TMPTYPE>::iterator r = R.begin();
1165 typename std::vector<double>::iterator it = tmp.begin();
1167 double ig[] = { 1.0, 0.0, -3.0, 2.0,
1168 0.0, 1.0, -2.0, 1.0,
1169 0.0, 0.0, 3.0, -2.0,
1170 0.0, 0.0, -1.0, 1.0 };
1176 for(y=0; y<h; ++y, ++in.y, ++idx.y)
1178 typename SrcIterator::row_iterator sr = in.rowIterator();
1179 typename TMPITER::row_iterator dr = idx.rowIterator();
1180 resizeImageInternalSplineGradient(sr, sr+w, sa,
1187 for(x=0; x<w; ++x, ++in.x, ++idy.x)
1189 typename SrcIterator::column_iterator sc = in.columnIterator();
1190 typename TMPITER::column_iterator dc = idy.columnIterator();
1191 resizeImageInternalSplineGradient(sc, sc+h, sa,
1196 idy = dy.upperLeft();
1199 for(y=0; y<h; ++y, ++idy.y, ++idxy.y)
1201 typename TMPITER::row_iterator sr = idy.rowIterator();
1202 typename TMPITER::row_iterator dr = idxy.rowIterator();
1203 resizeImageInternalSplineGradient(sr, sr+w, ta,
1207 double du = (double)(w-1) / (wnew-1);
1208 double dv = (double)(h-1) / (hnew-1);
1213 DestIterator xxd = id, yyd = id;
1215 static Diff2D down(0,1), right(1,0), downright(1,1);
1217 for(y=0; y<h-1; ++y, ++in.y, ov -= 1.0)
1219 if(y < h-2 && ov >= 1.0)
continue;
1226 SrcIterator xs = in;
1227 for(x=0; x<w-1; ++x, ++xs.x, ou -= 1.0)
1229 if(x < w-2 && ou >= 1.0)
continue;
1233 DestIterator xd =
id + Diff2D(ox,oy);
1236 W[0][2] = sa(xs, down);
1237 W[0][3] = dy(x, y1);
1239 W[1][1] = dxy(x, y);
1240 W[1][2] = dx(x, y1);
1241 W[1][3] = dxy(x, y1);
1242 W[2][0] = sa(xs, right);
1244 W[2][2] = sa(xs, downright);
1245 W[2][3] = dy(x1, y1);
1246 W[3][0] = dx(x1, y);
1247 W[3][1] = dxy(x1, y);
1248 W[3][2] = dx(x1, y1);
1249 W[3][3] = dxy(x1, y1);
1255 W1[j][i] = ig[j] * W[0][i];
1258 W1[j][i] += ig[j+4*k] * W[k][i];
1266 W[j][i] = ig[i] * W1[j][0];
1269 W[j][i] += ig[4*k+i] * W1[j][k];
1274 TMPTYPE a1,a2,a3,a4;
1277 for(v=ov, yy=oy; v<1.0; v+=dv, ++yyd.y, ++yy)
1279 a1 = W[0][0] + v * (W[0][1] +
1280 v * (W[0][2] + v * W[0][3]));
1281 a2 = W[1][0] + v * (W[1][1] +
1282 v * (W[1][2] + v * W[1][3]));
1283 a3 = W[2][0] + v * (W[2][1] +
1284 v * (W[2][2] + v * W[2][3]));
1285 a4 = W[3][0] + v * (W[3][1] +
1286 v * (W[3][2] + v * W[3][3]));
1289 for(u=ou, xx=ox; u<1.0; u+=du, ++xxd.x, ++xx)
1291 da.set(DestTraits::fromRealPromote(a1 + u * (a2 + u * (a3 + u * a4))), xxd);
1296 da.set(DestTraits::fromRealPromote(a1 + a2 + a3 + a4), xxd);
1302 a1 = W[0][0] + W[0][1] + W[0][2] + W[0][3];
1303 a2 = W[1][0] + W[1][1] + W[1][2] + W[1][3];
1304 a3 = W[2][0] + W[2][1] + W[2][2] + W[2][3];
1305 a4 = W[3][0] + W[3][1] + W[3][2] + W[3][3];
1307 DestIterator xxd = yyd;
1308 for(u=ou, xx=ox; u<1.0; u+=du, ++xxd.x, ++xx)
1310 da.set(DestTraits::fromRealPromote(a1 + u * (a2 + u * (a3 + u * a4))), xxd);
1315 da.set(DestTraits::fromRealPromote(a1 + a2 + a3 + a4), xxd);
1327 template <
class SrcIterator,
class SrcAccessor,
1328 class DestIterator,
class DestAccessor>
1331 DestIterator
id, DestIterator idend, DestAccessor da)
1333 int w = iend.x - is.x;
1334 int h = iend.y - is.y;
1336 int wnew = idend.x -
id.x;
1337 int hnew = idend.y -
id.y;
1339 vigra_precondition((w > 3) && (h > 3),
1340 "resizeImageSplineInterpolation(): "
1341 "Source image too small.\n");
1342 vigra_precondition((wnew > 1) && (hnew > 1),
1343 "resizeImageSplineInterpolation(): "
1344 "Destination image too small.\n");
1348 if(wnew < w || hnew < h)
1350 typedef typename SrcAccessor::value_type SRCVT;
1351 typedef typename NumericTraits<SRCVT>::RealPromote TMPTYPE;
1352 typedef typename BasicImage<TMPTYPE>::Iterator TMPITER;
1354 BasicImage<TMPTYPE> t(w,h);
1355 TMPITER it = t.upperLeft();
1360 it, t.accessor(), (double)w/wnew/scale);
1365 it, t.accessor(), (double)h/hnew/scale);
1371 it, t.accessor(), (double)h/hnew/scale);
1374 resizeImageInternalSplineInterpolation(it, t.lowerRight(), t.accessor(),
1379 resizeImageInternalSplineInterpolation(is, iend, sa,
id, idend, da);
1383 template <
class SrcIterator,
class SrcAccessor,
1384 class DestIterator,
class DestAccessor>
1388 triple<DestIterator, DestIterator, DestAccessor> dest)
1391 dest.first, dest.second, dest.third);
1393 #endif // old algorithm version
1399 #endif // VIGRA_RESIZEIMAGE_HXX