#include #include namespace icl { // {{{ constructors and destructors //---------------------------------------------------------------------------- template Img::Img(const ImgParams ¶ms): // {{{ open ImgBase(icl::getDepth(),params){ FUNCTION_LOG("Img(params)"); for(int i=0;i Img::Img(const Size &s,int iChannels): // {{{ open ImgBase(icl::getDepth(),ImgParams(s,iChannels)){ FUNCTION_LOG("Img(" << s.width <<","<< s.height << "," << iChannels << ") this:" << this ); for(int i=0;i Img::Img(const Size& s, format eFormat): // {{{ open ImgBase(icl::getDepth(),ImgParams(s,eFormat)){ FUNCTION_LOG("Img(" << s.width <<","<< s.height << "," << translateFormat(eFormat) << ") this:" << this ); for(int i=0;i Img::Img(const Size &s,int iChannels, format fmt): // {{{ open ImgBase(icl::getDepth(),ImgParams(s,iChannels,fmt)){ FUNCTION_LOG("Img(" << s.width <<","<< s.height << "," << iChannels << "," << translateFormat(fmt) << ") this:" << this ); for(int i=0;i Img::Img(const Size &s, int channels, const std::vector& vptData) : // {{{ open ImgBase(icl::getDepth(),ImgParams(s,channels)) { ICLASSERT_THROW (getChannels () <= (int) vptData.size(), InvalidImgParamException("channels")); FUNCTION_LOG("Img(" << s.width <<","<< s.height << "," << channels << ",Type**) this:" << this); typename std::vector::const_iterator it = vptData.begin(); for(int i=0; i(*it,false)); } } // }}} //---------------------------------------------------------------------------- template Img::Img(const Size &s, int channels, format fmt, const std::vector& vptData) : // {{{ open ImgBase(icl::getDepth(),ImgParams(s,channels,fmt)){ ICLASSERT_THROW (getChannels () <= (int) vptData.size(), InvalidImgParamException("channels")); FUNCTION_LOG("Img(" << s.width <<","<< s.height << "," << channels << "," << translateFormat(fmt) << ",Type**) this:" << this); typename std::vector::const_iterator it = vptData.begin(); for(int i=0; i(*it,false)); } } // }}} //---------------------------------------------------------------------------- template Img::Img(const Size &s, format eFormat, const std::vector& vptData) : // {{{ open ImgBase(icl::getDepth(),ImgParams(s,eFormat)){ ICLASSERT_THROW (getChannels () <= (int) vptData.size(), InvalidImgParamException("channels")); FUNCTION_LOG("Img(" << s.width <<","<< s.height << "," << translateFormat(eFormat) << ",Type**) this:" << this); typename std::vector::const_iterator it = vptData.begin(); for(int i=0; i(*it,false)); } } // }}} //--- Copy constructor ------------------------------------------------------- template Img::Img(const Img& tSrc) : // {{{ open ImgBase(tSrc.getDepth(),tSrc.getParams()) { FUNCTION_LOG("this: " << this); m_vecChannels = tSrc.m_vecChannels; } // }}} //---------------------------------------------------------------------------- template Img::~Img() // {{{ open { FUNCTION_LOG("this: " << this); } // }}} // }}} // {{{ operators: "=", ()-(float,float,channel,scalemode) template Img& Img::shallowCopy(const Img& tSrc) { // {{{ open FUNCTION_LOG(""); //---- Assign new channels to Img ---- m_oParams = tSrc.getParams (); m_vecChannels = tSrc.m_vecChannels; //take over timestamp this->setTime(tSrc.getTime()); return *this; } // }}} template Type Img::operator()(float fX, float fY, int iChannel, scalemode eScaleMode) const { // {{{ open switch(eScaleMode) { case 0: return Cast::cast (subPixelNN (fX, fY, iChannel)); case 1: return Cast::cast (subPixelLIN (fX, fY, iChannel)); default: ERROR_LOG ("interpolation method not yet implemented!"); return Cast::cast (subPixelLIN (fX, fY, iChannel)); } } // }}} // }}} // {{{ ensureCompatible, and ensureDepth utility templates //help function template inline Img* ensureCompatible (ImgBase** ppoDst, const ImgParams& p) // {{{ open { if (!ppoDst) return new Img(p); icl::ensureCompatible (ppoDst, icl::getDepth(), p); return (*ppoDst)->asImg(); } // }}} //help function template Img* ensureDepth(ImgBase **ppoDst){ // {{{ open icl::ensureDepth(ppoDst,getDepth()); return (*ppoDst)->asImg(); } // }}} // }}} // {{{ shallowCopy function template Img *Img::shallowCopy(const Rect &roi, const std::vector &channelIndices, format fmt, Time t, ImgBase **ppoDst){ // {{{ open ImgParams p(this->getSize(), 0); Img *poDst = ensureCompatible(ppoDst,p); /// Die ROi wird nicht übernommen ??? *poDst = *this; if(roi != Rect::null){ poDst->setROI(roi); } if(channelIndices.size()){ ICLASSERT_RETURN_VAL(fmt == formatMatrix || (int)channelIndices.size() == getChannelsOfFormat(fmt),0); poDst->setChannels(0); poDst->append(this,channelIndices); } poDst->setFormat(fmt); poDst->setTime(t); return poDst; } // }}} // }}} // {{{ copy functions: deepCopy, scaledCopy, flippedCopy convert (with and without ROI) // {{{ copy-functions with ImgBase** argument template Img *Img::deepCopy(ImgBase **ppoDst) const{ // {{{ open FUNCTION_LOG("ptr:"<(ppoDst,getParams()) ); } // }}} template Img *Img::scaledCopy( ImgBase **ppoDst, scalemode eScaleMode) const{ // {{{ open FUNCTION_LOG("ptr:"<(ppoDst), eScaleMode ); } // }}} template Img *Img::scaledCopy( const Size &newSize, scalemode eScaleMode) const{ // {{{ open FUNCTION_LOG("new size:"<(newSize, getChannels(), getFormat()), eScaleMode); } // }}} template Img *Img::deepCopyROI(ImgBase **ppoDst) const{ // {{{ open FUNCTION_LOG("ptr:"<(ppoDst) ); } // }}} template Img *Img::scaledCopyROI(const Size &newSize, scalemode eScaleMode) const{ // {{{ open FUNCTION_LOG("new size:"<(newSize, getChannels(),getFormat()), eScaleMode ); } // }}} template Img *Img::scaledCopyROI(ImgBase **ppoDst, scalemode eScaleMode) const{ // {{{ open FUNCTION_LOG("ptr:"<(ppoDst),eScaleMode ); } // }}} // }}} // {{{ copy-functions with Img*-argument template Img *Img::deepCopy(Img *poDst) const{ // {{{ open FUNCTION_LOG("ptr:"<(getParams()); else poDst->setParams(getParams()); poDst->setTime(getTime()); for(int c=getChannels()-1; c>=0; --c){ deepCopyChannel(this,c,poDst,c); } return poDst; } // }}} template Img *Img::scaledCopy(Img *poDst, scalemode eScaleMode) const{ // {{{ open FUNCTION_LOG("ptr:"<setChannels(getChannels()); poDst->setFormat(getFormat()); poDst->setTime(getTime()); // poDst->setFullROI(); for(int c=getChannels()-1; c>=0; --c){ scaledCopyChannelROI(this,c,Point::null,getSize(),poDst,c,Point::null,poDst->getSize(),eScaleMode); } return poDst; } // }}} template Img *Img::deepCopyROI(Img *poDst) const{ // {{{ open // NEW USING source ROI as well as destination images ROI FUNCTION_LOG("ptr:"<< poDst); if(!poDst){ poDst = new Img(getROISize(),getChannels(),getFormat()); }else{ ICLASSERT_RETURN_VAL( poDst->getROISize() == getROISize(), NULL); poDst->setChannels(getChannels()); poDst->setFormat(getFormat()); } poDst->setTime(getTime()); for(int c=getChannels()-1; c>=0; --c){ deepCopyChannelROI(this,c, getROIOffset(), getROISize(), poDst,c, poDst->getROIOffset(), poDst->getROISize() ); } return poDst; } // }}} template Img *Img::scaledCopyROI(Img *poDst, scalemode eScaleMode) const{ // {{{ open FUNCTION_LOG("ptr:"<setChannels(getChannels()); poDst->setFormat(getFormat()); poDst->setTime(getTime()); for(int c=getChannels()-1; c>=0; --c){ scaledCopyChannelROI(this,c, getROIOffset(), getROISize(), poDst,c, poDst->getROIOffset(), poDst->getROISize() , eScaleMode); } return poDst; } // }}} // }}} // {{{ channel management: detach, append remove, swap,... template void Img::detach(int iIndex){ // {{{ open FUNCTION_LOG("index:" << iIndex ); ICLASSERT_RETURN(iIndex < getChannels()); //---- Make the whole Img independent ---- for(int i=getStartIndex(iIndex),iEnd=getEndIndex(iIndex);i void Img::removeChannel(int iChannel) // {{{ open { FUNCTION_LOG("removeChannel(" << iChannel << ")"); ICLASSERT_RETURN(validChannel(iChannel)); m_vecChannels.erase(m_vecChannels.begin()+iChannel); m_oParams.setChannels(m_vecChannels.size()); } // }}} //---------------------------------------------------------------------------- template void Img::append(const Img *poSrc, int iIndex) // {{{ open { FUNCTION_LOG(""); ICLASSERT_RETURN( poSrc ); // iIndex < 0 is ok and means all channels ICLASSERT_RETURN( iIndex < poSrc->getChannels() ); ICLASSERT_RETURN( poSrc->getSize() == getSize() ); std::copy (poSrc->m_vecChannels.begin() + poSrc->getStartIndex(iIndex), poSrc->m_vecChannels.begin() + poSrc->getEndIndex(iIndex), back_inserter(m_vecChannels)); m_oParams.setChannels(m_vecChannels.size()); } // }}} template void Img::append(const Img *poSrc, const std::vector& vChannels) // {{{ open { FUNCTION_LOG(""); ICLASSERT_RETURN( poSrc ); ICLASSERT_RETURN( poSrc->getSize() == getSize() ); const int iMaxChannels = poSrc->getChannels(); for (std::vector::const_iterator it=vChannels.begin(), end=vChannels.end(); it != end; ++it) { if (*it < 0 || *it >= iMaxChannels) { ERROR_LOG ("channel index out of range: " << *it); } else { m_vecChannels.push_back (poSrc->m_vecChannels[*it]); } } m_oParams.setChannels(m_vecChannels.size()); } // }}} //---------------------------------------------------------------------------- template void Img::swapChannels(int iIndexA, int iIndexB) // {{{ open { FUNCTION_LOG("swapChannels("< inline void Img::replaceChannel(int iThisIndex, Img* poSrc, int iOtherIndex) // {{{ open { FUNCTION_LOG(""); ICLASSERT_RETURN(validChannel(iThisIndex)); ICLASSERT_RETURN(poSrc->validChannel(iOtherIndex)); m_vecChannels[iThisIndex] = poSrc->m_vecChannels[iOtherIndex]; } // }}} // }}} // {{{ inplace operations: scale, mirror //---------------------------------------------------------------------------- template void Img::scale(const Size &size, scalemode eScaleMode){ // {{{ open FUNCTION_LOG(""); ICLASSERT_RETURN (size.width > 0 && size.height > 0); if (!isEqual(size,getChannels())) { Img oTmp(size,getChannels(),getFormat()); scaledCopy(&oTmp,eScaleMode); (*this)=oTmp; } } // }}} //---------------------------------------------------------------------------- template void Img::mirror(axis eAxis, bool bOnlyROI) // {{{ open { FUNCTION_LOG(""); const Point& oOffset = bOnlyROI ? getROIOffset() : Point::null; const Size& oSize = bOnlyROI ? getROISize() : getSize(); for (int c=0; c < getChannels(); ++c) { this->mirror (eAxis, c, oOffset, oSize); } } // }}} static inline int getPointerOffset (int x, int y, int iLineLen) {return (x + y*iLineLen);} static bool getMirrorPointerOffsets (axis eAxis, bool bInplace, const Point& oSrcOffset, const int iSrcLineLen, const Point& oDstOffset, const int iDstLineLen, const Size& oSize, int& s, int& d, int& e, int& eLine, int& iLineWarpS, int& iLineWarpD) { // {{{ open int iRows=0, iCols=0; switch (eAxis) { case axisHorz: /* ..................... ....s->++++++++++l... ....+++++++++++++.... ....e------------.... ....*************.... ....d->**********.... ..................... */ iRows = bInplace ? oSize.height/2 : oSize.height; iCols = oSize.width; iLineWarpS = iSrcLineLen - iCols; iLineWarpD = -(iDstLineLen+iCols); s = getPointerOffset (oSrcOffset.x, oSrcOffset.y, iSrcLineLen); d = getPointerOffset (oDstOffset.x, oDstOffset.y + oSize.height - 1, iDstLineLen); e = iRows * iSrcLineLen; break; case axisVert: /* ..................... ....s->++++|l*<-d.... ....+++++++|*****.... ....+++++++|*****.... ....+++++++|*****.... ....+++++++|*****.... ....e................ */ iRows = oSize.height; iCols = bInplace ? oSize.width/2 : oSize.width; iLineWarpS = iSrcLineLen - iCols; iLineWarpD = iDstLineLen + iCols; s = getPointerOffset (oSrcOffset.x, oSrcOffset.y, iSrcLineLen); d = getPointerOffset (oDstOffset.x + oSize.width - 1, oDstOffset.y, iDstLineLen); e = iRows * iSrcLineLen; break; case axisBoth: /* ..................... ....s->++++++++++l... ....+++++++++++++.... ....+++++++e*****.... ....*************.... ....**********<-d.... ..................... */ iRows = bInplace ? oSize.height/2 : oSize.height; iCols = oSize.width; iLineWarpS = iSrcLineLen - iCols; iLineWarpD = iCols - iDstLineLen; s = getPointerOffset (oSrcOffset.x, oSrcOffset.y, iSrcLineLen); d = getPointerOffset (oDstOffset.x + oSize.width - 1, oDstOffset.y + oSize.height - 1, iDstLineLen); e = iRows * iSrcLineLen; if (bInplace && oSize.height % 2) { // odd ROI height iRows++; e += oSize.width/2; } break; } eLine = iCols; return (iRows != 0 && iCols != 0); } // }}} template static inline bool getMirrorPointers (axis eAxis, bool bInplace, const Type* const srcBegin, const Point& oSrcOffset, const int iSrcLineLen, Type* const dstBegin, const Point& oDstOffset, const int iDstLineLen, const Size& oSize, const Type*& s, Type*& d, const Type*& e, const Type*& eLine, int& iLineWarpS, int& iLineWarpD) { // {{{ open int deltaSrc, deltaDst, deltaEnd, deltaLineEnd; if (!getMirrorPointerOffsets (eAxis, bInplace, oSrcOffset, iSrcLineLen, oDstOffset, iDstLineLen, oSize, deltaSrc, deltaDst, deltaEnd, deltaLineEnd, iLineWarpS, iLineWarpD)) return false; s = srcBegin + deltaSrc; d = dstBegin + deltaDst; e = srcBegin + deltaEnd; eLine = srcBegin + deltaLineEnd; return true; } // }}} template static inline bool getMirrorPointers (axis eAxis, bool bInplace, Type* const srcBegin, const Point& oSrcOffset, const int iSrcLineLen, Type* const dstBegin, const Point& oDstOffset, const int iDstLineLen, const Size& oSize, Type*& s, Type*& d, const Type*& e, const Type*& eLine, int& iLineWarpS, int& iLineWarpD) { // {{{ open int deltaSrc, deltaDst, deltaEnd, deltaLineEnd; if (!getMirrorPointerOffsets (eAxis, bInplace, oSrcOffset, iSrcLineLen, oDstOffset, iDstLineLen, oSize, deltaSrc, deltaDst, deltaEnd, deltaLineEnd, iLineWarpS, iLineWarpD)) return false; s = srcBegin + deltaSrc; d = dstBegin + deltaDst; e = srcBegin + deltaEnd; eLine = srcBegin + deltaLineEnd; return true; } // }}} template void Img::mirror(axis eAxis, int iChannel, const Point& oOffset, const Size& oSize){ // {{{ open FUNCTION_LOG(""); static const int aiDstStep[] = {1,-1,-1}; int iLineWarpS, iLineWarpD; register const Type *e=0, *eLine=0; /* end pointer, line end pointer */ register Type *s=0, *d=0; /* source pointer, destination pointer */ if (!getMirrorPointers (eAxis, true, getData(iChannel), oOffset, getWidth(), getData(iChannel), oOffset, getWidth(), oSize, s, d, e, eLine, iLineWarpS, iLineWarpD)) return; register int dir = aiDstStep[eAxis]; do { std::swap (*s, *d); ++s; d += dir; if (s == eLine) { eLine += getWidth(); // end of line pointer jumps whole image width s += iLineWarpS; // source pointer jumps iLineWarpS d += iLineWarpD; } } while (s != e); } #ifdef WITH_IPP_OPTIMIZATION template <> void Img::mirror(axis eAxis, int iChannel, const Point &oOffset, const Size &oSize) { ippiMirror_8u_C1IR(getROIData(iChannel,oOffset),getLineStep(), oSize, (IppiAxis) eAxis); } template <> void Img::mirror(axis eAxis, int iChannel, const Point &oOffset, const Size &oSize) { ippiMirror_16u_C1IR((Ipp16u*) getROIData(iChannel,oOffset), getLineStep(), oSize, (IppiAxis) eAxis); } template <> void Img::mirror(axis eAxis, int iChannel, const Point &oOffset, const Size &oSize) { ippiMirror_32s_C1IR( getROIData(iChannel,oOffset), getLineStep(), oSize, (IppiAxis) eAxis); } template <> void Img::mirror(axis eAxis, int iChannel, const Point &oOffset, const Size &oSize) { ippiMirror_32s_C1IR((Ipp32s*) getROIData(iChannel,oOffset), getLineStep(), oSize, (IppiAxis) eAxis); } #endif // }}} // }}} // {{{ setter: setSize, setChannels //---------------------------------------------------------------------------- template void Img::setSize(const Size &s) // {{{ open { FUNCTION_LOG(""); Size oNewSize(s.width<0?getSize().width:s.width, s.height<0?getSize().height:s.height); //---- estimate destination values in respect to defaults ---- if (oNewSize != getSize()) { m_oParams.setSize(oNewSize); for(int i=0;i void Img::setChannels(int iNumNewChannels) // {{{ open { FUNCTION_LOG(""); ICLASSERT_RETURN(iNumNewChannels >= 0); if (iNumNewChannels == getChannels()) return; if(iNumNewChannels < getChannels()) { //---- reduce number of channels ---- m_vecChannels.erase(m_vecChannels.begin() + iNumNewChannels, m_vecChannels.end()); }else{ //---- Extend number of channels ---- m_vecChannels.reserve (iNumNewChannels); for(int i=getChannels();i < iNumNewChannels; ++i) m_vecChannels.push_back(createChannel()); } m_oParams.setChannels(m_vecChannels.size()); } // }}} // }}} // {{{ Get Min/Max functions: // {{{ getMax template Type Img::getMax() const{ FUNCTION_LOG(""); if (getChannels() == 0) return 0; Type tMax = getMax(0); for(int i=1;i Type Img::getMax(int iChannel) const { FUNCTION_LOG("iChannel: " << iChannel); ICLASSERT_RETURN_VAL( validChannel(iChannel), 0 ); const_iterator it = getROIIterator(iChannel); if (!it.inRegion()) return 0; // empty region Type vMax = *it; ++it; for (; it.inRegion(); ++it) { vMax = std::max (vMax, *it); } return vMax; } #ifdef WITH_IPP_OPTIMIZATION #define ICL_INSTANTIATE_DEPTH(T) \ template<> icl ## T \ Img::getMax(int iChannel) const { \ ICLASSERT_RETURN_VAL( validChannel(iChannel), 0 ); \ icl ## T vMax = 0; \ ippiMax_ ## T ## _C1R (getROIData(iChannel),getLineStep(),getROISize(),&vMax); \ return vMax; \ } ICL_INSTANTIATE_DEPTH(8u) ICL_INSTANTIATE_DEPTH(16s) ICL_INSTANTIATE_DEPTH(32f) #undef ICL_INSTANTIATE_DEPTH #endif // }}} // {{{ getMin template Type Img::getMin() const{ FUNCTION_LOG(""); if (getChannels() == 0) return 0; Type tMin = getMin(0); for(int i=1;i Type Img::getMin(int iChannel) const { FUNCTION_LOG("iChannel: " << iChannel); ICLASSERT_RETURN_VAL( validChannel(iChannel), 0 ); const_iterator it = getROIIterator(iChannel); if (!it.inRegion()) return 0; // empty region Type vMin = *it; ++it; for (; it.inRegion(); ++it) { vMin = std::min (vMin, *it); } return vMin; } #ifdef WITH_IPP_OPTIMIZATION #define ICL_INSTANTIATE_DEPTH(T) \ template<> icl##T \ Img::getMin(int iChannel) const { \ ICLASSERT_RETURN_VAL( validChannel(iChannel), 0 ); \ icl##T vMin = 0; \ ippiMin_##T##_C1R (getROIData(iChannel),getLineStep(),getROISize(),&vMin); \ return vMin; } ICL_INSTANTIATE_DEPTH(8u) ICL_INSTANTIATE_DEPTH(16s) ICL_INSTANTIATE_DEPTH(32f) #undef ICL_INSTANTIATE_DEPTH #endif // }}} // {{{ getMinMax template const Range Img::getMinMax() const { FUNCTION_LOG(""); if (getChannels() == 0) { return Range(); } Range r = getMinMax(0); for(int i=1;i k = getMinMax(i); r.minVal = std::min(r.minVal,k.minVal); r.maxVal = std::max(r.maxVal,k.maxVal); } return r; } // fallback for all types template const Range Img::getMinMax(int iChannel) const { FUNCTION_LOG("iChannel: " << iChannel); ICLASSERT_RETURN_VAL(validChannel(iChannel), Range()); Range r; const_iterator it = getROIIterator(iChannel); if (!it.inRegion()) return Range(); // empty region: return with 0, 0 r.minVal = r.maxVal = *it; ++it; for (; it.inRegion(); ++it) { r.minVal = std::min (r.minVal, *it); r.maxVal = std::max (r.maxVal, *it); } return r; } #ifdef WITH_IPP_OPTIMIZATION #define ICL_INSTANTIATE_DEPTH(T) \ template<> const Range \ Img::getMinMax(int iChannel) const { \ ICLASSERT_RETURN_VAL( validChannel(iChannel) ,Range()); \ Range r; \ ippiMinMax_ ## T ## _C1R (getROIData(iChannel),getLineStep(), \ getROISize(), &(r.minVal), &(r.maxVal)); \ return r; \ } ICL_INSTANTIATE_DEPTH(8u) ICL_INSTANTIATE_DEPTH(16s) ICL_INSTANTIATE_DEPTH(32f) #undef ICL_INSTANTIATE_DEPTH #endif // }}} // }}} // {{{ Auxillary functions template SmartPtr Img::createChannel(Type *ptDataToCopy) const { // {{{ open FUNCTION_LOG(""); int dim = getDim(); if(!dim) return SmartPtr(); Type *ptNewData = new Type[dim]; if(ptDataToCopy){ memcpy(ptNewData,ptDataToCopy,dim*sizeof(Type)); }else{ std::fill(ptNewData,ptNewData+dim,0); } return SmartPtr(ptNewData); } // }}} // sub-pixel access using linear interpolation template float Img::subPixelLIN(float fX, float fY, int iChannel) const { // {{{ open float fX0 = fX - floor(fX), fX1 = 1.0 - fX0; float fY0 = fY - floor(fY), fY1 = 1.0 - fY0; int xll = (int) fX; int yll = (int) fY; const Type* pLL = getData(iChannel) + xll + yll * getWidth(); float a = *pLL; // a b float b = *(++pLL); // c d pLL += getWidth(); float d = *pLL; float c = *(--pLL); // return fX1*fY1*a + fX0*fY1*b + fX0*fY0*d + fX1*fY0*c; return fX1 * (fY1*a + fY0*c) + fX0 * (fY1*b + fY0*d); } // }}} // sub-pixel access using region average interpolation template float Img::subPixelRA(float fX, float fY, int iChannel) const { // {{{ open ERROR_LOG ("region average interpolation is not yet implemented!"); return subPixelLIN (fX, fY, iChannel); } // }}} // }}} // {{{ normalize and clear // {{{ normalize wrappers template void Img::normalizeAllChannels(const Range &dstRange){ FUNCTION_LOG(""); for (int c=0;c void Img::normalizeChannel(int iChannel, const Range &srcRange, const Range &dstRange){ FUNCTION_LOG(""); normalize(iChannel, srcRange,dstRange); } template void Img::normalizeChannel(int iChannel,const Range &dstRange) { FUNCTION_LOG(""); normalize(iChannel, getMinMax(iChannel),dstRange); } template void Img::normalizeImg(const Range &srcRange, const Range &dstRange){ FUNCTION_LOG(""); for (int c=0;c void Img::normalizeImg(const Range &dstRange) { FUNCTION_LOG(""); for (int c=0;c void Img::normalize(int iChannel, const Range &srcRange, const Range &dstRange){ FUNCTION_LOG(""); for(int c = getStartIndex(iChannel);c::cast( icl::clip( fShift + (icl64f)(*p) * fScale, icl64f(dstRange.minVal),icl64f(dstRange.maxVal) ) ); } } } #ifdef WITH_IPP_OPTIMIZATION template <> void Img::normalize(int iChannel, const Range &srcRange, const Range &dstRange){ FUNCTION_LOG(""); for(int c = getStartIndex(iChannel);c void Img::clear(int iIndex, Type tValue, bool bROIOnly) // {{{ open { //---- Log Message ---- FUNCTION_LOG("clear(" << iIndex << "," << tValue << ")"); ICLASSERT_RETURN( iIndex < getChannels() ); Point offs = bROIOnly ? getROIOffset() : Point::null; Size size = bROIOnly ? getROISize() : getSize(); for(int i=getStartIndex(iIndex),iEnd=getEndIndex(iIndex);i const ImgType* combineImages (const std::vector& vec, ImgBase** ppoDst) { // {{{ open FUNCTION_LOG(""); // find first non-zero element typename std::vector::const_iterator first = std::find_if (vec.begin(), vec.end(), std::bind2nd(std::not_equal_to(), reinterpret_cast(0))), end = vec.end(); // check for empty vector if (first == vec.end()) return 0; // create image with parameters of first image in vector icl::ensureCompatible (ppoDst, *first); ImgType* poDst = static_cast(*ppoDst); // some cache variables const Size& dstSize = poDst->getSize(); const Rect& dstROI = poDst->getROI(); icl::format fmt = (*first)->getFormat(); bool bKeepROI=true; unsigned int nCount = 0; for (; first != end; ++first) { if ((*first)->getSize() == dstSize) { if ((*first)->getROI() != dstROI) bKeepROI = false; poDst->append (*first); ++nCount; } else ERROR_LOG ("image size doesn't match"); } if (nCount == 1) poDst->setFormat (fmt); // keep format of single source image if (!bKeepROI) poDst->setFullROI (); // reset ROI if subimages' ROIs do not match return poDst; } // }}} // file local (i.e. private) function to mediate between ImgBase and Img variants template const Img* __combineImages (const std::vector& vec, ImgBase** ppoDst) { // {{{ open std::vector*> vecTyped; // create correctly typed vector for (std::vector::const_iterator it=vec.begin(), end=vec.end(); it != end; ++it) { const ImgBase *pImgBase = *it; if (pImgBase->getDepth () == icl::getDepth()) vecTyped.push_back (pImgBase->asImg()); else ERROR_LOG ("image depth doesn't match"); } return combineImages (vecTyped, ppoDst); } // }}} template<> const ImgBase* combineImages (const std::vector& vec, ImgBase** ppoDst) { // {{{ open FUNCTION_LOG("ImgBase"); // find first non-zero element std::vector::const_iterator first = std::find_if (vec.begin(), vec.end(), std::bind2nd(std::not_equal_to(), reinterpret_cast(0))); // check for empty vector if (first == vec.end()) { // remove all channels from *ppoDst if (ppoDst && *ppoDst) {(*ppoDst)->setChannels(0); return *ppoDst;} // or return Null pointer directly else return 0; } switch ((*first)->getDepth()) { #define ICL_INSTANTIATE_DEPTH(T) \ case depth ## T: return __combineImages (vec, ppoDst); break; ICL_INSTANTIATE_ALL_DEPTHS #undef ICL_INSTANTIATE_DEPTH } return 0; } // }}} // scale channel ROI function for abitrary image scaling operations template void scaledCopyChannelROI(const Img *src, int srcC, const Point &srcOffs, const Size &srcSize, Img *dst, int dstC, const Point &dstOffs, const Size &dstSize, scalemode eScaleMode){ // {{{ open FUNCTION_LOG(""); ICLASSERT_RETURN( src && dst ); 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() ); float fSX = ((float)srcSize.width)/(float)(dstSize.width); float fSY = ((float)srcSize.height)/(float)(dstSize.height); float (Img::*subPixelMethod)(float fX, float fY, int iChannel) const; switch(eScaleMode) { case interpolateNN: subPixelMethod = &Img::subPixelNN; break; case interpolateLIN: fSX = ((float)srcSize.width-1)/(float)(dstSize.width); fSY = ((float)srcSize.height-1)/(float)(dstSize.height); subPixelMethod = &Img::subPixelLIN; break; default: ERROR_LOG("unknown interpoation method!"); subPixelMethod = &Img::subPixelNN; break; } ImgIterator itDst(dst->getData(dstC),dst->getSize().width,Rect(dstOffs,dstSize)); int xD = 0; int yD = 0; float yS = srcOffs.y + fSY * yD; for(; itDst.inRegion(); ++itDst) { *itDst = Cast::cast ((src->*subPixelMethod)(srcOffs.x + fSX * xD, yS, srcC)); if (++xD == dstSize.width) { yS = srcOffs.y + fSY * ++yD; xD = 0; } } } // }}} #define ICL_INSTANTIATE_DEPTH(D) template void scaledCopyChannelROI \ (const Img*,int,const Point&,const Size&, \ Img*,int,const Point&,const Size&,scalemode); /// IPP-OPTIMIZED specialization for icl8u to icl8u ROI sclaing (using ippiResize) #ifdef WITH_IPP_OPTIMIZATION template<> inline void scaledCopyChannelROI(const Img *src, int srcC, const Point &srcOffs, const Size &srcSize, Img *dst, int dstC, const Point &dstOffs, const Size &dstSize, scalemode eScaleMode) // {{{ open { FUNCTION_LOG(""); ICLASSERT_RETURN( src && dst ); 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() ); // attention: for source image IPP wants indeed the *image* origin ippiResize_8u_C1R(src->getData(srcC),src->getSize(),src->getLineStep(),Rect(srcOffs,srcSize), dst->getROIData(dstC,dstOffs),dst->getLineStep(),dstSize, (float)dstSize.width/(float)srcSize.width, (float)dstSize.height/(float)srcSize.height,(int)eScaleMode); } // }}} /// IPP-OPTIMIZED specialization for icl32f to icl32f ROI sclaing (using ippiResize) template<> inline void scaledCopyChannelROI(const Img *src, int srcC, const Point &srcOffs, const Size &srcSize, Img *dst, int dstC, const Point &dstOffs, const Size &dstSize, scalemode eScaleMode) // {{{ open { FUNCTION_LOG(""); ICLASSERT_RETURN( src && dst ); 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() ); // attention: for source image IPP wants indeed the *image* origin ippiResize_32f_C1R(src->getData(srcC),src->getSize(),src->getLineStep(),Rect(srcOffs,srcSize), dst->getROIData(dstC,dstOffs),dst->getLineStep(),dstSize, (float)dstSize.width/(float)srcSize.width, (float)dstSize.height/(float)srcSize.height,(int)eScaleMode); } // }}} // ipp case: do not instantiate the already specialized functions 8u and 32f ICL_INSTANTIATE_DEPTH(16s) ICL_INSTANTIATE_DEPTH(32s) ICL_INSTANTIATE_DEPTH(64f) #else // no-ipp case instantiate all functions ICL_INSTANTIATE_ALL_DEPTHS #endif #undef ICL_INSTANTIATE_DEPTH // {{{ flippedCopyChannelROI // mirror copy ROI of one image to the ROI of the other (for selected channel) template void flippedCopyChannelROI(axis eAxis, const Img *src, int srcC, const Point &srcOffs, const Size &srcSize, Img *dst, int dstC, const Point &dstOffs, const Size &dstSize){ // {{{ open 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() ); static const int aiDstStep[] = {1,-1,-1}; int iLineWarpS, iLineWarpD; register const T *s=0, *e=0, *eLine=0; /* source pointer, end pointer, line end pointer */ register T *d=0; /* destination pointer */ if (!getMirrorPointers (eAxis, false, src->getData(srcC), srcOffs, src->getWidth(), dst->getData(dstC), dstOffs, dst->getWidth(), srcSize, s, d, e, eLine, iLineWarpS, iLineWarpD)) return; if (eAxis == axisHorz) { int iSrcStep = src->getSize().width, iDstStep = dst->getSize().width; // int nBytes = sizeof(T) * srcSize.width; // line-wise memcpy is possible for (; s != e; s += iSrcStep, d -= iDstStep) icl::copy(s,s+srcSize.width,d);//memcpy (d, s, nBytes); return; } register int dir = aiDstStep[eAxis]; do { *d = *s; ++s; d += dir; if (s == eLine) { eLine += src->getSize().width; // end of line pointer jumps whole image width s += iLineWarpS; // source pointer jumps iLineWarpS d += iLineWarpD; } } while (s != e); } // }}} #define ICL_INSTANTIATE_DEPTH(D) template void flippedCopyChannelROI(axis eAxis, \ const Img *src, int srcC, const Point &srcOffs, const Size &srcSize, \ Img *dst, int dstC, const Point &dstOffs, const Size &dstSize); #ifdef WITH_IPP_OPTIMIZATION /// IPP-OPTIMIZED specialization for icl8u image flipping template <> inline void flippedCopyChannelROI(axis eAxis, const Img *src, int srcC, const Point &srcOffs, const Size &srcSize, Img *dst, int dstC, const Point &dstOffs, const Size &dstSize) { // {{{ open 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() ); ippiMirror_8u_C1R(src->getROIData(srcC,srcOffs),src->getLineStep(), dst->getROIData(dstC,dstOffs),dst->getLineStep(),srcSize,(IppiAxis) eAxis); } // }}} /// IPP-OPTIMIZED specialization for icl8u image flipping template <> inline void flippedCopyChannelROI(axis eAxis, const Img *src, int srcC, const Point &srcOffs, const Size &srcSize, Img *dst, int dstC, const Point &dstOffs, const Size &dstSize) { // {{{ open 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() ); ippiMirror_32s_C1R((Ipp32s*) src->getROIData(srcC,srcOffs),src->getLineStep(), (Ipp32s*) dst->getROIData(dstC,dstOffs),dst->getLineStep(),srcSize,(IppiAxis) eAxis); } // }}} // ipp case: do not instantiate the already specialized functions 8u and 32f ICL_INSTANTIATE_DEPTH(16s) ICL_INSTANTIATE_DEPTH(32s) ICL_INSTANTIATE_DEPTH(64f) #else // no-ipp case instantiate all functions ICL_INSTANTIATE_ALL_DEPTHS #endif #undef ICL_INSTANTIATE_DEPTH // }}} // {{{ flippedCopy / flippedCopyROI void flippedCopy(axis eAxis, const ImgBase *poSrc, ImgBase **ppoDst){ // {{{ open ICLASSERT_RETURN(poSrc); ImgBase *poDst = ensureCompatible(ppoDst,poSrc->getDepth(),poSrc->getSize(),poSrc->getChannels(),poSrc->getFormat()); poDst->setTime(poSrc->getTime()); // imagewidth = 300, roioffs=0, roiwidth=100 if(poSrc->getROISize() != poSrc->getSize()){ Size rs = poSrc->getROISize(); Size is = poSrc->getSize(); Point o = poSrc->getROIOffset(); Point newO = o; switch(eAxis){ case axisHorz: newO.y = is.height-o.y-rs.height; break; case axisVert: newO.x = is.width-o.x-rs.width; break; case axisBoth: newO.x = is.width-o.x-rs.width; newO.y = is.height-o.y-rs.height; break; } poDst->setROI(newO,rs); } const ImgBase *poFullSrc = poSrc->shallowCopy(Rect(Point::null,poSrc->getSize())); ImgBase *poFullDst = poDst->shallowCopy(Rect(Point::null,poDst->getSize())); flippedCopyROI(eAxis,poFullSrc,&poFullDst); } // }}} void flippedCopyROI(axis eAxis, const ImgBase *poSrc, ImgBase **ppoDst){ // {{{ open ICLASSERT_RETURN(poSrc); ImgBase *poDst = 0; if(!ppoDst){ poDst = imgNew(poSrc->getDepth(),poSrc->getROISize(),poSrc->getChannels(),poSrc->getFormat()); }else if(! *ppoDst){ poDst = imgNew(poSrc->getDepth(),poSrc->getROISize(),poSrc->getChannels(),poSrc->getFormat()); *ppoDst = poDst; }else{ poDst = ensureDepth(ppoDst,poSrc->getDepth()); ICLASSERT_RETURN( poDst->getROISize() == poSrc->getROISize()); poDst->setChannels(poSrc->getChannels()); poDst->setFormat(poSrc->getFormat()); } poDst->setTime(poSrc->getTime()); for(int c=poSrc->getChannels()-1; c>=0; --c){ switch(poSrc->getDepth()){ #define ICL_INSTANTIATE_DEPTH(D) \ case depth##D :flippedCopyChannelROI(eAxis,poSrc->asImg(),c, poSrc->getROIOffset(), poSrc->getROISize(), \ poDst->asImg(),c, poDst->getROIOffset(), poDst->getROISize() ); break; ICL_INSTANTIATE_ALL_DEPTHS; #undef ICL_INSTANTIATE_DEPTH } } } // }}} // }}} // }}} // {{{ explicit instantiation of the Img classes #define ICL_INSTANTIATE_DEPTH(D) template class Img; ICL_INSTANTIATE_ALL_DEPTHS #undef ICL_INSTANTIATE_DEPTH // }}} } //namespace icl