#include #include #include #include #ifndef __APPLE__ #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include namespace icl{ namespace { struct Color{ // {{{ open Color(const float *color){ for(int i=0;i<4;++i)COLOR[i]=color[i]; } float COLOR[4]; }; // }}} Color *savedColor = 0; Color *savedFill = 0; float COLOR[4] = {255,0,0,255}; float FILL[4] = {0,0,0,0}; void saveColorAndFill(){ // {{{ open if(savedColor) delete savedColor; if(savedFill) delete savedFill; savedColor = new Color(COLOR); savedFill = new Color(FILL); } // }}} void restoreColorAndFill(){ // {{{ open if(savedColor){ for(int i=0;i<4;i++)COLOR[i]=savedColor->COLOR[i]; delete savedColor; savedColor = 0; } if(savedFill){ for(int i=0;i<4;i++)FILL[i]=savedFill->COLOR[i]; delete savedFill; savedFill = 0; } } // }}} int FONTSIZE = 12; string FONTFAMILY = "Times"; void bresenham(int x0, int x1, int y0, int y1, vector &xs, vector &ys, int maxX, int maxY){ // {{{ open int steep = std::abs(y1 - y0) > std::abs(x1 - x0); if(steep){ swap(x0, y0); swap(x1, y1); } int steep2 = x0 > x1; if(steep2){ swap(x0, x1); swap(y0, y1); } int deltax = x1 - x0; int deltay = std::abs(y1 - y0); int error = 0; int ystep = y0 < y1 ? 1 : -1; for(int x=x0,y=y0;x<=x1;x++){ if(x>=0 && x<=maxX && y>=0 && y<=maxY){ if(steep){ xs.push_back(y); ys.push_back(x); }else{ xs.push_back(x); ys.push_back(y); } } error += deltay; if (2*error >= deltax){ y += ystep; error -=deltax; } } } // }}} #ifndef __APPLE__ static PWCGrabber *G[4] = {0,0,0,0}; struct PWCReleaser{ // {{{ open ~PWCReleaser(){ for(int i=0;i<4;i++){ if(G[i]) delete G[i]; } } }; // }}} static PWCReleaser __r; #endif inline ImgQ *prepare_for_binary_op(const ImgQ &a, const ImgQ &b, ImgQ &na, ImgQ &nb){ // {{{ open if(a.getROISize() == b.getROISize() && a.getChannels() == b.getChannels()){ na = copy(a); nb = copy(b); return new ImgQ(a.getParams()); } Size sa = a.getROISize(), sb = b.getROISize(); Size sr(max(sa.width,sb.width), max(sa.height,sb.height) ); int cr = max(a.getChannels(),b.getChannels()); na = ImgQ(sr,a.getChannels()); na.setROI(a.getROI()); a.deepCopyROI(&na); na.setFullROI(); na.setChannels(cr); nb = ImgQ(sr,b.getChannels()); nb.setROI(b.getROI()); b.deepCopyROI(&nb); nb.setFullROI(); nb.setChannels(cr); return new ImgQ(na.getParams()); } // }}} inline ImgQ apply_binary_arithmetical_op(const ImgQ &a, const ImgQ &b, BinaryArithmeticalOp::optype ot){ // {{{ open BinaryArithmeticalOp binop(ot); binop.setCheckOnly(true); binop.setClipToROI(true); if(a.getROISize() == b.getROISize() && a.getChannels() == b.getChannels()){ ImgBase *res = new ImgQ(a.getParams()); binop.apply(&a,&b,&res); ImgQ x = *(res->asImg()); delete res; return x; } Size sa = a.getROISize(), sb = b.getROISize(); Size sr(max(sa.width,sb.width), max(sa.height,sb.height) ); int cr = max(a.getChannels(),b.getChannels()); ImgQ na(sr,a.getChannels()); na.setROI(a.getROI()); a.deepCopyROI(&na); na.setFullROI(); na.setChannels(cr); ImgQ nb(sr,b.getChannels()); nb.setROI(b.getROI()); b.deepCopyROI(&nb); nb.setFullROI(); nb.setChannels(cr); ImgBase * res = new ImgQ(na.getParams()); binop.apply(&na,&nb,&res); ImgQ x = *(res->asImg()); delete res; return x; } // }}} inline ImgQ apply_unary_arithmetical_op(const ImgQ &image,ICL_QUICK_TYPE val, UnaryArithmeticalOp::optype ot){ // {{{ open ImgBase *dst = 0; UnaryArithmeticalOp(ot,val).apply(&image,&dst); ImgQ r = *(dst->asImg()); delete dst; return r; } // }}} Timer *TIMER=0; } using namespace std; ImgQ zeros(int width, int height, int channels){ // {{{ open return ImgQ(Size(width,height),channels); } // }}} ImgQ ones(int width, int height, int channels){ // {{{ open ImgQ a(Size(width,height),channels); a.clear(-1,1.0,false); return a; } // }}} ImgQ load(const string &filename, format fmt){ // {{{ open FileReader g(filename); ImgQ *image = g.grab()->convert(); if(!image){ return ImgQ(); } ImgQ im(image->getSize(),fmt); im.setTime(image->getTime()); cc(image,&im); delete image; return im; } // }}} ImgQ create(const string &name, format fmt){ // {{{ open ImgQ *image = TestImages::create(name,fmt,depth32f)->asImg(); if(!image){ return ImgQ(); } ImgQ im = *image; delete image; return im; } // }}} Img8u cvt8u(const ImgQ &image){ // {{{ open Img8u *p = image.convert(); Img8u r = *p; delete p; return r; } // }}} Img16s cvt16s(const ImgQ &image){ // {{{ open Img16s *p = image.convert(); Img16s r = *p; delete p; return r; } // }}} Img32s cvt32s(const ImgQ &image){ // {{{ open Img32s *p = image.convert(); Img32s r = *p; delete p; return r; } // }}} Img32f cvt32f(const ImgQ &image){ // {{{ open Img32f *p = image.convert(); Img32f r = *p; delete p; return r; } // }}} Img64f cvt64f(const ImgQ &image){ // {{{ open Img64f *p = image.convert(); Img64f r = *p; delete p; return r; } // }}} ImgQ cvt(const Img8u &image){ // {{{ open ImgQ *p = image.convert(); ImgQ r = *p; delete p; return r; } // }}} ImgQ cvt(const Img16s &image){ // {{{ open ImgQ *p = image.convert(); ImgQ r = *p; delete p; return r; } // }}} ImgQ cvt(const Img32s &image){ // {{{ open ImgQ *p = image.convert(); ImgQ r = *p; delete p; return r; } // }}} ImgQ cvt(const Img32f &image){ // {{{ open ImgQ *p = image.convert(); ImgQ r = *p; delete p; return r; } // }}} ImgQ cvt(const Img64f &image){ // {{{ open ImgQ *p = image.convert(); ImgQ r = *p; delete p; return r; } // }}} ImgQ pwc(int device, const Size &size, format fmt, bool releaseGrabber){ // {{{ open #ifndef __APPLE__ if(device > 4){ ERROR_LOG("device must be in 1,2,3 or 4"); return ImgQ(); } if(!G[device]){ G[device] = new PWCGrabber(Size(640,480),device); } ImgQ *image = G[device]->grab()->convert(); ImgQ im(size,fmt); im.setTime(image->getTime()); cc(image,&im); delete image; if(releaseGrabber){ delete G[device]; G[device] = 0; } return im; #else ImgQ im(size, fmt); return label(im,"PWC not supported"); #endif } // }}} ImgQ ieee(int device,const Size &size, format fmt, bool releaseGrabber){ // {{{ open WARNING_LOG("this function is not yet implemented"); return ImgQ(); } // }}} ImgQ filter(const ImgQ &image,const string &filter){ // {{{ open static map M; bool inited = false; if(!inited){ static icl8u mask[9] = {1,1,1,1,1,1,1,1,1}; static Size s3x3(3,3); M["sobelx"] = new ConvolutionOp(ConvolutionOp::kernelSobelX3x3); M["sobely"] = new ConvolutionOp(ConvolutionOp::kernelSobelY3x3); M["gauss"] = new ConvolutionOp(ConvolutionOp::kernelGauss3x3); M["laplace"] = new ConvolutionOp(ConvolutionOp::kernelLaplace3x3); M["median"] = new MedianOp(Size(3,3)); #ifdef WITH_IPP_OPTIMIZATION M["dilation"] = new MorphologicalOp(s3x3,(char*)mask, MorphologicalOp::dilate); M["erosion"] = new MorphologicalOp(s3x3,(char*)mask, MorphologicalOp::erode); M["opening"] = new MorphologicalOp(s3x3,(char*)mask, MorphologicalOp::openBorder); M["closing"] = new MorphologicalOp(s3x3,(char*)mask, MorphologicalOp::closeBorder); #endif } UnaryOp* u = M[filter]; if(!u){ WARNING_LOG("nothing known about filter type:" << filter); return ImgQ(); } ImgBase *dst = 0; u->apply(&image,&dst); ImgQ *dstQ = dst->convert(); delete dst; ImgQ im = *dstQ; delete dstQ; return im; } // }}} ImgQ copy(const ImgQ &image){ // {{{ open ImgQ *cpy = image.deepCopy()->asImg(); ImgQ im = *cpy; delete cpy; return im; } // }}} ImgQ copyroi(const ImgQ &image){ // {{{ open ImgQ *cpy = image.deepCopyROI()->asImg(); ImgQ im = *cpy; delete cpy; return im; } // }}} ImgQ norm(const ImgQ &image){ // {{{ open ImgQ *cpy = image.deepCopyROI(); cpy->normalizeAllChannels(Range(0,255)); ImgQ x = *cpy; delete cpy; return x; } // }}} void save(const ImgQ &image,const string &filename){ // {{{ open Img bla = Img(Size(5,5),5); // Img blub = bla; ImgQ roi = copyroi(image); // roi = copyroi(image); FileWriter(filename).write(&roi); } // }}} void show(const ImgQ &image){ // {{{ open if(image.hasFullROI()){ TestImages::xv(&image); }else{ ImgQ T = copy(image); saveColorAndFill(); color(255,0,0); fill(0,0,0,0); rect(T,T.getROI()); restoreColorAndFill(); T.setFullROI(); TestImages::xv(&T); } } // }}} void print(const ImgQ &image){ // {{{ open image.print("image"); } // }}} ImgQ operator+(const ImgQ &a,const ImgQ &b){ // {{{ open return apply_binary_arithmetical_op(a,b,BinaryArithmeticalOp::addOp); } // }}} ImgQ operator-(const ImgQ &a, const ImgQ &b){ // {{{ open return apply_binary_arithmetical_op(a,b,BinaryArithmeticalOp::subOp); } // }}} ImgQ operator*(const ImgQ &a, const ImgQ &b){ // {{{ open return apply_binary_arithmetical_op(a,b,BinaryArithmeticalOp::mulOp); } // }}} ImgQ operator/(const ImgQ &a, const ImgQ &b){ // {{{ open return apply_binary_arithmetical_op(a,b,BinaryArithmeticalOp::divOp); } // }}} ImgQ operator+(const ImgQ &image, float val){ // {{{ open return apply_unary_arithmetical_op(image,val,UnaryArithmeticalOp::addOp); } // }}} ImgQ operator-(const ImgQ &image, float val){ // {{{ open return apply_unary_arithmetical_op(image,val,UnaryArithmeticalOp::subOp); } // }}} ImgQ operator*(const ImgQ &image, float val){ // {{{ open return apply_unary_arithmetical_op(image,val,UnaryArithmeticalOp::mulOp); } // }}} ImgQ operator/(const ImgQ &image, float val){ // {{{ open return apply_unary_arithmetical_op(image,val,UnaryArithmeticalOp::divOp); } // }}} ImgQ operator+(float val, const ImgQ &image){ // {{{ open return image+val; } // }}} ImgQ operator-(float val, const ImgQ &image){ // {{{ open ImgQ res(image.getROISize(),image.getChannels()); for(int c=0;c itI = image.getROIIterator(c); ImgIterator itRes = res.getROIIterator(c); for(;itI.inRegion();++itI,++itRes){ *itRes = val - (*itI); } } return res; } // }}} ImgQ operator*(float val, const ImgQ &image){ // {{{ open return image*val; } // }}} ImgQ operator/(float val, const ImgQ &image){ // {{{ open ImgQ res(image.getROISize(),image.getChannels()); for(int c=0;c itI = image.getROIIterator(c); ImgIterator itRes = res.getROIIterator(c); for(;itI.inRegion();++itI,++itRes){ *itRes = ((*itI) == 0) ? 0 : val / (*itI); } } return res; } // }}} ImgQ cc(const ImgQ& image, format fmt){ // {{{ open ImgQ dst(image.getSize(),fmt); ImgQ src = copyroi(image); cc(&src,&dst); return dst; } // }}} ImgQ rgb(const ImgQ &image){ // {{{ open return cc(image,formatRGB); } // }}} ImgQ hls(const ImgQ &image){ // {{{ open return cc(image,formatHLS); } // }}} ImgQ lab(const ImgQ &image){ // {{{ open return cc(image,formatLAB); } // }}} ImgQ gray(const ImgQ &image){ // {{{ open return cc(image,formatGray); } // }}} ImgQ scale(const ImgQ& image, float factor){ // {{{ open return scale(image,(int)(factor*image.getWidth()), (int)(factor*image.getHeight())); } // }}} ImgQ scale(const ImgQ& image, int width, int height){ // {{{ open ImgQ *n = image.scaledCopyROI(Size(width,height)); ImgQ a = *n; delete n; return a; } // }}} ImgQ channel(const ImgQ &image, int channel){ // {{{ open const ImgQ *c = image.selectChannel(channel)->asImg(); const ImgQ a = copy(*c); delete c; return a; } // }}} ImgQ levels(const ImgQ &image, icl8u levels){ // {{{ open ImgBase *src = image.convertROI(depth8u); ImgBase *dst = 0; LUTOp(levels).apply(src,&dst); ImgQ *a = dst->convert(); ImgQ b = *a; delete a; delete src; delete dst; return b; } // }}} ImgQ thresh(const ImgQ &image, float threshold){ // {{{ open ImgQ r(image.getROISize(),image.getChannels(),image.getFormat()); r.setTime(image.getTime()); for(int c=0;c itSrc = image.getROIIterator(c); ImgIterator itDst = r.getIterator(c); for(;itSrc.inRegion();++itSrc,++itDst){ *itDst = *itSrc < threshold ? 0 : 255; } } return r; } // }}} ImgQ flipx(const ImgQ& image){ // {{{ open ImgQ r(image.getParams()); ImgBase *rr = &r; flippedCopy(axisVert,&image,&rr); return r; } // }}} ImgQ flipy(const ImgQ& image){ // {{{ open ImgQ r(image.getParams()); ImgBase *rr = &r; flippedCopy(axisHorz,&image,&rr); return r; } // }}} ImgQ exp(const ImgQ &image){ // {{{ open return apply_unary_arithmetical_op(image,0,UnaryArithmeticalOp::expOp); } // }}} ImgQ ln(const ImgQ &image){ // {{{ open return apply_unary_arithmetical_op(image,0,UnaryArithmeticalOp::lnOp); } // }}} ImgQ sqr(const ImgQ &image){ // {{{ open return apply_unary_arithmetical_op(image,0,UnaryArithmeticalOp::sqrOp); } // }}} ImgQ sqrt(const ImgQ &image){ // {{{ open return apply_unary_arithmetical_op(image,0,UnaryArithmeticalOp::sqrtOp); } // }}} ImgQ abs(const ImgQ &image){ // {{{ open return apply_unary_arithmetical_op(image,0,UnaryArithmeticalOp::absOp); } // }}} ImgQ operator-(const ImgQ &image){ // {{{ open return image*(-1); } // }}} ImgQ operator||(const ImgQ &a, const ImgQ &b){ // {{{ open ImgQ na,nb; ImgQ *res = prepare_for_binary_op(a,b,na,nb); ImgQ r = *res; delete res; for(int c=0;c itA = na.getROIIterator(c); ImgIterator itB = nb.getROIIterator(c); ImgIterator itR = r.getROIIterator(c); for(;itA.inRegion();++itA,++itB, ++itR){ *itR = *itA || *itB; } } return r; } // }}} ImgQ operator&&(const ImgQ &a, const ImgQ &b){ // {{{ open ImgQ na,nb; ImgQ *res = prepare_for_binary_op(a,b,na,nb); ImgQ r = *res; delete res; for(int c=0;c itA = na.getROIIterator(c); ImgIterator itB = nb.getROIIterator(c); ImgIterator itR = r.getROIIterator(c); for(;itA.inRegion();++itA,++itB, ++itR){ *itR = *itA && *itB; } } return r; } // }}} ImgQ operator,(const ImgQ &a, const ImgQ &b){ // {{{ open if(a.getSize() == Size::null) return copy(b); if(b.getSize() == Size::null) return copy(a); ImgQ r = zeros(a.getWidth()+b.getWidth(),max(a.getHeight(),b.getHeight()),max(a.getChannels(),b.getChannels())); r.setROI(a.getROI()); roi(r) = a; Rect newroi(Point(r.getROIXOffset()+r.getROIWidth(), r.getROIYOffset()),b.getROISize()); r.setROI(newroi); roi(r) = b; r.setFullROI(); return r; } // }}} ImgQ operator%(const ImgQ &a, const ImgQ &b){ // {{{ open if(a.getSize() == Size::null) return copy(b); if(b.getSize() == Size::null) return copy(a); ImgQ r = zeros(max(a.getWidth(),b.getWidth()),a.getHeight()+b.getHeight(),max(a.getChannels(),b.getChannels())); r.setROI(a.getROI()); roi(r) = a; Rect newroi(Point(r.getROIXOffset(),r.getROIYOffset()+r.getROIHeight()), b.getROISize()); r.setROI(newroi); roi(r) = b; r.setFullROI(); return r; } // }}} ImgQ operator|(const ImgQ &a, const ImgQ &b){ // {{{ open if(a.getChannels() == 0 || a.getROISize() == Size::null) return copy(b); if(b.getChannels() == 0 || b.getROISize() == Size::null) return copy(a); ImgQ r = zeros(max(a.getWidth(),b.getWidth()),max(a.getHeight(),b.getHeight()),a.getChannels()+b.getChannels()); r.setROI(a.getROI()); for(int c=0;c=0 && j>=0 && i 0) { ey--; dy = dy - radSqr2; d = d - dy; } ex++; dx = dx + radSqr2; d = d + radSqr + dx; saveColorAndFill(); for (int i = 0; i < 4; i++) COLOR[i] = FILL[i]; line(image, x - ex, y - ey, x + ex, y - ey); line(image, x - ex, y + ey, x + ex, y + ey); restoreColorAndFill(); float A = COLOR[3]/255; if(! A) return; for (int c = 0; c < image.getChannels() && c<3; c++){ float &t = image(x+ex, y+ey, c); t=(1.0-A)*t + A*COLOR[c]; float &u = image(x-ex, y+ey, c); u=(1.0-A)*u + A*COLOR[c]; float &v = image(x+ex, y-ey, c); v=(1.0-A)*v + A*COLOR[c]; float &w = image(x-ex, y-ey, c); w=(1.0-A)*w + A*COLOR[c]; } } d = (3 * (radSqr - radSqr) / 2 - (dx + dy)) / 2; for (int i = ey; i > 0; i--) { if (d < 0) { ex++; dx = dx + radSqr2; d = d + radSqr + dx; } ey--; dy = dy - radSqr2; d = d + radSqr - dy; saveColorAndFill(); for (int i = 0; i < 4; i++) COLOR[i] = FILL[i]; line(image, x - ex, y - ey, x + ex, y - ey); line(image, x - ex, y + ey, x + ex, y + ey); restoreColorAndFill(); float A = COLOR[3]/255; if(! A) return; for (int c = 0; c < image.getChannels() && c<3; c++){ float &t = image(x+ex, y+ey, c); t=(1.0-A)*t + A*COLOR[c]; float &u = image(x-ex, y+ey, c); u=(1.0-A)*u + A*COLOR[c]; float &v = image(x+ex, y-ey, c); v=(1.0-A)*v + A*COLOR[c]; float &w = image(x-ex, y-ey, c); w=(1.0-A)*w + A*COLOR[c]; } } restoreColorAndFill(); } // }}} void line(ImgQ &image, int x1, int y1, int x2, int y2){ // {{{ open std::vector xs,ys; bresenham(x1,x2,y1,y2,xs,ys,image.getWidth()-1,image.getHeight()-1); float A = COLOR[3]/255.0; for(vector::iterator itX=xs.begin(), itY=ys.begin(); itX != xs.end(); ++itX, ++itY){ for(int c=0;c= 0 && *itX < image.getWidth() && *itY >= 0 && *itY <= image.getHeight()){ float &v = image(*itX,*itY,c); v=(1.0-A)*v + A*COLOR[c]; } } } } // }}} void text(ImgQ &image, int xoffs, int yoffs, const string &text){ // {{{ open // first rendering the text int n = 0; char ** ppc = 0; static QApplication *QAPP = 0; if(!QAPP){ QAPP = new QApplication(n,ppc); } QFont f(FONTFAMILY.c_str(),FONTSIZE,QFont::DemiBold); QFontMetrics m(f); QSize br = m.size(Qt::TextSingleLine,text.c_str()); QImage img(br.width()+2,br.height()+2,QImage::Format_ARGB32_Premultiplied); img.fill(0); QPainter painter(&img); painter.setRenderHint(QPainter::TextAntialiasing); painter.setFont(f); painter.setPen(QColor(255,255,255,254)); painter.drawText(QPoint(1,img.height()-m.descent()-1),text.c_str()); painter.end(); QImageConverter qic(&img); const Img8u &t = *(qic.getImg()); for(int c=0;c= 0 && iy >= 0 && ix < image.getWidth() && iy < image.getHeight() ){ ICL_QUICK_TYPE &v = image(ix,iy,c); float A = (((float)t(x,y,c))/255.0) * (COLOR[3]/255); v=(1.0-A)*v + A*COLOR[c]; } } } } } // }}} inline void pix(ImgQ &image, int x, int y){ // {{{ open float A = COLOR[3]/255.0; if(x>=0 && y>=0 && x &pts){ // {{{ open for(vector::const_iterator it = pts.begin();it!=pts.end();++it){ pix(image,it->x,it->y); } } // }}} ImgQ label(const ImgQ &imageIn, const string &text){ // {{{ open ImgQ image = copy(imageIn); float _COLOR[4] = { COLOR[0],COLOR[1],COLOR[2],COLOR[3] }; int _FONTSIZE = FONTSIZE; string _FONTFAMILY = FONTFAMILY; FONTSIZE = 10; FONTFAMILY = "Arial"; COLOR[3]=255; std::fill(COLOR,COLOR+3,float(1.0)); icl::text(image,6,6,text); std::fill(COLOR,COLOR+3,float(255.0)); icl::text(image,5,5,text); std::copy((float*)_COLOR,_COLOR+4,COLOR); FONTSIZE = _FONTSIZE; FONTFAMILY = _FONTFAMILY; return image; } // }}} void font(int size, const string &family){ // {{{ open FONTSIZE = size; FONTFAMILY = family; } // }}} void fontsize(int size){ // {{{ open FONTSIZE = size; } // }}} void tic(){ // {{{ open if(!TIMER){ TIMER = new Timer(); TIMER->start(); }else{ printf("timer was already running: \n"); TIMER->stop(); delete TIMER; TIMER = new Timer(); TIMER->start(); } } // }}} void toc(){ // {{{ open if(!TIMER){ printf("could not stop timer: call tic first! \n"); }else{ TIMER->stop(); delete TIMER; TIMER = 0; } } // }}} template ImgBasePtrPtr::~ImgBasePtrPtr(){ // {{{ open if(!r){ ERROR_LOG("Result image is NULL"); if(o) delete o; return; } if(r && !o){ ERROR_LOG("Result image is NULL"); delete r; return; } /// r and o is given !! if(r != rbef ){ ERROR_LOG("Detected a pointer reallocation in Implicit Img to ImgBase** cast operation\n" "This warning implicates, that a local ImgBase* was reallocated instead of using\n" "the given Img. To enshure a maximum compability, the new result images data\n" "will be converted interanlly into the given image. To avoid this warning and to\n" "enhance performance, DO NOT USE THE \"bpp(..)\"-FUNCTION\n"); printf("convert: \n"); r->convert(o); printf("del \n"); delete r; printf("ret \n"); return; } if(o->getParams() != r->getParams()){ // shallow copy back ImgBase *poBase = o; r->shallowCopy(&poBase); // *o = *r; delete r; return; } delete r; } // }}} template ImgBasePtrPtr::ImgBasePtrPtr(Img &i){ r = new Img(i); o = &i; rbef = r; } template ImgBasePtrPtr::ImgBasePtrPtr(Img *i){ // {{{ open if(!i){ o = 0; r = 0; rbef = 0; }else{ r = new Img(*i); o = i; rbef = r; } } // }}} #define ICL_INSTANTIATE_DEPTH(D) template struct ImgBasePtrPtr; ICL_INSTANTIATE_ALL_DEPTHS #undef ICL_INSTANTIATE_DEPTH }