/******************************************************************** ** Image Component Library (ICL) ** ** ** ** Copyright (C) 2006-2012 CITEC, University of Bielefeld ** ** Neuroinformatics Group ** ** Website: www.iclcv.org and ** ** http://opensource.cit-ec.de/projects/icl ** ** ** ** File : include/ICLCore/CoreFunctions.h ** ** Module : ICLCore ** ** Authors: Christof Elbrechter, Michael Götting, Robert Haschke, ** ** Andre Justus ** ** ** ** Commercial License ** ** ICL can be used commercially, please refer to our website ** ** www.iclcv.org for more details. ** ** ** ** GNU General Public License Usage ** ** Alternatively, this file may be used under the terms of the ** ** GNU General Public License version 3.0 as published by the ** ** Free Software Foundation and appearing in the file LICENSE.GPL ** ** included in the packaging of this file. Please review the ** ** following information to ensure the GNU General Public License ** ** version 3.0 requirements will be met: ** ** http://www.gnu.org/copyleft/gpl.html. ** ** ** ** 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 <string> #include <cstring> #include <iostream> #include <vector> #include <ICLUtils/Macros.h> #include <ICLUtils/Point32f.h> #include <ICLUtils/ClippedCast.h> #include <ICLUtils/PThreadFix.h> #include <ICLCore/Types.h> #include <ICLCore/ImgParams.h> /// The ICL-namespace /** This namespace is dedicated for ICLCore- and all additional Computer-Vision packages, that are based on the ICLCore classes. **/ namespace icl { namespace core{ /* {{{ Global functions */ /// create a new image instance of the given depth type and with given parameters \ingroup IMAGE /** This function provides a common interface to instantiate images of arbitrary depth, selecting the appropriate constructor of the derived class Img<T>. Instead of selecting the correct constructor by yourself, you can simply call this common constructor function. To illustrate the advantage, look at the following example: <pre> class Foo{ public: Foo(...,Depth eDepth,...): poImage(eDepth==depth8u ? new Img8u(...) : new Img32f(...)){ } private: ImgBase *poImage; }; </pre> This will work, but the "?:"-statement makes the code hardly readable. The following code extract will show the advantage of using the imgNew instantiator: <pre> class Foo{ public: Foo(...,Depth eDepth,...): poImage(imgNew(eDepth,...)){ } private: ImgBase *poImage; }; </pre> The readability of the code is much better. @param d depth of the image that should be created @param params struct containing all neccessary parameters like: size: size of the new image fmt: format of the new image channels: number of channels (of an formatMatrix-type image) roi: ROI rectangle of the new image @return the new ImgBase* with underlying Img<Type>, where Type is depending on the first parameter eDepth **/ ImgBase *imgNew(depth d=depth8u, const ImgParams ¶ms = ImgParams::null); /// creates a new Img (see the above function for more details) \ingroup IMAGE inline ImgBase *imgNew(depth d, const utils::Size& size, format fmt, const utils::Rect &roi=utils::Rect::null){ return imgNew(d,ImgParams(size,fmt,roi)); } /// creates a new Img (see the above function for more details) \ingroup IMAGE inline ImgBase *imgNew(depth d, const utils::Size& size, int channels=1, const utils::Rect &roi=utils::Rect::null){ return imgNew(d,ImgParams(size,channels,roi)); } /// creates a new Img (see the above function for more details) \ingroup IMAGE inline ImgBase *imgNew(depth d, const utils::Size& size, int channels, format fmt, const utils::Rect &roi=utils::Rect::null){ return imgNew(d,ImgParams(size,channels,fmt,roi)); } /// ensures that an image has the specified depth \ingroup IMAGE /** This function will delete the original image pointed by (*ppoImage) and create a new one with identical parameters, if the given depth parameter is not the images depth. If the given image pointer (*ppoImage) is NULL, then an empty image of specified depth es created at *ppoImage. If ppoImage is NULL a new Image is created and returned. call: <pre> void func(ImgBase **ppoDst){ ImgBase *poDst = ensureDepth(ppoDst,anyDepth); } </pre> to ensure that an image is valid. @param ppoImage pointer to the image-pointer @param eDepth destination depth of the image @return the new image (this can be used e.g. if ppoImage is NULL) **/ ImgBase *ensureDepth(ImgBase **ppoImage, depth eDepth); /// ensures that an image has given depth and parameters \ingroup IMAGE ImgBase *ensureCompatible(ImgBase **dst, depth d,const ImgParams ¶ms); /// ensures that an image has given depth, size, number of channels and ROI \ingroup IMAGE /** If the given pointer to the destination image is 0, a new image with appropriate properties is created. Else the image properties are checked and adapted to the new values if neccessary. @param dst points the destination ImgBase*. If the images depth hasa to be converted, then a new Img<T>* is created at (*dst). @param d desired image depth @param size desired image size @param channels desired number of channels, if eFormat == formatMatrix for other format, the number of channels is determined by the format @param roi desired ROI rectangle. If the ROI parameters are not given, the ROI will comprise the whole image. **/ inline ImgBase *ensureCompatible(ImgBase **dst, depth d,const utils::Size& size,int channels, const utils::Rect &roi=utils::Rect::null) { return ensureCompatible(dst,d,ImgParams(size,channels,roi)); } /// ensures that an image has given depth, size, format and ROI \ingroup IMAGE inline ImgBase *ensureCompatible(ImgBase **dst, depth d,const utils::Size& size, format fmt, const utils::Rect &roi=utils::Rect::null) { return ensureCompatible(dst,d,ImgParams(size,fmt,roi)); } /// ensures that an image has given parameters \ingroup IMAGE /** The given format must be compatible to the given channel count. <b>If not:</b> The format is set to "formatMatrix" and an exception is thrown. */ ImgBase *ensureCompatible(ImgBase **dst, depth d, const utils::Size &size, int channels, format fmt, const utils::Rect &roi=utils::Rect::null); /// ensures that the destination image gets same depth, size, channel count, depth, format and ROI as source image \ingroup IMAGE /** If the given pointer to the destination image is 0, a new image is created as a deep copy of poSrc. Else the image properties are checked and adapted to the new values if neccessary. <b>Note:</b> If the destination images depth differs from the source images depth, it is adapted by deleting the <em>old</em> destination pointer by calling <em>delete *ppoDst</em> and creating a <em>brand new</em> Img<T> where T is the destination images depth. @param dst points the destination ImgBase*. If the images depth has to be converted, then a new Img<T>* is created, at (*ppoDst). @param src source image. All params of this image are extracted to define the destination parameters for *ppoDst. **/ ImgBase *ensureCompatible(ImgBase **dst, const ImgBase *src); /// determines the count of channels, for each color format \ingroup GENERAL /** @param fmt source format which channel count should be returned @return channel count of format eFormat **/ int getChannelsOfFormat(format fmt); /// getDepth<T> returns to depth enum associated to type T \ingroup GENERAL template<class T> inline depth getDepth(); /// puts a string representation of format into the given stream std::ostream &operator<<(std::ostream &s,const format &f); /// puts a string representation of depth into the given stream std::ostream &operator<<(std::ostream &s,const depth &d); /// puts a string representation of format into the given stream std::istream &operator>>(std::istream &s, format &f); /// puts a string representation of depth into the given stream std::istream &operator>>(std::istream &s, depth &d); /** \cond */ #define ICL_INSTANTIATE_DEPTH(T) \ template<> inline depth getDepth<icl ## T>() { return depth ## T; } ICL_INSTANTIATE_ALL_DEPTHS #undef ICL_INSTANTIATE_DEPTH /** \endcond */ /// return sizeof value for the given depth type \ingroup GENERAL unsigned int getSizeOf(depth eDepth); /// moves data from source to destination array (no casting possible) \ingroup GENERAL template <class T> inline void copy(const T *src, const T *srcEnd, T *dst){ //std::copy<T>(src,srcEnd,dst); memcpy(dst,src,(srcEnd-src)*sizeof(T)); } #ifdef HAVE_IPP /** \cond */ template <> inline void copy<icl8u>(const icl8u *poSrcStart, const icl8u *poSrcEnd, icl8u *poDst){ ippsCopy_8u(poSrcStart,poDst,(poSrcEnd-poSrcStart)); } template <> inline void copy<icl16s>(const icl16s *poSrcStart, const icl16s *poSrcEnd, icl16s *poDst){ ippsCopy_16s(poSrcStart,poDst,(poSrcEnd-poSrcStart)); } template <> inline void copy<icl32s>(const icl32s *poSrcStart, const icl32s *poSrcEnd, icl32s *poDst){ ippsCopy_32s(poSrcStart,poDst,(poSrcEnd-poSrcStart)); } template <> inline void copy<icl32f>(const icl32f *poSrcStart, const icl32f *poSrcEnd, icl32f *poDst){ ippsCopy_32f(poSrcStart,poDst,(poSrcEnd-poSrcStart)); } template <> inline void copy<icl64f>(const icl64f *poSrcStart, const icl64f *poSrcEnd, icl64f *poDst){ ippsCopy_64f(poSrcStart,poDst,(poSrcEnd-poSrcStart)); } /** \endcond */ #endif /// moves value from source to destination array (with casting on demand) \ingroup GENERAL template <class srcT,class dstT> inline void convert(const srcT *poSrcStart,const srcT *poSrcEnd, dstT *poDst){ std::transform(poSrcStart,poSrcEnd,poDst,utils::clipped_cast<srcT,dstT>); } #ifdef HAVE_IPP /** \cond */ /// from icl8u functions template<> inline void convert<icl8u,icl32f>(const icl8u *poSrcStart,const icl8u *poSrcEnd, icl32f *poDst){ ippsConvert_8u32f(poSrcStart,poDst,(poSrcEnd-poSrcStart)); } /// from icl16s functions template<> inline void convert<icl16s,icl32s>(const icl16s *poSrcStart,const icl16s *poSrcEnd, icl32s *poDst){ ippsConvert_16s32s(poSrcStart,poDst,(poSrcEnd-poSrcStart)); } template<> inline void convert<icl16s,icl32f>(const icl16s *poSrcStart,const icl16s *poSrcEnd, icl32f *poDst){ ippsConvert_16s32f(poSrcStart,poDst,(poSrcEnd-poSrcStart)); } template<> inline void convert<icl16s,icl64f>(const icl16s *poSrcStart,const icl16s *poSrcEnd, icl64f *poDst){ ippsConvert_16s64f_Sfs(poSrcStart,poDst,(poSrcEnd-poSrcStart),0); } // from icl32s functions template<> inline void convert<icl32s,icl16s>(const icl32s *poSrcStart,const icl32s *poSrcEnd, icl16s *poDst){ ippsConvert_32s16s(poSrcStart,poDst,(poSrcEnd-poSrcStart)); } template<> inline void convert<icl32s,icl32f>(const icl32s *poSrcStart,const icl32s *poSrcEnd, icl32f *poDst){ ippsConvert_32s32f(poSrcStart,poDst,(poSrcEnd-poSrcStart)); } template<> inline void convert<icl32s,icl64f>(const icl32s *poSrcStart,const icl32s *poSrcEnd, icl64f *poDst){ ippsConvert_32s64f(poSrcStart,poDst,(poSrcEnd-poSrcStart)); } // from icl32f functions template <> inline void convert<icl32f,icl8u>(const icl32f *poSrcStart, const icl32f *poSrcEnd, icl8u *poDst){ ippsConvert_32f8u_Sfs(poSrcStart,poDst,(poSrcEnd-poSrcStart),ippRndNear,0); } template <> inline void convert<icl32f,icl16s>(const icl32f *poSrcStart, const icl32f *poSrcEnd, icl16s *poDst){ ippsConvert_32f16s_Sfs(poSrcStart,poDst,(poSrcEnd-poSrcStart),ippRndNear,0); } template <> inline void convert<icl32f,icl32s>(const icl32f *poSrcStart, const icl32f *poSrcEnd, icl32s *poDst){ ippsConvert_32f32s_Sfs(poSrcStart,poDst,(poSrcEnd-poSrcStart),ippRndNear,0); } template <> inline void convert<icl32f,icl64f>(const icl32f *poSrcStart, const icl32f *poSrcEnd, icl64f *poDst){ ippsConvert_32f64f(poSrcStart,poDst,(poSrcEnd-poSrcStart)); } // from icl64f functions template<> inline void convert<icl64f,icl32f>(const icl64f *poSrcStart,const icl64f *poSrcEnd, icl32f *poDst){ ippsConvert_64f32f(poSrcStart,poDst,(poSrcEnd-poSrcStart)); } template <> inline void convert<icl64f,icl32s>(const icl64f *poSrcStart,const icl64f *poSrcEnd, icl32s *poDst){ ippsConvert_64f32s_Sfs(poSrcStart,poDst,(poSrcEnd-poSrcStart),ippRndNear,0); } /** \endcond */ #endif /// function, that calculates the mininum and the maximum value of three value \ingroup GENERAL /** @param a first input value @param b second input value @param c third input value @param minVal return value for the minimum @param maxVal return value for the maximum **/ template<class T> inline void getMinAndMax(T a, T b, T c, T &minVal, T &maxVal){ if(a<b) { minVal=a; maxVal=b; } else { minVal=b; maxVal=a; } if(c<minVal) minVal=c; else { maxVal = c>maxVal ? c : maxVal; } } /* }}} */ /// Computes the mean value of a ImgBase* ingroup MATH /** IPP-Optimized for icl32f and icl64f @param poImg input image @param iChannel channel index (-1 for all channels) @param roiOnly @return mean value of image or image channel (optionally: roi) */ std::vector<double> mean(const ImgBase *poImg, int iChannel=-1, bool roiOnly=false); /// Compute the variance value of an image a with given mean \ingroup MATH /** @param poImg input imge @param mean vector with channel means @param empiricMean if true, sum of square distances is devided by n-1 else by n @param iChannel channel index (-1 for all channels) @param roiOnly @return The variance value form the vector */ std::vector<double> variance(const ImgBase *poImg, const std::vector<double> &mean, bool empiricMean=true, int iChannel=-1, bool roiOnly=false); /// Compute the variance value of an image a \ingroup MATH /** @param poImg input imge @param iChannel channel index (-1 for all channels) @param roiOnly @return The variance value form the vector */ std::vector<double> variance(const ImgBase *poImg, int iChannel=-1, bool roiOnly=false); /// Compute the std::deviation of an image /** @param poImage input image @param iChannel channel index (all channels if -1) @param roiOnly */ std::vector<double> stdDeviation(const ImgBase *poImage, int iChannel=-1, bool roiOnly = false); /// Compute the std::deviation of an image with given channel means /** @param poImage input image @param mean vector with channel means @param empiricMean if true, sum of square distances is devided by n-1 else by n @param iChannel channel index (all channels if -1) @param roiOnly */ std::vector<double> stdDeviation(const ImgBase *poImage, const std::vector<double> mean, bool empiricMean=true, int iChannel=-1, bool roiOnly = false); /// Calculates mean and standard deviation of given image simultanously /** @param image input image @param iChannel image channel if < 0 all channels are used @param roiOnly @return vector v of pairs p with p.first = mean and p.second = stdDev v[i] containing i-th channel's results */ std::vector< std::pair<double,double> > meanAndStdDev(const ImgBase *image, int iChannel=-1, bool roiOnly = false); /// computes the color histogramm of given image channel std::vector<int> channelHisto(const ImgBase *image,int channel, int levels=256, bool roiOnly=false); /// computes the color histogramm of given image std::vector<std::vector<int> > hist(const ImgBase *image, int levels=256, bool roiOnly=false); } // namespace core } // namespace icl