#ifndef ICL_IMG_CHANNEL_H #define ICL_IMG_CHANNEL_H #include "iclImg.h" namespace icl{ /// Utility helper class for faster and more convenient access to single channel image data \ingroup IMAGE /** Yet, the (x,x,c)-operator of the Img class is slow, because of its high channel lookup overhead. The (x,y,c)-operator needs first to lookup for the channel c in the channel array of that object, before it can address a pixels value by dereferencing the shared pointers wrapped data pointer. In many cases, The programmer works on fixed channel images, and needs a simple (x,y)-data access operator, which translates an (x,y) pixel address into the raw data pointer address dataPointer[x+width*y].\n The ImgChannel class was designed to facilitate this procedure. To avoid the arise of an exploit for accessing const Img data as un-const, ImgChannels can only be created by the the template function pickChannel available (as const and unconst version) in the icl namespace, if the header "iclImgChannel.h" was included. The following code example shows how to replace the Imgs (x,y,c)-operator by using the ImgChannel template class: \code inline void copy_image(Img32f &A,Img32f &B){ for(int x=0;x<1000;x++){ // default version for an image copy for(int y=0;y<1000;y++){ // each pixel is addressed by the A(x,y,0)=B(x,y,0); // (x,y,c)-operator (image size is fixed) } } } inline void copy_image(Img32f &A,Img32f &B){ ImgChannel32f a = pickChannel(&A,0); // new faster version (about 6.5-times ImgChannel32f b = pickChannel(&B,0); // faster, than the above function for(int x=0;x<1000;x++){ // pixels are addressed by the for(int y=0;y<1000;y++){ // ImgChannel objects a(x,y)=b(x,y); } } } \endcode The lower function is about 6.5 times faster than the upper one! When working on multi channel images with a fixed channel count, the advantage of using the ImgChannel class becomes even greater: \code inline void copy_3_channels(ImgQ &A,ImgQ &B){ for(int x=0;x<1000;x++){ for(int y=0;y<1000;y++){ A(x,y,0)=B(x,y,0); A(x,y,1)=B(x,y,1); A(x,y,2)=B(x,y,2); } } } inline void copy_3_channels(ImgQ &A,ImgQ &B){ ImgChannel32f a[] = { pickChannel(&A,0),pickChannel(&A,1),pickChannel(&A,2) }; ImgChannel32f b[] = { pickChannel(&B,0),pickChannel(&B,1),pickChannel(&B,2) }; for(int x=0;x<1000;x++){ for(int y=0;y<1000;y++){ // more than one channel can be a[0](x,y)=b[0](x,y); // stored in a fixed size array of a[1](x,y)=b[1](x,y); // ImgChannel32f structs; this allows a[2](x,y)=b[2](x,y); // direct access to the channel data pointer } } } } \endcode In The above example, the lower version of the copy function is even 7 times as fast as the upper version. At last, we want to examine the speed advantage for dynamic channel count and image size. The corresponding code is illustrated in the following code example: \code inline void dynamic_image_copy(ImgQ &A,ImgQ &B){ for(int x=0;x template class is typedef'd for all current Img classes ImgChannel8u, ImgChannel16s, ImgChannel32s, ImgChannel32f, ImgChannel64f. */ template class ImgChannel{ public: /// Empty constructor (create an invalid ImgChannel object) /** This constructor is necessary for the creation of uninitialized dynamic size arrays of ImgChannel objects */ ImgChannel():m_ptData(0),m_iWidth(0),m_iHeight(0){} /// assign operator ImgChannel &operator=(ImgChannel &other){ m_ptData = other.m_ptData; m_iWidth = other.m_iWidth; m_iHeight = other.m_iHeight; m_iDim = other.m_iDim; return *this; } /// assign operator const ImgChannel &operator=(const ImgChannel &other) const{ m_ptData = other.m_ptData; m_iWidth = other.m_iWidth; m_iHeight = other.m_iHeight; m_iDim = other.m_iDim; return *this; } /// friend function to create ImgChannel objects (not const version) /** @see icl::pickChannel(icl::Img*,int) */ template friend ImgChannel pickChannel(Img*,int); /// friend function to create ImgChannel objects (const version) /** @see icl::pickChannel(const icl::Img*,int) */ template friend const ImgChannel pickChannel(const Img*,int); /// friend function to fill an array with ImgChannel objects (const version) /** @see icl::pickChannel(const icl::Img*,cost ImgChannel*) */ template friend void pickChannels(const Img*, const ImgChannel*); /// friend function to fill an array with ImgChannel objects (not const version) /** @see icl::pickChannel(icl::Img*,ImgChannel*) */ template friend void pickChannels(Img*,ImgChannel*); /// main working function: returns a reference to the pixel at position (x,y) /** The data address is calculated by x+ImageWidth*y. Note: no checks are performed to ensure, that the position is valid! @param x x-Position @param y y-Position @return reference to the Pixel at (x,y) */ inline T &operator()(int x, int y){ #ifdef CHECK_INDICES ICLASSERT(x>=0 && y>=0 && xNote: no checks are performed to ensure, that the position is valid! @param x x-Position @param y y-Position @return reference to the Pixel at (x,y) */ inline const T &operator()(int x, int y) const{ #ifdef CHECK_INDICES ICLASSERT(x>=0 && y>=0 && x=0 && idx < m_iDim); #endif return m_ptData[idx]; } /// working function for linear pixel array access (const version) /** @param idx pixel array index @return reference to the pixel at linear pixel offfset idx **/ inline const T &operator[](int idx) const { #ifdef CHECK_INDICES ICLASSERT(idx>=0 && idx < m_iDim); #endif return m_ptData[idx]; } /// returns the corresponding data pointer /** @return current wrapped data pointer */ inline T *getData(){ return m_ptData; } /// returns the corresponding data pointer (const version) /** @return current wrapped data pointer */ inline const T *getData() const { return m_ptData; } /// returns the wrapped images width /** @return wrapped images width */ inline int getWidth() const { return m_iWidth; } /// returns the wrapped images height /** @return wrapped images height */ inline int getHeight() const { return m_iHeight; } /// returns the wrapped images dim = width*height /** @return wrapped images pixel count */ inline int getDim() const { return m_iDim; } private: /// private constructor (called by the friend functions pickChannel) /** @see the pickChannel function available in the icl namespace @param image image wich's channel should be wrapped @param channelIndex index of the channel */ inline ImgChannel(const Img *image,int channelIndex){ ICLASSERT( image && image->getChannels() >channelIndex ); m_ptData = const_cast(image->getData(channelIndex)); m_iWidth = image->getWidth(); m_iHeight = image->getHeight(); m_iDim = m_iWidth * m_iHeight; } mutable T *m_ptData; /**< wrapped image data pointer */ mutable int m_iWidth; /**< wrapped images width */ mutable int m_iHeight; /**< wrapped images height */ mutable int m_iDim; /**< wrapped images width*height */ }; /// @{ @name ImgChannel creator functions /// Creation function for ImgChannel objects (not const version) \ingroup IMAGE /** This function creates an ImgChannel object of a given image and channel index. @param image image which's channel should be wrapped @param channelIndex index of the channel @return ImgChannel object */ template inline ImgChannel pickChannel(Img *image,int channelIndex){ return ImgChannel(image,channelIndex); } /// Creation function for ImgChannel objects (const version) \ingroup IMAGE /** This function creates an ImgChannel object of a given image and channel index. @param image image wich's channel should be wrapped @param channelIndex index of the channel @return ImgChannel object */ template inline const ImgChannel pickChannel(const Img *image,int channelIndex){ return ImgChannel(image,channelIndex); } /// picks all image channels into a given destination vector (const) template inline void pickChannels(const Img *image, const ImgChannel *dst){ for(int i=0;igetChannels();++i){ dst[i] = pickChannel(image,i); } } /// picks all image channels into a given destination vector template inline void pickChannels(Img *image, ImgChannel *dst){ for(int i=0;igetChannels();++i){ dst[i] = pickChannel(image,i); } } /// @} /** \cond */ #define ICL_INSTANTIATE_DEPTH(D) typedef ImgChannel ImgChannel##D; ICL_INSTANTIATE_ALL_DEPTHS #undef ICL_INSTANTIATE_DEPTH /** \endcond */ } #endif