00001 /*!@file Image/Image.H An image template class with many image processing 00002 functions */ 00003 00004 // //////////////////////////////////////////////////////////////////// // 00005 // The iLab Neuromorphic Vision C++ Toolkit - Copyright (C) 2001 by the // 00006 // University of Southern California (USC) and the iLab at USC. // 00007 // See http://iLab.usc.edu for information about this project. // 00008 // //////////////////////////////////////////////////////////////////// // 00009 // Major portions of the iLab Neuromorphic Vision Toolkit are protected // 00010 // under the U.S. patent ``Computation of Intrinsic Perceptual Saliency // 00011 // in Visual Environments, and Applications'' by Christof Koch and // 00012 // Laurent Itti, California Institute of Technology, 2001 (patent // 00013 // pending; application number 09/912,225 filed July 23, 2001; see // 00014 // http://pair.uspto.gov/cgi-bin/final/home.pl for current status). // 00015 // //////////////////////////////////////////////////////////////////// // 00016 // This file is part of the iLab Neuromorphic Vision C++ Toolkit. // 00017 // // 00018 // The iLab Neuromorphic Vision C++ Toolkit is free software; you can // 00019 // redistribute it and/or modify it under the terms of the GNU General // 00020 // Public License as published by the Free Software Foundation; either // 00021 // version 2 of the License, or (at your option) any later version. // 00022 // // 00023 // The iLab Neuromorphic Vision C++ Toolkit is distributed in the hope // 00024 // that it will be useful, but WITHOUT ANY WARRANTY; without even the // 00025 // implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR // 00026 // PURPOSE. See the GNU General Public License for more details. // 00027 // // 00028 // You should have received a copy of the GNU General Public License // 00029 // along with the iLab Neuromorphic Vision C++ Toolkit; if not, write // 00030 // to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, // 00031 // Boston, MA 02111-1307 USA. // 00032 // //////////////////////////////////////////////////////////////////// // 00033 // 00034 // Primary maintainer for this file: Laurent Itti <itti@usc.edu> 00035 // $HeadURL: svn://isvn.usc.edu/software/invt/trunk/saliency/src/Image/Image.H $ 00036 // $Id: Image.H 14755 2011-04-29 05:55:18Z itti $ 00037 // 00038 00039 #ifndef IMAGE_H_DEFINED 00040 #define IMAGE_H_DEFINED 00041 00042 // Uncomment this to allow range checking in Image iterators: 00043 //#define INVT_MEM_DEBUG 00044 00045 #include "Util/Assert.H" 00046 #include "Util/Promotions.H" 00047 #include "Image/ArrayData.H" 00048 #include "Image/Point2D.H" 00049 #include "Image/Rectangle.H" 00050 00051 #ifdef INVT_MEM_DEBUG 00052 #include "Image/CheckedIterator.H" 00053 #endif 00054 00055 #include <algorithm> // for std::min 00056 #include <iterator> 00057 00058 //! Generic image template class 00059 /*! This is a generic image template class that can handle grayscale 00060 as well as color or multispectral images. All Image methods should 00061 be instantiable for any type T that has the basic arithmetic 00062 operators. Note that some external Image functions will only work 00063 for scalar types (e.g. if comparison operators are needed), and 00064 other will only work for composite types such as PixRGB (e.g. if 00065 luminance() is needed). 00066 00067 Note also that many other image manipulation functions are defined 00068 as non-member functions in Image/ColorOps.H, Image/FilterOps.H, 00069 Image/IO.H, Image/MathOps.H, Image/Omni.H, Image/ShapeOps.H, and 00070 Image/Transforms.H. 00071 */ 00072 00073 template <class T> 00074 class Image 00075 { 00076 public: 00077 00078 // ############################################################ 00079 /*! @name Constructors, destructors, assignment */ 00080 //@{ 00081 00082 //! Construct from C array 00083 /*! Build from C array; an internal copy of the C array will be 00084 allocated, so the C array can (and should) be freed without 00085 affecting the Image. */ 00086 inline Image(const T* inarray, int width, int height); 00087 00088 //! Construct from C array 00089 /*! Build from C array; an internal copy of the C array will be 00090 allocated, so the C array can (and should) be freed without 00091 affecting the Image. */ 00092 inline Image(const T* inarray, const Dims& dims); 00093 00094 //! Allocates memory for given size, and optionally zero-clear that memory. 00095 inline Image(int width, int height, InitPolicy init); 00096 00097 //! Constructor that only allocates memory for given size 00098 inline explicit Image(const Dims& dims, InitPolicy init); 00099 00100 //! Construct an empty (0-by-0) image (useful for arrays of Images). 00101 inline Image(); 00102 00103 //! Copy constructor 00104 /*! e.g.: 00105 \code 00106 Image<byte> im(other); 00107 // or 00108 Image<byte> im = other; // with other also of type Image<byte> 00109 \endcode 00110 */ 00111 inline Image(const Image<T>& A); 00112 00113 //! Conversion copy constructor 00114 /*! e.g.: 00115 \code 00116 Image<byte> im(other); 00117 // or 00118 Image<byte> im = other; // with other of type Image<float> 00119 \endcode 00120 */ 00121 template <class T2> inline Image(const Image<T2>& A); 00122 00123 //! Assigment operator. 00124 /*! e.g.: 00125 \code 00126 Image<byte> im1, im2; im2 = im1; 00127 \endcode 00128 */ 00129 inline Image<T>& operator=(const Image<T>& A); 00130 00131 //! Conversion assigment operator. 00132 /*! e.g.: 00133 \code 00134 Image<byte> im1; Image<float> im2; im2 = im1; 00135 \endcode 00136 00137 */ 00138 template <class T2> inline Image<T>& operator=(const Image<T2>& A); 00139 00140 //! Destructor 00141 inline ~Image(); 00142 00143 //! Free memory and switch to uninitialized state. 00144 /*! Note that it is \b NOT necessary to call this function to ensure 00145 proper cleanup, that will be done in the destructor by 00146 default. Rather, freeMem() is offered just as a performance 00147 optimization, to allow you to release a potentially large chunk 00148 of memory when you are finished using it. */ 00149 inline void freeMem(); 00150 00151 //@} 00152 00153 // ############################################################ 00154 /*! @name Memory management functions */ 00155 //@{ 00156 00157 //! Swap the contents of two images 00158 inline void swap(Image<T>& other); 00159 00160 //! Use existing memory. 00161 /*! This is potentially dangerous and should really be avoided. The 00162 only case where this really is useful is to attach an image to 00163 an existing memory segment that is shared or into which data is 00164 streaming via DMA. */ 00165 inline void attach(T* array, const int width, const int height); 00166 00167 //! Detach previously attach()'ed image. 00168 /*! The main purpose of detach() is to make sure that this Image 00169 object does not continue to point at attach()'ed memory after 00170 that memory has been freed. Nevertheless, this function is not 00171 strictly necessary to ensure correct memory handling, since the 00172 Image destructor will only try to free memory if that memory is 00173 owned (i.e., not attach()'ed). All that it does is release any 00174 association with a previously attach()'ed memory block, by 00175 setting the current image to a new empty (zero-by-zero) 00176 ArrayData object. We assume that attached memory will be 00177 destroyed later. */ 00178 inline void detach(); 00179 00180 //! Return a new image object with a deep copy of the underlying data 00181 /*! This function is necessary for safe use of 00182 attach()/detach(). That is, unfortunately attach()/detach() are 00183 not safe for use with shared image objects -- consider the 00184 following code: 00185 00186 \code 00187 double d[4] = { 0.0, 1.0, 2.0, 3.0}; 00188 00189 // create an Image that is attach()'ed to the double array 00190 Image<double> a; 00191 a.attach(&d[0], 2, 2); 00192 00193 const Image<double> b = a; 00194 // now 'b' thinks it has a safe lock on some const values: 00195 00196 d[0] = -1.0; 00197 // OOPS! By changing values in the 'd' array directly, we'll now 00198 // have changed things to that b[0] == -1.0, even though 'b' was 00199 // declared as 'const' 00200 \endcode 00201 00202 The solution to this problem is to prohibit the copy done in 00203 'b=a' above (this triggers an LFATAL() in 00204 ArrayData::acquire()). That assures us that any ArrayData that 00205 has a StoragePolicy of WRITE_THRU will be un-shareable. 00206 00207 So, back to the point -- the correct way to write the code above 00208 would be to use deepcopy(): 00209 00210 \code 00211 double d[4] = { 0.0, 1.0, 2.0, 3.0}; 00212 00213 Image<double> a; 00214 a.attach(&d[0], 2, 2); 00215 00216 const Image<double> b = a.deepcopy(); 00217 00218 d[0] = -1.0; 00219 // Now, 'b' is insulated from any changes to 'd' since we've 00220 // done a deep copy, so even now we'll still have b[0]==0.0 00221 \endcode 00222 */ 00223 inline Image<T> deepcopy() const; 00224 00225 //! Free mem and realloc new array (array contents are lost). 00226 /*! Use rescale() instead if you want to preserve image contents. */ 00227 inline void resize(const Dims& dims, const bool clear = false); 00228 00229 //! Free mem and realloc new array (array contents are lost). 00230 /*! Use rescale() instead if you want to preserve image contents. */ 00231 inline void resize(const int width, const int height, 00232 const bool clear = false); 00233 00234 //@} 00235 00236 // ############################################################ 00237 /*! @name Iterators 00238 00239 There are const and non-const versions of iterators, which are 00240 returned by begin()/end() and beginw()/endw(), respectively. The 00241 "w" in beginw()/endw() is a mnemonic for "write" or 00242 "writeable". Beware that the non-const versions of these 00243 functions will invoke the copy-on-write mechanism (see 00244 ArrayHandle), so a deep copy of all the image data will be made 00245 if the current image object is not the unique owner of its image 00246 data. Thus, begin()/end() should always be used unless write 00247 access is specifically needed. (It is for this reason that we 00248 don't overload the const/non-const functions with the same names 00249 (even though this is possible in C++, as done in the STL 00250 containers)). 00251 00252 Debugging iterators (CheckedIterator) will be used if the macro 00253 INVT_MEM_DEBUG is #define'd. A checked iterator will check that 00254 it is within its proper bounds every time that it is 00255 dereferenced with either operator*() or operator->(). Note that 00256 the existence of the checked iterators means you cannot rely on 00257 an image iterator being a raw pointer. Instead, getArrayPtr() is 00258 available in case you unconditionally need a raw pointer to the 00259 image data. 00260 */ 00261 //@{ 00262 00263 #ifndef INVT_MEM_DEBUG 00264 // standard iterators are just pointers to the data: 00265 //! Read/write iterator. 00266 typedef T* iterator; 00267 //! Read-only iterator. 00268 typedef const T* const_iterator; 00269 #else 00270 // range-checked iterators can detect attempts to access past image bounds: 00271 //! Read/write iterator. 00272 typedef CheckedIterator<T> iterator; 00273 //! Read-only iterator. 00274 typedef CheckedIterator<const T> const_iterator; 00275 #endif 00276 00277 //! Returns a read-only iterator to the beginning of the image data 00278 inline const_iterator begin() const; 00279 00280 //! Returns a read-only iterator to one-past-the-end of the image data 00281 inline const_iterator end() const; 00282 00283 //! Returns a read-write iterator to the beginning of the image data 00284 inline iterator beginw(); 00285 00286 //! Returns a read-write iterator to one-past-the-end of the image data 00287 inline iterator endw(); 00288 00289 //@} 00290 00291 // ############################################################ 00292 /*! @name Access functions*/ 00293 //@{ 00294 00295 //! Check whether image is non-empty (i.e., non-zero height and width). 00296 inline bool initialized() const; 00297 00298 //! Get image size (width * height) 00299 inline int getSize() const; 00300 00301 //! Get image size (width * height) 00302 inline uint size() const; 00303 00304 //! Get image width 00305 inline int getWidth() const; 00306 00307 //! Get image height 00308 inline int getHeight() const; 00309 00310 //! Get image width+height in Dims struct 00311 inline const Dims& getDims() const; 00312 00313 //! Get image bounds as a rectangle with upper-left point at (0,0) and dims matching the image dims 00314 inline Rectangle getBounds() const; 00315 00316 //! Check if *this is the same size as the other thing 00317 /*! The other thing can be any type that exposes getHeight() and 00318 getWidth() */ 00319 template <class C> 00320 inline bool isSameSize(const C& other) const; 00321 00322 //! Check if the image is 1D, i.e., width == 1 or height == 1 00323 inline bool is1D() const; 00324 00325 //! Check if the image is a vector, i.e., width == 1 00326 inline bool isVector() const; 00327 00328 //! Check if the image is a transposed vector, i.e., height == 1 00329 inline bool isTransposedVector() const; 00330 00331 //! Check if the image is square, i.e., width == height 00332 inline bool isSquare() const; 00333 00334 //! Access image elements through C array index interface 00335 inline T& operator[](const int index); 00336 00337 //! Access image elements through C array index interface 00338 inline const T& operator[](const int index) const; 00339 00340 //! Access image elements through C array index interface 00341 inline T& operator[](const Point2D<int>& p); 00342 00343 //! Access image elements through C array index interface 00344 inline const T& operator[](const Point2D<int>& p) const; 00345 00346 //! Get pixel value at index in image 00347 inline const T& getVal(const int index) const; 00348 00349 //! Get pixel value at (x, y) in image 00350 inline const T& getVal(const int x, const int y) const; 00351 00352 //! Get pixel value at specified coordinates in image 00353 inline const T& getVal(const Point2D<int>& p) const; 00354 00355 //! Get value at (x,y), put in val rather that return it 00356 template <class T2> inline void getVal(const int x, const int y, 00357 T2& val) const; 00358 00359 //! Get pixel value at (x, y) in image with bilinear interpolation 00360 inline T getValInterp(const float x, const float y) const; 00361 00362 //! Get pixel value at (x, y) in image with bilinear interpolation 00363 inline T getValInterp(const Point2D<float>& p) const; 00364 00365 //! Get pixel value with bilinear interpolation at a location (x,y) specified in a different Dims scale 00366 /*! We first scale the coordinates into the proper Dims for this 00367 image, and then use getValInterp() */ 00368 inline T getValInterpScaled(const Point2D<int>& p, const Dims& pdims) const; 00369 00370 //! Set value in image at index 00371 template <class T2> inline void setVal(const int index, const T2& value); 00372 00373 //! Set value in image at (x, y) 00374 template <class T2> inline void setVal(const int x, const int y, 00375 const T2& value); 00376 00377 //! Set value in image at Point2D<int> 00378 template <class T2> inline void setVal(const Point2D<int>& p, const T2& value); 00379 00380 //! Returns read-only (const) pointer to internal image array 00381 inline const T* getArrayPtr() const; 00382 00383 //! Returns read/write (non-const) pointer to internal image array 00384 inline T* getArrayPtr(); 00385 00386 //! Test whether point falls inside array boundaries 00387 inline bool coordsOk(const Point2D<int>& P) const; 00388 00389 //! Test whether point falls inside array boundaries 00390 inline bool coordsOk(const int i, const int j) const; 00391 00392 //! Test whether point falls inside array boundaries 00393 /*! This test is intended to be used before you attempt a getValInterp() */ 00394 inline bool coordsOk(const Point2D<float>& p) const; 00395 00396 //! Test whether point falls inside array boundaries 00397 /*! This test is intended to be used before you attempt a getValInterp() */ 00398 inline bool coordsOk(const float i, const float j) const; 00399 00400 //! Test whether rectangle fits in image 00401 inline bool rectangleOk(const Rectangle& rect) const; 00402 00403 //@} 00404 00405 // ############################################################ 00406 /*! @name Operator overloads and basic image manipulations 00407 00408 Note that many other image manipulation functions are available 00409 in Image_ColorOps.H, Image_FilterOps.H, Image_IO.H, 00410 Image_MathOps.H, Image_Omni.H, Image_ShapeOps.H, 00411 Image_Transforms.H, and Image_Conversions.H. 00412 */ 00413 //@{ 00414 00415 //! Equality: true if the images are the same size and all pixels are equal. 00416 bool operator==(const Image<T>& that) const; 00417 00418 //! Add constant to image, clamp result as necessary 00419 Image<T>& operator+=(const T& val); 00420 00421 //! Subtract constant from image, clamp result as necessary 00422 Image<T>& operator-=(const T& val); 00423 00424 //! Multiply image by constant, clamp result as necessary 00425 Image<T>& operator*=(const T& val); 00426 00427 //! Divide image by constant, clamp result as necessary 00428 Image<T>& operator/=(const T& val); 00429 00430 //! Bit-shift left by constant (type T must have operator<<()) 00431 Image<T>& operator<<=(const unsigned int nbits); 00432 00433 //! Bit-shift right by constant (type T must have operator>>()) 00434 Image<T>& operator>>=(const unsigned int nbits); 00435 00436 00437 //! Add image to image, clamp result as necessary 00438 template <class T2> inline 00439 Image<T>& operator+=(const Image<T2>& A); 00440 00441 //! Subtract image from image, clamp result as necessary 00442 template <class T2> inline 00443 Image<T>& operator-=(const Image<T2>& A); 00444 00445 //! Multiply image by image, point-by-point, clamp result as necessary 00446 template <class T2> inline 00447 Image<T>& operator*=(const Image<T2>& A); 00448 00449 //! Divide image by image, point-by-point, clamp result as necessary 00450 template <class T2> inline 00451 Image<T>& operator/=(const Image<T2>& A); 00452 00453 //! Bitwise-or image by image, point-by-point, clamp result as necessary 00454 template <class T2> inline 00455 Image<T>& operator|=(const Image<T2>& A); 00456 00457 00458 //! Add scalar to each point in *this and return result 00459 template <class T2> inline 00460 Image<typename promote_trait<T,T2>::TP> operator+(const T2& val) const; 00461 00462 //! Subtract scalar from each point in *this and return result 00463 template <class T2> inline 00464 Image<typename promote_trait<T,T2>::TP> operator-(const T2& val) const; 00465 00466 //! Multiply scalar each point in *this by scalar and return result 00467 template <class T2> inline 00468 Image<typename promote_trait<T,T2>::TP> operator*(const T2& val) const; 00469 00470 //! Divide each point in *this by scalar and return result 00471 template <class T2> inline 00472 Image<typename promote_trait<T,T2>::TP> operator/(const T2& val) const; 00473 00474 //! Bit-shift left by constant and return result (type T must have operator<<()) 00475 Image<T> operator<<(const unsigned int nbits) const; 00476 00477 //! Bit-shift right by constant and return result (type T must have operator>>()) 00478 Image<T> operator>>(const unsigned int nbits) const; 00479 00480 00481 //! Point-wise add img to image and return result 00482 template <class T2> inline 00483 Image<typename promote_trait<T,T2>::TP> operator+(const 00484 Image<T2>& img) const; 00485 00486 //! Point-wise subtract img from *this and return result 00487 template <class T2> inline 00488 Image<typename promote_trait<T,T2>::TP> operator-(const 00489 Image<T2>& img) const; 00490 00491 //! Point-wise multiply *this by img and return result 00492 template <class T2> inline 00493 Image<typename promote_trait<T,T2>::TP> operator*(const 00494 Image<T2>& img) const; 00495 00496 //! Point-wise divide *this by img and return result 00497 template <class T2> inline 00498 Image<typename promote_trait<T,T2>::TP> operator/(const 00499 Image<T2>& img) const; 00500 00501 00502 //! clear contents (or set to given value) 00503 inline void clear(const T& val = T()); 00504 00505 //@} 00506 00507 // ############################################################ 00508 /*! @name Functions for testing/debugging only */ 00509 //@{ 00510 00511 //! For testing/debugging only. 00512 /*! See if we are pointing to the same ArrayData<T> as is the other 00513 Image<T>. */ 00514 bool hasSameData(const Image<T>& b) const; 00515 00516 //! For testing/debugging only. 00517 /*! Returns the current reference count. */ 00518 long refCount() const throw(); 00519 00520 //! For testing/debugging only. 00521 /*! Check if the ArrayHandle is shared. */ 00522 bool isShared() const throw(); 00523 00524 //@} 00525 00526 private: 00527 // ############################################################ 00528 // ##### Data: 00529 // ############################################################ 00530 ArrayHandle<T> itsHdl; 00531 inline const ArrayData<T>& impl() const; 00532 inline ArrayData<T>& uniq(); 00533 }; 00534 00535 // ###################################################################### 00536 // ###################################################################### 00537 // ###################################################################### 00538 // FREE FUNCTIONS: 00539 // ###################################################################### 00540 // ###################################################################### 00541 // ###################################################################### 00542 00543 //! Return a new Image with the same data, but interpreted as a different shape 00544 /*! NOTE that this is very different from resize()! With reshape(), we 00545 are not changing the number of elements in the Image; rather we 00546 are just changing the way that the internal 1-D memory array is 00547 mapped to a logical 2-D Image. For example, you could reshape a 00548 10x5 Image to a 50x1 Image, or a 25x2 Image, or vice versa. You 00549 need to be aware the fact that Image uses a row-major storage 00550 format internally (i.e., as you step through the memory, you first 00551 traverse all the pixels in row 1, then all the pixels in row 2, 00552 etc.). So if you reshape a WxH Image to a WHx1 Image, your new 1-D 00553 Image will appear to have the rows of the original Image arranged 00554 end-to-end. 00555 00556 Programmer note: In principle, we could support a reshape() 00557 operation that wouldn't require copying any data; in order to do 00558 that we'd need to split the Dims management out of ArrayData and 00559 ArrayHandle, so that a single ArrayData object could be used in 00560 multiple Image objects, each with potentially different Dims (but 00561 all with the same total number of pixels). However, for now we 00562 just use a simpler implementation which copies the data into the 00563 new Image. 00564 */ 00565 template <class T> 00566 inline Image<T> reshape(const Image<T>& orig, const Dims& newdims) 00567 { 00568 ASSERT(orig.getDims().sz() == newdims.sz()); 00569 return Image<T>(orig.getArrayPtr(), newdims); 00570 } 00571 00572 // ###################################################################### 00573 // ###################################################################### 00574 // ###################################################################### 00575 // Iterator traits 00576 // ###################################################################### 00577 // ###################################################################### 00578 // ###################################################################### 00579 namespace std 00580 { 00581 template <class T> struct iterator_traits< Image<T> > 00582 { 00583 typedef T difference_type; 00584 typedef T value_type; 00585 typedef T* pointer; 00586 typedef T& reference; 00587 typedef random_access_iterator_tag iterator_category; 00588 }; 00589 } 00590 00591 // ###################################################################### 00592 // ###################################################################### 00593 // ###################################################################### 00594 // INLINE FUNCTIONS: 00595 // ###################################################################### 00596 // ###################################################################### 00597 // ###################################################################### 00598 00599 // ###################################################################### 00600 // ##### Constructors & Destructors: 00601 // ###################################################################### 00602 00603 // ###################################################################### 00604 template <class T> inline 00605 Image<T>::Image(const T* inarray, int width, int height) : 00606 itsHdl(new ArrayData<T>(Dims(width, height), inarray)) 00607 {} 00608 00609 // ###################################################################### 00610 template <class T> inline 00611 Image<T>::Image(const T* inarray, const Dims& dims) : 00612 itsHdl(new ArrayData<T>(dims, inarray)) 00613 {} 00614 00615 // ###################################################################### 00616 template <class T> inline 00617 Image<T>::Image(int width, int height, InitPolicy init) : 00618 itsHdl(new ArrayData<T>(Dims(width, height), init)) 00619 {} 00620 00621 // ###################################################################### 00622 template <class T> inline 00623 Image<T>::Image(const Dims& dims, InitPolicy init) : 00624 itsHdl(new ArrayData<T>(dims, init)) 00625 {} 00626 00627 // ###################################################################### 00628 template <class T> inline 00629 Image<T>::Image() : 00630 itsHdl(new ArrayData<T>()) 00631 {} 00632 00633 // ###################################################################### 00634 template <class T> inline 00635 Image<T>::Image(const Image<T>& A) : 00636 itsHdl(A.itsHdl) 00637 {} 00638 00639 // ###################################################################### 00640 template <class T> template <class T2> inline 00641 Image<T>::Image(const Image<T2>& A) : 00642 itsHdl(new ArrayData<T>(A.getDims(), NO_INIT)) 00643 { 00644 typename Image<T2>::const_iterator sptr = A.begin(); 00645 typename Image<T>::iterator aptr = beginw(); 00646 typename Image<T>::iterator stop = endw(); 00647 while (aptr != stop) 00648 { 00649 *aptr++ = clamped_convert<T>(*sptr++); 00650 } 00651 } 00652 00653 // ###################################################################### 00654 template <class T> inline 00655 Image<T>& Image<T>::operator=(const Image<T>& A) 00656 { 00657 Image<T> A_copy( A ); 00658 this->swap(A_copy); 00659 return *this; 00660 } 00661 00662 // ###################################################################### 00663 template <class T> template <class T2> inline 00664 Image<T>& Image<T>::operator=(const Image<T2>& A) 00665 { 00666 // make a new image block if necessary 00667 if (this->getDims() != A.getDims() || itsHdl.isShared()) 00668 *this = Image<T>(A.getDims(), NO_INIT); 00669 00670 typename Image<T2>::const_iterator sptr = A.begin(); 00671 typename Image<T>::iterator aptr = this->beginw(); 00672 typename Image<T>::iterator stop = this->endw(); 00673 while (aptr != stop) *aptr++ = clamped_convert<T>(*sptr++); 00674 return *this; 00675 } 00676 00677 // ###################################################################### 00678 template <class T> inline 00679 Image<T>::~Image() 00680 { /* memory deallocation is handled by ArrayData's destructor */ } 00681 00682 // ###################################################################### 00683 template <class T> inline 00684 void Image<T>::freeMem() 00685 { 00686 Image<T> empty; 00687 this->swap(empty); 00688 } 00689 00690 // ###################################################################### 00691 // ##### Memory management functions: 00692 // ###################################################################### 00693 00694 // ###################################################################### 00695 template <class T> inline 00696 void Image<T>::swap(Image<T>& other) 00697 { 00698 itsHdl.swap(other.itsHdl); 00699 } 00700 00701 // ###################################################################### 00702 template <class T> inline 00703 void Image<T>::attach(T* array, const int w, const int h) 00704 { 00705 ArrayHandle<T> attached(new ArrayData<T>(Dims(w, h), array, WRITE_THRU)); 00706 itsHdl.swap(attached); 00707 } 00708 00709 // ###################################################################### 00710 template <class T> inline 00711 void Image<T>::detach() 00712 { 00713 ArrayHandle<T> emptyHdl; 00714 itsHdl.swap(emptyHdl); 00715 } 00716 00717 // ###################################################################### 00718 template <class T> inline 00719 Image<T> Image<T>::deepcopy() const 00720 { 00721 // see comment in class definition for why deepcopy() might be 00722 // needed 00723 return Image<T>(this->getArrayPtr(), this->getDims()); 00724 } 00725 00726 // ###################################################################### 00727 template <class T> inline 00728 void Image<T>::resize(const Dims& dims, const bool do_clear) 00729 { 00730 // This algorithm is slightly more convoluted than may appear necessary 00731 // at first, in order to be most efficient in the context of 00732 // copy-on-write. If the requested size is different than the current 00733 // size, it's very simple: we just make a new image of the right size, 00734 // clearing it if so requested. Otherwise, if we're keeping the same 00735 // size, we don't necessarily have to make a new data block; instead we 00736 // just delegate to clear(), which does the right thing depending on 00737 // whether we currently have a shared or unshared data block. 00738 00739 if (dims != getDims()) 00740 { 00741 ArrayHandle<T> resized(new ArrayData<T>(dims, do_clear ? ZEROS:NO_INIT)); 00742 itsHdl.swap(resized); 00743 } 00744 else // we're keeping the same size, so just clear() if necessary 00745 { 00746 if (do_clear) clear( T() ); 00747 } 00748 } 00749 00750 // ###################################################################### 00751 template <class T> inline 00752 void Image<T>::resize(const int width, const int height, const bool do_clear) 00753 { 00754 resize(Dims(width, height), do_clear); 00755 } 00756 00757 // ###################################################################### 00758 // ##### Iterators: 00759 // ###################################################################### 00760 00761 #ifndef INVT_MEM_DEBUG 00762 00763 template<class T> inline 00764 typename Image<T>::const_iterator Image<T>::begin() const 00765 { return impl().data(); } 00766 00767 template<class T> inline 00768 typename Image<T>::const_iterator Image<T>::end() const 00769 { return impl().end(); } 00770 00771 template<class T> inline 00772 typename Image<T>::iterator Image<T>::beginw() 00773 { return uniq().dataw(); } 00774 00775 template<class T> inline 00776 typename Image<T>::iterator Image<T>::endw() 00777 { return uniq().endw(); } 00778 00779 #else 00780 00781 template <class T> inline 00782 typename Image<T>::const_iterator Image<T>::begin() const 00783 { return const_iterator(impl().data(), impl().data(), impl().end()); } 00784 00785 template <class T> inline 00786 typename Image<T>::const_iterator Image<T>::end() const 00787 { return const_iterator(impl().end(), impl().data(), impl().end()); } 00788 00789 template <class T> inline 00790 typename Image<T>::iterator Image<T>::beginw() 00791 { return iterator(uniq().dataw(), uniq().dataw(), uniq().endw()); } 00792 00793 template <class T> inline 00794 typename Image<T>::iterator Image<T>::endw() 00795 { return iterator(uniq().endw(), uniq().dataw(), uniq().endw()); } 00796 00797 #endif 00798 00799 // ###################################################################### 00800 // ##### Access functions: 00801 // ###################################################################### 00802 00803 // ###################################################################### 00804 template <class T> inline 00805 bool Image<T>::initialized() const 00806 { return getWidth() > 0 && getHeight() > 0; } 00807 00808 // ###################################################################### 00809 template <class T> inline 00810 int Image<T>::getSize() const 00811 { return getDims().sz(); } 00812 00813 // ###################################################################### 00814 template <class T> inline 00815 uint Image<T>::size() const 00816 { return getDims().sz(); } 00817 00818 // ###################################################################### 00819 template <class T> inline 00820 int Image<T>::getWidth() const 00821 { return itsHdl.get().w(); } 00822 00823 // ###################################################################### 00824 template <class T> inline 00825 int Image<T>::getHeight() const 00826 { return itsHdl.get().h(); } 00827 00828 // ###################################################################### 00829 template <class T> inline 00830 const Dims& Image<T>::getDims() const 00831 { return itsHdl.get().dims(); } 00832 00833 // ###################################################################### 00834 template <class T> inline 00835 Rectangle Image<T>::getBounds() const 00836 { return Rectangle(Point2D<int>(0,0), itsHdl.get().dims()); } 00837 00838 // ###################################################################### 00839 template <class T> template <class C> inline 00840 bool Image<T>::isSameSize(const C& other) const 00841 { return getWidth() == other.getWidth() && getHeight() == other.getHeight(); } 00842 00843 // ###################################################################### 00844 template <class T> inline 00845 bool Image<T>::is1D() const 00846 { return (getWidth() == 1) || (getHeight() == 1); } 00847 00848 // ###################################################################### 00849 template <class T> inline 00850 bool Image<T>::isVector() const 00851 { return (getWidth() == 1); } 00852 00853 // ###################################################################### 00854 template <class T> inline 00855 bool Image<T>::isTransposedVector() const 00856 { return (getHeight() == 1); } 00857 00858 // ###################################################################### 00859 template <class T> inline 00860 bool Image<T>::isSquare() const 00861 { return (getWidth() == getHeight()); } 00862 00863 // ###################################################################### 00864 template <class T> inline 00865 T& Image<T>::operator[](int index) 00866 { 00867 ASSERT(index >= 0 && index < this->getSize()); 00868 return beginw()[index]; 00869 } 00870 00871 // ###################################################################### 00872 template <class T> inline 00873 const T& Image<T>::operator[](int index) const 00874 { 00875 ASSERT(index >= 0 && index < this->getSize()); 00876 return begin()[index]; 00877 } 00878 00879 // ###################################################################### 00880 template <class T> inline 00881 T& Image<T>::operator[](const Point2D<int>& p) 00882 { 00883 ASSERT(this->coordsOk(p)); 00884 return this->beginw()[p.i + p.j * this->getWidth()]; 00885 } 00886 00887 // ###################################################################### 00888 template <class T> inline 00889 const T& Image<T>::operator[](const Point2D<int>& p) const 00890 { 00891 ASSERT(this->coordsOk(p)); 00892 return this->begin()[p.i + p.j * this->getWidth()]; 00893 } 00894 00895 // ###################################################################### 00896 template <class T> inline 00897 const T& Image<T>::getVal(const int index) const 00898 { 00899 ASSERT(index >= 0 && index < this->getSize()); 00900 return begin()[index]; 00901 } 00902 00903 // ###################################################################### 00904 template <class T> inline 00905 const T& Image<T>::getVal(const int x, const int y) const 00906 { 00907 ASSERT(coordsOk(x, y)); 00908 return(begin()[x + y * getWidth()]); 00909 } 00910 00911 // ###################################################################### 00912 template <class T> inline 00913 const T& Image<T>::getVal(const Point2D<int>& p) const 00914 { 00915 ASSERT(coordsOk(p)); 00916 return(begin()[p.i + p.j * getWidth()]); 00917 } 00918 00919 // ###################################################################### 00920 template <class T> template <class T2> inline 00921 void Image<T>::getVal(const int x, const int y, T2& val) const 00922 { 00923 ASSERT(coordsOk(x, y)); 00924 val = begin()[x + y * getWidth()]; 00925 } 00926 00927 // ###################################################################### 00928 template <class T> inline 00929 T Image<T>::getValInterp(const float x, const float y) const 00930 { 00931 typename Image<T>::const_iterator const sptr = begin(); 00932 const int wid = getWidth(), hei = getHeight(); 00933 00934 const int y0 = int(y); 00935 const int y1 = std::min(y0 + 1, hei - 1); 00936 const float fy = y - float(y0); 00937 00938 const int wy0 = wid * y0; 00939 const int wy1 = wid * y1; 00940 00941 const int x0 = int(x); 00942 const int x1 = std::min(x0 + 1, wid - 1); 00943 const float fx = x - float(x0); 00944 00945 ASSERT(coordsOk(x0, y0)); 00946 typename promote_trait<T, float>::TP const 00947 d00( sptr[x0 + wy0] ), d10( sptr[x1 + wy0] ), 00948 d01( sptr[x0 + wy1] ), d11( sptr[x1 + wy1] ), 00949 dx0( d00 + (d10 - d00) * fx ), 00950 dx1( d01 + (d11 - d01) * fx ); 00951 00952 return T( dx0 + (dx1 - dx0) * fy ); // no need to clamp 00953 } 00954 00955 // ###################################################################### 00956 template <class T> inline 00957 T Image<T>::getValInterp(const Point2D<float>& p) const 00958 { 00959 return this->getValInterp(p.i, p.j); 00960 } 00961 00962 // ###################################################################### 00963 template <class T> inline 00964 T Image<T>::getValInterpScaled(const Point2D<int>& p, 00965 const Dims& pdims) const 00966 { 00967 const float x = 00968 std::max(0.0f, (float(p.i)+0.5f) * float(this->getWidth())/pdims.w() - 0.5f); 00969 const float y = 00970 std::max(0.0f, (float(p.j)+0.5f) * float(this->getHeight())/pdims.h() - 0.5f); 00971 00972 return this->getValInterp(x, y); 00973 } 00974 00975 // ###################################################################### 00976 template <class T> template <class T2> inline 00977 void Image<T>::setVal(const int index, const T2& value) 00978 { 00979 ASSERT(index >= 0 && index < this->getSize()); 00980 beginw()[index] = clamped_convert<T>(value); 00981 } 00982 00983 // ###################################################################### 00984 template <class T> template <class T2> inline 00985 void Image<T>::setVal(const int x, const int y, const T2& value) 00986 { 00987 ASSERT(coordsOk(x, y)); 00988 beginw()[x + y * getWidth()] = clamped_convert<T>(value); 00989 } 00990 00991 // ###################################################################### 00992 template <class T> template <class T2> inline 00993 void Image<T>::setVal(const Point2D<int>& p, const T2& value) 00994 { 00995 ASSERT(coordsOk(p)); 00996 beginw()[p.i + p.j * getWidth()] = clamped_convert<T>(value); 00997 } 00998 00999 // ###################################################################### 01000 template <class T> inline 01001 const T* Image<T>::getArrayPtr() const 01002 { 01003 return impl().data(); 01004 } 01005 01006 // ###################################################################### 01007 template <class T> inline 01008 T* Image<T>::getArrayPtr() 01009 { 01010 return uniq().dataw(); 01011 } 01012 01013 // ###################################################################### 01014 template <class T> inline 01015 bool Image<T>::coordsOk(const Point2D<int>& P) const 01016 { 01017 return (P.i >= 0 && P.j >= 0 && P.i < getWidth() && P.j < getHeight()); 01018 } 01019 01020 // ###################################################################### 01021 template <class T> inline 01022 bool Image<T>::coordsOk(const int i, const int j) const 01023 { 01024 return (i >= 0 && j >= 0 && i < getWidth() && j < getHeight()); 01025 } 01026 01027 // ###################################################################### 01028 template <class T> inline 01029 bool Image<T>::coordsOk(const Point2D<float>& p) const 01030 { 01031 return this->coordsOk(p.i, p.j); 01032 } 01033 01034 // ###################################################################### 01035 template <class T> inline 01036 bool Image<T>::coordsOk(const float i, const float j) const 01037 { 01038 return (i >= 0.0F && j >= 0.0F && 01039 i < float(getWidth() - 1) && j < float(getHeight() - 1)); 01040 } 01041 01042 // ###################################################################### 01043 template <class T> inline 01044 bool Image<T>::rectangleOk(const Rectangle& rect) const 01045 { 01046 return (rect.left() < getWidth() && rect.rightI() < getWidth() && 01047 rect.top() < getHeight() && rect.bottomI() < getHeight() && 01048 rect.left() >= 0 && rect.rightI() >= 0 && 01049 rect.top() >= 0 && rect.bottomI() >= 0); 01050 } 01051 01052 // ###################################################################### 01053 template <class T> 01054 bool Image<T>::operator==(const Image<T>& that) const 01055 { 01056 if (!this->isSameSize(that)) return false; 01057 01058 return std::equal(this->begin(), this->end(), that.begin()); 01059 } 01060 01061 // ###################################################################### 01062 template <class T> inline 01063 Image<T>& Image<T>::operator+=(const T& val) 01064 { 01065 for (typename Image<T>::iterator itr = beginw(), stop = endw(); 01066 itr != stop; ++itr) 01067 *itr = clamped_convert<T>( (*itr) + val ); 01068 return *this; 01069 } 01070 01071 // ###################################################################### 01072 template <class T> inline 01073 Image<T>& Image<T>::operator-=(const T& val) 01074 { 01075 for (typename Image<T>::iterator itr = beginw(), stop = endw(); 01076 itr != stop; ++itr) 01077 *itr = clamped_convert<T>( (*itr) - val ); 01078 return *this; 01079 } 01080 01081 // ###################################################################### 01082 template <class T> inline 01083 Image<T>& Image<T>::operator*=(const T& val) 01084 { 01085 for (typename Image<T>::iterator itr = beginw(), stop = endw(); 01086 itr != stop; ++itr) 01087 *itr = clamped_convert<T>( (*itr) * val ); 01088 return *this; 01089 } 01090 01091 // ###################################################################### 01092 template <class T> inline 01093 Image<T>& Image<T>::operator/=(const T& val) 01094 { 01095 for (typename Image<T>::iterator itr = beginw(), stop = endw(); 01096 itr != stop; ++itr) 01097 *itr = clamped_convert<T>( (*itr) / val ); 01098 return *this; 01099 } 01100 01101 // ###################################################################### 01102 template <class T> inline 01103 Image<T>& Image<T>::operator<<=(const unsigned int nbits) 01104 { 01105 for (typename Image<T>::iterator itr = beginw(), stop = endw(); 01106 itr != stop; ++itr) 01107 *itr <<= nbits; 01108 return *this; 01109 } 01110 01111 // ###################################################################### 01112 template <class T> inline 01113 Image<T>& Image<T>::operator>>=(const unsigned int nbits) 01114 { 01115 for (typename Image<T>::iterator itr = beginw(), stop = endw(); 01116 itr != stop; ++itr) 01117 *itr >>= nbits; 01118 return *this; 01119 } 01120 01121 // ###################################################################### 01122 template <class T> template <class T2> inline 01123 Image<T>& Image<T>::operator+=(const Image<T2>& A) 01124 { 01125 ASSERT(isSameSize(A)); 01126 typename Image<T2>::const_iterator itr2 = A.begin(); 01127 for (typename Image<T>::iterator itr = beginw(), stop = endw(); 01128 itr != stop; ++itr, ++itr2) 01129 *itr = clamped_convert<T>( (*itr) + (*itr2) ); 01130 return *this; 01131 } 01132 01133 // ###################################################################### 01134 template <class T> template <class T2> inline 01135 Image<T>& Image<T>::operator-=(const Image<T2>& A) 01136 { 01137 ASSERT(isSameSize(A)); 01138 typename Image<T2>::const_iterator itr2 = A.begin(); 01139 for (typename Image<T>::iterator itr = beginw(), stop = endw(); 01140 itr != stop; ++itr, ++itr2) 01141 *itr = clamped_convert<T>( (*itr) - (*itr2) ); 01142 return *this; 01143 } 01144 01145 // ###################################################################### 01146 template <class T> template <class T2> inline 01147 Image<T>& Image<T>::operator*=(const Image<T2>& A) 01148 { 01149 ASSERT(isSameSize(A)); 01150 typename Image<T2>::const_iterator itr2 = A.begin(); 01151 for (typename Image<T>::iterator itr = beginw(), stop = endw(); 01152 itr != stop; ++itr, ++itr2) 01153 *itr = clamped_convert<T>( (*itr) * (*itr2) ); 01154 return *this; 01155 } 01156 01157 // ###################################################################### 01158 template <class T> template <class T2> inline 01159 Image<T>& Image<T>::operator/=(const Image<T2>& A) 01160 { 01161 ASSERT(isSameSize(A)); 01162 typename Image<T2>::const_iterator itr2 = A.begin(); 01163 for (typename Image<T>::iterator itr = beginw(), stop = endw(); 01164 itr != stop; ++itr, ++itr2) 01165 *itr = clamped_convert<T>( (*itr) / (*itr2) ); 01166 return *this; 01167 } 01168 01169 // ###################################################################### 01170 template <class T> template <class T2> inline 01171 Image<T>& Image<T>::operator|=(const Image<T2>& A) 01172 { 01173 ASSERT(isSameSize(A)); 01174 typename Image<T2>::const_iterator itr2 = A.begin(); 01175 for (typename Image<T>::iterator itr = beginw(), stop = endw(); 01176 itr != stop; ++itr, ++itr2) 01177 *itr = clamped_convert<T>( (*itr) | (*itr2) ); 01178 return *this; 01179 } 01180 // ###################################################################### 01181 template <class T> template <class T2> inline 01182 Image<typename promote_trait<T,T2>::TP> Image<T>::operator+(const T2& val) const 01183 { 01184 typedef typename promote_trait<T,T2>::TP TPRO; 01185 Image<TPRO> result(getWidth(), getHeight(), NO_INIT); 01186 typename Image<TPRO>::iterator ritr = result.beginw(); 01187 for (typename Image<T>::const_iterator itr = begin(), stop = end(); 01188 itr != stop; ++itr, ++ritr) 01189 *ritr = (*itr) + val; 01190 return result; 01191 } 01192 01193 // ###################################################################### 01194 template <class T> template <class T2> inline 01195 Image<typename promote_trait<T,T2>::TP> Image<T>::operator-(const T2& val) const 01196 { 01197 typedef typename promote_trait<T,T2>::TP TPRO; 01198 Image<TPRO> result(getWidth(), getHeight(), NO_INIT); 01199 typename Image<TPRO>::iterator ritr = result.beginw(); 01200 for (typename Image<T>::const_iterator itr = begin(), stop = end(); 01201 itr != stop; ++itr, ++ritr) 01202 *ritr = (*itr) - val; 01203 return result; 01204 } 01205 01206 // ###################################################################### 01207 template <class T> template <class T2> inline 01208 Image<typename promote_trait<T,T2>::TP> Image<T>::operator*(const T2& val) const 01209 { 01210 typedef typename promote_trait<T,T2>::TP TPRO; 01211 Image<TPRO> result(getWidth(), getHeight(), NO_INIT); 01212 typename Image<TPRO>::iterator ritr = result.beginw(); 01213 for (typename Image<T>::const_iterator itr = begin(), stop = end(); 01214 itr != stop; ++itr, ++ritr) 01215 *ritr = (*itr) * val; 01216 return result; 01217 } 01218 01219 // ###################################################################### 01220 template <class T> template <class T2> inline 01221 Image<typename promote_trait<T,T2>::TP> Image<T>::operator/(const T2& val) const 01222 { 01223 typedef typename promote_trait<T,T2>::TP TPRO; 01224 Image<TPRO> result(getWidth(), getHeight(), NO_INIT); 01225 typename Image<TPRO>::iterator ritr = result.beginw(); 01226 for (typename Image<T>::const_iterator itr = begin(), stop = end(); 01227 itr != stop; ++itr, ++ritr) 01228 *ritr = (*itr) / val; 01229 return result; 01230 } 01231 01232 // ###################################################################### 01233 template <class T> inline 01234 Image<T> Image<T>::operator<<(const unsigned int nbits) const 01235 { 01236 Image<T> result(getWidth(), getHeight(), NO_INIT); 01237 typename Image<T>::iterator ritr = result.beginw(); 01238 for (typename Image<T>::const_iterator itr = this->begin(), stop = this->end(); 01239 itr != stop; ++itr, ++ritr) 01240 *ritr = ((*itr) << nbits); 01241 return result; 01242 } 01243 01244 // ###################################################################### 01245 template <class T> inline 01246 Image<T> Image<T>::operator>>(const unsigned int nbits) const 01247 { 01248 Image<T> result(getWidth(), getHeight(), NO_INIT); 01249 typename Image<T>::iterator ritr = result.beginw(); 01250 for (typename Image<T>::const_iterator itr = this->begin(), stop = this->end(); 01251 itr != stop; ++itr, ++ritr) 01252 *ritr = ((*itr) >> nbits); 01253 return result; 01254 } 01255 01256 // ###################################################################### 01257 template <class T> template <class T2> inline 01258 Image<typename promote_trait<T,T2>::TP> Image<T>::operator+(const Image<T2>& img) const 01259 { 01260 ASSERT(isSameSize(img)); 01261 typedef typename promote_trait<T,T2>::TP TPRO; 01262 Image<TPRO> result(getWidth(), getHeight(), NO_INIT); 01263 typename Image<TPRO>::iterator ritr = result.beginw(); 01264 typename Image<T2>::const_iterator itr2 = img.begin(); 01265 for (typename Image<T>::const_iterator itr = begin(), stop = end(); 01266 itr != stop; ++itr, ++itr2, ++ritr) 01267 *ritr = (*itr) + (*itr2); 01268 return result; 01269 } 01270 01271 // ###################################################################### 01272 template <class T> template <class T2> inline 01273 Image<typename promote_trait<T,T2>::TP> Image<T>::operator-(const Image<T2>& img) const 01274 { 01275 ASSERT(isSameSize(img)); 01276 typedef typename promote_trait<T,T2>::TP TPRO; 01277 Image<TPRO> result(getWidth(), getHeight(), NO_INIT); 01278 typename Image<TPRO>::iterator ritr = result.beginw(); 01279 typename Image<T2>::const_iterator itr2 = img.begin(); 01280 for (typename Image<T>::const_iterator itr = begin(), stop = end(); 01281 itr != stop; ++itr, ++itr2, ++ritr) 01282 *ritr = (*itr) - (*itr2); 01283 return result; 01284 } 01285 01286 // ###################################################################### 01287 template <class T> template <class T2> inline 01288 Image<typename promote_trait<T,T2>::TP> Image<T>::operator*(const Image<T2>& img) const 01289 { 01290 ASSERT(isSameSize(img)); 01291 typedef typename promote_trait<T,T2>::TP TPRO; 01292 Image<TPRO> result(getWidth(), getHeight(), NO_INIT); 01293 typename Image<TPRO>::iterator ritr = result.beginw(); 01294 typename Image<T2>::const_iterator itr2 = img.begin(); 01295 for (typename Image<T>::const_iterator itr = begin(), stop = end(); 01296 itr != stop; ++itr, ++itr2, ++ritr) 01297 *ritr = (*itr) * (*itr2); 01298 return result; 01299 } 01300 01301 // ###################################################################### 01302 template <class T> template <class T2> inline 01303 Image<typename promote_trait<T,T2>::TP> Image<T>::operator/(const Image<T2>& img) const 01304 { 01305 ASSERT(isSameSize(img)); 01306 typedef typename promote_trait<T,T2>::TP TPRO; 01307 Image<TPRO> result(getWidth(), getHeight(), NO_INIT); 01308 typename Image<TPRO>::iterator ritr = result.beginw(); 01309 typename Image<T2>::const_iterator itr2 = img.begin(); 01310 for (typename Image<T>::const_iterator itr = begin(), stop = end(); 01311 itr != stop; ++itr, ++itr2, ++ritr) 01312 *ritr = (*itr) / (*itr2); 01313 return result; 01314 } 01315 01316 // ###################################################################### 01317 template <class T> inline 01318 void Image<T>::clear(const T& val) 01319 { 01320 // Check if we have a shared implementation... if yes, then for 01321 // efficiency we should release our copy before doing the iterative 01322 // loop, which would otherwise unnecessarily make a unique copy of 01323 // the shared data for us, which we would then ceremoniously ignore 01324 // as we clear it to a new value. 01325 if (itsHdl.isShared()) 01326 *this = Image<T>(getDims(), NO_INIT); 01327 01328 for (iterator itr = beginw(), stop = endw(); itr != stop; ++itr) 01329 *itr = val; 01330 } 01331 01332 // ###################################################################### 01333 // ##### Functions for testing/debugging only: 01334 // ###################################################################### 01335 01336 template <class T> inline 01337 bool Image<T>::hasSameData(const Image<T>& b) const 01338 { return itsHdl.hasSameData(b.itsHdl); } 01339 01340 // ###################################################################### 01341 template <class T> inline 01342 long Image<T>::refCount() const throw() { return itsHdl.refCount(); } 01343 01344 // ###################################################################### 01345 template <class T> inline 01346 bool Image<T>::isShared() const throw() { return itsHdl.isShared(); } 01347 01348 // ###################################################################### 01349 // ##### Private methods: 01350 // ###################################################################### 01351 01352 template <class T> inline 01353 const ArrayData<T>& Image<T>::impl() const 01354 { return itsHdl.get(); } 01355 01356 // ###################################################################### 01357 template <class T> inline 01358 ArrayData<T>& Image<T>::uniq() 01359 { return itsHdl.uniq(); } 01360 01361 // ###################################################################### 01362 /* So things look consistent in everyone's emacs... */ 01363 /* Local Variables: */ 01364 /* indent-tabs-mode: nil */ 01365 /* End: */ 01366 01367 #endif