Main Page | Modules | Namespace List | Class Hierarchy | Alphabetical List | Class List | Directories | File List | Namespace Members | Class Members | File Members | Related Pages

Image.H

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

Generated on Sat Nov 21 13:45:14 2009 for iLab Neuromorphic Vision Toolkit by  doxygen 1.4.4