void distanceTransform::sedFiltering(channel &chnl, bool useEightSED) const { const float fv = 0.0f; const int undef = -2; matrix<point> dist(chnl.size()); int row, col; //init for(row = 0; row < chnl.rows(); ++row){ for(col = 0; col < chnl.columns(); ++col){ if(chnl.at(row, col) == fv) dist.at(row, col) = point(0, 0); else dist.at(row, col) = point(undef, undef); } } if(useEightSED) eightSEDFiltering(chnl, dist); else fourSEDFiltering(chnl, dist); //set the distances for(row = 0; row < chnl.rows(); ++row) for(col = 0; col < chnl.columns(); ++col) chnl.at(row, col) = static_cast<float>(dist.at(row, col).distanceSqr(point(0,0))); }
void distanceTransform::EDT_1D(channel& chnl) const { const float undef = -1.0f; //means any undefined value (distance or pos) //remember: all foreground pixel are > 0.0f // all background pixel are == 0.0f for(int y = 0; y < chnl.rows(); ++y){ int x, pos = static_cast<int>(undef); //first step: forward propagation for(x = 0; x < chnl.columns(); ++x){ if(chnl.at(y, x) == 0.0f){ //found background pixel //now 0.0 means distance to closest background pixel pos = x; } else if(pos >= 0){ int tmp = pos - x; chnl.at(y, x) = static_cast<float>(tmp * tmp); } else chnl.at(y, x) = undef; } //no background pixel in row => all pixel are set to undef; //continue with next row if(pos == undef) continue; else{ pos = static_cast<int>(undef); for(x = chnl.columns() - 1; x >= 0; --x){ if(chnl.at(y, x) == 0){ pos = x; //found fv } else if(pos != undef){ int tmp = pos - x; tmp *=tmp; int ret = static_cast<int>(chnl.at(y, x)); if(ret > tmp || ret == undef){ chnl.at(y, x) = static_cast<float>(tmp); } } } } } }
/* * compute cornerness */ bool harrisCorners::getCornerness(const channel& fxx, const channel& fxy, const channel& fyy, const float scale, channel& cornerness, float& maxCornerness) const { // we can assume that all channels are connected, but try it out if not if ((fxx.getMode() != channel::Connected) || (fxy.getMode() != channel::Connected) || (fyy.getMode() != channel::Connected)) { setStatusString("Channels not contigous in getCornerness"); return false; } if (fxx.empty() || fxy.empty() || fyy.empty()) { cornerness.clear(); maxCornerness = 0.0f; return false; } int i; const int end = fxx.rows()*fxx.columns(); const float *const pfxx = &fxx.at(0); const float *const pfxy = &fxy.at(0); const float *const pfyy = &fyy.at(0); cornerness.resize(fxx.size(),0,false,false); float* pcor = &cornerness.at(0); float det,trace,txx,txy,tyy,c; float maxc = 0.0f; for (i=0;i<end;++i) { txx=pfxx[i]; txy=pfxy[i]; tyy=pfyy[i]; det=txx*tyy - txy*txy; trace=txx+tyy; c = det-scale*trace*trace; pcor[i]=c; if (c>maxc) { maxc=c; } } maxCornerness = maxc; return true; }
bool hessianFunctor::classicXY(const channel& src, channel& xy) const { if (src.columns() < 3) { setStatusString("width less than 3"); xy.clear(); return false; } if (src.rows() < 3) { setStatusString("height less than 3"); xy.clear(); return false; } if (src.getMode()!=channel::Connected) { setStatusString("src must be Connected"); xy.clear(); return false; } const int width = src.columns(); const int height = src.rows(); xy.resize(height,width,0.f,false,false); float* fpxy = &xy.at(0,0); const float* fpSrc = &src.at(0,0); const float* rowy; const float* colx; float* pidxy; const int w1 = width-1; const int w2 = width-2; const int last = (height-1)*width; // index of begin of last row const int lastRow = -w1; // offset from actual column pointer to // last row const int nextRow = width+1; // offset from actual column pointer to // next row const int nextRow2 = width+2; // offset from actual column pointer to // next row + 1 // top-left corner fpxy[0]=(fpSrc[0]-fpSrc[1]-fpSrc[width]+fpSrc[nextRow]); // top pidxy = &fpxy[1]; for (colx=&fpSrc[0],rowy=&fpSrc[w1]; colx<rowy; ++colx,++pidxy) { *pidxy=(*colx - colx[2] - colx[width] + colx[nextRow2]); } // top-right corner fpxy[w1]=(fpSrc[w2]-fpSrc[w1]-fpSrc[w2+width]+fpSrc[w1+width]); // main loop (begin at coordinates (1,0) pidxy = &fpxy[width]; const float *const rowEnd = &fpSrc[last]; for (rowy=&fpSrc[width]; rowy<rowEnd; rowy+=width) { // left side *pidxy=(rowy[-width] - rowy[lastRow] - rowy[width] + rowy[nextRow]); ++pidxy; // middle const float *const colEnd = &rowy[w2]; for (colx=rowy; colx<colEnd; ++colx,++pidxy) { *pidxy=(colx[-width] - colx[-w2] - colx[width] + colx[nextRow2]); } // right side *pidxy=(colx[-width] - colx[lastRow] - colx[width] + colx[nextRow]); ++pidxy; } // bottom-left corner fpxy[last]=(fpSrc[last+1]-fpSrc[last]); // bottom pidxy = &fpxy[last+1]; const float *const colEnd = &rowEnd[w2]; for (colx=rowEnd; colx<colEnd; ++colx,++pidxy) { *pidxy=(colx[-width] - colx[-w2] - *colx + colx[2]); } // bottom-right corner fpxy[last+w1]=(fpSrc[last-2]-fpSrc[last-1]-fpSrc[last+w2]+fpSrc[last+w1]); return true; };
void distanceTransform::fourSEDFiltering(channel &chnl, matrix<point> &dist) const { //create all masks point mask0[] = { point(-1, 0) }; sedMask l(mask0, 1); point mask1[] = { point(0, -1) }; sedMask u(mask1, 1); point mask2[] = { point(0, -1), point(-1, 0) }; sedMask ul(mask2, 2); point mask3[] = { point(1, 0) }; sedMask r(mask3, 1); point mask4[] = { point(0, 1) }; sedMask d(mask4, 1); point mask5[] = { point(1, 0), point(0, 1) }; sedMask rd(mask5, 2); point pos; pos.y = 0; //first line for(pos.x = 1; pos.x < chnl.columns(); ++pos.x) l.filter(dist, pos); for(pos.x = chnl.columns() - 2; pos.x >= 0; --pos.x) r.filter(dist, pos); for(pos.y = 1; pos.y < chnl.rows(); ++pos.y){ pos.x = 0; //step down u.filter(dist, pos); for(pos.x = 1; pos.x < chnl.columns(); ++pos.x) ul.filter(dist, pos); for(pos.x = chnl.columns() - 2; pos.x >= 0; --pos.x) r.filter(dist, pos); } //and now filter the picture in the opposite direction pos.y = chnl.rows() - 1; //last line for(pos.x = chnl.columns() - 2; pos.x >= 0; --pos.x) r.filter(dist, pos); for(pos.x = 1; pos.x < chnl.columns(); ++pos.x) l.filter(dist, pos); for(pos.y = chnl.rows() - 2; pos.y >= 0; --pos.y){ pos.x = chnl.columns() - 1; //step up d.filter(dist, pos); for(pos.x = chnl.columns() - 2; pos.x >= 0; --pos.x) rd.filter(dist, pos); for(pos.x = 1; pos.x < chnl.columns(); ++pos.x) l.filter(dist, pos); } }
void distanceTransform::iteration4(channel& chnl) const { int x,y,z; const int rowm1 = chnl.rows()-1; const int colm1 = chnl.columns()-1; static const int deltax[6] = {1,0,-1, 0, 1,0}; static const int deltay[6] = {0,1, 0,-1, 0,1}; float minimum; // upper-left if (chnl.at(0,0) > 0) { chnl.at(0,0) = 1.0f+min(chnl.at(0,1),chnl.at(1,0)); } // top y = 0; for (x=1;x<colm1;++x) { if (chnl.at(y,x) > 0) { // valid pixel, let's check for the distance value minimum = chnl.at(y+deltay[0],x+deltax[0]); for (z=1;z<3;++z) { minimum = min(minimum,chnl.at(y+deltay[z],x+deltax[z])); } chnl.at(y,x) = minimum+1.0f; } } // upper-right if (chnl.at(0,colm1) > 0) { chnl.at(0,colm1) = 1.0f+min(chnl.at(0,colm1-1),chnl.at(1,colm1)); } // inner of the image only... for (y=1;y<rowm1;++y) { // left border x = 0; if (chnl.at(y,x) > 0) { minimum = chnl.at(y+deltay[3],x+deltax[3]); for (z=0;z<2;++z) { minimum = min(minimum,chnl.at(y+deltay[z],x+deltax[z])); } chnl.at(y,x) = minimum+1.0f; } // inner of the line for (x=1;x<colm1;++x) { if (chnl.at(y,x) > 0) { // valid pixel, let's check for the distance value minimum = chnl.at(y+deltay[0],x+deltax[0]); for (z=1;z<4;++z) { minimum = min(minimum,chnl.at(y+deltay[z],x+deltax[z])); } chnl.at(y,x) = minimum+1.0f; } } // right border if (chnl.at(y,x) > 0) { minimum = chnl.at(y+deltay[1],x+deltax[1]); for (z=2;z<4;++z) { minimum = min(minimum,chnl.at(y+deltay[z],x+deltax[z])); } chnl.at(y,x) = minimum+1.0f; } } // bottom-left if (chnl.at(rowm1,0) > 0) { chnl.at(rowm1,0) = 1.0f+min(chnl.at(rowm1,1),chnl.at(rowm1-1,0)); } // bottom for (x=1;x<colm1;++x) { if (chnl.at(y,x) > 0) { // valid pixel, let's check for the distance value minimum = chnl.at(y+deltay[2],x+deltax[2]); for (z=3;z<5;++z) { minimum = min(minimum,chnl.at(y+deltay[z],x+deltax[z])); } chnl.at(y,x) = minimum+1.0f; } } // bottom-right if (chnl.at(rowm1,colm1) > 0) { chnl.at(rowm1,colm1) = 1.0f+min(chnl.at(rowm1,colm1-1), chnl.at(rowm1-1,colm1)); } }
// On place apply for type channel8! bool distanceTransform::apply(channel& srcdest) const { if ((srcdest.rows() < 2) || (srcdest.columns() < 2)) { setStatusString("At least 2 pixels at each axis expected"); return false; } const parameters& param = getParameters(); if( param.distance == parameters::EightNeighborhood || param.distance == parameters::FourNeighborhood){ // ensure that the non-zero values are maximal int y; vector<channel::value_type>::iterator it,eit; const float max = static_cast<float>(srcdest.rows()+srcdest.columns()); for (y=0;y<srcdest.rows();y++) { vector<channel::value_type>& vct = srcdest.getRow(y); for (it=vct.begin(),eit=vct.end();it!=eit;++it) { if ((*it)>0.0f) { (*it)=max; } } } } switch(param.distance){ case parameters::EightNeighborhood: iteration8back(srcdest); iteration8(srcdest); return true; case parameters::FourNeighborhood: iteration4back(srcdest); iteration4(srcdest); return true; case parameters::Euclidean: EDT_1D(srcdest); EDT_2D(srcdest); srcdest.apply(sqrt); return true; case parameters::EuclideanSqr: EDT_1D(srcdest); EDT_2D(srcdest); return true; case parameters::EightSED: sedFiltering(srcdest, true); srcdest.apply(sqrt); return true; case parameters::EightSEDSqr: sedFiltering(srcdest,true); return true; case parameters::FourSED: sedFiltering(srcdest, false); srcdest.apply(sqrt); return true; case parameters::FourSEDSqr: sedFiltering(srcdest, false); return true; default: return false; } };
inline void distanceTransform::EDT_2D(channel& chnl) const { //voronoiEDT_2D must be called for every column for(int x = 0; x < chnl.columns(); ++x){ voronoiEDT_2D(chnl, x); } }
void distanceTransform::eightSEDFiltering(channel &chnl, matrix<point> &dist)const{ //create all masks point mask0[] = { point(-1, 0) }; sedMask xo(mask0, 1); point mask1[] = { point(-1,-1), point(0,-1), point(1,-1), point(-1, 0) }; sedMask xxxxo(mask1, 4); point mask2[] = { point(-1, -1), point(0, -1), point(-1, 0) }; sedMask xxxo(mask2, 3); point mask3[] = { point(0, -1), point(1, -1) }; sedMask xxo(mask3, 2); point mask4[] = { point(1, 0) }; sedMask ox(mask4, 1); point mask5[] = { point(1, 0), point(-1, 1), point(0, 1), point(1, 1) }; sedMask oxxxx(mask5, 4); point mask6[] = { point(1, 0), point(0, 1), point(1, 1) }; sedMask oxxx(mask6, 3); point mask7[] = { point(-1, 1), point(0, 1) }; sedMask oxx(mask7, 2); //filter the picture point pos; pos.y = 0; //first row for(pos.x = 1; pos.x < chnl.columns(); ++pos.x) xo.filter(dist, pos); for(pos.x = chnl.columns() - 2; pos.x >= 0; --pos.x) ox.filter(dist, pos); for(pos.y = 1; pos.y < chnl.rows(); ++pos.y){ pos.x = 0; //step up xxo.filter(dist, pos); for(pos.x = 1; pos.x < chnl.columns() - 1; ++pos.x) xxxxo.filter(dist, pos); xxxo.filter(dist, pos); for(pos.x = chnl.columns() - 2; pos.x >= 0; --pos.x) ox.filter(dist, pos); } //and now filter the picture in the opposite direction pos.y = chnl.rows() - 1; //last row for(pos.x = chnl.columns() - 2; pos.x >= 0; --pos.x) ox.filter(dist, pos); for(pos.x = 1; pos.x < chnl.columns(); ++pos.x) xo.filter(dist, pos); for(pos.y = chnl.rows() - 2; pos.y >= 0; --pos.y){ pos.x = chnl.columns() - 1; //step down oxx.filter(dist, pos); for(pos.x = chnl.columns() - 2; pos.x > 0; --pos.x) oxxxx.filter(dist, pos); oxxx.filter(dist, pos); for(pos.x = 1; pos.x < chnl.columns() - 1; ++pos.x) xo.filter(dist, pos); } }
// On copy apply for type channel! bool huMoments::apply(const channel& src,dvector& dest, dvector& more) const { channel::value_type val; dest.resize(NUM_FEAT,0,false,true); more.resize(MORE_FEAT,0,false,true); double m00=0.0; double cm11,cm20,cm02,cm30,cm03,cm12,cm21; cm11=cm20=cm02=cm30=cm03=cm12=cm21=0.0; double xcog, ycog; xcog=ycog=0.0; int r, rows=src.rows(); int c, cols=src.columns(); // compute simple moments and cog for (r=0; r<rows; r++) { for (c=0; c<cols; c++) { val = src.at(r,c); m00+=val; xcog+=c*val; ycog+=r*val; } } // end here, if no content if (m00==0) { return false; } // compute cog's more[huMoments::xcog]=xcog=xcog/m00; //xcog more[huMoments::ycog]=ycog=ycog/m00; //ycog // compute central moments for (r=0; r<rows; r++) { for (c=0; c<cols; c++) { val = src.at(r,c); double x_xcog = c-xcog; double y_ycog = r-ycog; cm11+=(x_xcog)*(y_ycog)*val; cm20+=(x_xcog)*(x_xcog)*val; cm02+=(y_ycog)*(y_ycog)*val; cm30+=(x_xcog)*(x_xcog)*(x_xcog)*val; cm03+=(y_ycog)*(y_ycog)*(y_ycog)*val; cm12+=(x_xcog)*(y_ycog)*(y_ycog)*val; cm21+=(x_xcog)*(x_xcog)*(y_ycog)*val; } } double m00pow2,m00pow2_5; m00pow2 = m00*m00; m00pow2_5 = pow(m00,2.5); // normalized central moments cm02 = cm02/m00pow2; cm03 = cm03/m00pow2_5; cm11 = cm11/m00pow2; cm12 = cm12/m00pow2_5; cm20 = cm20/m00pow2; cm21 = cm21/m00pow2_5; cm30 = cm30/m00pow2_5; // calculate moment invariants dest[huMoments::hu1] = cm20 + cm02; dest[huMoments::hu2] = pow((cm20 - cm02),2) + 4*pow(cm11,2); dest[huMoments::hu3] = pow((cm30 - 3*cm12),2) + pow((3*cm21 - cm03),2); dest[huMoments::hu4] = pow((cm30 + cm12),2) + pow((cm21 + cm03),2); dest[huMoments::hu5] = (cm30-3*cm12)*(cm30+cm12)*( pow((cm30+cm12),2) - 3*pow((cm21+cm03),2) ) + (3*cm21-cm03)*(cm21+cm03)*( 3*pow((cm30+cm12),2) - pow((cm21+cm03),2) ); dest[huMoments::hu6] = (cm20-cm02)*( pow((cm30+cm12),2) - pow((cm21+cm03),2) ) + 4*cm11*(cm30+cm12)*(cm21+cm03); dest[huMoments::hu7] = (3*cm21-cm03)*(cm30+cm12)*( pow((cm30+cm12),2) - 3*pow((cm21+cm03),2) ) - (cm30-3*cm12)*(cm21+cm03)*( 3*pow((cm30+cm12),2) - pow((cm21+cm03),2) ); double temp = sqrt( (cm20 - cm02)*(cm20 - cm02) + 4*cm11*cm11 ); more[huMoments::eigen1]=m00*0.5*((cm20+cm02) + temp); //eigen 1 more[huMoments::eigen2]=m00*0.5*((cm20+cm02) - temp); //eigen 2 more[huMoments::orientation]=0.5*atan2(2*cm11, cm20 - cm02); //orientation more[huMoments::m00]=m00; //m00 const parameters& param = getParameters(); if (param.scaling) { int i; for (i=0; i<dest.size();i++){ dest[i]=-logn(dest[i]); } } return true; }