/////////////////////////////////////////////////////////////////////////////// // IMPORTANT: READ BEFORE DOWNLOADING, COPYING, INSTALLING OR USING. // // By downloading, copying, installing or using the software you agree to // this license. If you do not agree to this license, do not download, // install, copy or use the software. // // License Agreement // For Open Source Computer Vision Library // // Copyright (C) 2008, Google, all rights reserved. // Third party copyrights are property of their respective owners. // // Redistribution and use in source and binary forms, with or without // modification, are permitted provided that the following conditions are met: // // * Redistribution's of source code must retain the above copyright notice, // this list of conditions and the following disclaimer. // // * Redistribution's in binary form must reproduce the above copyright notice, // this list of conditions and the following disclaimer in the documentation // and/or other materials provided with the distribution. // // * The name of Intel Corporation or contributors may not be used to endorse // or promote products derived from this software without specific // prior written permission. // // This software is provided by the copyright holders and contributors "as is" // and any express or implied warranties, including, but not limited to, the // implied warranties of merchantability and fitness for a particular purpose // are disclaimed. In no event shall the Intel Corporation or contributors be // liable for any direct, indirect, incidental, special, exemplary, or // consequential damages // (including, but not limited to, procurement of substitute goods or services; // loss of use, data, or profits; or business interruption) however caused // and on any theory of liability, whether in contract, strict liability, // or tort (including negligence or otherwise) arising in any way out of // the use of this software, even if advised of the possibility of such damage. ///////////////////////////////////////////////////////////////////////////////// // // Image class which provides a thin layer around an IplImage. The goals // of the class design are: // 1. All the data has explicit ownership to avoid memory leaks // 2. No hidden allocations or copies for performance. // 3. Easy access to OpenCV methods (which will access IPP if available) // 4. Can easily treat external data as an image // 5. Easy to create images which are subsets of other images // 6. Fast pixel access which can take advantage of number of channels // if known at compile time. // // The WImage class is the image class which provides the data accessors. // The 'W' comes from the fact that it is also a wrapper around the popular // but inconvenient IplImage class. A WImage can be constructed either using a // WImageBuffer class which allocates and frees the data, // or using a WImageView class which constructs a subimage or a view into // external data. The view class does no memory management. Each class // actually has two versions, one when the number of channels is known at // compile time and one when it isn't. Using the one with the number of // channels specified can provide some compile time optimizations by using the // fact that the number of channels is a constant. // // We use the convention (c,r) to refer to column c and row r with (0,0) being // the upper left corner. This is similar to standard Euclidean coordinates // with the first coordinate varying in the horizontal direction and the second // coordinate varying in the vertical direction. // Thus (c,r) is usually in the domain [0, width) X [0, height) // // Example usage: // WImageBuffer3_b im(5,7); // Make a 5X7 3 channel image of type uchar // WImageView3_b sub_im(im, 2,2, 3,3); // 3X3 submatrix // vector<float> vec(10, 3.0f); // WImageView1_f user_im(&vec[0], 2, 5); // 2X5 image w/ supplied data // // im.SetZero(); // same as cvSetZero(im.Ipl()) // *im(2, 3) = 15; // Modify the element at column 2, row 3 // MySetRand(&sub_im); // // // Copy the second row into the first. This can be done with no memory // // allocation and will use SSE if IPP is available. // int w = im.Width(); // im.View(0,0, w,1).CopyFrom(im.View(0,1, w,1)); // // // Doesn't care about source of data since using WImage // void MySetRand(WImage_b* im) { // Works with any number of channels // for (int r = 0; r < im->Height(); ++r) { // float* row = im->Row(r); // for (int c = 0; c < im->Width(); ++c) { // for (int ch = 0; ch < im->Channels(); ++ch, ++row) { // *row = uchar(rand() & 255); // } // } // } // } // // Functions that are not part of the basic image allocation, viewing, and // access should come from OpenCV, except some useful functions that are not // part of OpenCV can be found in wimage_util.h #ifndef _CV_WIMAGE_H_ #define _CV_WIMAGE_H_ #include "cxcore.h" #ifdef __cplusplus namespace cv { template <typename T> class WImage; template <typename T> class WImageBuffer; template <typename T> class WImageView; template<typename T, int C> class WImageC; template<typename T, int C> class WImageBufferC; template<typename T, int C> class WImageViewC; // Commonly used typedefs. typedef WImage<uchar> WImage_b; typedef WImageView<uchar> WImageView_b; typedef WImageBuffer<uchar> WImageBuffer_b; typedef WImageC<uchar, 1> WImage1_b; typedef WImageViewC<uchar, 1> WImageView1_b; typedef WImageBufferC<uchar, 1> WImageBuffer1_b; typedef WImageC<uchar, 3> WImage3_b; typedef WImageViewC<uchar, 3> WImageView3_b; typedef WImageBufferC<uchar, 3> WImageBuffer3_b; typedef WImage<float> WImage_f; typedef WImageView<float> WImageView_f; typedef WImageBuffer<float> WImageBuffer_f; typedef WImageC<float, 1> WImage1_f; typedef WImageViewC<float, 1> WImageView1_f; typedef WImageBufferC<float, 1> WImageBuffer1_f; typedef WImageC<float, 3> WImage3_f; typedef WImageViewC<float, 3> WImageView3_f; typedef WImageBufferC<float, 3> WImageBuffer3_f; // There isn't a standard for signed and unsigned short so be more // explicit in the typename for these cases. typedef WImage<short> WImage_16s; typedef WImageView<short> WImageView_16s; typedef WImageBuffer<short> WImageBuffer_16s; typedef WImageC<short, 1> WImage1_16s; typedef WImageViewC<short, 1> WImageView1_16s; typedef WImageBufferC<short, 1> WImageBuffer1_16s; typedef WImageC<short, 3> WImage3_16s; typedef WImageViewC<short, 3> WImageView3_16s; typedef WImageBufferC<short, 3> WImageBuffer3_16s; typedef WImage<ushort> WImage_16u; typedef WImageView<ushort> WImageView_16u; typedef WImageBuffer<ushort> WImageBuffer_16u; typedef WImageC<ushort, 1> WImage1_16u; typedef WImageViewC<ushort, 1> WImageView1_16u; typedef WImageBufferC<ushort, 1> WImageBuffer1_16u; typedef WImageC<ushort, 3> WImage3_16u; typedef WImageViewC<ushort, 3> WImageView3_16u; typedef WImageBufferC<ushort, 3> WImageBuffer3_16u; // // WImage definitions // // This WImage class gives access to the data it refers to. It can be // constructed either by allocating the data with a WImageBuffer class or // using the WImageView class to refer to a subimage or outside data. template<typename T> class WImage { public: typedef T BaseType; // WImage is an abstract class with no other virtual methods so make the // destructor virtual. virtual ~WImage() = 0; // Accessors IplImage* Ipl() {return image_; } const IplImage* Ipl() const {return image_; } T* ImageData() { return reinterpret_cast<T*>(image_->imageData); } const T* ImageData() const { return reinterpret_cast<const T*>(image_->imageData); } int Width() const {return image_->width; } int Height() const {return image_->height; } // WidthStep is the number of bytes to go to the pixel with the next y coord int WidthStep() const {return image_->widthStep; } int Channels() const {return image_->nChannels; } int ChannelSize() const {return sizeof(T); } // number of bytes per channel // Number of bytes per pixel int PixelSize() const {return Channels() * ChannelSize(); } // Return depth type (e.g. IPL_DEPTH_8U, IPL_DEPTH_32F) which is the number // of bits per channel and with the signed bit set. // This is known at compile time using specializations. int Depth() const; inline const T* Row(int r) const { return reinterpret_cast<T*>(image_->imageData + r*image_->widthStep); } inline T* Row(int r) { return reinterpret_cast<T*>(image_->imageData + r*image_->widthStep); } // Pixel accessors which returns a pointer to the start of the channel inline T* operator() (int c, int r) { return reinterpret_cast<T*>(image_->imageData + r*image_->widthStep) + c*Channels(); } inline const T* operator() (int c, int r) const { return reinterpret_cast<T*>(image_->imageData + r*image_->widthStep) + c*Channels(); } // Copy the contents from another image which is just a convenience to cvCopy void CopyFrom(const WImage<T>& src) { cvCopy(src.Ipl(), image_); } // Set contents to zero which is just a convenient to cvSetZero void SetZero() { cvSetZero(image_); } // Construct a view into a region of this image WImageView<T> View(int c, int r, int width, int height); protected: // Disallow copy and assignment WImage(const WImage&); void operator=(const WImage&); explicit WImage(IplImage* img) : image_(img) { assert(!img || img->depth == Depth()); } void SetIpl(IplImage* image) { assert(!image || image->depth == Depth()); image_ = image; } IplImage* image_; }; // Image class when both the pixel type and number of channels // are known at compile time. This wrapper will speed up some of the operations // like accessing individual pixels using the () operator. template<typename T, int C> class WImageC : public WImage<T> { public: typedef typename WImage<T>::BaseType BaseType; enum { kChannels = C }; explicit WImageC(IplImage* img) : WImage<T>(img) { assert(!img || img->nChannels == Channels()); } // Construct a view into a region of this image WImageViewC<T, C> View(int c, int r, int width, int height); // Copy the contents from another image which is just a convenience to cvCopy void CopyFrom(const WImageC<T, C>& src) { cvCopy(src.Ipl(), WImage<T>::image_); } // WImageC is an abstract class with no other virtual methods so make the // destructor virtual. virtual ~WImageC() = 0; int Channels() const {return C; } protected: // Disallow copy and assignment WImageC(const WImageC&); void operator=(const WImageC&); void SetIpl(IplImage* image) { assert(!image || image->depth == WImage<T>::Depth()); WImage<T>::SetIpl(image); } }; // // WImageBuffer definitions // // Image class which owns the data, so it can be allocated and is always // freed. It cannot be copied but can be explicity cloned. // template<typename T> class WImageBuffer : public WImage<T> { public: typedef typename WImage<T>::BaseType BaseType; // Default constructor which creates an object that can be WImageBuffer() : WImage<T>(0) {} WImageBuffer(int width, int height, int nchannels) : WImage<T>(0) { Allocate(width, height, nchannels); } // Constructor which takes ownership of a given IplImage so releases // the image on destruction. explicit WImageBuffer(IplImage* img) : WImage<T>(img) {} // Allocate an image. Does nothing if current size is the same as // the new size. void Allocate(int width, int height, int nchannels); // Set the data to point to an image, releasing the old data void SetIpl(IplImage* img) { ReleaseImage(); WImage<T>::SetIpl(img); } // Clone an image which reallocates the image if of a different dimension. void CloneFrom(const WImage<T>& src) { Allocate(src.Width(), src.Height()); CopyFrom(src); } ~WImageBuffer() { ReleaseImage(); } // Release the image if it isn't null. void ReleaseImage() { if (WImage<T>::image_) { IplImage* image = WImage<T>::image_; cvReleaseImage(&image); WImage<T>::SetIpl(0); } } bool IsNull() const {return WImage<T>::image_ == NULL; } private: // Disallow copy and assignment WImageBuffer(const WImageBuffer&); void operator=(const WImageBuffer&); }; // Like a WImageBuffer class but when the number of channels is known // at compile time. template<typename T, int C> class WImageBufferC : public WImageC<T, C> { public: typedef typename WImage<T>::BaseType BaseType; enum { kChannels = C }; // Default constructor which creates an object that can be WImageBufferC() : WImageC<T, C>(0) {} WImageBufferC(int width, int height) : WImageC<T, C>(0) { Allocate(width, height); } // Constructor which takes ownership of a given IplImage so releases // the image on destruction. explicit WImageBufferC(IplImage* img) : WImageC<T, C>(img) {} // Allocate an image. Does nothing if current size is the same as // the new size. void Allocate(int width, int height); // Set the data to point to an image, releasing the old data void SetIpl(IplImage* img) { ReleaseImage(); WImageC<T, C>::SetIpl(img); } // Clone an image which reallocates the image if of a different dimension. void CloneFrom(const WImageC<T, C>& src) { Allocate(src.Width(), src.Height()); CopyFrom(src); } ~WImageBufferC() { ReleaseImage(); } // Release the image if it isn't null. void ReleaseImage() { if (WImage<T>::image_) { IplImage* image = WImage<T>::image_; cvReleaseImage(&image); WImageC<T, C>::SetIpl(0); } } bool IsNull() const {return WImage<T>::image_ == NULL; } private: // Disallow copy and assignment WImageBufferC(const WImageBufferC&); void operator=(const WImageBufferC&); }; // // WImageView definitions // // View into an image class which allows treating a subimage as an image // or treating external data as an image // template<typename T> class WImageView : public WImage<T> { public: typedef typename WImage<T>::BaseType BaseType; // Construct a subimage. No checks are done that the subimage lies // completely inside the original image. WImageView(WImage<T>* img, int c, int r, int width, int height); // Refer to external data. // If not given width_step assumed to be same as width. WImageView(T* data, int width, int height, int channels, int width_step = -1); // Refer to external data. This does NOT take ownership // of the supplied IplImage. WImageView(IplImage* img) : WImage<T>(img) {} // Copy constructor WImageView(const WImage<T>& img) : WImage<T>(0) { header_ = *(img.Ipl()); WImage<T>::SetIpl(&header_); } WImageView& operator=(const WImage<T>& img) { header_ = *(img.Ipl()); WImage<T>::SetIpl(&header_); return *this; } protected: IplImage header_; }; template<typename T, int C> class WImageViewC : public WImageC<T, C> { public: typedef typename WImage<T>::BaseType BaseType; enum { kChannels = C }; // Default constructor needed for vectors of views. WImageViewC(); virtual ~WImageViewC() {} // Construct a subimage. No checks are done that the subimage lies // completely inside the original image. WImageViewC(WImageC<T, C>* img, int c, int r, int width, int height); // Refer to external data WImageViewC(T* data, int width, int height, int width_step = -1); // Refer to external data. This does NOT take ownership // of the supplied IplImage. WImageViewC(IplImage* img) : WImageC<T, C>(img) {} // Copy constructor which does a shallow copy to allow multiple views // of same data. gcc-4.1.1 gets confused if both versions of // the constructor and assignment operator are not provided. WImageViewC(const WImageC<T, C>& img) : WImageC<T, C>(0) { header_ = *(img.Ipl()); WImageC<T, C>::SetIpl(&header_); } WImageViewC(const WImageViewC<T, C>& img) : WImageC<T, C>(0) { header_ = *(img.Ipl()); WImageC<T, C>::SetIpl(&header_); } WImageViewC& operator=(const WImageC<T, C>& img) { header_ = *(img.Ipl()); WImageC<T, C>::SetIpl(&header_); return *this; } WImageViewC& operator=(const WImageViewC<T, C>& img) { header_ = *(img.Ipl()); WImageC<T, C>::SetIpl(&header_); return *this; } protected: IplImage header_; }; // Specializations for depth template<> inline int WImage<uchar>::Depth() const {return IPL_DEPTH_8U; } template<> inline int WImage<schar>::Depth() const {return IPL_DEPTH_8S; } template<> inline int WImage<short>::Depth() const {return IPL_DEPTH_16S; } template<> inline int WImage<ushort>::Depth() const {return IPL_DEPTH_16U; } template<> inline int WImage<int>::Depth() const {return IPL_DEPTH_32S; } template<> inline int WImage<float>::Depth() const {return IPL_DEPTH_32F; } template<> inline int WImage<double>::Depth() const {return IPL_DEPTH_64F; } // // Pure virtual destructors still need to be defined. // template<typename T> inline WImage<T>::~WImage() {} template<typename T, int C> inline WImageC<T, C>::~WImageC() {} // // Allocate ImageData // template<typename T> inline void WImageBuffer<T>::Allocate(int width, int height, int nchannels) { if (IsNull() || WImage<T>::Width() != width || WImage<T>::Height() != height || WImage<T>::Channels() != nchannels) { ReleaseImage(); WImage<T>::image_ = cvCreateImage(cvSize(width, height), WImage<T>::Depth(), nchannels); } } template<typename T, int C> inline void WImageBufferC<T, C>::Allocate(int width, int height) { if (IsNull() || WImage<T>::Width() != width || WImage<T>::Height() != height) { ReleaseImage(); WImageC<T, C>::SetIpl(cvCreateImage(cvSize(width, height),WImage<T>::Depth(), C)); } } // // ImageView methods // template<typename T> WImageView<T>::WImageView(WImage<T>* img, int c, int r, int width, int height) : WImage<T>(0) { header_ = *(img->Ipl()); header_.imageData = reinterpret_cast<char*>((*img)(c, r)); header_.width = width; header_.height = height; WImage<T>::SetIpl(&header_); } template<typename T> WImageView<T>::WImageView(T* data, int width, int height, int nchannels, int width_step) : WImage<T>(0) { cvInitImageHeader(&header_, cvSize(width, height), WImage<T>::Depth(), nchannels); header_.imageData = reinterpret_cast<char*>(data); if (width_step > 0) { header_.widthStep = width_step; } WImage<T>::SetIpl(&header_); } template<typename T, int C> WImageViewC<T, C>::WImageViewC(WImageC<T, C>* img, int c, int r, int width, int height) : WImageC<T, C>(0) { header_ = *(img->Ipl()); header_.imageData = reinterpret_cast<char*>((*img)(c, r)); header_.width = width; header_.height = height; WImageC<T, C>::SetIpl(&header_); } template<typename T, int C> WImageViewC<T, C>::WImageViewC() : WImageC<T, C>(0) { cvInitImageHeader(&header_, cvSize(0, 0), WImage<T>::Depth(), C); header_.imageData = reinterpret_cast<char*>(0); WImageC<T, C>::SetIpl(&header_); } template<typename T, int C> WImageViewC<T, C>::WImageViewC(T* data, int width, int height, int width_step) : WImageC<T, C>(0) { cvInitImageHeader(&header_, cvSize(width, height), WImage<T>::Depth(), C); header_.imageData = reinterpret_cast<char*>(data); if (width_step > 0) { header_.widthStep = width_step; } WImageC<T, C>::SetIpl(&header_); } // Construct a view into a region of an image template<typename T> WImageView<T> WImage<T>::View(int c, int r, int width, int height) { return WImageView<T>(this, c, r, width, height); } template<typename T, int C> WImageViewC<T, C> WImageC<T, C>::View(int c, int r, int width, int height) { return WImageViewC<T, C>(this, c, r, width, height); } } // end of namespace #endif // __cplusplus #endif // _CV_WIMAGE_H_