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);
    }
  }
Exemplo n.º 10
0
  // 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;
  }