/*
   * compute the second order.
   */
  bool harrisCorners::getSecondOrder(channel& gx,
                                     channel& gy,
                                     channel& fxy) const {

    const parameters& par = getParameters();

    fxy.resize(gx.size(),false,false);
    gaussKernel2D<float> gk(par.kernelSize,par.variance);
    convolution filter;
    convolution::parameters filterPar;
    filterPar.boundaryType = lti::Constant;
    filterPar.setKernel(gk);
    filter.setParameters(filterPar);

    channel::iterator igx=gx.begin();
    channel::iterator igxend=gx.end();
    channel::iterator igy=gy.begin();
    channel::iterator ifxy=fxy.begin();
    float tx, ty;

    while (igx!=igxend) {
      tx=(*igx);
      ty=(*igy);
      (*igx)=tx*tx;
      (*igy)=ty*ty;
      (*ifxy)=tx*ty;
      ++igx; ++igy; ++ifxy;
    }

    return (filter.apply(gx) && filter.apply(gy) && filter.apply(fxy));
  }
  // split image into float channels
  bool splitImageToxyY::apply(const image& img,
                              channel& c1,
                              channel& c2,
                              channel& c3) const {
    point p;             // coordinates
    rgbPixel pix;          // single Pixel Element in RGB-values...
    float Y;               // channels
    float X, XYZ;          // help variables

    // make the channels size of source image...
    c1.resize(img.rows(),img.columns(),0,false,false);
    c2.resize(img.rows(),img.columns(),0,false,false);
    c3.resize(img.rows(),img.columns(),0,false,false);

    for (p.y=0;p.y<img.rows();p.y++)
      for (p.x=0;p.x<img.columns();p.x++) {
        // take pixel at position p
        pix = img.at(p);

  // see Gonzales & Woods for explanation of magic numbers
        X   = (((float)(pix.getRed())) *0.412453f +
               ((float)(pix.getGreen())) *0.357580f +
               ((float)(pix.getBlue())) *0.180423f)/255.0f;   // x
        Y   = (((float)(pix.getRed())) *0.212671f +
               ((float)(pix.getGreen())) *0.715160f +
               ((float)(pix.getBlue())) *0.072169f)/255.0f;   // y
        XYZ = (((float)(pix.getRed())) *0.644458f +
               ((float)(pix.getGreen())) *1.191933f +
               ((float)(pix.getBlue())) *1.202819f)/255.0f;   // Y

        if (XYZ>0.0f) {
          c1.at(p) = X/XYZ;  // x
          c2.at(p) = Y/XYZ;  // y
        }
        else {
          c1.at(p) = 0;   // x
          c2.at(p) = 0;   // y
        }
        c3.at(p) = Y;     // Y
      } // loop
    return true;
  }
  /*
   * 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;
  };
  // return probability channel
  bool probabilityMap2D::apply(const channel8& src1, const channel8& src2, channel& dest) const {
      const parameters& param = getParameters();
      point chnl1_size = src1.size();
      point chnl2_size = src2.size();
      
      // size of src1 equals src2 ?
      if ( (chnl1_size.x != chnl2_size.x) || (chnl1_size.y != chnl2_size.y) ) {
          setStatusString("probabilityMap2D: channels do not match");
          return false;
      }
      
      // the color model MUST have 2 dimensions!
      if (probabilityHistogram.dimensions() == 2) {
          // resize probability channel
          dest.resize(src1.size());
          
          ivector theBin(2);
  
          // compute first iteration
	  int y;
	  vector<channel8::value_type>::const_iterator srcIterator1, eit1;
	  vector<channel8::value_type>::const_iterator srcIterator2, eit2;
	  vector<channel::value_type>::iterator destIterator;
	  for (y=0;y<src1.rows();++y) {
	    srcIterator1 = src1.getRow(y).begin();
	    eit1 = src1.getRow(y).end();
	    srcIterator2 = src2.getRow(y).begin();
	    eit2 = src2.getRow(y).end();

	    destIterator = dest.getRow(y).begin();
	    while (srcIterator1 != eit1) {
	      
	      theBin[0] = lookupTable[0][*srcIterator1];
	      theBin[1] = lookupTable[1][*srcIterator2];
	      (*destIterator)=static_cast<float>(probabilityHistogram.at(theBin));
	      
	      srcIterator1++;
	      srcIterator2++;
	      destIterator++;
	    }
	  }     

          // compute all other iterations
          if (param.iterations > 1) {
              int i;
              
              if (param.gaussian) {
                  gaussKernel2D<float> gk(param.windowSize,param.variance);
                  convolution convolver;
                  convolution::parameters convParam;
                  
                  convParam.boundaryType = lti::Mirror;
                  convParam.setKernel(gk);
                  convolver.setParameters(convParam);

                  for (i=1;i<param.iterations;++i) {
                    convolver.apply(dest);
                    computeMap(src1,src2,dest);
                  }
              } else {
                  squareConvolution<float> convolver;
                  squareConvolution<float>::parameters convParam;

                  convParam.boundaryType = lti::Mirror;
                  convParam.initSquare(param.windowSize);

                  convolver.setParameters(convParam);

                  for (i=1;i<param.iterations;++i) {
                    convolver.apply(dest);
                    computeMap(src1,src2,dest);
                  }
              }
          } // of (param.iterations > 1)

          return true;
          
      } // of (probabilityHistogram.dimensions() == 2)

      setStatusString("probabilityMap2D: no models loaded");
      return false;
  }