/******************************************************************** ** Image Component Library (ICL) ** ** ** ** Copyright (C) 2006-2013 CITEC, University of Bielefeld ** ** Neuroinformatics Group ** ** Website: www.iclcv.org and ** ** http://opensource.cit-ec.de/projects/icl ** ** ** ** File : ICLCore/src/ICLCore/Img.h ** ** Module : ICLCore ** ** Authors: Christof Elbrechter, Michael Goetting, Robert ** ** Haschke, Andre Justus, Sergius Gaulik ** ** ** ** ** ** GNU LESSER GENERAL PUBLIC LICENSE ** ** This file may be used under the terms of the GNU Lesser General ** ** Public License version 3.0 as published by the ** ** ** ** Free Software Foundation and appearing in the file LICENSE.LGPL ** ** included in the packaging of this file. Please review the ** ** following information to ensure the license requirements will ** ** be met: http://www.gnu.org/licenses/lgpl-3.0.txt ** ** ** ** The development of this software was supported by the ** ** Excellence Cluster EXC 277 Cognitive Interaction Technology. ** ** The Excellence Cluster EXC 277 is a grant of the Deutsche ** ** Forschungsgemeinschaft (DFG) in the context of the German ** ** Excellence Initiative. ** ** ** ********************************************************************/ #pragma once #include #include #include #include #include #include #include #include #include namespace icl { namespace core{ /// The Img class implements the ImgBase Image interface with type specific functionalities \ingroup IMAGE \ingroup TYPES template class ICLCore_API Img : public ImgBase { /* this is declare as fried, because it accesses the private append function */ template friend const ImgType* combineImages (const std::vector& vec, ImgBase** ppoDst); /// Private assign operator (internally used) /** This must be kept private! Because the assign operator could otherwise be exploited to violate the Img's const concept **/ Img& shallowCopy(const Img& tSource); /// private append function for a specified image channel /** This must be kept private! Because it could otherwise be exploited to violate the Img's const concept **/ void append(const Img *src, int iChannel=-1); /// private append function for a specified image channel /** This must be kept private! Because it could otherwise be exploited to violate the Img's const concept **/ void append(const Img *src, const std::vector& vChannels); protected: /** @{ @name data **/ /* {{{ open */ /// internally used storage for the image channels std::vector > m_vecChannels; /// @} /* }}} */ /** @{ @name auxiliary functions **/ /* {{{ open */ /// Internally creates a new deep copy of a specified Type* /** if the give Type* ptDataToCopy is not NULL, the data addressed from it, is copied deeply into the new created data pointer **/ utils::SmartArray createChannel(Type *ptDataToCopy=0) const; /// returns the start index for a channel loop /** In some functions to cases must be regarded: - if given channel index is -1, then it has to be iterated over all image channels - else only the given image channel has to be touched To avoid code doublication, one can use the following for-loop
          void foo(int iChannel){
             for(int i = iIndex < 0 ? 0 : iIndex, iEnd = iIndex < 0 ? m_iChannels : iIndex+1; i < iEnd; i++)   { 
                   // do something
             }
          }
          
