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 to small.\n");
281 vigra_precondition((wnew > 1) && (hnew > 1),
282 "resizeImageNoInterpolation(): "
283 "Destination image to 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 to small.\n");
476 vigra_precondition((wnew > 1) && (hnew > 1),
477 "resizeImageLinearInterpolation(): "
478 "Destination image to 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 to small.\n");
685 vigra_precondition((width_new > 1) && (height_new > 1),
686 "resizeImageSplineInterpolation(): "
687 "Destination image to 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 DestIterator dest = dest_iter;
767 kernels.resize(xperiod);
768 createResamplingKernels(spline, xmapCoordinate, kernels);
770 for(y=0; y < height_new; ++y, ++y_tmp.y, ++dest_iter.y)
772 typename DestIterator::row_iterator r_dest = dest_iter.rowIterator();
773 typename TmpImageIterator::row_iterator r_tmp = y_tmp.rowIterator();
775 if(prefilterCoeffs.size() == 0)
777 if(width_new >= width_old)
780 r_dest, r_dest + width_new, dest_acc,
781 kernels, xmapCoordinate);
786 line_tmp, line.accessor(), (double)width_old/width_new/scale);
788 r_dest, r_dest + width_new, dest_acc,
789 kernels, xmapCoordinate);
795 line_tmp, line.accessor(),
796 prefilterCoeffs[0], BORDER_TREATMENT_REFLECT);
797 for(
unsigned int b = 1; b < prefilterCoeffs.size(); ++b)
800 line_tmp, line.accessor(),
801 prefilterCoeffs[b], BORDER_TREATMENT_REFLECT);
803 if(width_new < width_old)
806 line_tmp, line.accessor(), (double)width_old/width_new/scale);
809 r_dest, r_dest + width_new, dest_acc,
810 kernels, xmapCoordinate);
815 template <
class SrcIterator,
class SrcAccessor,
816 class DestIterator,
class DestAccessor,
821 triple<DestIterator, DestIterator, DestAccessor> dest,
822 SPLINE
const & spline)
825 dest.first, dest.second, dest.third, spline);
828 template <
class SrcIterator,
class SrcAccessor,
829 class DestIterator,
class DestAccessor>
832 DestIterator
id, DestIterator idend, DestAccessor da)
837 template <
class SrcIterator,
class SrcAccessor,
838 class DestIterator,
class DestAccessor>
842 triple<DestIterator, DestIterator, DestAccessor> dest)
845 dest.first, dest.second, dest.third);
893 template <
class SrcIterator,
class SrcAccessor,
894 class DestIterator,
class DestAccessor>
897 DestIterator dest_iter, DestIterator dest_iter_end, DestAccessor dest_acc)
900 CatmullRomSpline<double>());
903 template <
class SrcIterator,
class SrcAccessor,
904 class DestIterator,
class DestAccessor>
908 triple<DestIterator, DestIterator, DestAccessor> dest)
911 dest.first, dest.second, dest.third);
932 template <
class SrcIterator,
class SrcAccessor,
933 class DestIterator,
class DestAccessor>
935 resizeImageCubicInterpolation(SrcIterator src_iter, SrcIterator src_iter_end, SrcAccessor src_acc,
936 DestIterator dest_iter, DestIterator dest_iter_end, DestAccessor dest_acc)
939 BSpline<3, double>());
942 template <
class SrcIterator,
class SrcAccessor,
943 class DestIterator,
class DestAccessor>
946 resizeImageCubicInterpolation(triple<SrcIterator, SrcIterator, SrcAccessor> src,
947 triple<DestIterator, DestIterator, DestAccessor> dest)
949 resizeImageCubicInterpolation(src.first, src.second, src.third,
950 dest.first, dest.second, dest.third);
999 template <
class SrcIterator,
class SrcAccessor,
1000 class DestIterator,
class DestAccessor>
1003 DestIterator dest_iter, DestIterator dest_iter_end, DestAccessor dest_acc)
1006 CoscotFunction<double>());
1009 template <
class SrcIterator,
class SrcAccessor,
1010 class DestIterator,
class DestAccessor>
1014 triple<DestIterator, DestIterator, DestAccessor> dest)
1017 dest.first, dest.second, dest.third);
1021 #if 0 // old version of the spline interpolation algorithm
1030 template <
class SrcIterator,
class SrcAccessor,
class VALUETYPE>
1032 resizeCalculateSplineCoefficients(SrcIterator i1, SrcIterator iend,
1033 SrcAccessor a, VALUETYPE * i2)
1039 VALUETYPE zero = NumericTraits<VALUETYPE>::zero();
1040 VALUETYPE two = 2.0 * NumericTraits<VALUETYPE>::one();
1041 VALUETYPE half = 0.5 * NumericTraits<VALUETYPE>::one();
1046 std::vector<VALUETYPE> vec(n);
1047 typename std::vector<VALUETYPE>::iterator u = vec.begin();
1051 for(++i1, ++i2, ++u, --iend; i1 != iend; ++i1, ++i2, ++u)
1053 VALUETYPE p = 0.5 * i2[-1] + two;
1055 *u = 3.0 *(a(i1,1) - 2.0 * a(i1) + a(i1, -1)) - 0.5 * u[-1] / p;
1060 for(--i2, --u; u != vec; --u, --i2)
1062 *i2 = *i2 * i2[1] + *u;
1072 template <
class SrcIterator,
class SrcAccessor,
1073 class DoubleIterator,
class TempIterator,
class DestIterator>
1075 resizeImageInternalSplineGradient(SrcIterator in, SrcIterator inend, SrcAccessor sa,
1076 DoubleIterator tmp, TempIterator r, DestIterator
id)
1082 typedef typename SrcAccessor::value_type SRCVT;
1083 typedef typename NumericTraits<SRCVT>::RealPromote TMPTYPE;
1086 SrcIterator xs = in;
1087 TMPTYPE p0 = -11.0/6.0 * sa(xs); ++xs;
1088 p0 += 3.0 * sa(xs); ++xs;
1089 p0 += -1.5 * sa(xs); ++xs;
1090 p0 += 1.0/3.0 * sa(xs);
1093 TMPTYPE pw = 11.0/6.0 * sa(xs); --xs;
1094 pw += -3.0 * sa(xs); --xs;
1095 pw += 1.5 * sa(xs); --xs;
1096 pw += -1.0/3.0 * sa(xs);
1099 SrcIterator xs1 = in;
1101 for(x=1; x<w-1; ++x, ++xs, ++xs1)
1103 r[x] = 3.0 * (sa(xs) - sa(xs1));
1113 id[1] = 0.25 * r[1];
1115 for(x=2; x<w-1; ++x)
1118 q = 1.0 / (4.0 - q);
1119 id[x] = q * (r[x] -
id[x-1]);
1122 for(x=w-3; x>=1; --x)
1124 id[x] -= tmp[x+1]*
id[x+1];
1134 template <
class SrcIterator,
class SrcAccessor,
1135 class DestIterator,
class DestAccessor>
1137 resizeImageInternalSplineInterpolation(SrcIterator is, SrcIterator iend, SrcAccessor sa,
1138 DestIterator
id, DestIterator idend, DestAccessor da)
1140 int w = iend.x - is.x;
1141 int h = iend.y - is.y;
1143 int wnew = idend.x -
id.x;
1144 int hnew = idend.y -
id.y;
1146 typedef typename SrcAccessor::value_type SRCVT;
1147 typedef typename NumericTraits<SRCVT>::RealPromote TMPTYPE;
1148 typedef typename BasicImage<TMPTYPE>::Iterator TMPITER;
1150 NumericTraits<typename DestAccessor::value_type> DestTraits;
1152 BasicImage<TMPTYPE> dx(w,h);
1153 BasicImage<TMPTYPE> dy(w,h);
1154 BasicImage<TMPTYPE> dxy(w,h);
1155 BasicImage<TMPTYPE> W(4,4), W1(4,4);
1156 std::vector<TMPTYPE> R(w > h ? w : h);
1157 std::vector<double> tmp(w > h ? w : h);
1159 typename BasicImage<TMPTYPE>::Accessor ta;
1161 SrcIterator in = is;
1163 TMPITER idx = dx.upperLeft();
1164 TMPITER idy = dy.upperLeft();
1165 TMPITER idxy = dxy.upperLeft();
1166 typename std::vector<TMPTYPE>::iterator r = R.begin();
1167 typename std::vector<double>::iterator it = tmp.begin();
1169 double ig[] = { 1.0, 0.0, -3.0, 2.0,
1170 0.0, 1.0, -2.0, 1.0,
1171 0.0, 0.0, 3.0, -2.0,
1172 0.0, 0.0, -1.0, 1.0 };
1178 for(y=0; y<h; ++y, ++in.y, ++idx.y)
1180 typename SrcIterator::row_iterator sr = in.rowIterator();
1181 typename TMPITER::row_iterator dr = idx.rowIterator();
1182 resizeImageInternalSplineGradient(sr, sr+w, sa,
1189 for(x=0; x<w; ++x, ++in.x, ++idy.x)
1191 typename SrcIterator::column_iterator sc = in.columnIterator();
1192 typename TMPITER::column_iterator dc = idy.columnIterator();
1193 resizeImageInternalSplineGradient(sc, sc+h, sa,
1198 idy = dy.upperLeft();
1201 for(y=0; y<h; ++y, ++idy.y, ++idxy.y)
1203 typename TMPITER::row_iterator sr = idy.rowIterator();
1204 typename TMPITER::row_iterator dr = idxy.rowIterator();
1205 resizeImageInternalSplineGradient(sr, sr+w, ta,
1209 double du = (double)(w-1) / (wnew-1);
1210 double dv = (double)(h-1) / (hnew-1);
1215 DestIterator xxd = id, yyd = id;
1217 static Diff2D down(0,1), right(1,0), downright(1,1);
1219 for(y=0; y<h-1; ++y, ++in.y, ov -= 1.0)
1221 if(y < h-2 && ov >= 1.0)
continue;
1228 SrcIterator xs = in;
1229 for(x=0; x<w-1; ++x, ++xs.x, ou -= 1.0)
1231 if(x < w-2 && ou >= 1.0)
continue;
1235 DestIterator xd =
id + Diff2D(ox,oy);
1238 W[0][2] = sa(xs, down);
1239 W[0][3] = dy(x, y1);
1241 W[1][1] = dxy(x, y);
1242 W[1][2] = dx(x, y1);
1243 W[1][3] = dxy(x, y1);
1244 W[2][0] = sa(xs, right);
1246 W[2][2] = sa(xs, downright);
1247 W[2][3] = dy(x1, y1);
1248 W[3][0] = dx(x1, y);
1249 W[3][1] = dxy(x1, y);
1250 W[3][2] = dx(x1, y1);
1251 W[3][3] = dxy(x1, y1);
1257 W1[j][i] = ig[j] * W[0][i];
1260 W1[j][i] += ig[j+4*k] * W[k][i];
1268 W[j][i] = ig[i] * W1[j][0];
1271 W[j][i] += ig[4*k+i] * W1[j][k];
1276 TMPTYPE a1,a2,a3,a4;
1279 for(v=ov, yy=oy; v<1.0; v+=dv, ++yyd.y, ++yy)
1281 a1 = W[0][0] + v * (W[0][1] +
1282 v * (W[0][2] + v * W[0][3]));
1283 a2 = W[1][0] + v * (W[1][1] +
1284 v * (W[1][2] + v * W[1][3]));
1285 a3 = W[2][0] + v * (W[2][1] +
1286 v * (W[2][2] + v * W[2][3]));
1287 a4 = W[3][0] + v * (W[3][1] +
1288 v * (W[3][2] + v * W[3][3]));
1291 for(u=ou, xx=ox; u<1.0; u+=du, ++xxd.x, ++xx)
1293 da.set(DestTraits::fromRealPromote(a1 + u * (a2 + u * (a3 + u * a4))), xxd);
1298 da.set(DestTraits::fromRealPromote(a1 + a2 + a3 + a4), xxd);
1304 a1 = W[0][0] + W[0][1] + W[0][2] + W[0][3];
1305 a2 = W[1][0] + W[1][1] + W[1][2] + W[1][3];
1306 a3 = W[2][0] + W[2][1] + W[2][2] + W[2][3];
1307 a4 = W[3][0] + W[3][1] + W[3][2] + W[3][3];
1309 DestIterator xxd = yyd;
1310 for(u=ou, xx=ox; u<1.0; u+=du, ++xxd.x, ++xx)
1312 da.set(DestTraits::fromRealPromote(a1 + u * (a2 + u * (a3 + u * a4))), xxd);
1317 da.set(DestTraits::fromRealPromote(a1 + a2 + a3 + a4), xxd);
1329 template <
class SrcIterator,
class SrcAccessor,
1330 class DestIterator,
class DestAccessor>
1333 DestIterator
id, DestIterator idend, DestAccessor da)
1335 int w = iend.x - is.x;
1336 int h = iend.y - is.y;
1338 int wnew = idend.x -
id.x;
1339 int hnew = idend.y -
id.y;
1341 vigra_precondition((w > 3) && (h > 3),
1342 "resizeImageSplineInterpolation(): "
1343 "Source image to small.\n");
1344 vigra_precondition((wnew > 1) && (hnew > 1),
1345 "resizeImageSplineInterpolation(): "
1346 "Destination image to small.\n");
1350 if(wnew < w || hnew < h)
1352 typedef typename SrcAccessor::value_type SRCVT;
1353 typedef typename NumericTraits<SRCVT>::RealPromote TMPTYPE;
1354 typedef typename BasicImage<TMPTYPE>::Iterator TMPITER;
1356 BasicImage<TMPTYPE> t(w,h);
1357 TMPITER it = t.upperLeft();
1362 it, t.accessor(), (double)w/wnew/scale);
1367 it, t.accessor(), (double)h/hnew/scale);
1373 it, t.accessor(), (double)h/hnew/scale);
1376 resizeImageInternalSplineInterpolation(it, t.lowerRight(), t.accessor(),
1381 resizeImageInternalSplineInterpolation(is, iend, sa,
id, idend, da);
1385 template <
class SrcIterator,
class SrcAccessor,
1386 class DestIterator,
class DestAccessor>
1390 triple<DestIterator, DestIterator, DestAccessor> dest)
1393 dest.first, dest.second, dest.third);
1395 #endif // old alghorithm version
1401 #endif // VIGRA_RESIZEIMAGE_HXX