00001 /*!@file Image/CutPaste.C Cut+paste operations from/to Image subregions */ 00002 00003 // //////////////////////////////////////////////////////////////////// // 00004 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00005 // University of Southern California (USC) and the iLab at USC. // 00006 // See http://iLab.usc.edu for information about this project. // 00007 // //////////////////////////////////////////////////////////////////// // 00008 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00009 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00010 // in Visual Environments, and Applications'' by Christof Koch and // 00011 // Laurent Itti, California Institute of Technology, 2001 (patent // 00012 // pending; application number 09/912,225 filed July 23, 2001; see // 00013 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00014 // //////////////////////////////////////////////////////////////////// // 00015 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00016 // // 00017 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00018 // redistribute it and/or modify it under the terms of the GNU General // 00019 // Public License as published by the Free Software Foundation; either // 00020 // version 2 of the License, or (at your option) any later version. // 00021 // // 00022 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00023 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00024 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00025 // PURPOSE. See the GNU General Public License for more details. // 00026 // // 00027 // You should have received a copy of the GNU General Public License // 00028 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00029 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00030 // Boston, MA 02111-1307 USA. // 00031 // //////////////////////////////////////////////////////////////////// // 00032 // 00033 // Primary maintainer for this file: Rob Peters <rjpeters@klab.caltech.edu> 00034 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Image/CutPaste.C $ 00035 // $Id: CutPaste.C 14535 2011-02-18 22:40:51Z siagian $ 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() // Skip downward over starting rows 00189 + pt.i; // Skip rightward over starting columns 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 // make sure the source image is valid 00238 ASSERT(srcImg.initialized()); 00239 00240 // create and clear the return image 00241 Dims dim(srcImg.getDims()); 00242 Image<T> retImg(srcImg.getDims(), ZEROS); 00243 00244 // create the source and destination iterators 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 // adjust the pointers according to the direction of image shift 00251 int shiftAmt = dy * dim.w() + dx; 00252 if(shiftAmt < 0) 00253 srcBegPtr -= shiftAmt; 00254 else 00255 retBegPtr += shiftAmt; 00256 00257 // determine width of the actual data to be transferred 00258 // int newW = dim.w() - abs(dx); 00259 // int quad = dx*dy; 00260 00261 // transfer from source to destination image 00262 // for(int i=0; (srcBegPtr != srcEndPtr) && (retBegPtr != retEndPtr); 00263 // ++i, ++srcBegPtr, ++retBegPtr) { 00264 // if(((quad < 0) && (i%dim.w() < abs(dx))) || 00265 // ((quad > 0) && (i%dim.w() >= newW))) 00266 // *retBegPtr = T(0); 00267 // else 00268 // *retBegPtr = *srcEndPtr; 00269 // } // for block 00270 00271 // transfer from source to destination image 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 // make sure the source image is valid 00285 ASSERT(srcImg.initialized()); 00286 00287 // create and clear the return image 00288 Dims dim(srcImg.getDims()); 00289 int w = dim.w(), h = dim.h(); 00290 Image<T> retImg(dim, ZEROS); 00291 00292 // prepare a couple of variable for the x direction 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 // prepare a couple of variable for the y direction 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 // dispatch to faster shiftClean() if displacements are roughly integer: 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 // prepare the coefficients 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 // prepare the pointers 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 // now loop over the images 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 // make sure the source image is valid 00363 ASSERT(srcImg.initialized()); 00364 00365 // create and clear the return image 00366 int w = srcImg.getWidth(), h = srcImg.getHeight(); 00367 Image<T> retImg(w, h, NO_INIT); retImg.clear(bgval); 00368 00369 // create the source and destination iterators 00370 typename Image<T>::const_iterator src = srcImg.begin(); 00371 typename Image<T>::iterator dst = retImg.beginw(); 00372 00373 // find range of pixels to copy: 00374 int startx = std::max(0, -dx), endx = std::min(w - 1, w - 1 - dx); 00375 if (startx >= w || endx < 0) return retImg; // empty result 00376 int starty = std::max(0, -dy), endy = std::min(h - 1, h - 1 - dy); 00377 if (starty >= h || endy < 0) return retImg; // empty result 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 // do the copy: 00388 for (int j = starty; j <= endy; j ++) 00389 { 00390 for (int i = startx; i <= endx; i ++) *dst++ = *src++; 00391 00392 // ready for next row of pixels: 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 // take larger of scale factors if keep aspect ratio: 00463 if (keep_aspect) 00464 { 00465 if (sw > sh) sh = sw; 00466 if (sh > sw) sw = sh; 00467 } 00468 00469 // determine bounds of actual embedded image, within rectangle: 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 // top empty lines: 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 // bulk of embedded image: 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 ); // no need to clamp 00511 } 00512 for (int i = imax; i < ww; i ++) *aptr++ = background; 00513 aptr += myw - ww; 00514 } 00515 00516 // bottom empty lines: 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 // NOTE: can only have one mask in the image 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 // find x offset 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 // find y 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 // find width 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 // find height 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 //Fix any bounding problems 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 // Include the explicit instantiations (color instantiations are now 00608 // requested by using "T_or_RGB" for the template formal parameter name in 00609 // the declarations in the .H file). 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 /* So things look consistent in everyone's emacs... */ 00643 /* Local Variables: */ 00644 /* indent-tabs-mode: nil */ 00645 /* End: */