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 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
Generated on Sun May 8 08:05:12 2011 for iLab Neuromorphic Vision Toolkit by  doxygen 1.6.3