00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043 #ifndef IMAGE_SHAPEOPS_C_DEFINED
00044 #define IMAGE_SHAPEOPS_C_DEFINED
00045
00046 #include "Image/ShapeOps.H"
00047
00048 #include "Image/CutPaste.H"
00049 #include "Image/FilterOps.H"
00050 #include "Image/Image.H"
00051 #include "Image/Pixels.H"
00052 #include "Image/vec2.h"
00053 #include "Util/Assert.H"
00054 #include "Util/StringUtil.H"
00055 #include "Util/log.H"
00056 #include "Util/safecopy.H"
00057 #include "rutz/trace.h"
00058
00059 #include <algorithm>
00060 #include <cmath>
00061 #include <limits>
00062 #include <vector>
00063
00064 #define ADD_RGB(buf,Weight,bWeight,in) do { \
00065 *buf += *in * (Weight); \
00066 *bWeight += Weight; } while (0);
00067
00068
00069 template <class T>
00070 Image<T> quickLocalAvg(const Image<T>& array, const int scale)
00071 {
00072 GVX_TRACE(__PRETTY_FUNCTION__);
00073
00074 ASSERT(array.initialized());
00075 int lw = array.getWidth(), lh = array.getHeight();
00076 int sw = std::max(1, lw / scale), sh = std::max(1, lh / scale);
00077 int scalex = lw / sw, scaley = lh / sh;
00078 int remx = lw - 1 - (lw % sw), remy = lh - 1 - (lh % sh);
00079
00080 typedef typename promote_trait<T, float>::TP TF;
00081 Image<TF> result(sw, sh, ZEROS);
00082
00083 int i, j, ci = 0, cj = 0; float fac = 1.0f / float(scale * scale);
00084 typename Image<T>::const_iterator lptr = array.begin();
00085 typename Image<TF>::iterator dptr = result.beginw();
00086
00087 for (j = 0; j < lh; ++j)
00088 {
00089 for (i = 0; i < lw; ++i)
00090 {
00091 *dptr += (*lptr++);
00092 if ((++ci) == scalex && i != remx) { ci = 0; ++dptr; }
00093 }
00094 if (ci) { ci = 0; ++dptr; }
00095 if ( (++cj) == scaley && j != remy) cj = 0; else dptr -= sw;
00096 }
00097
00098 Image<T> ret = result * fac;
00099 return ret;
00100 }
00101
00102
00103 template <class T>
00104 Image<T> quickLocalAvg2x2(const Image<T>& src)
00105 {
00106 const int w = src.getWidth();
00107 const int h = src.getHeight();
00108
00109 const int nw = w / 2;
00110 const int nh = h / 2;
00111
00112 Image<T> result(nw, nh, ZEROS);
00113
00114 typename Image<T>::const_iterator sptr = src.begin();
00115 typename Image<T>::iterator dptr = result.beginw();
00116
00117 for (int y = 0; y < nh; ++y)
00118 {
00119 typename Image<T>::const_iterator sptr2 = sptr + y*2*w;
00120 for (int x = 0; x < nw; ++x)
00121 {
00122 *dptr++ = T((sptr2[0] + sptr2[1] + sptr2[w] + sptr2[w+1]) * 0.25);
00123 sptr2 += 2;
00124 }
00125 }
00126
00127 return result;
00128 }
00129
00130
00131
00132 namespace
00133 {
00134 template <class T>
00135 T element_wise_max(const T& t1, const T& t2)
00136 {
00137 return std::max(t1, t2);
00138 }
00139
00140 template <class T>
00141 PixRGB<T> element_wise_max(const PixRGB<T>& t1,
00142 const PixRGB<T>& t2)
00143 {
00144 return PixRGB<T>(std::max(t1.red(), t2.red()),
00145 std::max(t1.green(), t2.green()),
00146 std::max(t1.blue(), t2.blue()));
00147 }
00148 }
00149
00150 template <class T>
00151 Image<T> quickLocalMax(const Image<T>& array, const int scale)
00152 {
00153 GVX_TRACE(__PRETTY_FUNCTION__);
00154
00155 ASSERT(array.initialized());
00156 int lw = array.getWidth(), lh = array.getHeight();
00157 int sw = std::max(1, lw / scale), sh = std::max(1, lh / scale);
00158 int scalex = lw / sw, scaley = lh / sh;
00159 int remx = lw - 1 - (lw % sw), remy = lh - 1 - (lh % sh);
00160 Image<T> result(sw, sh, ZEROS);
00161 int i, j, ci = 0, cj = 0;
00162 typename Image<T>::const_iterator lptr = array.begin();
00163 typename Image<T>::iterator dptr = result.beginw();
00164
00165 for (j = 0; j < lh; ++j)
00166 {
00167 for (i = 0; i < lw; ++i)
00168 {
00169 *dptr = element_wise_max(*dptr, *lptr);
00170 ++lptr;
00171 if ((++ci) == scalex && i != remx) { ci = 0; ++dptr; }
00172 }
00173 if (ci) { ci = 0; ++dptr; }
00174 if ((++cj) == scaley && j != remy) cj = 0; else dptr -= sw;
00175 }
00176 return result;
00177 }
00178
00179
00180
00181 namespace
00182 {
00183 template <class T>
00184 T element_wise_min(const T& t1, const T& t2)
00185 {
00186 return std::min(t1, t2);
00187 }
00188
00189 template <class T>
00190 PixRGB<T> element_wise_min(const PixRGB<T>& t1,
00191 const PixRGB<T>& t2)
00192 {
00193 return PixRGB<T>(std::min(t1.red(), t2.red()),
00194 std::min(t1.green(), t2.green()),
00195 std::min(t1.blue(), t2.blue()));
00196 }
00197 }
00198
00199 template <class T>
00200 Image<T> quickLocalMin(const Image<T>& array, const int scale)
00201 {
00202 GVX_TRACE(__PRETTY_FUNCTION__);
00203
00204 ASSERT(array.initialized());
00205 int lw = array.getWidth(), lh = array.getHeight();
00206 int sw = std::max(1, lw / scale), sh = std::max(1, lh / scale);
00207 int scalex = lw / sw, scaley = lh / sh;
00208 int remx = lw - 1 - (lw % sw), remy = lh - 1 - (lh % sh);
00209 Image<T> result(sw, sh, ZEROS);
00210 int i, j, ci = 0, cj = 0;
00211 typename Image<T>::const_iterator lptr = array.begin();
00212 typename Image<T>::iterator dptr = result.beginw();
00213
00214 for (j = 0; j < lh; ++j)
00215 {
00216 for (i = 0; i < lw; ++i)
00217 {
00218 *dptr = element_wise_min(*dptr, *lptr);
00219 ++lptr;
00220 if ((++ci) == scalex && i != remx) { ci = 0; ++dptr; }
00221 }
00222 if (ci) { ci = 0; ++dptr; }
00223 if ((++cj) == scaley && j != remy) cj = 0; else dptr -= sw;
00224 }
00225 return result;
00226 }
00227
00228
00229 template <class T>
00230 Image<T> quickInterpolate(const Image<T>& src, const int sfactor)
00231 {
00232 GVX_TRACE(__PRETTY_FUNCTION__);
00233
00234 ASSERT(src.initialized()); ASSERT(sfactor >= 2);
00235 const int sw = src.getWidth();
00236 const int sh = src.getHeight();
00237 int lw = sw * sfactor, lh = sh * sfactor;
00238 Image<T> result(lw, lh, NO_INIT);
00239 int i, j, ci = 0, cj = 0;
00240 typename Image<T>::iterator lptr = result.beginw();
00241 typename Image<T>::const_iterator sptr = src.begin();
00242
00243 for (j = 0; j < lh; ++j)
00244 {
00245 for (i = 0; i < lw; ++i)
00246 {
00247 *lptr++ = *sptr;
00248 if ((++ci) == sfactor) { ci = 0; ++sptr; }
00249 }
00250 if ((++cj) == sfactor) cj = 0; else sptr -= sw;
00251 }
00252
00253 return result;
00254 }
00255
00256
00257 template <class T>
00258 Image<T> interpolate(const Image<T>& src)
00259 {
00260 GVX_TRACE(__PRETTY_FUNCTION__);
00261
00262 ASSERT(src.initialized());
00263 const int sw = src.getWidth(), sh = src.getHeight();
00264 const int dw = sw * 2, dh = sh * 2;
00265 Image<T> result(dw, dh, NO_INIT);
00266
00267 typename Image<T>::const_iterator sptr = src.begin();
00268 typename Image<T>::iterator dptr = result.beginw();
00269
00270
00271 for (int j = 0; j < sh-1; j ++)
00272 {
00273
00274 for (int i = 0; i < sw-1; i ++)
00275 {
00276
00277 dptr[0] = sptr[0];
00278
00279
00280 dptr[dw] = T( (sptr[0] + sptr[sw]) * 0.5F );
00281
00282
00283 dptr[1] = T( (sptr[0] + sptr[1]) * 0.5F );
00284
00285
00286 dptr[dw+1] = T( (sptr[0] + sptr[1] + sptr[sw] + sptr[sw+1])*0.25F );
00287
00288 dptr += 2; ++sptr;
00289 }
00290
00291
00292
00293
00294 dptr[0] = sptr[0];
00295
00296
00297 dptr[dw] = T( (sptr[0] + sptr[sw]) * 0.5F );
00298
00299
00300 dptr[1] = T( sptr[0] * 0.75F );
00301
00302
00303 dptr[dw+1] = T( dptr[dw] * 0.75F );
00304
00305 dptr += 2 + dw; ++sptr;
00306 }
00307
00308
00309 for (int i = 0; i < sw-1; i ++)
00310 {
00311
00312 dptr[0] = sptr[0];
00313
00314
00315 dptr[dw] = T( sptr[0] * 0.75F );
00316
00317
00318 dptr[1] = T( (sptr[0] + sptr[1]) * 0.5F );
00319
00320
00321 dptr[dw+1] = T( dptr[1] * 0.75F );
00322
00323 dptr += 2; ++sptr;
00324 }
00325
00326
00327
00328
00329 dptr[0] = sptr[0];
00330
00331
00332 dptr[dw] = T( sptr[0] * 0.75F );
00333
00334
00335 dptr[1] = T( sptr[0] * 0.75F );
00336
00337
00338 dptr[dw+1] = T( sptr[0] * 0.5F );
00339
00340 return result;
00341 }
00342
00343
00344 template <class T>
00345 Image<T> rescaleBilinear(const Image<T>& src, const Dims& dims)
00346 {
00347 return rescaleBilinear(src, dims.w(), dims.h());
00348 }
00349
00350
00351 template <class T>
00352 Image<T> rescaleBilinear(const Image<T>& src, const int new_w, const int new_h)
00353 {
00354 GVX_TRACE(__PRETTY_FUNCTION__);
00355
00356 ASSERT(src.initialized()); ASSERT(new_w > 0 && new_h > 0);
00357
00358 const int orig_w = src.getWidth();
00359 const int orig_h = src.getHeight();
00360
00361
00362 if (new_w == orig_w && new_h == orig_h) return src;
00363
00364 const float sw = float(orig_w) / float(new_w);
00365 const float sh = float(orig_h) / float(new_h);
00366
00367 Image<T> result(new_w, new_h, NO_INIT);
00368 typename Image<T>::iterator dptr = result.beginw();
00369 typename Image<T>::const_iterator const sptr = src.begin();
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
00381
00382 for (int j = 0; j < new_h; ++j)
00383 {
00384 const float y = std::max(0.0f, (j+0.5f) * sh - 0.5f);
00385
00386 const int y0 = int(y);
00387 const int y1 = std::min(y0 + 1, orig_h - 1);
00388
00389 const float fy = y - float(y0);
00390
00391 const int wy0 = orig_w * y0;
00392 const int wy1 = orig_w * y1;
00393
00394 for (int i = 0; i < new_w; ++i)
00395 {
00396 const float x = std::max(0.0f, (i+0.5f) * sw - 0.5f);
00397
00398 const int x0 = int(x);
00399 const int x1 = std::min(x0 + 1, orig_w - 1);
00400
00401 const float fx = x - float(x0);
00402
00403 typename promote_trait<T, float>::TP const
00404 d00( sptr[x0 + wy0] ), d10( sptr[x1 + wy0] ),
00405 d01( sptr[x0 + wy1] ), d11( sptr[x1 + wy1] ),
00406 dx0( d00 + (d10 - d00) * fx ),
00407 dx1( d01 + (d11 - d01) * fx );
00408
00409 *dptr++ = T( dx0 + (dx1 - dx0) * fy );
00410 }
00411 }
00412 return result;
00413 }
00414
00415
00416
00417
00418
00419
00420
00421
00422 template <>
00423 Image<PixRGB<byte> > rescaleBilinear(const Image<PixRGB<byte> >& src,
00424 const int new_w, const int new_h)
00425 {
00426 GVX_TRACE(__PRETTY_FUNCTION__);
00427
00428 ASSERT(src.initialized()); ASSERT(new_w > 0 && new_h > 0);
00429
00430 const int orig_w = src.getWidth();
00431 const int orig_h = src.getHeight();
00432
00433
00434 if (new_w == orig_w && new_h == orig_h) return src;
00435
00436 const float sw = float(orig_w) / float(new_w);
00437 const float sh = float(orig_h) / float(new_h);
00438
00439 Image<PixRGB<byte> > result(new_w, new_h, NO_INIT);
00440 Image<PixRGB<byte> >::iterator dptr = result.beginw();
00441 Image<PixRGB<byte> >::const_iterator const sptr = src.begin();
00442
00443 for (int j = 0; j < new_h; ++j)
00444 {
00445 const float y = std::max(0.0f, (j+0.5f) * sh - 0.5f);
00446
00447 const int y0 = int(y);
00448 const int y1 = std::min(y0 + 1, orig_h - 1);
00449
00450 const float fy = y - float(y0);
00451
00452 const int wy0 = orig_w * y0;
00453 const int wy1 = orig_w * y1;
00454
00455 for (int i = 0; i < new_w; ++i)
00456 {
00457 const float x = std::max(0.0f, (i+0.5f) * sw - 0.5f);
00458
00459 const int x0 = int(x);
00460 const int x1 = std::min(x0 + 1, orig_w - 1);
00461
00462 const float fx = x - float(x0);
00463
00464
00465
00466
00467
00468
00469
00470
00471
00472
00473
00474 #define RGB_BILINEAR_INTERP(EL) \
00475 do { \
00476 const float \
00477 d00( sptr[x0 + wy0].p[EL] ), d10( sptr[x1 + wy0].p[EL] ), \
00478 d01( sptr[x0 + wy1].p[EL] ), d11( sptr[x1 + wy1].p[EL] ); \
00479 \
00480 const float \
00481 dx0( d00 + (d10 - d00) * fx ), \
00482 dx1( d01 + (d11 - d01) * fx ); \
00483 \
00484 dptr->p[EL] = byte( dx0 + (dx1 - dx0) * fy ); \
00485 } while(0)
00486
00487 RGB_BILINEAR_INTERP(0);
00488 RGB_BILINEAR_INTERP(1);
00489 RGB_BILINEAR_INTERP(2);
00490
00491 #undef RGB_BILINEAR_INTERP
00492
00493 ++dptr;
00494 }
00495 }
00496 return result;
00497 }
00498
00499
00500 template <class T>
00501 Image<T> rescaleNI(const Image<T>& src, const Dims& dims)
00502 {
00503 return rescaleNI(src, dims.w(), dims.h());
00504 }
00505
00506
00507 template <class T>
00508 Image<T> rescaleNI(const Image<T>& src, const int new_w, const int new_h)
00509 {
00510 GVX_TRACE(__PRETTY_FUNCTION__);
00511
00512 ASSERT(src.initialized()); ASSERT(new_w > 0 && new_h > 0);
00513
00514 const int orig_w = src.getWidth();
00515 const int orig_h = src.getHeight();
00516
00517
00518 if (new_w == orig_w && new_h == orig_h) return src;
00519
00520
00521
00522 if (new_w >= orig_w && (new_w % orig_w) == 0
00523 &&
00524 new_h >= orig_h && (new_h % orig_h) == 0)
00525 return zoomXY(src, new_w / orig_w, new_h / orig_h);
00526
00527
00528
00529 if (new_w <= orig_w && (orig_w % new_w) == 0
00530 &&
00531 new_h <= orig_h && (orig_h % new_h) == 0)
00532 return decXY(src, orig_w / new_w, orig_h / new_h);
00533
00534 const float sw = float(orig_w) / float(new_w);
00535 const float sh = float(orig_h) / float(new_h);
00536
00537 Image<T> result(new_w, new_h, NO_INIT);
00538 typename Image<T>::iterator dptr = result.beginw();
00539 typename Image<T>::const_iterator const sptr = src.begin();
00540
00541 for (int j = 0; j < new_h; ++j)
00542 for (int i = 0; i < new_w; ++i)
00543 *dptr++ = sptr[int(j * sh) * orig_w + int(i * sw)];
00544 return result;
00545 }
00546
00547
00548 RescaleType getRescaleTypeFromChar(char ftype)
00549 {
00550 switch (ftype)
00551 {
00552 case 'o': return RESCALE_SIMPLE_NOINTERP;
00553 case 'r': return RESCALE_SIMPLE_BILINEAR;
00554 case 'b': return RESCALE_FILTER_BOX;
00555 case 't': return RESCALE_FILTER_TRIANGLE;
00556 case 'q': return RESCALE_FILTER_BELL;
00557 case 'B': return RESCALE_FILTER_BSPLINE;
00558 case 'h': return RESCALE_FILTER_HERMITE;
00559 case 'l': return RESCALE_FILTER_LANCZOS3;
00560 case 'm': return RESCALE_FILTER_MITCHELL;
00561 default: LFATAL("invalid rescale type char '%c'", ftype);
00562 }
00563 ASSERT(0); return (RescaleType) -1;
00564 }
00565
00566
00567 std::string convertToString(RescaleType ftype)
00568 {
00569 switch (ftype)
00570 {
00571 case RESCALE_SIMPLE_NOINTERP: return "Nointerp";
00572 case RESCALE_SIMPLE_BILINEAR: return "Bilinear";
00573 case RESCALE_FILTER_BOX : return "Box";
00574 case RESCALE_FILTER_TRIANGLE: return "Triangle";
00575 case RESCALE_FILTER_BELL : return "Bell";
00576 case RESCALE_FILTER_BSPLINE : return "Bspline";
00577 case RESCALE_FILTER_HERMITE : return "Hermite";
00578 case RESCALE_FILTER_LANCZOS3: return "Lanczos3";
00579 case RESCALE_FILTER_MITCHELL: return "Mitchell";
00580 default: LFATAL("invalid rescale type %d", int(ftype));
00581 }
00582 ASSERT(0); return std::string();
00583 }
00584
00585
00586 void convertFromString(const std::string& str1, RescaleType& ftype)
00587 {
00588 const std::string str = toLowerCase(str1);
00589
00590 if (str.compare("nointerp") == 0) ftype = RESCALE_SIMPLE_NOINTERP;
00591 else if (str.compare("bilinear") == 0) ftype = RESCALE_SIMPLE_BILINEAR;
00592 else if (str.compare("box") == 0) ftype = RESCALE_FILTER_BOX ;
00593 else if (str.compare("triangle") == 0) ftype = RESCALE_FILTER_TRIANGLE;
00594 else if (str.compare("bell") == 0) ftype = RESCALE_FILTER_BELL ;
00595 else if (str.compare("bspline") == 0) ftype = RESCALE_FILTER_BSPLINE ;
00596 else if (str.compare("hermite") == 0) ftype = RESCALE_FILTER_HERMITE ;
00597 else if (str.compare("lanczos3") == 0) ftype = RESCALE_FILTER_LANCZOS3;
00598 else if (str.compare("mitchell") == 0) ftype = RESCALE_FILTER_MITCHELL;
00599 else
00600 LFATAL("invalid rescale type '%s'", str1.c_str());
00601 }
00602
00603
00604 namespace
00605 {
00606
00607
00608 struct HermiteFilter
00609 {
00610 static double support() { return 1.0; }
00611
00612 static double filter(double t)
00613 {
00614
00615 if (t < 0.0) t = -t;
00616 if (t < 1.0) return((2.0 * t - 3.0) * t * t + 1.0);
00617 return(0.0);
00618 }
00619 };
00620
00621 struct BoxFilter
00622 {
00623 static double support() { return 0.5; }
00624
00625 static double filter(double t)
00626 {
00627 if ((t > -0.5) && (t <= 0.5)) return(1.0);
00628 return(0.0);
00629 }
00630 };
00631
00632 struct TriangleFilter
00633 {
00634 static double support() { return 1.0; }
00635
00636 static double filter(double t)
00637 {
00638 if (t < 0.0) t = -t;
00639 if (t < 1.0) return(1.0 - t);
00640 return(0.0);
00641 }
00642 };
00643
00644 struct BellFilter
00645 {
00646 static double support() { return 1.5; }
00647
00648 static double filter(double t)
00649 {
00650 if (t < 0) t = -t;
00651 if (t < .5) return(.75 - (t * t));
00652 if (t < 1.5) {
00653 t = (t - 1.5);
00654 return(.5 * (t * t));
00655 }
00656 return(0.0);
00657 }
00658 };
00659
00660 struct BsplineFilter
00661 {
00662 static double support() { return 2.0; }
00663
00664 static double filter(double t)
00665 {
00666 double tt;
00667
00668 if (t < 0) t = -t;
00669 if (t < 1) {
00670 tt = t * t;
00671 return((.5 * tt * t) - tt + (2.0 / 3.0));
00672 } else if (t < 2) {
00673 t = 2 - t;
00674 return((1.0 / 6.0) * (t * t * t));
00675 }
00676 return(0.0);
00677 }
00678 };
00679
00680 inline double sinc(double x)
00681 {
00682 x *= M_PI;
00683 if (x != 0) return(sin(x) / x);
00684 return(1.0);
00685 }
00686
00687 struct Lanczos3Filter
00688 {
00689 static double support() { return 3.0; }
00690
00691 static double filter(double t)
00692 {
00693 if (t < 0) t = -t;
00694 if (t < 3.0) return(sinc(t) * sinc(t/3.0));
00695 return(0.0);
00696 }
00697 };
00698
00699 struct MitchellFilter
00700 {
00701 static double support() { return 2.0; }
00702
00703 static double filter(double t)
00704 {
00705 #define B (1.0 / 3.0)
00706 #define C (1.0 / 3.0)
00707 double tt;
00708
00709 tt = t * t;
00710 if (t < 0) t = -t;
00711 if (t < 1.0) {
00712 t = (((12.0 - 9.0 * B - 6.0 * C) * (t * tt))
00713 + ((-18.0 + 12.0 * B + 6.0 * C) * tt)
00714 + (6.0 - 2 * B));
00715 return(t / 6.0);
00716 } else if (t < 2.0) {
00717 t = (((-1.0 * B - 6.0 * C) * (t * tt))
00718 + ((6.0 * B + 30.0 * C) * tt)
00719 + ((-12.0 * B - 48.0 * C) * t)
00720 + (8.0 * B + 24 * C));
00721 return(t / 6.0);
00722 }
00723 return(0.0);
00724 #undef B
00725 #undef C
00726 }
00727 };
00728
00729
00730
00731
00732
00733 struct CONTRIB {
00734 CONTRIB() : pixel(0), weight(0.0) {}
00735
00736 CONTRIB(int p, double w) : pixel(p), weight(w) {}
00737
00738 int pixel;
00739 double weight;
00740 };
00741
00742 struct CLIST {
00743 std::vector<CONTRIB> p;
00744
00745 void normalize()
00746 {
00747 double sum = 0.0;
00748 for (size_t i = 0; i < p.size(); ++i)
00749 sum += p[i].weight;
00750 for (size_t i = 0; i < p.size(); ++i)
00751 p[i].weight /= sum;
00752 }
00753 };
00754
00755
00756
00757
00758
00759
00760
00761
00762
00763
00764
00765 template <class F>
00766 void calc_x_contrib(CLIST* contribX,
00767 double xscale,
00768 int dstwidth,
00769 int srcwidth,
00770 int i)
00771 {
00772 if (xscale < 1.0)
00773 {
00774
00775 const double width = F::support() / xscale;
00776
00777 contribX->p.resize(0);
00778 contribX->p.reserve(int(width * 2 + 1));
00779
00780 const double center = (double) i / xscale;
00781 const int left = int(ceil(center - width)) - 1;
00782 const int right = int(floor(center + width)) + 1;
00783 for (int j = left; j <= right; ++j)
00784 {
00785 double weight = i - (double) j * xscale;
00786 weight = F::filter(weight) * xscale;
00787 const int n = clampValue(j, 0, srcwidth - 1);
00788 if (weight != 0.0)
00789 contribX->p.push_back(CONTRIB(n, weight));
00790 }
00791 contribX->normalize();
00792 }
00793 else
00794 {
00795
00796 contribX->p.resize(0);
00797 contribX->p.reserve(int(F::support() * 2 + 1));
00798
00799 const double center = (double) i / xscale;
00800 const int left = int(ceil(center - F::support())) - 1;
00801 const int right = int(floor(center + F::support())) + 1;
00802
00803 for (int j = left; j <= right; ++j)
00804 {
00805 double weight = (double) i / xscale - (double) j;
00806 weight = F::filter(weight);
00807 const int n = clampValue(j, 0, srcwidth - 1);
00808 if (weight != 0.0)
00809 contribX->p.push_back(CONTRIB(n, weight));
00810 }
00811 contribX->normalize();
00812 }
00813 }
00814
00815
00816
00817
00818
00819
00820
00821 template <class F, class T>
00822 Image<T> genericRescale(const Image<T>& src, const Dims& newdims)
00823 {
00824 typedef typename promote_trait<T, double>::TP TF;
00825
00826 Image<T> dst(newdims, ZEROS);
00827
00828 const int src_w = src.getWidth();
00829 const int src_h = src.getHeight();
00830 const int dst_w = dst.getWidth();
00831 const int dst_h = dst.getHeight();
00832
00833
00834 std::vector<TF> tmp(src_h);
00835
00836 const double xscale = (double) dst_w / (double) src_w;
00837
00838
00839
00840 std::vector<CLIST> contribY(dst_h);
00841
00842 const double yscale = (double) dst_h / (double) src_h;
00843
00844 if (yscale < 1.0)
00845 {
00846 const double width = F::support() / yscale;
00847
00848 for (int i = 0; i < dst_h; ++i)
00849 {
00850 contribY[i].p.resize(0);
00851 contribY[i].p.reserve(int(width * 2 + 1));
00852
00853 const double center = (double) i / yscale;
00854 const int left = int(ceil(center - width)) - 1;
00855 const int right = int(floor(center + width)) + 1;
00856 for (int j = left; j <= right; ++j) {
00857 double weight = i - (double) j * yscale;
00858 weight = F::filter(weight) * yscale;
00859 const int n = clampValue(j, 0, src_h -1);
00860 if (weight != 0.0)
00861 contribY[i].p.push_back(CONTRIB(n, weight));
00862 }
00863 contribY[i].normalize();
00864 }
00865 }
00866 else
00867 {
00868 for (int i = 0; i < dst_h; ++i) {
00869 contribY[i].p.resize(0);
00870 contribY[i].p.reserve(int(F::support() * 2 + 1));
00871
00872 const double center = (double) i / yscale;
00873 const int left = int(ceil(center - F::support())) - 1;
00874 const int right = int(floor(center + F::support())) + 1;
00875 for (int j = left; j <= right; ++j) {
00876 double weight = (double) i / yscale - (double) j;
00877 weight = F::filter(weight);
00878 const int n = clampValue(j, 0, src_h -1);
00879 if (weight != 0.0)
00880 contribY[i].p.push_back(CONTRIB(n, weight));
00881 }
00882 contribY[i].normalize();
00883 }
00884 }
00885
00886
00887 for (int xx = 0; xx < dst_w; ++xx)
00888 {
00889 CLIST contribX;
00890 calc_x_contrib<F>(&contribX, xscale,
00891 dst_w, src_w, xx);
00892
00893
00894 for (int k = 0; k < src_h; ++k)
00895 {
00896 TF weight = TF();
00897 bool bPelDelta = false;
00898
00899 const T* const srcrowptr =
00900 src.getArrayPtr() + k * src_w;
00901
00902 ASSERT((contribX.p[0].pixel >= 0)
00903 && (contribX.p[0].pixel < src_w));
00904
00905 const T pel = srcrowptr[contribX.p[0].pixel];
00906
00907 for (size_t j = 0; j < contribX.p.size(); ++j)
00908 {
00909 ASSERT((contribX.p[j].pixel >= 0)
00910 && (contribX.p[j].pixel < src_w));
00911
00912 const T pel2 = srcrowptr[contribX.p[j].pixel];
00913 if (pel2 != pel)
00914 bPelDelta = true;
00915 weight += TF(pel2) * contribX.p[j].weight;
00916 }
00917 tmp[k] = bPelDelta ? weight : TF(pel);
00918 }
00919
00920
00921
00922 for (int i = 0; i < dst_h; ++i)
00923 {
00924 TF weight = TF();
00925 bool bPelDelta = false;
00926 const TF pel = tmp[contribY[i].p[0].pixel];
00927
00928 for (size_t j = 0; j < contribY[i].p.size(); ++j)
00929 {
00930 const TF pel2 = tmp[contribY[i].p[j].pixel];
00931 if (pel2 != pel)
00932 bPelDelta = true;
00933 weight += pel2 * contribY[i].p[j].weight;
00934 }
00935
00936 ASSERT(xx >= 0 && xx < dst_w);
00937 ASSERT(i >= 0 && i < dst_h);
00938
00939 dst.getArrayPtr()[xx + i * dst_w] =
00940 bPelDelta
00941 ? clamped_rounded_convert<T>(weight)
00942 : clamped_rounded_convert<T>(pel);
00943 }
00944 }
00945
00946 return dst;
00947 }
00948 }
00949
00950
00951 template <class T>
00952 Image<T> rescale(const Image<T>& src, const Dims& newdims,
00953 RescaleType ftype)
00954 {
00955 switch (ftype)
00956 {
00957 case RESCALE_SIMPLE_NOINTERP: return rescaleNI(src, newdims);
00958 case RESCALE_SIMPLE_BILINEAR: return rescaleBilinear(src, newdims);
00959 case RESCALE_FILTER_BOX : return genericRescale<BoxFilter>(src, newdims);
00960 case RESCALE_FILTER_TRIANGLE: return genericRescale<TriangleFilter>(src, newdims);
00961 case RESCALE_FILTER_BELL : return genericRescale<BellFilter>(src, newdims);
00962 case RESCALE_FILTER_BSPLINE : return genericRescale<BsplineFilter>(src, newdims);
00963 case RESCALE_FILTER_HERMITE : return genericRescale<HermiteFilter>(src, newdims);
00964 case RESCALE_FILTER_LANCZOS3: return genericRescale<Lanczos3Filter>(src, newdims);
00965 case RESCALE_FILTER_MITCHELL: return genericRescale<MitchellFilter>(src, newdims);
00966 default: LFATAL("invalid ftype '%c'", ftype);
00967 }
00968 ASSERT(0); return Image<T>();
00969 }
00970
00971
00972 template <class T>
00973 Image<T> rescale(const Image<T>& src, const int width, const int height,
00974 RescaleType ftype)
00975 {
00976 return rescale(src, Dims(width, height), ftype);
00977 }
00978
00979
00980 template <class T>
00981 Image<T> rescaleOpt(const Image<T>& src, const Dims& dims, const bool interp)
00982 {
00983 if (interp) return rescaleBilinear(src, dims);
00984 else return rescaleNI(src, dims);
00985 }
00986
00987
00988 template <class T>
00989 Image<T> rescaleOpt(const Image<T>& src, const int new_w, const int new_h,
00990 const bool interp)
00991 {
00992 if (interp) return rescaleBilinear(src, new_w, new_h);
00993 else return rescaleNI(src, new_w, new_h);
00994 }
00995
00996
00997
00998 template <class T>
00999 Image<PixRGB<T> > downscaleFancy(const Image<PixRGB<T> >& src,
01000 int width, int height, int weighting_slope,
01001 bool no_weight_black)
01002
01003 {
01004 GVX_TRACE(__PRETTY_FUNCTION__);
01005
01006 PixRGB<T> pix(0);
01007 Image<PixRGB<T> > buffer;
01008 Image<PixRGB<T> > out;
01009 Image<T> bufferWeight;
01010
01011 buffer.resize(width,height,true);
01012 out.resize(width,height,true);
01013 bufferWeight.resize(width,height,true);
01014
01015 T scalex = (T)width / (T)src.getWidth();
01016 T scaley = (T)height / (T)src.getHeight();
01017 T dx, dy, weight, xweight, yweight, xfrac, yfrac;
01018 typename Image<PixRGB<T> >::iterator bufelem;
01019 typename Image<T>::iterator bufw;
01020 dx = (T)0.0;
01021 dy = (T)0.0;
01022
01023 for (int sy = (int)0; sy < (int)src.getHeight();
01024 sy++, dy += scaley)
01025 {
01026
01027 yfrac = dy - (T)floor(dy);
01028 switch (weighting_slope)
01029 {
01030 case 5: yweight = yfrac < 0.5 ? 0 : 1;
01031 break;
01032 case 4: yweight = (T)(0.5 + 0.5*tanh(15*(yfrac - 0.5)));
01033 break;
01034 case 3: yweight = (T)(0.5 + 0.5*tanh(8*(yfrac - 0.5)));
01035 break;
01036 case 2: yweight = (T)(0.5 + 0.5*tanh(5*(yfrac - 0.5)));
01037 break;
01038 case 1: yweight = (T)(0.5 - 0.5*cos(yfrac*M_PI));
01039 break;
01040 case 0: yweight = yfrac;
01041 break;
01042 default : LERROR("illegal weighting slope");
01043 yweight = yfrac;
01044 }
01045
01046 dx = (T)0;
01047 for (int sx = (int)0; sx < (int)src.getWidth();
01048 sx++, dx += scalex)
01049 {
01050
01051 xfrac = dx - (T)floor(dx);
01052 switch (weighting_slope)
01053 {
01054 case 5: xweight = xfrac < 0.5 ? 0 : 1;
01055 break;
01056 case 4: xweight = (T)(0.5 + 0.5*tanh(15*(xfrac - 0.5)));
01057 break;
01058 case 3: xweight = (T)(0.5 + 0.5*tanh(8*(xfrac - 0.5)));
01059 break;
01060 case 2: xweight = (T)(0.5 + 0.5*tanh(5*(xfrac - 0.5)));
01061 break;
01062 case 1: xweight = (T)(0.5 - 0.5*cos(xfrac*M_PI));
01063
01064 break;
01065 case 0: xweight = xfrac;
01066 break;
01067 default : LINFO("illegal weighting slope");
01068 xweight = xfrac;
01069 }
01070
01071 int floordx = (int)floor((T)dx);
01072 int floordy = (int)floor((T)dy);
01073 const PixRGB<T> *in_sy_sx = &src.getVal(sx,sy);
01074
01075 if (no_weight_black)
01076 if (in_sy_sx->red() == 0 &&
01077 in_sy_sx->green() == 0 &&
01078 in_sy_sx->blue() == 0)
01079 continue;
01080
01081 bufelem = buffer.beginw()
01082 + buffer.getWidth()*floordy + floordx;
01083
01084 bufw = bufferWeight.beginw()
01085 + bufferWeight.getWidth()*floordy + floordx;
01086
01087 ADD_RGB(bufelem, ((T)1.0-xweight)*((T)1.0-yweight), bufw, in_sy_sx);
01088
01089 if (dx < width - 1)
01090 {
01091 bufelem++; bufw++;
01092 ADD_RGB(bufelem, xweight*((T)1.0-yweight), bufw, in_sy_sx);
01093 }
01094
01095 if (dy < height - 1)
01096 {
01097 bufelem = buffer.beginw()
01098 + buffer.getWidth()*(floordy+1) + floordx;
01099 bufw = bufferWeight.beginw()
01100 + bufferWeight.getWidth()*(floordy+1) + floordx;
01101
01102 ADD_RGB(bufelem, ((T)1.0-xweight)*yweight, bufw, in_sy_sx);
01103 if (dx < width - 1) {
01104 bufelem++;
01105 bufw++;
01106
01107 ADD_RGB(bufelem, xweight*yweight, bufw, in_sy_sx);
01108 }
01109 }
01110 }
01111 if (floorf(dy + scaley) > floorf(dy))
01112 {
01113
01114 int dsty = (int)floor(dy);
01115 for (int dstx = 0; dstx < width; dstx++)
01116 {
01117 weight = bufferWeight.getVal(dstx,dsty);
01118 if(weight != 0.0)
01119 {
01120 pix = buffer.getVal(dstx,dsty);
01121 pix /= weight;
01122 out.setVal(dstx,dsty,pix);
01123 }
01124 PixRGB<T> zero(0);
01125 buffer.setVal(dstx,dsty,zero);
01126 bufferWeight.setVal(dstx,dsty,0);
01127 }
01128 }
01129 }
01130 return out;
01131 }
01132
01133
01134
01135 template <class T>
01136 Image<T> downSize(const Image<T>& src, const Dims& dims,
01137 const int filterWidth)
01138 {
01139 return downSize(src, dims.w(), dims.h(), filterWidth);
01140 }
01141
01142
01143 template <class T>
01144 Image<T> downSize(const Image<T>& src, const int new_w, const int new_h,
01145 const int filterWidth)
01146 {
01147 GVX_TRACE(__PRETTY_FUNCTION__);
01148
01149 if (src.getWidth() == new_w && src.getHeight() == new_h) return src;
01150
01151 ASSERT(src.getWidth() / new_w > 1 && src.getHeight() / new_h > 1);
01152
01153 const int wdepth = int(0.5+log(double(src.getWidth() / new_w)) / M_LN2);
01154 const int hdepth = int(0.5+log(double(src.getHeight() / new_h)) / M_LN2);
01155
01156 if (wdepth != hdepth)
01157 LFATAL("arrays must have same proportions");
01158
01159 Image<T> result = src;
01160
01161 for (int i = 0; i < wdepth; ++i)
01162 {
01163 result = decX(lowPassX(filterWidth, result));
01164 result = decY(lowPassY(filterWidth, result));
01165 }
01166
01167 return result;
01168 }
01169
01170
01171 Image<float> downSizeClean(const Image<float>& src, const Dims& new_dims,
01172 const int filterWidth)
01173 {
01174 GVX_TRACE(__PRETTY_FUNCTION__);
01175
01176 if (src.getDims() == new_dims) return src;
01177
01178 ASSERT(new_dims.isNonEmpty());
01179 ASSERT(filterWidth >= 1);
01180
01181 Image<float> result = src;
01182
01183 while (result.getWidth() > new_dims.w() * 2 &&
01184 result.getHeight() > new_dims.h() * 2)
01185 {
01186 if (filterWidth == 1)
01187 {
01188 result = decX(result);
01189 result = decY(result);
01190 }
01191 else if (filterWidth == 2)
01192 {
01193 result = quickLocalAvg2x2(result);
01194 }
01195 else
01196 {
01197 result = decX(lowPassX(filterWidth, result));
01198 result = decY(lowPassY(filterWidth, result));
01199 }
01200 }
01201
01202 return rescaleBilinear(result, new_dims);
01203 }
01204
01205
01206 template <class T>
01207 Image<T> concatArray(const Image<T> arr[], const int nbarr, const int Nx,
01208 const int destX, const int destY)
01209 {
01210 GVX_TRACE(__PRETTY_FUNCTION__);
01211
01212 int width, height;
01213
01214 if (destX <= 0 || destY <= 0)
01215 {
01216 width = arr[0].getWidth(); height = arr[0].getHeight();
01217 }
01218 else { width = destX; height = destY; }
01219 int tw = width * Nx;
01220 int th = height * (int)ceil(((double)nbarr) / ((double)Nx));
01221 Image<T> result(tw, th, NO_INIT);
01222 T zeros[width]; for (int i = 0; i < width; ++i) zeros[i] = T();
01223
01224 int arrnb = 0;
01225 for (int j = 0; j < th; j += height)
01226 for (int i = 0; i < tw; i += width)
01227 {
01228 if (destX <= 0 || destY <= 0)
01229 {
01230 if (arrnb < nbarr)
01231 {
01232 ASSERT(arr[arrnb].getWidth() == width &&
01233 arr[arrnb].getHeight() == height);
01234 for (int jj = 0; jj < height; jj ++)
01235 safecopy(result.beginw() + (i + (j + jj) * tw),
01236 arr[arrnb].begin() + (jj * width),
01237 width);
01238 }
01239 else
01240 for (int jj = 0; jj < height; jj ++)
01241 safecopy(result.beginw() + (i + (j + jj) * tw),
01242 zeros,
01243 width);
01244 }
01245 else
01246 {
01247 if (arrnb < nbarr)
01248 {
01249 Image<T> tmp = rescaleBilinear(arr[arrnb], width, height);
01250 for (int jj = 0; jj < height; jj ++)
01251 safecopy(result.beginw() + (i + (j + jj) * tw),
01252 tmp.begin() + (jj * width),
01253 width);
01254 }
01255 else
01256 for (int jj = 0; jj < height; jj ++)
01257 safecopy(result.beginw() + (i + (j + jj) * tw),
01258 zeros, width);
01259 }
01260 arrnb ++;
01261 }
01262
01263 return result;
01264 }
01265
01266
01267 template <class T>
01268 Image<T> decXY(const Image<T>& src,
01269 const int xfactor, const int yfactor_raw)
01270 {
01271 GVX_TRACE(__PRETTY_FUNCTION__);
01272
01273 const int yfactor = yfactor_raw >= 0 ? yfactor_raw : xfactor;
01274
01275
01276 if (src.getWidth() <= 1 && src.getHeight() <= 1) return src;
01277
01278 if (src.getWidth() == 1)
01279 {
01280 int h2 = src.getHeight() / yfactor;
01281
01282 Image<T> result(1, h2, NO_INIT);
01283
01284 for (int j = 0; j < h2; ++j)
01285 result.setVal(j, src.getVal(j * yfactor));
01286
01287 return result;
01288 }
01289 if (src.getHeight() == 1)
01290 {
01291 int w2 = src.getWidth() / xfactor;
01292
01293 Image<T> result(w2, 1, NO_INIT);
01294
01295 for (int i = 0; i < w2; ++i)
01296 result.setVal(i, src.getVal(i * xfactor));
01297
01298 return result;
01299 }
01300
01301 const int w2 = src.getWidth() / xfactor;
01302 const int h2 = src.getHeight() / yfactor;
01303
01304 Image<T> result(w2, h2, NO_INIT);
01305
01306 typename Image<T>::const_iterator sptr = src.begin();
01307 typename Image<T>::iterator dptr = result.beginw();
01308 const int skip = src.getWidth() % xfactor + src.getWidth() * (yfactor - 1);
01309
01310 for (int j = 0; j < h2; ++j)
01311 {
01312 for (int i = 0; i < w2; ++i)
01313 {
01314 *dptr++ = *sptr;
01315 sptr += xfactor;
01316 }
01317 sptr += skip;
01318 }
01319
01320 return result;
01321 }
01322
01323
01324 template <class T>
01325 Image<T> decX(const Image<T>& src, const int factor)
01326 {
01327 GVX_TRACE(__PRETTY_FUNCTION__);
01328
01329 ASSERT(factor > 0);
01330
01331 if (src.getWidth() <= 1) return src;
01332
01333 const int h = src.getHeight();
01334 int w2 = src.getWidth() / factor;
01335 int skip = src.getWidth() % factor;
01336 if (w2 == 0)
01337 {
01338 w2 = 1;
01339 skip = src.getWidth() - factor;
01340 }
01341
01342 Image<T> result(w2, h, NO_INIT);
01343
01344 typename Image<T>::const_iterator sptr = src.begin();
01345 typename Image<T>::iterator dptr = result.beginw();
01346
01347 for (int j = 0; j < h; ++j)
01348 {
01349 for (int i = 0; i < w2; ++i)
01350 {
01351 *dptr++ = *sptr;
01352 sptr += factor;
01353 }
01354 sptr += skip;
01355 }
01356
01357 return result;
01358 }
01359
01360
01361 template <class T>
01362 Image<T> decY(const Image<T>& src, const int factor)
01363 {
01364 GVX_TRACE(__PRETTY_FUNCTION__);
01365
01366 ASSERT(factor > 0);
01367
01368 if (src.getHeight() <= 1) return src;
01369
01370 const int w = src.getWidth();
01371 int h2 = src.getHeight() / factor;
01372 if (h2 == 0) h2 = 1;
01373
01374 Image<T> result(w, h2, NO_INIT);
01375
01376 typename Image<T>::const_iterator sptr = src.begin();
01377 typename Image<T>::iterator dptr = result.beginw();
01378 int skip = w * factor;
01379
01380 for (int j = 0; j < h2; ++j)
01381 {
01382 safecopy(dptr, sptr, w);
01383 dptr += w; sptr += skip;
01384 }
01385
01386 return result;
01387 }
01388
01389
01390 template <class T>
01391 Image<T> blurAndDecY(const Image<T>& src, const int factor)
01392 {
01393 GVX_TRACE(__PRETTY_FUNCTION__);
01394
01395 ASSERT(factor > 0);
01396
01397 if (src.getHeight() <= 1) return src;
01398
01399 const int w = src.getWidth();
01400 const int h1 = src.getHeight();
01401 int h2 = h1 / factor;
01402 if (h2 == 0) h2 = 1;
01403
01404 Image<T> result(w, h2, ZEROS);
01405
01406 typename Image<T>::const_iterator const sptr = src.begin();
01407 typename Image<T>::iterator dptr = result.beginw();
01408
01409 for (int j2 = 0; j2 < h2; ++j2)
01410 {
01411 int j1start = j2 * factor - (factor/2);
01412 int j1end = j1start + factor;
01413 if (j1start < 0) j1start = 0;
01414 if (j1end > h1) j1end = h1;
01415
01416 const int nj = j1end-j1start;
01417
01418 ASSERT(nj > 0);
01419
01420 const double factor = 1.0/nj;
01421
01422 for (int j1 = j1start; j1 < j1end; ++j1)
01423 for (int i = 0; i < w; ++i)
01424 dptr[i] += T(factor * sptr[i + j1*w]);
01425
01426 dptr += w;
01427 }
01428
01429 return result;
01430 }
01431
01432
01433 template <class T>
01434 Image<T> intXY(const Image<T>& src, const bool dupli)
01435 {
01436 GVX_TRACE(__PRETTY_FUNCTION__);
01437
01438 ASSERT(src.initialized());
01439
01440 const int w = src.getWidth();
01441 const int h = src.getHeight();
01442
01443 const int w2 = w * 2;
01444 const int h2 = h * 2;
01445
01446 Image<T> result(w2, h2, NO_INIT);
01447
01448 typename Image<T>::const_iterator sptr = src.begin();
01449 typename Image<T>::iterator dptr = result.beginw();
01450 if (dupli)
01451 for (int j = 0; j < h; ++j)
01452 {
01453 for (int i = 0; i < w; ++i)
01454 {
01455 *dptr++ = *sptr;
01456 *dptr++ = *sptr++;
01457 }
01458
01459 safecopy(dptr, dptr - w2, w2);
01460 dptr += w2;
01461 }
01462 else
01463 {
01464 T zeros[w2];
01465 for (int i = 0; i < w2; ++i) zeros[i] = T();
01466 for (int j = 0; j < h; ++j)
01467 {
01468 for (int i = 0; i < w; ++i)
01469 {
01470 *dptr++ = *sptr++;
01471 *dptr++ = zeros[0];
01472 }
01473 safecopy(dptr, zeros, w2);
01474 dptr += w2;
01475 }
01476 }
01477
01478 return result;
01479 }
01480
01481
01482 template <class T>
01483 Image<T> intX(const Image<T>& src, const bool dupli)
01484 {
01485 GVX_TRACE(__PRETTY_FUNCTION__);
01486
01487 ASSERT(src.initialized());
01488
01489 const int w2 = src.getWidth() * 2;
01490
01491 Image<T> result(w2, src.getHeight(), NO_INIT);
01492
01493 typename Image<T>::const_iterator sptr = src.begin();
01494 typename Image<T>::iterator dptr = result.beginw();
01495 T zero = T();
01496
01497 const int siz = src.getSize();
01498
01499 if (dupli)
01500 for (int i = 0; i < siz; ++i)
01501 {
01502 *dptr++ = *sptr;
01503 *dptr++ = *sptr++;
01504 }
01505 else
01506 for (int i = 0; i < siz; ++i)
01507 {
01508 *dptr++ = *sptr++;
01509 *dptr++ = zero;
01510 }
01511
01512 return result;
01513 }
01514
01515
01516 template <class T>
01517 Image<T> intY(const Image<T>& src, const bool dupli)
01518 {
01519 GVX_TRACE(__PRETTY_FUNCTION__);
01520
01521 ASSERT(src.initialized());
01522
01523 const int w = src.getWidth();
01524 const int h = src.getHeight();
01525 const int h2 = h * 2;
01526
01527 Image<T> result(w, h2, NO_INIT);
01528
01529 typename Image<T>::const_iterator sptr = src.begin();
01530 typename Image<T>::iterator dptr = result.beginw();
01531
01532 if (dupli)
01533 for (int j = 0; j < h; ++j)
01534 {
01535 safecopy(dptr, sptr, w);
01536 dptr += w;
01537 safecopy(dptr, sptr, w);
01538 dptr += w;
01539 sptr += w;
01540 }
01541 else
01542 {
01543 T zeros[w];
01544 for (int i = 0; i < w; ++i) zeros[i] = T();
01545 for (int j = 0; j < h; ++j)
01546 {
01547 safecopy(dptr, sptr, w);
01548 dptr += w;
01549 safecopy(dptr, zeros, w);
01550 dptr += w;
01551 sptr += w;
01552 }
01553 }
01554
01555 return result;
01556 }
01557
01558
01559 template <class T>
01560 Image<T> zoomXY(const Image<T>& src, int xzoom, int yzoom)
01561 {
01562 GVX_TRACE(__PRETTY_FUNCTION__);
01563
01564 if (yzoom < 0) yzoom = xzoom;
01565
01566 if (xzoom == 0 || yzoom == 0) return Image<T>();
01567 if (xzoom == 1 && yzoom == 1) return src;
01568
01569 Image<T> result(src.getWidth()*xzoom, src.getHeight()*yzoom, NO_INIT);
01570
01571 typename Image<T>::iterator dptr = result.beginw();
01572
01573 for (int y = 0; y < src.getHeight(); ++y)
01574 {
01575 for (int yz = 0; yz < yzoom; ++yz)
01576 {
01577 typename Image<T>::const_iterator sptr =
01578 src.begin() + y*src.getWidth();
01579 for (int x = 0; x < src.getWidth(); ++x)
01580 {
01581 for (int xz = 0; xz < xzoom; ++xz)
01582 {
01583 *dptr = *sptr;
01584 ++dptr;
01585 }
01586 ++sptr;
01587 }
01588 }
01589 }
01590
01591 return result;
01592 }
01593
01594
01595 template <class T>
01596 Image<T> rotate(const Image<T>& srcImg, const int x, const int y,
01597 const float ang)
01598 {
01599 GVX_TRACE(__PRETTY_FUNCTION__);
01600
01601
01602 ASSERT(srcImg.initialized());
01603
01604
01605 int w = srcImg.getWidth(), h = srcImg.getHeight();
01606 Image<T> retImg(w, h, ZEROS);
01607
01608
01609
01610
01611 int pad = int(ceil(sqrt(w * w + h * h)));
01612 int wR = 2 * pad + w;
01613 int hR = 2 * pad + h;
01614 Image<T> tempImg(wR, hR, ZEROS);
01615 inplacePaste(tempImg, srcImg, Point2D<int>(pad,pad));
01616
01617 typename Image<T>::iterator rBPtr = retImg.beginw();
01618 float cAng = cos(ang), sAng = sin(ang);
01619
01620
01621 float xR = 0.0; float yR = 0.0;
01622 int dx = pad + x, dy = pad + y;
01623 for(int j = -y; j < h-y; j++)
01624 for(int i = -x; i < w-x; i++)
01625 {
01626 xR = dx + i*cAng + j*sAng;
01627 yR = dy - i*sAng + j*cAng;
01628 *rBPtr++ = T(tempImg.getValInterp(xR,yR));
01629 }
01630
01631 return retImg;
01632 }
01633
01634
01635
01636
01637 #include "inst/Image/ShapeOps.I"
01638
01639 template Image<double> quickLocalAvg2x2(const Image<double>&);
01640 template Image<int> decX(const Image<int>&, int);
01641 template Image<int> decY(const Image<int>&, int);
01642 template Image<int> decXY(const Image<int>&, int, int);
01643 template Image<double> intXY(const Image<double>&, bool);
01644 template Image<PixH2SV2<float> > decXY(const Image<PixH2SV2<float> >&, int, int);
01645 template Image<PixH2SV2<float> > rescaleBilinear(const Image<PixH2SV2<float> >& src, int, int);
01646 template Image<geom::vec2f> rotate(const Image<geom::vec2f>&, int, int,float);
01647 template Image<uint16> zoomXY(const Image<uint16>&, int, int);
01648 template Image<uint16> rescale(const Image<uint16>&, const Dims&, RescaleType);
01649
01650
01651
01652
01653
01654
01655
01656 #endif // !IMAGE_SHAPEOPS_C_DEFINED