/******************************************************************** ** Image Component Library (ICL) ** ** ** ** Copyright (C) 2006-2010 CITEC, University of Bielefeld ** ** Neuroinformatics Group ** ** Website: www.iclcv.org and ** ** http://opensource.cit-ec.de/projects/icl ** ** ** ** File : ICLFilter/src/LocalThresholdOp.cpp ** ** Module : ICLFilter ** ** Authors: Christof Elbrechter ** ** ** ** ** ** 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. ** ** ** *********************************************************************/ #include #include #include #include #include #include namespace icl{ LocalThresholdOp::LocalThresholdOp(unsigned int maskSize, float globalThreshold, float gammaSlope): // {{{ open m_maskSize(maskSize),m_globalThreshold(globalThreshold), m_gammaSlope(gammaSlope),m_roiBufSrc(0), m_roiBufDst(0), m_iiOp(new IntegralImgOp),m_algorithm(regionMean), m_cmp(new BinaryCompareOp(BinaryCompareOp::gt)), m_tiledBuf1(0),m_tiledBuf2(0){ } // }}} LocalThresholdOp::LocalThresholdOp(LocalThresholdOp::algorithm a, int maskSize, float globalThreshold, float gammaSlope): // {{{ open m_maskSize(maskSize),m_globalThreshold(globalThreshold), m_gammaSlope(gammaSlope),m_roiBufSrc(0), m_roiBufDst(0), m_iiOp(new IntegralImgOp),m_algorithm(a), m_cmp(new BinaryCompareOp(BinaryCompareOp::gt)), m_tiledBuf1(0),m_tiledBuf2(0){ } // }}} LocalThresholdOp::~LocalThresholdOp(){ // {{{ open ICL_DELETE(m_roiBufDst); ICL_DELETE(m_iiOp); ICL_DELETE(m_cmp); ICL_DELETE(m_tiledBuf1); ICL_DELETE(m_tiledBuf2); } // }}} void LocalThresholdOp::setMaskSize(unsigned int maskSize){ // {{{ open m_maskSize = maskSize; } // }}} void LocalThresholdOp::setGlobalThreshold(float globalThreshold){ // {{{ open m_globalThreshold = globalThreshold; } // }}} void LocalThresholdOp::setGammaSlope(float gammaSlope){ // {{{ open this->m_gammaSlope = gammaSlope; } // }}} unsigned int LocalThresholdOp::getMaskSize() const{ // {{{ open return m_maskSize; } // }}} float LocalThresholdOp::getGlobalThreshold() const{ // {{{ open return m_globalThreshold; } // }}} float LocalThresholdOp::getGammaSlope() const{ // {{{ open return m_gammaSlope; } // }}} void LocalThresholdOp::setup(unsigned int maskSize, float globalThreshold, LocalThresholdOp::algorithm a, float gammaSlope){ // {{{ open setMaskSize(maskSize); setGlobalThreshold(globalThreshold); setGammaSlope(gammaSlope); setAlgorithm(a); } // }}} /// returns currently used algorithm type LocalThresholdOp::algorithm LocalThresholdOp::getAlgorithms() const{ // {{{ open return m_algorithm; } // }}} /// sets internally used algorithm void LocalThresholdOp::setAlgorithm(algorithm a){ // {{{ open m_algorithm = a; } // }}} template static void fast_lt(const Img &src, const Img &iim, Img &dst, int r, TT t, float gs, int channel){ // {{{ open const TI *ii = iim.begin(channel); const TS *psrc = src.begin(channel); TD *pdst = dst.begin(channel); // first, we leave out the borders: const int w = src.getWidth(); const int h = src.getHeight(); const int r2 = 2*r; const int yEnd = h-r; const int dim = r2*r2; t*=dim; // help to avoid /dim in the loop /* Explanation B-----C | | | x<-|--- here we are mean value in rect is B - C - D + A | | D-----A Image parts for all border Regions (id = 1..8) we have to work with a pixel dependend rectangle dimension 1| 2 |3 ------------------- | | 4| CENTER |5 | | ------------------- 6| 7 |8 */ #define GET_II(x,y) ii[(x)+(y)*w] #define GET_A(rx,ry,rw,rh) GET_II((rx+rw),(ry+rh)) #define GET_B(rx,ry,rw,rh) GET_II((rx),(ry)) #define GET_C(rx,ry,rw,rh) GET_II((rx+rw),(ry)) #define GET_D(rx,ry,rw,rh) GET_II((rx),(ry+rh)) #define GET_RECT(rx,ry,rw,rh) (GET_B((rx),(ry),(rw),(rh)) - GET_C((rx),(ry),(rw),(rh)) - GET_D((rx),(ry),(rw),(rh)) + GET_A((rx),(ry),(rw),(rh)) + t) #define COMPLEX_STEP(rx,ry,rw,rh) pdst[x+w*y] = (!WITH_GAMMA) ? \ (255 * (psrc[x+w*y]*((rw)*(rh)) > (GET_RECT((rx),(ry),(rw),(rh)))) ) : \ ((TD)clip( gs * (psrc[x+w*y] - float(GET_RECT((rx),(ry),(rw),(rh)))/((rw)*(rh)) ) + 128,float(0),float(255))) // [1][2][3] for(int y=0;y (*B - *C - *D + *A + t))) : \ ((TD)clip( gs * (*s - float(*B - *C - *D + *A + t)/dim ) + 128,float(0),float(255))) \ ; ++B; ++C; ++D; ++A; ++s; ++d; // 16x loop unrolling here for(int n = ((int)(ends-s)) >> 4; n > 0; --n){ STEP STEP STEP STEP STEP STEP STEP STEP STEP STEP STEP STEP STEP STEP STEP STEP } while(s void apply_local_threshold_six(const Img &src,const Img &ii, ImgBase *dst, float t, int m, float gs){ // {{{ open switch(dst->getDepth()){ case depth8u: if(gs!=0.0f){ for(int c=0;c(src,ii,*dst->asImg(),m,int(t),gs,c); } }else{ for(int c=0;c(src,ii,*dst->asImg(),m,int(t),gs,c); } } break; case depth32f: if(gs!=0.0f){ for(int c=0;c(src,ii,*dst->asImg(),m,t,gs,c); } }else{ for(int c=0;c(src,ii,*dst->asImg(),m,t,gs,c); } } break; default: // this may not happen ICL_INVALID_DEPTH; } } // }}} /// this template resolves the integral image depths template void apply_local_threshold_sxx(const Img &src,const ImgBase *ii, ImgBase *dst, float t,unsigned int m, float gs){ // {{{ open switch(ii->getDepth()){ case depth32s: apply_local_threshold_six(src,*ii->asImg(),dst,t,m,gs); break; case depth32f: apply_local_threshold_six(src,*ii->asImg(),dst,t,m,gs); break; case depth64f: apply_local_threshold_six(src,*ii->asImg(),dst,t,m,gs); break; default: // this may not happen ICL_INVALID_DEPTH; } } // }}} template void LocalThresholdOp::apply_a(const ImgBase*, ImgBase**){ // {{{ open throw ICLException("this algorithm is not yet implemented for the LocalThresholdOp class"); } // }}} template struct CountPix{ mutable volatile B &t; CountPix(volatile B &t):t(t){} inline void operator()(const T &v) const{ t += v; } }; template inline T roi_mean(Img &s, int dim){ volatile icl64f t = 0 ; s.forEach(CountPix(t)); return T(t/dim); } template<> inline icl8u roi_mean(Img &s, int dim){ volatile unsigned int t = 0 ; s.forEach(CountPix(t)); return icl8u(t/dim); } template<> inline icl16s roi_mean(Img &s, int dim){ volatile int64_t t = 0; s.forEach(CountPix(t)); return icl16s(t/dim); } template<> inline icl32s roi_mean(Img &s, int dim){ volatile int64_t t = 0 ; s.forEach(CountPix(t)); return icl32s(t/dim); } template static void apply_tiled_thresh(Img s, Img8u &dst, Img &buf1, Img &buf2, int ts, int threshold, BinaryCompareOp *cmp, bool lin){ S *pbuf1 = buf1.begin(0); int w = s.getWidth(); int bw = w/ts; int h = s.getHeight(); Size t(ts,ts); int dim = ts*ts; int NX = w/ts; int NY = h/ts; Rect r(0,0,ts,ts); for(int c=s.getChannels()-1;c>=0;--c){ for(int y=0;yapply(&s,&buf2,bpp(dst)); } template<> void LocalThresholdOp::apply_a(const ImgBase *src, ImgBase **dst){ // {{{ open int ts = 2*m_maskSize; ICLASSERT_RETURN(ts>1); Size size = src->getSize(); ensureCompatible(&m_tiledBuf1,src->getDepth(),size/ts, 1, formatMatrix); ensureCompatible(&m_tiledBuf2,src->getDepth(),size,1,formatMatrix); switch(src->getDepth()){ #define ICL_INSTANTIATE_DEPTH(D) \ case depth##D: \ apply_tiled_thresh(*src->asImg(), \ *(*dst)->asImg(), \ *m_tiledBuf1->asImg(), \ *m_tiledBuf2->asImg(), \ ts, m_globalThreshold, m_cmp, \ m_algorithm == tiledLIN); \ break; ICL_INSTANTIATE_ALL_DEPTHS #undef ICL_INSTANTIATE_DEPTH } } // }}} template<> void LocalThresholdOp::apply_a(const ImgBase *src, ImgBase **dst){ // {{{ open apply_a(src,dst); // LIN vs NN is handled by a runtime-bool } // }}} template<> void LocalThresholdOp::apply_a(const ImgBase *src, ImgBase **dst){ // {{{ open m_iiOp->setIntegralImageDepth((src->getDepth() == depth8u || src->getDepth() == depth16s) ? depth32s : src->getDepth()); const ImgBase *ii = m_iiOp->apply(src); switch(src->getDepth()){ #define ICL_INSTANTIATE_DEPTH(D) case depth##D: apply_local_threshold_sxx(*src->asImg(), ii, *dst, m_globalThreshold, m_maskSize, m_gammaSlope); break; ICL_INSTANTIATE_ALL_DEPTHS; #undef ICL_INSTANTIATE_DEPTH } } // }}} void LocalThresholdOp::apply(const ImgBase *src, ImgBase **dst){ // {{{ open ICLASSERT_RETURN( src ); ICLASSERT_RETURN( src->getSize() != Size::null ); ICLASSERT_RETURN( src->getChannels() ); ICLASSERT_RETURN( dst ); ICLASSERT_RETURN( src != *dst ); const ImgBase *srcOrig = src; bool roi = false; // cut the roi of src if set if(!(src->hasFullROI())){ ensureCompatible(&m_roiBufSrc, src->getDepth(), src->getROISize(), src->getChannels(), src->getFormat()); src->deepCopyROI(&m_roiBufSrc); src = m_roiBufSrc; roi = true; } ICLASSERT_RETURN(src->getWidth() > 2*(int)m_maskSize); ICLASSERT_RETURN(src->getHeight() > 2*(int)m_maskSize); // prepare the destination image depth dstDepth = m_algorithm == regionMean ? (m_gammaSlope ? depth32f : depth8u) : depth8u; ImgBase **useDst = roi ? &m_roiBufDst : dst; if(!prepare(useDst, dstDepth, src->getSize(), formatMatrix, src->getChannels(), Rect::null)){ ERROR_LOG("prepare failure [code 1]"); return; } switch(m_algorithm){ case regionMean: apply_a(src,useDst); break; case tiledNN: apply_a(src,useDst); break; case tiledLIN: apply_a(src,useDst); break; default: throw ICLException(std::string(__FUNCTION__)+": invalid algorithm value"); } if(roi){ if(!prepare(dst, srcOrig, (*useDst)->getDepth())){ ERROR_LOG("prepare failure [code 2]"); return; } (*useDst)->deepCopyROI(dst); } } // }}} }