/******************************************************************** ** 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 : ICLFilter/src/ICLFilter/UnaryOp.cpp ** ** Module : ICLFilter ** ** Authors: Christof Elbrechter ** ** ** ** ** ** 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. ** ** ** ********************************************************************/ #include #include #include #include #include #include #include #include #include #include #include #ifdef ICL_HAVE_IPP #include #endif #include #include #include #include using namespace icl::utils; using namespace icl::core; namespace icl{ namespace filter{ void UnaryOp::initConfigurable(){ addProperty("UnaryOp.clip to ROI","menu","on,off",m_oROIHandler.getClipToROI() ? "on" : "off",0, "If this option is set to true, the result images are always adapted\n" "to contain the computed result pixels only. If it is set to false,\n" "and the source image did have a ROI set, the result image will become\n" "as large as the source image, it's ROI will also be the same and\n" "only ROI pixels will be processed"); addProperty("UnaryOp.check only","menu","on,off",m_oROIHandler.getCheckOnly() ? "on" : "off",0, "If check only is set to true, images, that are passed to the apply\n" "method are not adapted. Instead the given result images are checked\n" "for their compatibility. In case of uncompatible result images,\n" "an exception is thrown."); } UnaryOp::UnaryOp():m_poMT(0),m_buf(0){ initConfigurable(); } UnaryOp::UnaryOp(const UnaryOp &other): m_poMT(0),m_oROIHandler(other.m_oROIHandler),m_buf(0){ initConfigurable(); } UnaryOp &UnaryOp::operator=(const UnaryOp &other){ m_oROIHandler = other.m_oROIHandler; ICL_DELETE( m_poMT ); prop("UnaryOp.clip to ROI").value = other.prop("UnaryOp.clip to ROI").value; prop("UnaryOp.check only").value = other.prop("UnaryOp.check only").value; return *this; } UnaryOp::~UnaryOp(){ ICL_DELETE( m_poMT ); ICL_DELETE( m_buf ); } const ImgBase *UnaryOp::apply(const ImgBase *src){ apply(src,&m_buf); return m_buf; } void UnaryOp::applyMT(const ImgBase *poSrc, ImgBase **ppoDst, unsigned int nThreads){ ICLASSERT_RETURN( nThreads > 0 ); ICLASSERT_RETURN( poSrc ); if(nThreads == 1){ apply(poSrc,ppoDst); return; } if(!prepare (ppoDst, poSrc)) return; bool ctr = getClipToROI(); bool co = getCheckOnly(); setClipToROI(false); setCheckOnly(true); const std::vector srcs = ImageSplitter::split(poSrc,nThreads); std::vector dsts = ImageSplitter::split(*ppoDst,nThreads); MultiThreader::WorkSet works(nThreads); for(unsigned int i=0;i(dsts[i])); } if(!m_poMT){ m_poMT = new MultiThreader(nThreads); }else{ if(m_poMT->getNumThreads() != (int)nThreads){ delete m_poMT; m_poMT = new MultiThreader(nThreads); } } (*m_poMT)( works ); for(unsigned int i=0;i paramlist; typedef UnaryOp* (*creator)(const paramlist ¶ms); struct Creator{ Creator(creator c=0, const std::string &n="", const std::string &s=""):c(c),s(s),n(n){} creator c; std::string s; // syntax std::string n; // name operator const std::string&() const{ return n; } UnaryOp *operator()(const paramlist ¶ms) const { return c(params); } }; static std::map CREATORS; UnaryOp *create_generic_conv(const paramlist ¶msIn){ paramlist params = paramsIn; ICLASSERT_THROW(params.size() >= 2,ICLException(str(__FUNCTION__)+":param list must have at least two elements")); Size kernelSize = parse(params[0]); ICLASSERT_THROW(kernelSize.getDim()>=1,ICLException(str(__FUNCTION__)+":kernel dimension is <=0")) params.erase(params.begin()); std::vector kernelValues = parseVec(params); ICLASSERT_THROW(kernelSize.getDim() == (int)kernelValues.size(),ICLException(str(__FUNCTION__)+":kernel dimension is "+ str(kernelSize.getDim())+" kernel value list's size is "+ str(kernelValues.size()))); return new ConvolutionOp(ConvolutionKernel(kernelValues.data(),kernelSize)); } template UnaryOp *create_fixed_conv(const paramlist ¶ms){ ICLASSERT_THROW(!params.size(),ICLException(str(__FUNCTION__)+": no parameters allowed here")); return new ConvolutionOp(ConvolutionKernel(t)); } template UnaryOp *create_fixed_morph(const paramlist ¶ms){ Size kernelSize = params.size()?parse(params.front()):Size(3,3); ICLASSERT_THROW(kernelSize.getDim()>=1,ICLException(str(__FUNCTION__)+": kernel dimension is <=0")); return new MorphologicalOp(t,kernelSize); } UnaryOp *create_median(const paramlist ¶ms){ Size kernelSize = params.size()?parse(params.front()):Size(3,3); ICLASSERT_THROW(kernelSize.getDim()>=1,ICLException(str(__FUNCTION__)+": kernel dimension is <=0")); return new MedianOp(kernelSize); } struct PassOp:public UnaryOp{ void apply(const ImgBase *src, ImgBase **dst){ ICLASSERT(dst); const_cast(src)->deepCopy(dst); (*dst)->setFullROI(); } static UnaryOp *create(const paramlist ¶ms){ ICLASSERT_THROW(!params.size(),ICLException(str(__FUNCTION__)+": no parameters allowed here")); return new PassOp; } }; UnaryOp *create_rotate(const paramlist ¶ms){ ICLASSERT_THROW(params.size() == 1,ICLException(str(__FUNCTION__)+": params list size must be 1 here")); float angle = parse(params.front()); return new RotateOp(angle); } UnaryOp *create_scale(const paramlist ¶ms){ ICLASSERT_THROW(params.size() == 1 ||params.size() == 2 || params.size() == 3,ICLException(str(__FUNCTION__)+": params list size must be 1,2 or 3 here")); float fx = parse(params[0]); if(fx > 5) throw ICLException(str(__FUNCTION__)+": scale factor fx must not be higher than 5"); float fy = params.size()>1 ? parse(params[1]) : fx; if(fy > 5) throw ICLException(str(__FUNCTION__)+": scale factor fy must not be higher than 5"); scalemode sm = interpolateNN; if(params.size()==3 && params[2] == "NN"){} else if(params.size()==3 && params[2] == "LIN"){sm = interpolateLIN;} else if(params.size()==3 && params[2] == "RA"){sm = interpolateRA;} else if(params.size()==3) throw ICLException(str(__FUNCTION__)+": 3rd param must be one of NN, LIN or RA"); return new ScaleOp(fx,fy,sm); } #ifdef ICL_HAVE_IPP UnaryOp *create_canny(const paramlist ¶ms){ ICLASSERT_THROW(params.size() == 2 ||params.size() == 3,ICLException(str(__FUNCTION__)+": params list size must be 2 or 3 here")); float low = parse(params[0]); float hi = parse(params[1]); bool preblur = params.size()==3?parse(params[2]):false; return new CannyOp(low,hi,preblur); } #endif template UnaryOp *create_any(const paramlist ¶ms){ ICLASSERT_THROW(!params.size(),ICLException(str(__FUNCTION__)+": no params allowed here")); return new T; } UnaryOp *create_gabor(const paramlist ¶ms){ ICLASSERT_THROW(params.size()<=6,ICLException(str(__FUNCTION__)+": max 6. params allowed")); Size kernelSize(5,5); float lambda = 1; float theta = 1; float psi = 1; float sigma = 1; float gamma = 1; if(params.size() > 0){ kernelSize = parse(params[0]); if(kernelSize.getDim() < 1) throw ICLException(str(__FUNCTION__)+": kernel dimension must be > 0"); } if(params.size() > 1)lambda = parse(params[1]); if(params.size() > 2)theta = parse(params[2]); if(params.size() > 3)psi = parse(params[3]); if(params.size() > 4)sigma = parse(params[4]); if(params.size() > 5)gamma = parse(params[5]); return new GaborOp(kernelSize,std::vector(1,lambda),std::vector(1,theta), std::vector(1,psi),std::vector(1,sigma),std::vector(1,gamma)); } UnaryOp *create_compare(const paramlist ¶ms){ ICLASSERT_THROW(params.size()<=4,ICLException(str(__FUNCTION__)+": max 3. params allowed")); UnaryCompareOp::optype ot = UnaryCompareOp::lteq; icl64f value = 127; icl64f toll = 0; if(params.size()>0){ if(params[0] == "<") ot = UnaryCompareOp::lt; else if(params[0] == "<") ot = UnaryCompareOp::lt; else if(params[0] == ">") ot = UnaryCompareOp::gt; else if(params[0] == "<=") ot = UnaryCompareOp::lteq; else if(params[0] == ">=") ot = UnaryCompareOp::gteq; else if(params[0] == "==") ot = UnaryCompareOp::eq; } if(params.size()>1){ value = parse(params[1]); } if(params.size()>2){ toll = parse(params[2]); } return new UnaryCompareOp(ot,value,toll); } UnaryOp *create_localThresh(const paramlist ¶ms){ ICLASSERT_THROW(params.size()<=4,ICLException(str(__FUNCTION__)+": max 3. params allowed")); unsigned int maskSize=10; int globalThreshold=0; float gammaSlope=0; if(params.size()>0) maskSize = parse(params[0]); if(!maskSize) throw ICLException(str(__FUNCTION__)+": masksize is 0"); if(params.size()>1) globalThreshold = parse(params[1]); if(params.size()>2) gammaSlope = parse(params[2]); return new LocalThresholdOp(maskSize,globalThreshold,gammaSlope); } void static_init(){ static bool first = true; if(!first)return; first = false; CREATORS["copy"] = Creator(PassOp::create,"copy",""); // convolution op #define FIXED_CONV_CREATOR_ENTRY(X) \ CREATORS[#X] = Creator(create_fixed_conv,#X,"") FIXED_CONV_CREATOR_ENTRY(gauss3x3); FIXED_CONV_CREATOR_ENTRY(laplace3x3); FIXED_CONV_CREATOR_ENTRY(sobelX3x3); FIXED_CONV_CREATOR_ENTRY(sobelY3x3); FIXED_CONV_CREATOR_ENTRY(gauss5x5); FIXED_CONV_CREATOR_ENTRY(laplace5x5); FIXED_CONV_CREATOR_ENTRY(sobelX5x5); FIXED_CONV_CREATOR_ENTRY(sobelY5x5); CREATORS["conv"] = Creator(create_generic_conv,"conv", "size,comma sep. value list"); #undef FIXED_CONV_CREATOR_ENTRY // morphological op #define FIXED_MORPH_CREATOR_ENTRY(X) \ CREATORS[#X] = Creator(create_fixed_morph,#X,"kernel-size WxH=3x3"); FIXED_MORPH_CREATOR_ENTRY(dilate); FIXED_MORPH_CREATOR_ENTRY(erode); FIXED_MORPH_CREATOR_ENTRY(dilate3x3); FIXED_MORPH_CREATOR_ENTRY(erode3x3); FIXED_MORPH_CREATOR_ENTRY(dilateBorderReplicate); FIXED_MORPH_CREATOR_ENTRY(erodeBorderReplicate); FIXED_MORPH_CREATOR_ENTRY(openBorder); FIXED_MORPH_CREATOR_ENTRY(closeBorder); FIXED_MORPH_CREATOR_ENTRY(tophatBorder); FIXED_MORPH_CREATOR_ENTRY(blackhatBorder); FIXED_MORPH_CREATOR_ENTRY(gradientBorder); #undef FIXED_MORPH_CREATOR_ENTRY // median CREATORS["median"] = Creator(create_median,"median","kernel-size WxH=3x3"); CREATORS["rotate"] = Creator(create_rotate,"rotate","angle in degree"); CREATORS["scale"] = Creator(create_scale,"scale","fx (<5),fy (<5)=fx,interplation=NN (one of RA,LIN or NN)"); #ifdef ICL_HAVE_IPP CREATORS["canny"] = Creator(create_canny,"canny","lowThresh,highThresh,preblur=false (true or false)"); #endif CREATORS["chamfer"] = Creator(create_any,"chamfer",""); CREATORS["gabor"] = Creator(create_gabor,"gabor","kernelSize=(5,5),lambda=1,theta=1,psi=1,sigma=1,gamma=1"); CREATORS["compare"] = Creator(create_compare,"compare","op=>= (one of <,<=,>,>= or ==), value=127, tollerance=0"); CREATORS["localThresh"] = Creator(create_localThresh,"localThresh","maskSize=10,globalThreshold=0,gammaSlope=0"); } } UnaryOp *UnaryOp::fromString(const std::string &definition) throw (ICLException){ unary_op_from_string::static_init(); //bool hasParams = true; if(!definition.size()) throw ICLException(str(__FUNCTION__)+": empty defintion string"); std::string::size_type a = definition.find('('); std::string name; std::vector plist; if(a == std::string::npos){ //hasParams = false; name = definition; }else{ if(definition[definition.size()-1] != ')') throw ICLException(str(__FUNCTION__)+": missing closing ')' in definition ["+definition+"]"); name = definition.substr(0,a); std::string ps = definition.substr(a+1); plist = tok(ps.substr(0,ps.size()-1),","); } std::map::iterator it=unary_op_from_string::CREATORS.find(name); if(it == unary_op_from_string::CREATORS.end()) throw ICLException(str(__FUNCTION__)+": no op found for given specifier ["+name+"]"); UnaryOp * op = it->second(plist); if(!op) throw ICLException("wrong parameter list syntax"); return op; } std::string UnaryOp::getFromStringSyntax(const std::string &opSpecifier) throw (ICLException){ unary_op_from_string::static_init(); std::map::iterator it=unary_op_from_string::CREATORS.find(opSpecifier); if(it == unary_op_from_string::CREATORS.end()) throw ICLException(str(__FUNCTION__)+": no op found for given specifier ["+opSpecifier+"]"); return it->second.s; } std::vector UnaryOp::listFromStringOps(){ unary_op_from_string::static_init(); std::vector v(unary_op_from_string::CREATORS.size()); int i=0; for(std::map::iterator it=unary_op_from_string::CREATORS.begin(); it!=unary_op_from_string::CREATORS.end();++it){ v[i++] = it->second; } return v; } void UnaryOp::applyFromString(const std::string &definition, const ImgBase *src, ImgBase **dst) throw (ICLException){ unary_op_from_string::static_init(); UnaryOp *op = fromString(definition); if(!op) throw ICLException(str(__FUNCTION__)+": no op found for given definition string ["+definition+"]"); op->apply(src,dst); delete op; } void UnaryOp::setPropertyValue(const std::string &propertyName, const Any &value) throw (ICLException){ if(propertyName == "UnaryOp.clip to ROI") setClipToROI(value == "on"); else if(propertyName == "UnaryOp.check only") setCheckOnly(value == "on"); Configurable::setPropertyValue(propertyName,value); } struct UnaryOp_VIRTUAL : public UnaryOp{ virtual void apply(const ImgBase *,ImgBase **){} }; REGISTER_CONFIGURABLE_DEFAULT(UnaryOp_VIRTUAL); } // namespace filter }