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 #include "Image/CutPaste.H"
00039
00040 #include "Image/Image.H"
00041 #include "Image/Pixels.H"
00042 #include "Util/Assert.H"
00043 #include "Util/safecopy.H"
00044 #include "rutz/trace.h"
00045 #include "Image/vec2.h"
00046
00047 #include <algorithm>
00048
00049
00050 template <class T>
00051 Image<T> concatX(const Image<T>& left, const Image<T>& right)
00052 {
00053 GVX_TRACE(__PRETTY_FUNCTION__);
00054
00055 if (!left.initialized()) return right;
00056 else if (!right.initialized()) return left;
00057
00058 ASSERT(left.getHeight() == right.getHeight());
00059 const int h = left.getHeight();
00060 const int wl = left.getWidth();
00061 const int wr = right.getWidth();
00062 Image<T> result(wl + wr, left.getHeight(), NO_INIT);
00063 typename Image<T>::const_iterator lptr = left.begin();
00064 typename Image<T>::const_iterator rptr = right.begin();
00065 typename Image<T>::iterator dptr = result.beginw();
00066 for (int j = 0; j < h; ++j)
00067 {
00068 for (int i1 = 0; i1 < wl; i1 ++) *dptr++ = *lptr++;
00069 for (int i2 = 0; i2 < wr; i2 ++) *dptr++ = *rptr++;
00070 }
00071
00072 return result;
00073 }
00074
00075
00076 template <class T>
00077 Image<T> concatY(const Image<T>& top, const Image<T>& bottom)
00078 {
00079 GVX_TRACE(__PRETTY_FUNCTION__);
00080
00081 if (!top.initialized()) return bottom;
00082 else if (!bottom.initialized()) return top;
00083
00084 ASSERT(top.getWidth() == bottom.getWidth());
00085 const int w = top.getWidth();
00086 const int ht = top.getHeight();
00087 const int hb = bottom.getHeight();
00088 Image<T> result(w, ht + hb, NO_INIT);
00089 typename Image<T>::const_iterator tptr = top.begin();
00090 typename Image<T>::const_iterator bptr = bottom.begin();
00091 typename Image<T>::iterator dptr = result.beginw();
00092 for (int i = 0; i < ht * w; ++i) *dptr++ = *tptr++;
00093 for (int i2 = 0; i2 < hb * w; i2 ++) *dptr++ = *bptr++;
00094 return result;
00095 }
00096
00097
00098 template <class T>
00099 Image<T> concatLooseY(const Image<T>& topImg,
00100 const Image<T>& bottomImg,
00101 const T& bgColor)
00102 {
00103 GVX_TRACE(__PRETTY_FUNCTION__);
00104
00105 const int dsth = topImg.getHeight() + bottomImg.getHeight();
00106 const int dstw = std::max(topImg.getWidth(), bottomImg.getWidth());
00107
00108 const int topw = topImg.getWidth();
00109 const int toph = topImg.getHeight();
00110 const int botw = bottomImg.getWidth();
00111 const int both = bottomImg.getHeight();
00112
00113 Image<T> result = Image<T>(dstw, dsth, NO_INIT);
00114
00115 result.clear(bgColor);
00116
00117 T* const dptr = result.getArrayPtr();
00118 const T* const topptr = topImg.getArrayPtr();
00119 const T* const botptr = bottomImg.getArrayPtr();
00120
00121 for (int j=0; j < toph; ++j)
00122 for (int i=0; i < topw; ++i)
00123 dptr[i + j * dstw] = topptr[i + j * topw];
00124
00125 for (int j=0; j < both; ++j)
00126 for (int i=0; i < botw; ++i)
00127 dptr[i + (j+toph) * dstw] = botptr[i + j * botw];
00128
00129 return result;
00130 }
00131
00132
00133 template <class T>
00134 Image<T> concatLooseX(const Image<T>& leftImg,
00135 const Image<T>& rightImg,
00136 const T& bgColor)
00137 {
00138 GVX_TRACE(__PRETTY_FUNCTION__);
00139
00140 const int dstw = leftImg.getWidth() + rightImg.getWidth();
00141 const int dsth = std::max(leftImg.getHeight(), rightImg.getHeight());
00142
00143 const int lw = leftImg.getWidth();
00144 const int lh = leftImg.getHeight();
00145 const int rw = rightImg.getWidth();
00146 const int rh = rightImg.getHeight();
00147
00148 Image<T> result = Image<T>(dstw, dsth, NO_INIT);
00149
00150 result.clear(bgColor);
00151
00152 T* const dptr = result.getArrayPtr();
00153 const T* const lptr = leftImg.getArrayPtr();
00154 const T* const rptr = rightImg.getArrayPtr();
00155
00156 for (int j=0; j < lh; ++j)
00157 for (int i=0; i < lw; ++i)
00158 dptr[i + j * dstw] = lptr[i + j * lw];
00159
00160 for (int j=0; j < rh; ++j)
00161 for (int i=0; i < rw; ++i)
00162 dptr[(i + lw) + j * dstw] = rptr[i + j * rw];
00163
00164 return result;
00165 }
00166
00167
00168 template <class T>
00169 Image<T> crop(const Image<T>& src, const Point2D<int>& pt, const Dims& dims,
00170 const bool zerofill)
00171 {
00172 GVX_TRACE(__PRETTY_FUNCTION__);
00173
00174 if (pt == Point2D<int>(0,0) && dims == src.getDims())
00175 return src;
00176
00177 Image<T> result(dims, NO_INIT);
00178
00179 typename Image<T>::iterator dptr = result.beginw();
00180
00181 if (!zerofill)
00182 {
00183 ASSERT(src.coordsOk(pt));
00184 ASSERT(src.coordsOk(pt.i + dims.w() - 1, pt.j + dims.h() - 1));
00185
00186 typename Image<T>::const_iterator sptr =
00187 src.begin()
00188 + pt.j * src.getWidth()
00189 + pt.i;
00190
00191 const int src_catchup = src.getWidth() - result.getWidth();
00192
00193 for (int y = 0; y < dims.h(); ++y)
00194 {
00195 for (int x = 0; x < dims.w(); ++x)
00196 {
00197 *dptr++ = *sptr++;
00198 }
00199 sptr += src_catchup;
00200 }
00201 }
00202 else
00203 {
00204 const T zero = T();
00205
00206 const int ymax = pt.j + dims.h();
00207 const int xmax = pt.i + dims.w();
00208
00209 for (int y = pt.j; y < ymax; ++y)
00210 for (int x = pt.i; x < xmax; ++x)
00211 {
00212 if (src.coordsOk(x, y)) *dptr = src.getVal(x, y);
00213 else *dptr = zero;
00214 ++dptr;
00215 }
00216 }
00217
00218 return result;
00219 }
00220
00221
00222 template <class T>
00223 Image<T> crop(const Image<T>& src, const Rectangle& rect, const bool zerofill)
00224 {
00225 return crop(src,
00226 Point2D<int>(rect.left(), rect.top()),
00227 Dims(rect.width(), rect.height()),
00228 zerofill);
00229 }
00230
00231
00232 template <class T>
00233 Image<T> shift(const Image<T>& srcImg, const int dx, const int dy)
00234 {
00235 GVX_TRACE(__PRETTY_FUNCTION__);
00236
00237
00238 ASSERT(srcImg.initialized());
00239
00240
00241 Dims dim(srcImg.getDims());
00242 Image<T> retImg(srcImg.getDims(), ZEROS);
00243
00244
00245 typename Image<T>::const_iterator srcBegPtr = srcImg.begin();
00246 typename Image<T>::const_iterator srcEndPtr = srcImg.end();
00247 typename Image<T>::iterator retBegPtr = retImg.beginw();
00248 typename Image<T>::iterator retEndPtr = retImg.endw();
00249
00250
00251 int shiftAmt = dy * dim.w() + dx;
00252 if(shiftAmt < 0)
00253 srcBegPtr -= shiftAmt;
00254 else
00255 retBegPtr += shiftAmt;
00256
00257
00258
00259
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271
00272 while((srcBegPtr != srcEndPtr) && (retBegPtr != retEndPtr))
00273 *retBegPtr++ = *srcBegPtr++;
00274
00275 return retImg;
00276 }
00277
00278
00279 template <class T>
00280 Image<T> shiftImage(const Image<T>& srcImg, const float dx, const float dy)
00281 {
00282 GVX_TRACE(__PRETTY_FUNCTION__);
00283
00284
00285 ASSERT(srcImg.initialized());
00286
00287
00288 Dims dim(srcImg.getDims());
00289 int w = dim.w(), h = dim.h();
00290 Image<T> retImg(dim, ZEROS);
00291
00292
00293 int xt = (int)floor(dx);
00294 float xfrac = dx - xt;
00295 int startx = std::max(0,xt);
00296 int endx = std::min(0,xt) + w;
00297 if (fabs(xfrac) < 1.0e-10) xfrac = 0.0;
00298 else endx--;
00299
00300
00301 int yt = (int)floor(dy);
00302 float yfrac = dy - yt;
00303 int starty = std::max(0,yt);
00304 int endy = std::min(0,yt) + h;
00305 if (fabs(yfrac) < 1.0e-10) yfrac = 0.0;
00306 else endy--;
00307
00308
00309 if (fabs(xfrac) < 1.0e-10 && fabs(yfrac) < 1.0e-10)
00310 return shiftClean(srcImg, xt, yt);
00311
00312 if (xfrac > 0.0)
00313 {
00314 xfrac = 1.0 - xfrac;
00315 xt++;
00316 }
00317
00318 if (yfrac > 0.0)
00319 {
00320 yfrac = 1.0 - yfrac;
00321 yt++;
00322 }
00323
00324
00325 float tl = (1.0 - xfrac) * (1.0 - yfrac);
00326 float tr = xfrac * (1.0 - yfrac);
00327 float bl = (1.0 - xfrac) * yfrac;
00328 float br = xfrac * yfrac;
00329
00330
00331 typename Image<T>::const_iterator src, src2 = srcImg.begin();
00332 typename Image<T>::iterator ret, ret2 = retImg.beginw();
00333 if (xt > 0) ret2 += xt;
00334 if (xt < 0) src2 -= xt;
00335 if (yt > 0) ret2 += yt * w;
00336 if (yt < 0) src2 -= yt * w;
00337
00338
00339 for (int y = starty; y < endy; ++y)
00340 {
00341 src = src2; ret = ret2;
00342 for (int x = startx; x < endx; ++x)
00343 {
00344 (*ret) = (T)((*src) * tl);
00345 if (tr > 0.0) (*ret) += (T)((*(src + 1)) * tr);
00346 if (bl > 0.0) (*ret) += (T)((*(src + w)) * bl);
00347 if (br > 0.0) (*ret) += (T)((*(src + w + 1)) * br);
00348 ++src; ++ret;
00349 }
00350 src2 += w; ret2 += w;
00351 }
00352 return retImg;
00353 }
00354
00355
00356 template <class T>
00357 Image<T> shiftClean(const Image<T>& srcImg, const int dx, const int dy,
00358 const T bgval)
00359 {
00360 GVX_TRACE(__PRETTY_FUNCTION__);
00361
00362
00363 ASSERT(srcImg.initialized());
00364
00365
00366 int w = srcImg.getWidth(), h = srcImg.getHeight();
00367 Image<T> retImg(w, h, NO_INIT); retImg.clear(bgval);
00368
00369
00370 typename Image<T>::const_iterator src = srcImg.begin();
00371 typename Image<T>::iterator dst = retImg.beginw();
00372
00373
00374 int startx = std::max(0, -dx), endx = std::min(w - 1, w - 1 - dx);
00375 if (startx >= w || endx < 0) return retImg;
00376 int starty = std::max(0, -dy), endy = std::min(h - 1, h - 1 - dy);
00377 if (starty >= h || endy < 0) return retImg;
00378
00379 int dstx = std::max(0, std::min(w - 1, dx));
00380 int dsty = std::max(0, std::min(h - 1, dy));
00381
00382 src += startx + starty * w;
00383 dst += dstx + dsty * w;
00384
00385 int skip = w - endx + startx - 1;
00386
00387
00388 for (int j = starty; j <= endy; j ++)
00389 {
00390 for (int i = startx; i <= endx; i ++) *dst++ = *src++;
00391
00392
00393 src += skip; dst += skip;
00394 }
00395
00396 return retImg;
00397 }
00398
00399
00400 template <class T>
00401 void inplacePaste(Image<T>& dst,
00402 const Image<T>& img, const Point2D<int>& pos)
00403 {
00404 GVX_TRACE(__PRETTY_FUNCTION__);
00405
00406 int w = dst.getWidth(), h = dst.getHeight();
00407 int iw = img.getWidth(), ih=img.getHeight();
00408
00409 ASSERT(pos.i + iw <= w && pos.j + ih <= h);
00410
00411 typename Image<T>::const_iterator sptr = img.begin();
00412 typename Image<T>::iterator dptr = dst.beginw() + pos.i + pos.j * w;
00413 for (int j = 0; j < ih; j ++)
00414 {
00415 safecopy(dptr, sptr, iw);
00416 dptr += w;
00417 sptr += iw;
00418 }
00419 }
00420
00421
00422 template <class T>
00423 void inplaceClearRegion(Image<T>& dst,
00424 const Rectangle& region1, const T& val)
00425 {
00426 GVX_TRACE(__PRETTY_FUNCTION__);
00427
00428 const Rectangle region = region1.getOverlap(dst.getBounds());
00429
00430 if (!region.isValid() || !dst.initialized())
00431 return;
00432
00433 const int w = dst.getWidth();
00434 const int iw = region.width(), ih = region.height();
00435
00436 ASSERT(dst.rectangleOk(region));
00437
00438 typename Image<T>::iterator dptr = dst.beginw() + region.left() + region.top() * w;
00439 for (int j = 0; j < ih; ++j)
00440 {
00441 for (int i = 0; i < iw; ++i)
00442 dptr[i] = val;
00443 dptr += w;
00444 }
00445 }
00446
00447
00448 template <class T>
00449 void inplaceEmbed(Image<T>& dst,
00450 const Image<T>& img, const Rectangle& r,
00451 const T background, const bool keep_aspect)
00452 {
00453 GVX_TRACE(__PRETTY_FUNCTION__);
00454
00455 ASSERT(dst.initialized() && img.initialized());
00456 ASSERT(dst.rectangleOk(r));
00457 int ww = r.width(), hh = r.height();
00458 int iw = img.getWidth(), ih = img.getHeight();
00459 int myw = dst.getWidth();
00460 float sw = float(iw) / float(ww), sh = float(ih) / float(hh);
00461
00462
00463 if (keep_aspect)
00464 {
00465 if (sw > sh) sh = sw;
00466 if (sh > sw) sw = sh;
00467 }
00468
00469
00470 const int imin = (ww - int(float(iw) / sw)) / 2;
00471 const int imax = ww - imin;
00472 const int jmin = (hh - int(float(ih) / sh)) / 2;
00473 const int jmax = hh - jmin;
00474
00475 typename Image<T>::iterator aptr = dst.beginw();
00476 typename Image<T>::const_iterator sptr = img.begin();
00477 aptr += r.top() * myw + r.left();
00478
00479
00480 for (int j = 0; j < jmin; j ++)
00481 {
00482 for (int i = 0; i < ww; i ++) *aptr++ = background;
00483 aptr += myw - ww;
00484 }
00485
00486
00487 for (int j = jmin; j < jmax; j ++)
00488 {
00489 for (int i = 0; i < imin; i ++) *aptr++ = background;
00490
00491 const float y = std::max(0.0F, float(j - jmin) * sh);
00492 const int y0 = int(y);
00493 const float fy = y - float(y0);
00494 const int y1 = std::min(y0 + 1, ih - 1);
00495 const int wy0 = iw * y0, wy1 = iw * y1;
00496
00497 for (int i = imin; i < imax; i ++)
00498 {
00499 const float x = std::max(0.0F, float(i - imin) * sw);
00500 const int x0 = int(x);
00501 const float fx = x - float(x0);
00502 const int x1 = std::min(x0 + 1, iw - 1);
00503
00504 typename promote_trait<T, float>::TP
00505 d00( sptr[x0 + wy0] ), d10( sptr[x1 + wy0] ),
00506 d01( sptr[x0 + wy1] ), d11( sptr[x1 + wy1] ),
00507 dx0( d00 + (d10 - d00) * fx ),
00508 dx1( d01 + (d11 - d01) * fx );
00509
00510 *aptr++ = T( dx0 + (dx1 - dx0) * fy );
00511 }
00512 for (int i = imax; i < ww; i ++) *aptr++ = background;
00513 aptr += myw - ww;
00514 }
00515
00516
00517 for (int j = jmax; j < hh; j ++)
00518 {
00519 for (int i = 0; i < ww; i ++) *aptr++ = background;
00520 aptr += myw - ww;
00521 }
00522 }
00523
00524
00525
00526 template <class T>
00527 Rectangle findBoundingRect(const Image<T>& src,
00528 const T threshold)
00529 {
00530 GVX_TRACE(__PRETTY_FUNCTION__);
00531
00532 ASSERT(src.initialized());
00533
00534 int x1 = -1; int y1 = -1; int x2 = -1; int y2 = -1;
00535 int w = src.getWidth(); int h = src.getHeight();
00536
00537
00538 for(int i = 0; i < src.getWidth(); i++)
00539 for (int j = 0; j < src.getHeight(); j++)
00540 if (src.getVal(i,j) >= threshold){ x1 = i; i = w; break; }
00541 LDEBUG("x1 = %d", x1);
00542
00543
00544 for(int j = 0; j < src.getHeight(); j++)
00545 for (int i = 0; i < src.getWidth(); i++)
00546 if (src.getVal(i,j) >= threshold) { y1 = j; j = h; break; }
00547 LDEBUG("y1 = %d", y1);
00548
00549
00550 for(int i = src.getWidth()-1; i >= 0; i--)
00551 for (int j = 0; j < src.getHeight(); j++)
00552 if (src.getVal(i,j) >= threshold) { x2 = i; i =-1; break; }
00553 LDEBUG("x2 = %d", x2);
00554
00555
00556 for(int j = src.getHeight()-1; j >= 0; j--)
00557 for (int i = 0; i < src.getWidth(); i++)
00558 if (src.getVal(i,j) >= threshold) { y2 = j; j =-1; break; }
00559 LDEBUG("y2 = %d", y2);
00560
00561 return Rectangle::tlbrI(y1,x1,y2,x2);
00562 }
00563
00564
00565 Rectangle findBoundingRect(const std::vector<Point2D<int> >& poly, const Dims imgDims)
00566 {
00567 GVX_TRACE(__PRETTY_FUNCTION__);
00568
00569 Point2D<int> upperLeft = poly[0];
00570 Point2D<int> bottomRight = poly[0];
00571
00572 for(uint i=0; i<poly.size(); i++)
00573 {
00574 if (poly[i].i < upperLeft.i)
00575 upperLeft.i = poly[i].i;
00576
00577 if (poly[i].j < upperLeft.j)
00578 upperLeft.j = poly[i].j;
00579
00580 if (poly[i].i > bottomRight.i)
00581 bottomRight.i = poly[i].i;
00582
00583 if (poly[i].j > bottomRight.j)
00584 bottomRight.j = poly[i].j;
00585 }
00586 Dims size(bottomRight.i-upperLeft.i,
00587 bottomRight.j - upperLeft.j);
00588
00589 int width = bottomRight.i-upperLeft.i;
00590 int height = bottomRight.j - upperLeft.j;
00591
00592 if (imgDims.w() > 0 && imgDims.h() > 0)
00593 {
00594
00595 if (upperLeft.i < 0) upperLeft.i = 0;
00596 if (upperLeft.j < 0) upperLeft.j = 0;
00597 if (upperLeft.i + width > imgDims.w())
00598 width = imgDims.w() - upperLeft.i;
00599 if (upperLeft.j + height > imgDims.h())
00600 height = imgDims.h() - upperLeft.j;
00601 }
00602
00603 return Rectangle(upperLeft, Dims(width, height));
00604 }
00605
00606
00607
00608
00609
00610 #include "inst/Image/CutPaste.I"
00611
00612 template Image<double>
00613 crop(const Image<double>&, const Point2D<int>&, const Dims&, bool);
00614
00615 template Image<PixRGB<unsigned short> >
00616 crop(Image<PixRGB<unsigned short> > const&, Point2D<int> const&, Dims const&, bool);
00617
00618 template Image<unsigned short>
00619 concatX(Image<unsigned short> const&, Image<unsigned short> const&);
00620
00621 template void
00622 inplacePaste(Image<double>&, const Image<double>&, const Point2D<int>&);
00623
00624 template Image<int>
00625 shiftClean(const Image<int>& srcImg, const int dx, const int dy,
00626 const int bgval);
00627
00628 template Image<geom::vec2f>
00629 shiftClean(const Image<geom::vec2f>& srcImg, const int dx, const int dy,
00630 const geom::vec2f bgval);
00631
00632 template void
00633 inplacePaste(Image<geom::vec2f>&, const Image<geom::vec2f>&, const Point2D<int>&);
00634
00635 template void inplaceEmbed(Image<uint16>&, const Image<uint16>&, const Rectangle&,
00636 const uint16 background, const bool);
00637
00638 template Image<uint16> crop(const Image<uint16>&, const Rectangle&, const bool);
00639 template Image<double> crop(const Image<double>&, const Rectangle&, const bool);
00640
00641
00642
00643
00644
00645