When using the getIndex functions the loop becomes much more readable:
          void foo(int iChannel){
             for(int i=getStartIndex(iIndex), iEnd=getEndIndex(iIndex); i
          @param iIndex channel index
          @return start index for for-loops
          @see getEndIndex
          **/
      int getStartIndex(int iIndex) const { return iIndex < 0 ? 0 : iIndex; }
  
      /// returns the end index for a channel loop
      /** this function behaves essentially like the above function 
          @param iIndex channel index
          @return end index for for-loops
          @see getStartIndex
          */
      int getEndIndex(int iIndex) const { return iIndex < 0 ? getChannels() : iIndex+1; }
  
      /// @}
  
      /* }}} */
            
      /** @{ @name basic image manipulation */
      /* {{{ open */
  
      /// Scales pixel values from given min/max values to new min/max values (for internal use)
      /** Values exceeding the given range are set to the new min/max values.
          For an automatic scaling use the results of  min(),max() as as arguments.
          (Defining a range allows to compare different images.)
          @param iChannel channel index (if set to -1, then operation is 
          @param srcRange assumption of the images range
          @param dstRange image range after the operation
  
          performed on all channels)
          **/
      void normalize(int iChannel, 
                     const utils::Range &srcRange, 
                     const utils::Range &dstRange);
  
      /// in-place mirror operation on the given image rect (for internal use)
      /** @param eAxis axis for the mirror operation
          @param iChannel channel index to work on
          @param oOffset image rects offset to use
          @param oSize image rects size to use
      **/
      void mirror(axis eAxis, int iChannel,
                  const utils::Point& oOffset,
                  const utils::Size& oSize);
      /// @}
      /* }}} */
      
      public:
      
      /// null sized and null channel image
      static const Img null;
      
      /* {{{ open */
      /// creates a new image specified by the given param struct
      /** @param params initializing image parameters, if null, then a 
          null image is created  
          */
      Img(const ImgParams ¶ms = ImgParams::null);
    
      /// Creates an image with specified number of channels and size.    
      /** the format of the image will be set to "formatMatrix"
          @param size image size
          @param channels Number of Channels 
          **/
      Img(const utils::Size &size, int channels);
   
      /// Creates an image with specified size, number of channels and format
      /** @param s size of the new image
          @param fmt (color)-format of the image
          **/
      Img(const utils::Size &s, format fmt);
   
      /// Crates an image with given size, channel count and format
      /** Note: channel count and format depend on each other, so if
          the given channel count and the given format are not compatible,
          an exception is thrown
          @param s size of the image
          @param channels channel count of the image (must be compatible to fmt)
          @param fmt format of the image (must be compatible to channels)
          */
      Img(const utils::Size &s, int channels, format fmt);
    
      /// Creates an image with specified size and format, using shared data pointers as channel data
      /** The channel count is set to the channel count that is associated with given the format
          @param size new image size
          @param format (color)-format of the image
          @param vptData holds channel data pointers. It must contain 
          enough Type-pointers for the given format. The data must not be 
          deleted during the "lifetime" of the Img unless data ownership
          is passed to the Img instance by setting passOwnerShip to true. 
          Call detach after the constructor call, to induce the Img to 
          allocate own memory for the image data if ownership cannot be passed.
          @param passOwnerShip flag to specify the passed ownership
          **/
      Img(const utils::Size &size, format format, const std::vector& vptData, 
          bool passOwnerShip=false);
    
      /// Creates an image with specified size and channel count, using shared data pointers as channel data
      /** the format is set to formatMatrix
          @param size new image size
          @param channels channel count of the image (format is set to "formatMatrix")
          @param vptData holds channel data pointers. It must contain 
          at least 'channels' data pointers. The data must not be 
          deleted during the "lifetime" of the Img unless data ownership
          is passed to the Img instance by setting passOwnerShip to true. 
          Call detach after the constructor call, to induce the Img to 
          allocate own memory for the image data if ownership cannot be passed.
          @param passOwnerShip flag to specify the passed ownership
          **/
      Img(const utils::Size &size, int channels, 
          const std::vector& vptData, bool passOwnerShip=false);
  
      /// Crates an image with given size, channel count and format
      /** Note: channel count and format depend on each other, so if
          the given channel count and the given format are not compatible,
          an exception is thrown
          @param size size of the image
          @param channels channel count of the image (must be compatible to fmt)
          @param fmt format of the image (must be compatible to channels)
          @param vptData array of data pointers, which are used as shared 
          pointers. Ensure, that these pointers are persistent
          during the lifetime of the image unless ownership is passed by setting
          passOwnerShip to true, or call detach, to
          make the image allocate it own memory for the data
          @param passOwnerShip flag to specify the passed ownership
          */
      Img(const utils::Size &size, int channels, format fmt, 
          const std::vector& vptData, bool passOwnerShip=false);
  
      /// Copy constructor WARNING: Violates const concept
      /** Creates a flat copy of the source image. The new image will contain a
          flat copy of all channels of the source image. This constructor is only
          applicable to non-const Img references.
          Note: this implicit shallow copy can be exploited to
          violate ICL's const concept:
          \code
          void func(const Img8u &a){
            Img8u b = a;
            // b is now unconst and therewith the data of
            // a can b chaned
          }
          \endcode   
    
          @param tSrc non-const reference of source instance
          **/
      Img(const Img& tSrc);
      
  
      /// This constructor provides tight integration with DynMatrix template class
      /** creates a shallow Img-wrapper around a set of DynMatrix instances.
          Note, of course this consturctor might be used to break DynMatrix's 
          const concept, so please be aware of this!.
          The resulting image counts that many channels as given count (up to 5) of
          non-null DynMatrix instances. All null instances must have the same size,
          otherwise, an exception of type InvalidMatrixDimensionException is thrown.
          @param c1 first image channel (mandatory) (if this is null, the image becomes null)
          @param c2 optional 2nd image channel. Must have the same size as c1.
          @param c3 optional 3rd image channel. Must have the same size as c1 and c2.
          @param c4 optional 4th image channel. Must have the same size as c1 - c3.
          @param c5 optional 5th image channel. Must have the same size as c1 - c4.
      */
      Img(const math::DynMatrix &c1, 
          const math::DynMatrix &c2=math::DynMatrix(), 
          const math::DynMatrix &c3=math::DynMatrix(), 
          const math::DynMatrix &c4=math::DynMatrix(), 
          const math::DynMatrix &c5=math::DynMatrix()) throw (math::InvalidMatrixDimensionException);
  
      
      /// Destructor
      ~Img();
  
      /// null check : null images have 0-Channels and null-size
      bool isNull() const{
        return getSize()==utils::Size::null && getChannels() == 0;
      }
      
  
      /* }}} */
    
      /** @{ @name operators */
      /* {{{ open */
      
      /// implicit cast to it's own reference (?)
      operator Img&(){
        return *this;
      }
  
      /// implicit cast to it's own reference (?) (const)
      operator const Img&() const {
        return *this;
      }
  
      /// Assign operator (flat copy of channels) WARNING: Violates const concept
      /** Both images will share their channel data. 
          Use deepCopy() to obtain a copy of an image which is not attached to the 
          source image.     
          Note: this implicit shallow copy can be exploited to
          violate ICL's const concept:
          \code
          void func(const Img8u &a){
            Img8u b = a;
            // b is now unconst and therewith the data of
            // a can b chaned
          }
          \endcode        
          @param tSource Reference to source object. 
          **/
      Img& operator=(const Img& tSource) {
        // call private const-version
        return this->shallowCopy (static_cast&>(tSource));
      }
      /*
          #ifdef WIN32  
          Img& operator=(const Img& tSource) {
          // call private const-version
          return this->shallowCopy (static_cast&>(tSource));
          }
          #endif
          
          #ifdef GCC_VER_423
          Img& operator=(const Img& tSource) {
          // call private const-version
          return this->shallowCopy (static_cast&>(tSource));
          }
          #endif
      */
  
      /// pixel access operator
      /** This operator may be used, to access the pixel data of the image
          e.g. copy of image data:
          
          Img8u oA(Size(320,240),1),oB(Size(320,240),1);
          for(int x=0;x<320;x++){
          for(int y=0;y<240;y++){
          oB(x,y,0)=oA(x,y,0);
          }
          }
          

Efficiency

Although the ()-operator is compiled inline, and optimized, it is very slow, as it has to select a channel internally (array access) followed by the data access of the selected channel (return array[x+w*y]). A measurement with a "-O3" binary brought the result that pixel access is up to 10 times faster when working directly with a channel data pointer. Nevertheless, the ()-operator is provided in the Img-class, as it offers a very intuitive access to the pixel data. Note: The also provided ImgIterator provides an additional ROI handling mechanism and is more than 5 times faster. @see ImgIterator @see getIterator() @see beginROI() @param iX X-Position of the referenced pixel @param iY Y-Position of the referenced pixel @param iChannel channel index **/ Type& operator()(int iX, int iY, int iChannel) { return const_cast(static_cast*>(this)->operator()(iX,iY,iChannel)); } /// as above, but const const Type& operator()(int iX, int iY, int iChannel) const { return getData(iChannel)[iX+getWidth()*iY]; } /// extracts a pixels channel values at once /** This enables the user to write imageA(x,y) = imageB(a,b); */ inline PixelRef operator()(int x, int y){ return PixelRef(x,y,getWidth(),m_vecChannels); } /// as above, but const inline const PixelRef operator()(int x, int y) const{ return const_cast*>(this)->operator()(x,y); } /// extracts an image channel /** @see ICLUtils::iclDynMatrix.h @param channel valid channel index */ inline Channel operator[](int channel) { return Channel(begin(channel),getSize(),getROI()); } /// extracts an image channel /** @see ICLUtils::iclDynMatrix.h @param channel valid channel index */ inline const Channel operator[](int channel) const { return Channel(const_cast(begin(channel)),getSize(),getROI()); } /// sub-pixel access using nearest neighbor interpolation float subPixelNN(float fX, float fY, int iChannel) const { return (*this)((int)fX, (int)fY, iChannel); } /// sub-pixel access using linear interpolation float subPixelLIN(float fX, float fY, int iChannel) const; /// sub-pixel access using region average interpolation float subPixelRA(float fX, float fY, float w, float h, int iChannel) const; float subPixelRA(const unsigned int xB, const unsigned int xE, const unsigned int yB, const unsigned int yE, const float xBMul, const float xEMul, const float BMul, const float yEMul, const Type *d, const unsigned int w) const; /// sub-pixel access operator, uses given interpolation method Type operator()(float fX, float fY, int iChannel, scalemode eMode) const; /// @} /* }}} */ /** @{ @name extractChannel functions */ /* {{{ open */ /*inline operator[](int channel) throw (InvalidMatrixDimensionException){ return DynMatrix(getWidth(),getHeight(),begin(channel),false); }*/ /// extracts given channel as DynMatrix /* This function cannot be called on (0,x) or (x,0)-sized images */ inline math::DynMatrix extractDynMatrix(int channel) throw (math::InvalidMatrixDimensionException){ return math::DynMatrix(getWidth(),getHeight(),begin(channel),false); } /// extracts given channel as DynMatrix const /* This function cannot be called on (0,x) or (x,0)-sized images */ inline const math::DynMatrix extractDynMatrix(int channel) const throw (math::InvalidMatrixDimensionException){ return math::DynMatrix(getWidth(),getHeight(),const_cast(begin(channel)),false); } /// extracts all image channels at once into given channel pointer inline void extractChannels(Channel *dst){ ICLASSERT_RETURN(dst); for(int i=0;i *dst) const{ (void)dst; ERROR_LOG("extracting channels of a const Img into an un-const Channel\n" "is forbidden because it violates the const concept"); } /// extracts all image channels at once into given channel pointer (const) /** Plese note that the given dst-pointer must also be const */ inline void extractChannels(const Channel *dst) const{ return const_cast*>(this)->extractChannels(const_cast*>(dst)); } /// extracts all data pointers into given destination pointer inline void extractPointers(Type **dst){ for(int i=0;i *shallowCopy(const utils::Rect &roi, const std::vector &channelIndices, format fmt, utils::Time time = utils::Time::null, ImgBase **ppoDst = NULL); /** Create a shallow copy of an image with given (const version) @see the above function @param roi ROI of the new Image @param channelIndices indices to select from the source image. These channels are shallow-copied into the destination image (if size is null, all channels are selected) @param fmt format of the new image (the channel count that is associated with this format must be equal to the channel count that is implicitely defined by the size of the vector channelIndices @param time new timestamp for the returned image @return shallow-copied image **/ const Img *shallowCopy(const utils::Rect &roi, const std::vector &channelIndices, format fmt, utils::Time time=utils::Time::null) const{ // casting constness away is safe, because we effectively return a const Img* return const_cast*>(this)->shallowCopy(roi,channelIndices,fmt,time,0); } /// Create a shallow copy of this image with a new format /** @param newFmt new format to choose. This must be compatible to the channel count of this image. @param poDst destination image (exploited as possible) @return shallow copie with given format of NULL if an error occured **/ Img *reinterpretChannels(format newFmt, Img *poDst = NULL){ ImgBase *poDstBase = poDst; return shallowCopy(getROI(),std::vector(),newFmt,getTime(),&poDstBase); } /// Create a shallow copy of this image with a new format (const version) /** @param newFmt new format to choose. This must be compatible to the channel count of this image. @return shallow copie with given format of NULL if an error occured **/ const Img *reinterpretChannels(format newFmt){ return shallowCopy(getROI(),std::vector(),newFmt,getTime()); } /// Create a shallow copy of the image /** It exploits the given destination image if possible, i.e. if the pixel depth matches. Else this image is released and a new one is created. Optionally a second argument can be specified to get a new image with the given ROI. @param poDst pointer to the destination image pointer If ppoDst is NULL, a new image is created, if ppoDst points to NULL, a new image is created at *ppoDst; @param roi new ROI of the new image. If Rect::null, the source images roi is used. @return shallow copy of this image **/ Img* shallowCopy(const utils::Rect &roi,Img* poDst = NULL){ ImgBase *poDstBase = poDst; return shallowCopy(roi,std::vector(),getFormat(),getTime(),&poDstBase); } /// Create a shallow copy of a const source image /** In contrast to the not const function shallowCopy, the const one does not provide to specify a destination image pointer, because this must neither be const nor not const. If it would be const, it would not be possible to adapt it to correct parameters, otherwise it would violate the const concept as it could be used to change the const result.\n This function can only be used to get const copy of a source image with a special ROI. @param roi ROI of the returned image (Rect::null is not allowed!) @return shallow copy of this image with specified ROI */ const Img* shallowCopy(const utils::Rect& roi) const { // casting constness away is safe, because we effectively return a const Img* return const_cast*>(this)->shallowCopy(roi,0); } /// Create a shallow copy of selected channels of an image /** This function can be used if only one or some channels of a given const image should be used in further processing steps. It helps to avoid the necessity of "deepCopy" calls there. @param channelIndices vector containing channel indices to copy @param poDst destination image (if Null, a new one is created) @return image containing only the selected channels (as shallow copies) format of that image becomes formatMatrix @see shallowCopy */ Img* selectChannels (const std::vector& channelIndices, Img* poDst=0){ ImgBase *poDstBase = poDst; return shallowCopy(getROI(),channelIndices,formatMatrix,getTime(),&poDstBase); } /// Create a shallow copy of a single image channel of an image /** This function is a shortcut to use icl::ImgBase::selectChannels(const std::vector&,icl::ImgBase**) to select a single channel from an image @param channelIndex index of the channel to select (if invalid, NULL is returned) @param poDst destination image @return image containing only the selected channel **/ Img *selectChannel(int channelIndex, Img *poDst=0){ ICLASSERT_RETURN_VAL(validChannel(channelIndex), 0); std::vector v(1); v[0]= channelIndex; return selectChannels(v,poDst); } /// Create a shallow copy of selected channels of a const image. /** @param channelIndices vector containing channel indices to copy @return const image containing only the selected channels */ const Img* selectChannels (const std::vector& channelIndices) const { // casting constness away is safe, because we effectively return a const Img* return const_cast*>(this)->selectChannels(channelIndices, 0); } /// Create a shallow copy of a single image channel of a const image /** This function is a shortcut to use icl::ImgBase::selectChannels(const std::vector&)const to select a single channel from a const image image @param channelIndex index of the channel to select (if invalid, NULL is returned) @return const image containing only the selected channel **/ const Img *selectChannel(int channelIndex) const{ ICLASSERT_RETURN_VAL(validChannel(channelIndex), 0); std::vector v(1); v[0]= channelIndex; return selectChannels(v); } //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ //------------------------------------------------------------------------------ /// Perform a deep copy of an image /** \copydoc icl::core::ImgBase::deepCopy(icl::core::ImgBase**)const */ virtual Img* deepCopy(ImgBase** ppoDst=0) const; /// Perform a deep copy of an image /** This is an overloaded version of the above function. It behaves essentially like the above function, except getting an Img* as destination image argument, what allows to apply the operation without a depth switch. @param poDst destination image, if NULL, a new Img is created @return deep copy of this image **/ Img *deepCopy(Img *poDst) const; /// Perform a deep copy of an images ROI /** \copydoc icl::core::ImgBase::deepCopyROI(icl::core::ImgBase**)const */ virtual Img *deepCopyROI(ImgBase **ppoDst=0) const; /// Perform a deep copy of an images ROI /** This is an overloaded version of the above function. It behaves essentially like the above function, except getting an Img* as destination image argument, what allows to apply the operation without a depth switch. @param poDst destination image, if NULL, a new Img is created. poDst must have either ROI size identical to this images ROI size or zero-dim size (in this case poDst's size is set to this images ROI size) @return deep copy of this images ROI **/ Img *deepCopyROI(Img *poDst) const; /// @} /* }}} */ /** @{ scaled-, and flipped-Copy functions */ /* {{{ open */ /// create a scaled copy of this image /** \copydoc icl::core::ImgBase::scaledCopy(const icl::utils::Size&,icl::core::scalemode)const */ virtual Img *scaledCopy(const utils::Size &newSize, scalemode eScaleMode=interpolateNN) const; /// create a scaled copy of this image /** \copydoc icl::core::ImgBase::scaledCopy(icl::core::ImgBase**,icl::core::scalemode)const */ virtual Img *scaledCopy(ImgBase **ppoDst=0, scalemode eScaleMode=interpolateNN) const; /// create a scaled copy of this image /** Overloaded function to create a scaled copy of an image. This function gets an Img* as destination, what allows to apply the operation without any depth-switch. @param poDst destination image pointer, if NULL, a new Img is created @param eScaleMode interpolation method to use when scaling */ Img *scaledCopy(Img *poDst, scalemode eScaleMode=interpolateNN) const; /// create a scaled copy of an images ROI with given size /** \copydoc icl::core::ImgBase::scaledCopyROI(const icl::utils::Size&,icl::core::scalemode)const */ virtual Img *scaledCopyROI(const utils::Size &newSize, scalemode eScaleMode=interpolateNN) const; /// create a scaled copy of an images ROI with given destination image /** \copydoc icl::core::ImgBase::scaledCopyROI(icl::core::ImgBase**,icl::core::scalemode)const*/ virtual Img *scaledCopyROI(ImgBase **ppoDst=0, scalemode eScaleMode=interpolateNN) const; /// create a scaled copy of this images ROI /** Overloaded function to create a scaled copy of an images ROI. This function gets an Img* as destination, what allows to apply the operation without any depth-switch. @param poDst destination image pointer, if NULL, a new Img is created @param eScaleMode interpolation method to use when scaling */ Img *scaledCopyROI(Img *poDst, scalemode eScaleMode=interpolateNN) const; /// @} /* }}} */ /** @{ @name organization and channel management */ /* {{{ open */ /// Makes the image channels inside the Img independent from other Img. /** \copydoc icl::core::ImgBase::detach(int) */ virtual void detach(int iIndex = -1); /// Utility method, that returns a detached version of this image /** This method can be seen as a deep-copy method. With this method, you can copy an image deeply be calling \code Img8u sourceImage(Size::VGA,formatRGB) Img8u deeplyCopiedInstance = sourceImage.detached(); \endcode */ inline Img detached() const { Img detachedCopy = *this; detachedCopy.detach(); return detachedCopy; } /// Removes a specified channel. /** \copydoc icl::core::ImgBase::removeChannel(int) */ virtual void removeChannel(int iChannel); /// Append channels of external Img to the existing Img. /** Both objects will share their data (cheap copy). If a non-matrix format image gets new channels using it's append method, the new channel count will not match to the channel count, that is associated with the current format. In this case, a waring is written to std::out, and the format will be set to formatMatrix implicitly. @param src source image @param iChannel channel to append (or all, if < 0) **/ void append(Img *src, int iChannel=-1) { // call private const-version this->append (static_cast*>(src), iChannel); } /// Append a set of selected channels from source image /** @param src source image @param vChannels vector of channels indices */ void append(Img *src, const std::vector& vChannels) { // call private const-version this->append (static_cast*>(src), vChannels); } /// Returns a new image with a shallow copied single channel of this image /** param index channel index to extract (must be valid, else resulting image has no channels and error message) */ Img extractChannelImg(int index); /// Returns a new image with a shallow copied single channel of this image /** param index channel index to extract (must be valid, else resulting image has no channels and error message) */ const Img extractChannelImg(int index) const; /// Returns a new image with shallow copied single channels of this image /** param indices channel indices to extract (each must be valid, else error and channel index that does not match is omitted) */ Img extractChannelImg(const std::vector &indices); /// Returns a new image with shallow copied single channels of this image /** param indices channel indices to extract (each must be valid, else error and channel index that does not match is omitted) */ const Img extractChannelImg(const std::vector &indices) const; /// Swap channel A and B /** \copydoc icl::core::ImgBase::swapChannels(int,int) */ virtual void swapChannels(int iIndexA, int iIndexB); /// Replace the channel A of this image with the channel B another image. /** Both images must have the same width and height. @param iThisIndex channel to replace @param iOtherIndex channel to replace with @param poOtherImg Image that contains the new channel **/ void replaceChannel(int iThisIndex, Img *poOtherImg, int iOtherIndex); /// sets the channel count to a new value /** \copydoc icl::core::ImgBase::setChannels(int) */ virtual void setChannels(int iNewNumChannels); /// resizes the image to new values /** \copydoc icl::core::ImgBase::setSize(const icl::utils::Size&) */ virtual void setSize(const utils::Size &s); /// @} /* }}} */ /** @{ @name getter functions */ /* {{{ open */ /// Returns max pixel value of channel iChannel within ROI /** @param iChannel Index of channel @param coords (optinal) if not null, the pixel position of the max is written into this argument **/ Type getMax(int iChannel, utils::Point *coords=0) const; /// Returns min pixel value of channel iChannel within ROI /** @param iChannel Index of channel @param coords (optinal) if not null, the pixel position of the min is written into this argument **/ Type getMin(int iChannel, utils::Point *coords=0) const; /// return maximal pixel value over all channels (restricted to ROI) Type getMin() const; /// return minimal pixel value over all channels (restricted to ROI) Type getMax() const; /// Returns min and max pixel values of channel iChannel within ROI /** @param iChannel Index of channel @param minCoords (optinal) if not null, the pixel position of the min is written into this argument @param maxCoords (optinal) if not null, the pixel position of the max is written into this argument **/ const utils::Range getMinMax(int iChannel, utils::Point *minCoords=0, utils::Point *maxCoords=0) const; /// return minimal and maximal pixel values over all channels (restricted to ROI) const utils::Range getMinMax() const; /// Returns the width of an image line in bytes /** \copydoc icl::core::ImgBase::getLineStep()const **/ virtual int getLineStep() const{ return getSize().width*sizeof(Type); } /// returns a Type save data data pointer to the channel data origin /** If the channel index is not valid (<0 or >= getChannels) NULL is returned and an error is written to std::err @param iChannel specifies the channel @return data origin pointer to the specified channel */ Type* getData(int iChannel) { return const_cast(static_cast*>(this)->getData(iChannel)); } /// returns a Type save data data pointer to the channel data origin (const) /** \copydoc getData(int)*/ const Type* getData(int iChannel) const { FUNCTION_LOG(""); ICLASSERT_RETURN_VAL(validChannel(iChannel), 0); return m_vecChannels[iChannel].get(); } /// returns a Type save data pointer to the first pixel within the images roi /** The following ASCII image shows an images ROI.
                         1st roi-pixel
                              |
                          ....|....................         ---
                          ....|..ooooooooo......... ---      |
                          ....|..ooooooooo.........  |       |
                          ....|..ooooooooo......... roi-h  image-h
          1st image pixel ....|..ooooooooo.........  |       |
               |          ....+->xoooooooo......... ---      |
               +--------->x........................         ---
                                 |-roi-w-|
                          |---------image-w-------|
    
          
Note: most ipp-function require the ROI-data pointer @param iChannel specifies the channel @return roi data pointer **/ Type* getROIData(int iChannel) { return const_cast(static_cast*>(this)->getROIData(iChannel)); } /// returns a Type save data pointer to the first pixel within the images roi (const) /** \copydoc getROIData(int) */ const Type* getROIData(int iChannel) const { FUNCTION_LOG(""); ICLASSERT_RETURN_VAL(validChannel(iChannel),0); return getData(iChannel) + m_oParams.getPixelOffset(); } /// returns the data pointer to a pixel with defined offset /** In some functions like filters, it might be necessary to change the images ROI parameters before applying the underlying image operation. Temporarily changing the images ROI parameters causes problems in multi-threaded environments. To avoid this, this function provides access to a data pointer to an arbitrary notional ROI-offset @param iChannel selects the channel @param p notional ROI offset @return data pointer with notional ROI offset p **/ Type* getROIData(int iChannel, const utils::Point &p) { return const_cast(static_cast*>(this)->getROIData(iChannel, p)); } /// returns the data pointer to a pixel with defined offset (const) /** \copydoc icl::core::Img::getROIData(int,const utils::Point&) */ const Type* getROIData(int iChannel, const utils::Point &p) const { FUNCTION_LOG(""); ICLASSERT_RETURN_VAL(validChannel(iChannel),0); return getData(iChannel) + p.x + (p.y * getWidth()); } /// returns the raw- data pointer of an image channel /** \copydoc icl::core::ImgBase::getDataPtr(int) **/ virtual void* getDataPtr(int iChannel){ return getData(iChannel); } /// returns the raw- data pointer of an image channel (const) /** \copydoc icl::core::ImgBase::getDataPtr(int)const **/ virtual const void* getDataPtr(int iChannel) const{ return getData(iChannel); } /// @} /* }}} */ /** @{ @name basic in-place image manipulations */ /* {{{ open */ /// STL based "for_each" implementations applying an Unary function on each ROI-pixel of given channel /** Internally this function uses std::for_each Example:\n \code #include struct Thresh{ inline void operator()(float &f){ f = f>128 ? 0 : 255; } }; inline void ttt(float &f){ f = f>128 ? 0 : 255; } int main(){ ImgQ a = create("parrot"); a.forEach_C(ttt,1); a.forEach_C(Thresh(),0); show(scale(a,0.2)); return 0; } \endcode @param f unary function or functor implementing "AnyType operator()(Type &val)" @param channel valid channel index for this image */ template inline Img &forEach_C(UnaryFunction f, int channel){ ICLASSERT_RETURN_VAL(validChannel(channel),*this); if(hasFullROI()){ std::for_each(getData(channel),getData(channel)+getDim(),f); }else{ const_roi_iterator end = endROI(channel); for(ImgIterator it = beginROI(channel); it != end; it.incRow()){ std::for_each(&(*it),&(*it)+it.getSubRectWidth(),f); } } return *this; } /// STL based "for_each" implementations applying an Unary function on each ROI-pixel /** Internally using std::for_each by calling Img::forEach_C for all channels Example:\n \code #include struct Thresh{ inline void operator()(float &f){ f = f>128 ? 0 : 255; } }; int main(){ ImgQ a = scale(create("parrot"),0.2); a.forEach(Thresh()); show(a); return 0; } \endcode @param f unary function or functor implementing "AnyType operator()(Type &val)" */ template inline Img &forEach(UnaryFunction f){ for(int c=0;c struct Thresh{ inline float operator()(const float &f){ return f>128 ? 0 : 255; } }; int main(){ ImgQ a = scale(create("parrot"),0.2); ImgQ b(a.getParams()); a.transform_C(Thresh(),1,2,b); show(b); return 0; } \endcode @param f unary function of functor implementing "dstType operator()(const Type &val)" @param srcChannel valid channel index for this image @param dstChannel valid channel index for dst image @param dst destination image with identical ROI-size to this images ROI-size */ template inline Img &transform_C(UnaryFunction f, int srcChannel, int dstChannel, Img &dst) const{ ICLASSERT_RETURN_VAL(getROISize() == dst.getROISize(),dst); ICLASSERT_RETURN_VAL(validChannel(srcChannel),dst); ICLASSERT_RETURN_VAL(dst.validChannel(dstChannel),dst); if(hasFullROI() && dst.hasFullROI()){ std::transform(getData(srcChannel),getData(srcChannel)+getDim(),dst.getData(dstChannel),f); }else{ ImgIterator itDst = dst.beginROI(dstChannel); const_roi_iterator end = endROI(srcChannel); for(const_roi_iterator it = beginROI(srcChannel); it != end; it.incRow(), itDst.incRow()){ std::transform(&(*it),&(*it)+it.getSubRectWidth(),&(*itDst),f); } } return dst; } /// STL based "transform" implementation applying an Unary function on ROI-pixles with given destination image /** Internally this function uses std::transform. Example:\n \code #include inline icl8u t_func(const float &f){ return f>128 ? 0 : 255; } int main(){ ImgQ a = scale(create("parrot"),0.2); Img8u b(a.getParams()); a.transform(t_func,b); show(cvt(b)); return 0; } \endcode @param f unary function of functor implementing "dstType operator()(const Type &val)" @param dst destination image with identical ROI-size and channel count (compared to this image) */ template inline Img &transform(UnaryFunction f, Img &dst) const{ ICLASSERT_RETURN_VAL(getChannels() == dst.getChannels(),dst); for(int c=0;c inline bool gt_func(const float &a,const float &b){ return a > b; } struct EqFunctor{ bool operator()(const float &a, const float &b){ return a == b; } }; int main(){ ImgQ a = scale(create("parrot"),640,480); ImgQ b = scale(create("women"),640,480); Img8u dst(a.getParams()); a.setROI(Rect(10,10,500,400)); b.setROI(Rect(10,10,500,400)); dst.setROI(Rect(10,10,500,400)); a.combine_C(std::less(),0,0,0,b,dst); a.combine_C(gt_func,1,1,1,b,dst); a.combine_C(EqFunctor(),2,2,2,b,dst); dst.setFullROI(); show(norm(cvt(dst))); return 0; } \endcode @param f binary function of functor implementing "dstType operator() const(Type &a, otherSrcType &b) const" @param thisChannel valid channel of this image @param otherSrcChannel valid channel index for give 2nd source image @param dstChannel valid channel index of dst image @param otherSrc 2nd source image (ROI-size must be equal to this' ROI size) @param dst destination image (ROI-size must be equal to this' ROI size) */ template inline Img &combine_C(BinaryFunction f, int thisChannel, int otherSrcChannel, int dstChannel, const Img &otherSrc, Img &dst) const{ ICLASSERT_RETURN_VAL(getROISize() == dst.getROISize()&& getROISize() == otherSrc.getROISize(),dst); ICLASSERT_RETURN_VAL(validChannel(thisChannel),dst); ICLASSERT_RETURN_VAL(otherSrc.validChannel(otherSrcChannel),dst); ICLASSERT_RETURN_VAL(dst.validChannel(dstChannel),dst); if(hasFullROI() && dst.hasFullROI() && otherSrc.hasFullROI()){ std::transform(getData(thisChannel),getData(thisChannel)+getDim(),otherSrc.getData(otherSrcChannel),dst.getData(dstChannel),f); }else{ ImgIterator itDst = dst.beginROI(dstChannel); const ImgIterator itOtherSrc = otherSrc.beginROI(otherSrcChannel); const_roi_iterator end = endROI(thisChannel); for(const_roi_iterator it = beginROI(thisChannel); it!=end; it.incRow(), itDst.incRow(),itOtherSrc.incRow()){ std::transform(&(*it),&(*it)+it.getROIWidth(),&(*itOtherSrc),&(*itDst),f); } } return dst; } /// STL-based "transform function combining two images pixel-wise into a given destination image (with ROI support)" /** This function calls D = F(A,B), with D: destination ROI pixel, F: given binary functor/function, A: pixel of this image and B: pixel of other given src image. Internally this function uses std::transform Beispiel: \code #include int main(){ ImgQ a = scale(create("parrot"),640,480); ImgQ b = scale(create("women"),640,480); Img8u dst(a.getParams()); a.setROI(Rect(10,10,300,100)); b.setROI(Rect(10,10,300,100)); dst.setROI(Rect(10,10,300,100)); a.combine(std::less(),b,dst); dst.setFullROI(); show(norm(cvt(dst))); return 0; } \endcode @param f binary function or functor implementing "dstType operator() const(Type &a, otherSrcType &b) const" @param otherSrc 2nd source image @param dst destination image */ template inline Img &combine(BinaryFunction f, const Img &otherSrc, Img &dst) const{ ICLASSERT_RETURN_VAL(getChannels() == otherSrc.getChannels(),dst); ICLASSERT_RETURN_VAL(getChannels() == dst.getChannels(),dst); for(int c=0;c static inline void reduce_arrays(const Tsrc *src[Nsrc], Tdst *dst[Ndst], unsigned int dim, ReduceFunc reduce){ for(int i=dim-1;i>=0;--i){ Tsrc tsrc[Nsrc]; Tdst tdst[Ndst]; for(int j=0;j t); } }; Img8u bgMask(const Img8u &image,const Img8u &bgImage, int tollerance){ Img8u imageAndBG; imageAndBG.append(&const_cast(image)); // const_cast is ok here, imageAndBG.append(&const_cast(bgImage)); // we will not change them! Img8u dst(image.getSize(),formatMatrix); imageAndBG.reduce_channels(dst,Thresh(tollerance)); return dst; } \endcode \section PERF Performace Twearks Source and destination channel count is given as template parameter, to allow the compiler to leave out loops over single values or to unroll short ones. Besides, the compiler is able to use fixed sized arrays on the stack, instead of dynamically allocated heap arrays. By this means performance of reduce_channels is accelerated by factor 12. \section BENCHMARK Benchmarks Exemplarily, the example function above takes about 4-5ms on a 2GHz Core2Duo (using -O4 and -funroll-loop optimization of gcc) on a VGA-sized image (640x480) */ template void reduce_channels(Img &dst, ReduceFunc reduce) const { ICLASSERT_RETURN(this->getROISize() == dst.getROISize()); ICLASSERT_RETURN((Nthis > 0) && (Ndst > 0)); ICLASSERT_RETURN((this->getChannels()==Nthis) && (dst.getChannels()==Ndst)); const Type *psrc[Nthis]; Tdst *pdst[Ndst]; if(this->hasFullROI() && dst.hasFullROI()){ for(int i=0;igetData(i),++i) {} for(int i=0;i(psrc,pdst,this->getDim(),reduce); }else{ const_roi_iterator itSrc[Nthis]; ImgIterator itDst[Ndst]; for(int i=0;ibeginROI(i),++i) {} for(int i=0;igetROI().height-1, w=this->getROI().width ;l>=0;--l){ for(int i=0;i(psrc,pdst,w,reduce); } } } ///applys a lookup function using the given lookup table /** The lookup table has 2^bits entries. Source values are assumed to be in range [0,255]. If the given destination image is 0, a new image is created and returned IPP-accellerated for icl8u */ Img *lut(const Type *lut, Img *dst = 0,int bits=8) const; /// perform an in-place resize of the image (keeping the data) /** \copydoc icl::core::ImgBase::scale(const icl::utils::Size&,icl::core::scalemode)*/ virtual void scale(const utils::Size &s, scalemode eScaleMode=interpolateNN); /// perform an in-place mirror operation on the image /** \copydoc icl::core::ImgBase::mirror(icl::core::axis,bool) */ virtual void mirror(axis eAxis, bool bOnlyROI=false); /// Sets the ROI pixels of one or all channels to a specified value /** @param iChannel Channel to fill with zero (default: -1 = all channels) @param tValue destination value (default: 0) @param bROIOnly if set false, the whole image is set to tValue **/ void clear(int iChannel = -1, Type tValue = 0, bool bROIOnly=true); /// fills the whole image with given source type value /** In contrast to icl::Img::clear, which is highly optimized, this methods use std::fill. By this means, the given source value is really assigned to each value. This can e.g. be used to fill an image with random values \code #include #include #include void foo(){ Img8u image(Size::QQVGA,3); image.fill(URandI(255)); show(image); } \endcode \image html img-fill.jpg "result if Img::fill example" */ template inline void fill(const T &value){ for(int i=0;i inline void fillChannel(int channel, const T &value){ std::fill(begin(channel),end(channel),value); } /// fills the whole image with given source type value template inline void fillROI(const T &value){ for(int i=0;i inline void fillChannelROI(int channel, const T &value){ std::fill(beginROI(channel),endROI(channel),value); } /// Normalize the channel min/ max range to the new min, max range. /** The min/ max range from the source channels are automatically detected, separately for each channel. @param dstRange new image range **/ void normalizeAllChannels(const utils::Range &dstRange); /// Normalize the channel from a given min/max range to the new range /** @param iChannel channel index @param srcRange notional image range befor this function call @param dstRange image range after this function call **/ void normalizeChannel(int iChannel, const utils::Range &srcRange, const utils::Range &dstRange); /// Normalize the channel from a given min/max range to the new range /** The min/ max range from the source channel is automatically detected, separately for this channel @param iChannel channel index @param dstRange destination image range **/ void normalizeChannel(int iChannel,const utils::Range &dstRange); /// Normalize the image from a given min/max range to the new range /** @param srcRange notional image range befor this function call @param dstRange image range after this function call **/ void normalizeImg(const utils::Range &srcRange, const utils::Range &dstRange); /// Normalize the image from a min/max range to the new range /** The min/ max range from the image is automatically detected, combined over all image channels. @param dstRange destination image range **/ void normalizeImg(const utils::Range &dstRange); /// @} /* }}} */ /** @{ @name pixel access using roi iterator */ /* {{{ open */ /// iterator type (just a data pointer) typedef Type* iterator; /// const iterator type (just a const pointer) typedef const Type* const_iterator; /// type definition for ROI iterator typedef ImgIterator roi_iterator; /// type definition for a const ROI iterator typedef const ImgIterator const_roi_iterator; // old typedef constConstImgIterator const_iterator; /// returns the image iterator (equal to getData(channel)) inline iterator begin(int channel){ return getData(channel); } /// returns the image iterator (equal to getData(channel)) (const) inline const_iterator begin(int channel) const{ return const_cast*>(this)->begin(channel); } /// returns the image end-iterator (equal to getData(channel)+getDim()) iterator end(int channel){ return getData(channel)+getDim(); } /// returns the image end-iterator (const) const_iterator end(int channel) const{ return getData(channel)+getDim(); } /// returns the iterator for an images ROI inline roi_iterator beginROI(int channel){ ICLASSERT_RETURN_VAL(validChannel(channel), roi_iterator()); return roi_iterator(getData(channel),getWidth(),getROI()); } /// returns the iterator for an images ROI (const) inline const_roi_iterator beginROI(int channel) const{ ICLASSERT_RETURN_VAL(validChannel(channel), roi_iterator()); return const_cast*>(this)->beginROI(channel); } /// returns the end-iterator for an images ROI /** the returned iterator must not be incremented or decremented! */ inline roi_iterator endROI(int channel) { ICLASSERT_RETURN_VAL(validChannel(channel), roi_iterator()); return roi_iterator::create_end_roi_iterator(getData(channel),getWidth(),getROI()); } /// returns the end-iterator for an images ROI (const) inline const_roi_iterator endROI(int channel) const{ ICLASSERT_RETURN_VAL(validChannel(channel), roi_iterator()); return const_roi_iterator::create_end_roi_iterator(getData(channel),getWidth(),getROI()); } /// returns the x,y-coordinates of a pointer whithin a given channel /** E.g channel c's pointer of image I points to adress p=1005, image width is 10 and data depth is 1 (icl-8u image). Then I.getLocation(1006,c) returns Point(1,0) and I.getLocation(1015,c) returns Point(0,1).\n The following rule is always true: Point p = somewhat; image i = somewhat; p == i.getLocation(i.getData(0)+p.x+image.getWidth()*p.y,any-valid-channel); Optionally, returned point can be calculated w.r.t. the images roi offset. **/ utils::Point getLocation(const Type *p, int channel, bool relToROI=false) const; /// shows the image value by value at std::out /** Warning: SLOW @param format this string is passed to printf internally uchars can be printed e.g. using format="3.0" @param visROI indicates ROI-pixels with a 'r'-postfix (only if image has no full-ROI) **/ void printAsMatrix(const std::string &format="5.3", bool visROI=true) const; /// shows wheter all image channels are currently not share with another image /** @\copydoc bool icl::core::ImgBase::isIndependent() const */ virtual bool isIndependent() const; /// @} /* }}} */ /** @{ @name border functions */ /* {{{ open */ /// extrudes ROI borders through non-ROI borders /** This function can be used fill all image border pixles (pixels outside the current ROI with the value of the closest ROI-pixel */ virtual void fillBorder(bool setFullROI=true); /// fills all non-ROI pixels with a given value virtual void fillBorder(icl64f val, bool setFullROI=true); /// fills all non-ROI pixels with a given value /** here, for each channel a given value is used, so vals.size() must be at least this->getChannels() */ virtual void fillBorder(const std::vector &vals, bool setFullROI=true); /// copies images non-border pixels from source image. /** The source image must provided pixel values for each non border pixel of this image. So the source images size must be at least (X+1)x(Y+1) where (X,Y) is the lower right non-border pixel of this image.*/ virtual void fillBorder(const ImgBase *src, bool setFullROI=true); /// @} /* }}} */ };// class Img /* {{{ global functions */ /// utility class that helps for an implicit conversion between Img* to ImgBase** \ingroup IMAGE /** @see bpp(Img &) @see bpp(Img *) */ template struct ICLCore_API ImgBasePtrPtr { /// 1st private constructor ImgBasePtrPtr(Img &i); /// 2nd private constructor ImgBasePtrPtr(Img *i); /// Destructor /** In this class, the destrutctor does all of the work: if the pointer returned by the implicit cast to ImgBase** operator was chnaged (reallocated) it is detected here, and a warnig is writte to std::out. To ensure compability for later computation, the reallocated images data is converted into the given source image. By this means, the result image gets all parameters of the source image except its depth. Images, that are not further needed, are deleted automatically. */ ~ImgBasePtrPtr(); /// Implicit cast operator (allows to place an ImgBasePtrPtr where an ImgBase** is expected) operator ImgBase** (){ return &r; } private: /// Internal image pointers ImgBase *o,*r,*rbef; }; /// utility function to cast an Img implicitly into an ImgBase ** \ingroup IMAGE /** This function may be useful, whenever you are working with Img objects are Pointers. As some functions expect ImgBase** arguments to ensure, that the destination image can be adapted even in its depth, this function can be used to get an ImgBase** that points to a pointer of the given image. This is a necessary concept, but mutch additional work, if you are just want to try out some algorithm on your Img. If you are shure, that the result image will not be adapted by the function you can easily use the bpp-function, which will additionally warn you if this assumption was wrong. The following code example demonstrates this: \code void apply_func(ImageBase **dst){ ... // this function may realloc dst } Img8u src; Img8u dst; // without bpp function ImgBase *pDst= &Dst; apply_func(&src,&pDst); // this will cause an error if pDst is reallocated // because stack objects may not be released // with bpp function apply_func(&src,bpp(dst)); // this will cause a warning at maxinum \endcode **/ template ImgBasePtrPtr bpp(Img *image) { return ImgBasePtrPtr(image); } /// utility function to cast an Img* implicitly into an ImgBase ** \ingroup IMAGE /** see the above function for more details */ template ImgBasePtrPtr bpp(Img &image) { return ImgBasePtrPtr(image); } /// Conversion function to transform a pointer into an object /** This function is very common: in many cases, Img member functions return pointer instead of objects. This might lead to some extra code lines, if these pointer are used locally: \code void foo(const Img8u *image){ const Img8u *channel0 = image->selectChannel(0); const Img8u *imageWithFullROI = image->shallowCopy(image->getImageRect()); // do something with the shallow copies // e.g. call some other functions show_one_channel_image(*channel0); process_image_with_full_roi(*imageWithFullROI); delete channel0; delete imageWithFullROI; } \endcode This code can be written much shorter using the *NEW* p2o function: \code void foo(const Img8u *image){ show_one_channel_image(p2o(image->selectChannel(0))); process_image_with_full_roi(p2o(image->shallowCopy(image->getImageRect()))); } \endcode internally: p2o uses a smart pointer to ensure given pointer is released properly before function returns \section IMPL implementation \code template inline T p2o(T *ptr){ return T(*SmartPtr(const_cast(ptr))); } \endcode \section CMPLX Complexity the function internally creates a smart Pointer object and calls the copy constructor of given T once. Hence the function complexity scales with the implementation of the standard copy constructor of T. Particularly for ICL's Img classes, the default copy constructor performs a shallow copy internally which induces negligible computational costs. */ template static inline T p2o(T *ptr){ return *utils::SmartPtr(ptr); } /// Combine several images using shallow copy. \ingroup IMAGE template const ImgType* combineImages(const std::vector& vec); /// Combine several images using shallow copy. Non-const version \ingroup IMAGE template ImgType* combineImages(const std::vector& vec) { return const_cast(combineImages(reinterpret_cast&>(vec))); } /* {{{ deepCopyChannel */ /// Copies the channel from one image to another \ingroup IMAGE template inline void deepCopyChannel(const Img *src, int srcC, Img *dst, int dstC){ FUNCTION_LOG(""); ICLASSERT_RETURN( src && dst ); ICLASSERT_RETURN( src->getSize() == dst->getSize() ); ICLASSERT_RETURN( src->validChannel(srcC) ); ICLASSERT_RETURN( dst->validChannel(dstC) ); icl::core::copy(src->getData(srcC),src->getData(srcC)+src->getDim(),dst->getData(dstC)); } /* }}} */ /* {{{ convertChannel */ /// copies/converts the data from one image to another image (IPP-OPTIMIZED) \ingroup IMAGE /** The deepCopyChannel function is a higher lever wrapper for the icl::copy(..) function. It extracts the data pointers and data dimension from the source- and destination image to call icl::copy(..) @param src source image @param srcC source images channel @param dst destination image @param dstC destination image channel **/ template inline void convertChannel(const Img *src, int srcC, Img *dst, int dstC){ FUNCTION_LOG(""); ICLASSERT_RETURN( src && dst ); ICLASSERT_RETURN( src->getSize() == dst->getSize() ); ICLASSERT_RETURN( src->validChannel(srcC) ); ICLASSERT_RETURN( dst->validChannel(dstC) ); icl::core::convert(src->getData(srcC),src->getData(srcC)+src->getDim(),dst->getData(dstC)); } /* }}} */ /* {{{ clearChannelROI */ /// sets an arbitrary image ROI to a given value \ingroup IMAGE /** This function is used as basic operation for higher level image operation like Img::clear(T value). @param im image @param c channel @param clearVal value for the cleared pixels @param offs lower left point for the to-be-cleared region @param size size of the to-be-cleared region */ template inline void clearChannelROI(Img *im, int c, T clearVal, const utils::Point &offs, const utils::Size &size) { FUNCTION_LOG(""); ICLASSERT_RETURN( im ); ImgIterator it(im->getData(c),im->getSize().width,utils::Rect(offs,size)); const ImgIterator itEnd = ImgIterator::create_end_roi_iterator(im->getData(c), im->getWidth(), utils::Rect(offs,size)); std::fill(it,itEnd,clearVal); } /** \cond */ #ifdef ICL_HAVE_IPP /// IPP-OPTIMIZED specialization for icl8u clearing (using ippiSet) template <> inline void clearChannelROI(Img *im, int c, icl8u clearVal, const utils::Point &offs, const utils::Size &size){ FUNCTION_LOG(""); ICLASSERT_RETURN( im ); ippiSet_8u_C1R(clearVal,im->getROIData(c,offs),im->getLineStep(),size); } /// IPP-OPTIMIZED specialization for icl16s clearing (using ippiSet) template <> inline void clearChannelROI(Img *im, int c, icl16s clearVal, const utils::Point &offs, const utils::Size &size){ FUNCTION_LOG(""); ICLASSERT_RETURN( im ); ippiSet_16s_C1R(clearVal,im->getROIData(c,offs),im->getLineStep(),size); } /// IPP-OPTIMIZED specialization for icl32s clearing (using ippiSet) template <> inline void clearChannelROI(Img *im, int c, icl32s clearVal, const utils::Point &offs, const utils::Size &size){ FUNCTION_LOG(""); ICLASSERT_RETURN( im ); ippiSet_32s_C1R(clearVal,im->getROIData(c,offs),im->getLineStep(),size); } /// IPP-OPTIMIZED specialization for icl32f clearing (using ippiSet) template <> inline void clearChannelROI(Img *im, int c, icl32f clearVal, const utils::Point &offs, const utils::Size &size){ FUNCTION_LOG(""); ICLASSERT_RETURN( im ); ippiSet_32f_C1R(clearVal,im->getROIData(c,offs),im->getLineStep(),size); } #endif /** \endcond */ /* }}} */ /** {{{ check function */ /// \cond #define CHECK_VALUES(src,srcC,srcOffs,srcSize,dst,dstC,dstOffs,dstSize) \ FUNCTION_LOG(""); \ ICLASSERT_RETURN( src && dst ); \ ICLASSERT_RETURN( srcSize == dstSize ); \ ICLASSERT_RETURN( src->validChannel(srcC) ); \ ICLASSERT_RETURN( dst->validChannel(dstC) ); \ ICLASSERT_RETURN( srcOffs.x >= 0 && srcOffs.y >= 0 && dstOffs.x >= 0 && dstOffs.y >= 0); \ ICLASSERT_RETURN( srcOffs.x+srcSize.width <= src->getWidth() && srcOffs.y+srcSize.height <= src->getHeight() ); \ ICLASSERT_RETURN( dstOffs.x+dstSize.width <= dst->getWidth() && dstOffs.y+dstSize.height <= dst->getHeight() ); /// \endcond /** }}} */ /* {{{ deepCopyChannelROI */ /// copies the channel roi from one image to another \ingroup IMAGE /** Essential deep copy function. @param src source image @param srcC source channel @param srcOffs source images ROI offset @param srcSize source images ROI size @param dst destination image @param dstC destination channel @param dstOffs destination images ROI offset @param dstSize destination images ROI size (must be equal to srcSize) **/ template inline void deepCopyChannelROI(const Img *src, int srcC, const utils::Point &srcOffs, const utils::Size &srcSize, Img *dst,int dstC, const utils::Point &dstOffs, const utils::Size &dstSize) { CHECK_VALUES(src,srcC,srcOffs,srcSize,dst,dstC,dstOffs,dstSize); const ImgIterator itSrc(const_cast(src->getData(srcC)), src->getSize().width, utils::Rect(srcOffs,srcSize)); ImgIterator itDst(dst->getData(dstC),dst->getSize().width,utils::Rect(dstOffs,dstSize)); const ImgIterator itSrcEnd = ImgIterator::create_end_roi_iterator(src->getData(srcC), src->getWidth(), utils::Rect(srcOffs,srcSize)); for(;itSrc != itSrcEnd;itSrc.incRow(),itDst.incRow()){ icl::core::copy(&*itSrc,&*itSrc+srcSize.width,&*itDst); } } /* }}} */ /* {{{ convertChannelROI */ /// @{ @name type conversion of channel ROIs /// copies/converts the ROI data from one image to the ROI of another image (IPP-OPTIMIZED) \ingroup IMAGE /** This function is used by all other deepCopyROI functions internally. It copies / converts ROI image data to another images ROI using the icl::copy(..) function line by line or, in case of IPP-optimization enabled, corresponding ippCopy/ippConvert Calls (see the following specialized template functions also). @param src source image @param srcC source image channel @param srcOffs source images ROI-offset (src->getROIOffset() is not regarded) @param srcROISize source images ROI-size (src->getROISize() is not regarded) @param dst destination image @param dstC destination image channel @param dstOffs destination images ROI-offset (dst->getROIOffset() is not regarded) @param dstROISize destination images ROI-size (dst->getROISize() is not regarded) **/ template inline void convertChannelROI(const Img *src, int srcC, const utils::Point &srcOffs, const utils::Size &srcROISize, Img *dst,int dstC, const utils::Point &dstOffs, const utils::Size &dstROISize) { FUNCTION_LOG(""); CHECK_VALUES(src,srcC,srcOffs,srcROISize,dst,dstC,dstOffs,dstROISize); const ImgIterator itSrc(const_cast(src->getData(srcC)), src->getSize().width, utils::Rect(srcOffs,srcROISize)); ImgIterator itDst(dst->getData(dstC),dst->getSize().width, utils::Rect(dstOffs,dstROISize)); const ImgIterator itSrcEnd = ImgIterator::create_end_roi_iterator(src->getData(srcC), src->getWidth(), utils::Rect(srcOffs,srcROISize)); for(;itSrc != itSrcEnd ;itSrc.incRow(),itDst.incRow()){ icl::core::convert(&*itSrc,&*itSrc+srcROISize.width,&*itDst); } } /// @} /* }}} */ /* {{{ scaledCopyChannelROI */ /// @{ @name scaling of channel ROIs /// scales an image channels ROI into another images ROI (with implicit type conversion) (IPP-OPTIMIZED) \ingroup IMAGE /** This function provides all necessary functionalities for scaling images. Please regard, that the fallback- implementation is very slow. Only scaling operations with identical source and destination type is optimized by corresponding ippResize calls (see also the specialized template functions). @param src source image @param srcC source image channel @param srcOffs source images ROI-offset (src->getROIOffset() is not regarded) @param srcSize source images ROI-size (src->getROISize() is not regarded) @param dst destination image @param dstC destination image channel @param dstOffs destination images ROI-offset (dst->getROIOffset() is not regarded) @param dstSize destination images ROI-size (dst->getROISize() is not regarded) @param eScaleMode scaling mode to use (nearest neighbor, linear, or region-average) **/ template ICLCore_API void scaledCopyChannelROI(const Img *src, int srcC, const utils::Point &srcOffs, const utils::Size &srcSize, Img *dst,int dstC, const utils::Point &dstOffs, const utils::Size &dstSize, scalemode eScaleMode); /* }}} */ /* {{{ flippedCopyChannelROI */ /// mirror copy ROI data from one image to the ROI of another image (IPP-OPTIMIZED) \ingroup IMAGE /** This function is used by flippedCopyROI and Mirror operator. @param eAxis mirror axis (axisHorz, axisVert or axisBoth) @param src source image @param srcC source image channel @param srcOffs source images ROI-offset (src->getROIOffset() is not regarded) @param srcSize source images ROI-size (src->getROISize() is not regarded) @param dst destination image @param dstC destination image channel @param dstOffs destination images ROI-offset (dst->getROIOffset() is not regarded) @param dstSize destination images ROI-size (dst->getROISize() is not regarded) @param dstSize destination images ROI-size (dst->getROISize() is not regarded) **/ template ICLCore_API void flippedCopyChannelROI(axis eAxis, const Img *src,int srcC, const utils::Point &srcOffs, const utils::Size &srcSize, Img *dst,int dstC, const utils::Point &dstOffs, const utils::Size &dstSize); /// mirror copy of an image from source to destination image (1:1 copy) \ingroup IMAGE /** This function creates a flipped instance of this image. Even the ROI is flipped internally. Example:
          ......                    ......     r = roi
          ..rrrr  -> flipped x ->   rrrr..
          ..rrrr                    rrrr..
        
@param eAxis axis to flip @param poSrc source image @param ppoDst image. This image is exploited if possible. It is adjusted to the source image in depth, size,channels,format,and time **/ ICLCore_API void flippedCopy(axis eAxis, const ImgBase *poSrc, ImgBase **ppoDst = 0); /// mirror copy of an images ROI into a destination images ROI \ingroup IMAGE /** Example:
          ......                    ......    R,r = roi
          ..RRrr  -> flipped x ->   rrRR..
          ..RRrr                    rrRR..
        
@param eAxis axis to flip @param poSrc source image @param ppoDst destination image (expoited if possible). This images ROI size must be equal to ppoDst's ROI size otherwise an errormessage is shown, and the function returns 0. If ppoDst is null, a new image is created with size of this images ROI size. If ppoDst points to NULL, the new image is created at *ppoDst. @return flippedCopy **/ ICLCore_API void flippedCopyROI(axis eAxis, const ImgBase *poSrc, ImgBase **ppoDst = 0); /* }}} */ /* }}} */ } // namespace core } //namespace icl #undef CHECK_VALUES