/////////////////////////////////////////////////////////////////////////////// // 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 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 class WImage; template class WImageBuffer; template class WImageView; template class WImageC; template class WImageBufferC; template class WImageViewC; // Commonly used typedefs. typedef WImage WImage_b; typedef WImageView WImageView_b; typedef WImageBuffer WImageBuffer_b; typedef WImageC WImage1_b; typedef WImageViewC WImageView1_b; typedef WImageBufferC WImageBuffer1_b; typedef WImageC WImage3_b; typedef WImageViewC WImageView3_b; typedef WImageBufferC WImageBuffer3_b; typedef WImage WImage_f; typedef WImageView WImageView_f; typedef WImageBuffer WImageBuffer_f; typedef WImageC WImage1_f; typedef WImageViewC WImageView1_f; typedef WImageBufferC WImageBuffer1_f; typedef WImageC WImage3_f; typedef WImageViewC WImageView3_f; typedef WImageBufferC WImageBuffer3_f; // There isn't a standard for signed and unsigned short so be more // explicit in the typename for these cases. typedef WImage WImage_16s; typedef WImageView WImageView_16s; typedef WImageBuffer WImageBuffer_16s; typedef WImageC WImage1_16s; typedef WImageViewC WImageView1_16s; typedef WImageBufferC WImageBuffer1_16s; typedef WImageC WImage3_16s; typedef WImageViewC WImageView3_16s; typedef WImageBufferC WImageBuffer3_16s; typedef WImage WImage_16u; typedef WImageView WImageView_16u; typedef WImageBuffer WImageBuffer_16u; typedef WImageC WImage1_16u; typedef WImageViewC WImageView1_16u; typedef WImageBufferC WImageBuffer1_16u; typedef WImageC WImage3_16u; typedef WImageViewC WImageView3_16u; typedef WImageBufferC 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 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(image_->imageData); } const T* ImageData() const { return reinterpret_cast(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(image_->imageData + r*image_->widthStep); } inline T* Row(int r) { return reinterpret_cast(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(image_->imageData + r*image_->widthStep) + c*Channels(); } inline const T* operator() (int c, int r) const { return reinterpret_cast(image_->imageData + r*image_->widthStep) + c*Channels(); } // Copy the contents from another image which is just a convenience to cvCopy void CopyFrom(const WImage& 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 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 class WImageC : public WImage { public: typedef typename WImage::BaseType BaseType; enum { kChannels = C }; explicit WImageC(IplImage* img) : WImage(img) { assert(!img || img->nChannels == Channels()); } // Construct a view into a region of this image WImageViewC 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& src) { cvCopy(src.Ipl(), WImage::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::Depth()); WImage::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 class WImageBuffer : public WImage { public: typedef typename WImage::BaseType BaseType; // Default constructor which creates an object that can be WImageBuffer() : WImage(0) {} WImageBuffer(int width, int height, int nchannels) : WImage(0) { Allocate(width, height, nchannels); } // Constructor which takes ownership of a given IplImage so releases // the image on destruction. explicit WImageBuffer(IplImage* img) : WImage(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::SetIpl(img); } // Clone an image which reallocates the image if of a different dimension. void CloneFrom(const WImage& src) { Allocate(src.Width(), src.Height()); CopyFrom(src); } ~WImageBuffer() { ReleaseImage(); } // Release the image if it isn't null. void ReleaseImage() { if (WImage::image_) { IplImage* image = WImage::image_; cvReleaseImage(&image); WImage::SetIpl(0); } } bool IsNull() const {return WImage::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 class WImageBufferC : public WImageC { public: typedef typename WImage::BaseType BaseType; enum { kChannels = C }; // Default constructor which creates an object that can be WImageBufferC() : WImageC(0) {} WImageBufferC(int width, int height) : WImageC(0) { Allocate(width, height); } // Constructor which takes ownership of a given IplImage so releases // the image on destruction. explicit WImageBufferC(IplImage* img) : WImageC(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::SetIpl(img); } // Clone an image which reallocates the image if of a different dimension. void CloneFrom(const WImageC& src) { Allocate(src.Width(), src.Height()); CopyFrom(src); } ~WImageBufferC() { ReleaseImage(); } // Release the image if it isn't null. void ReleaseImage() { if (WImage::image_) { IplImage* image = WImage::image_; cvReleaseImage(&image); WImageC::SetIpl(0); } } bool IsNull() const {return WImage::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 class WImageView : public WImage { public: typedef typename WImage::BaseType BaseType; // Construct a subimage. No checks are done that the subimage lies // completely inside the original image. WImageView(WImage* 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(img) {} // Copy constructor WImageView(const WImage& img) : WImage(0) { header_ = *(img.Ipl()); WImage::SetIpl(&header_); } WImageView& operator=(const WImage& img) { header_ = *(img.Ipl()); WImage::SetIpl(&header_); return *this; } protected: IplImage header_; }; template class WImageViewC : public WImageC { public: typedef typename WImage::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* 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(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& img) : WImageC(0) { header_ = *(img.Ipl()); WImageC::SetIpl(&header_); } WImageViewC(const WImageViewC& img) : WImageC(0) { header_ = *(img.Ipl()); WImageC::SetIpl(&header_); } WImageViewC& operator=(const WImageC& img) { header_ = *(img.Ipl()); WImageC::SetIpl(&header_); return *this; } WImageViewC& operator=(const WImageViewC& img) { header_ = *(img.Ipl()); WImageC::SetIpl(&header_); return *this; } protected: IplImage header_; }; // Specializations for depth template<> inline int WImage::Depth() const {return IPL_DEPTH_8U; } template<> inline int WImage::Depth() const {return IPL_DEPTH_8S; } template<> inline int WImage::Depth() const {return IPL_DEPTH_16S; } template<> inline int WImage::Depth() const {return IPL_DEPTH_16U; } template<> inline int WImage::Depth() const {return IPL_DEPTH_32S; } template<> inline int WImage::Depth() const {return IPL_DEPTH_32F; } template<> inline int WImage::Depth() const {return IPL_DEPTH_64F; } // // Pure virtual destructors still need to be defined. // template inline WImage::~WImage() {} template inline WImageC::~WImageC() {} // // Allocate ImageData // template inline void WImageBuffer::Allocate(int width, int height, int nchannels) { if (IsNull() || WImage::Width() != width || WImage::Height() != height || WImage::Channels() != nchannels) { ReleaseImage(); WImage::image_ = cvCreateImage(cvSize(width, height), WImage::Depth(), nchannels); } } template inline void WImageBufferC::Allocate(int width, int height) { if (IsNull() || WImage::Width() != width || WImage::Height() != height) { ReleaseImage(); WImageC::SetIpl(cvCreateImage(cvSize(width, height),WImage::Depth(), C)); } } // // ImageView methods // template WImageView::WImageView(WImage* img, int c, int r, int width, int height) : WImage(0) { header_ = *(img->Ipl()); header_.imageData = reinterpret_cast((*img)(c, r)); header_.width = width; header_.height = height; WImage::SetIpl(&header_); } template WImageView::WImageView(T* data, int width, int height, int nchannels, int width_step) : WImage(0) { cvInitImageHeader(&header_, cvSize(width, height), WImage::Depth(), nchannels); header_.imageData = reinterpret_cast(data); if (width_step > 0) { header_.widthStep = width_step; } WImage::SetIpl(&header_); } template WImageViewC::WImageViewC(WImageC* img, int c, int r, int width, int height) : WImageC(0) { header_ = *(img->Ipl()); header_.imageData = reinterpret_cast((*img)(c, r)); header_.width = width; header_.height = height; WImageC::SetIpl(&header_); } template WImageViewC::WImageViewC() : WImageC(0) { cvInitImageHeader(&header_, cvSize(0, 0), WImage::Depth(), C); header_.imageData = reinterpret_cast(0); WImageC::SetIpl(&header_); } template WImageViewC::WImageViewC(T* data, int width, int height, int width_step) : WImageC(0) { cvInitImageHeader(&header_, cvSize(width, height), WImage::Depth(), C); header_.imageData = reinterpret_cast(data); if (width_step > 0) { header_.widthStep = width_step; } WImageC::SetIpl(&header_); } // Construct a view into a region of an image template WImageView WImage::View(int c, int r, int width, int height) { return WImageView(this, c, r, width, height); } template WImageViewC WImageC::View(int c, int r, int width, int height) { return WImageViewC(this, c, r, width, height); } } // end of namespace #endif // __cplusplus #endif // _CV_WIMAGE_H_