/*
   * compute the second and up iterations of a probability map
   * using the given aPriori probabilites per pixel.
   */
  bool probabilityMap2D::computeMap(const channel8& src1, const channel8& src2,
				    channel& aPrioriDest) const {
 
    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;

    } else {
      int y;
      vector<channel8::value_type>::const_iterator srcIterator1, eit1;
      vector<channel8::value_type>::const_iterator srcIterator2, eit2;
      vector<channel::value_type>::iterator destIterator;
 
      const parameters& param = getParameters();
      const thistogram<double>& objModel = param.getObjectColorModel();
      const thistogram<double>& nonObjModel = param.getNonObjectColorModel();
      
      float relObjProb;
      float relNonObjProb;
      
      ivector theBin(2);
      
      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 = aPrioriDest.getRow(y).begin();

	while (srcIterator1 != eit1) {
	  theBin[0] = lookupTable[0][*srcIterator1];
	  theBin[1] = lookupTable[1][*srcIterator2];
	  
	  relObjProb = static_cast<float>(objModel.getProbability(theBin) *
					  (*destIterator));
	  relNonObjProb = static_cast<float>(nonObjModel.getProbability(theBin)*
					     (1.0f-(*destIterator)));

	  // assume non-object if no entries are given
	  if ((relObjProb == 0.0f) && (relNonObjProb == 0.0f)) {
	    (*destIterator) = 0.0f;
	  } else {
	    // bayes
	    (*destIterator) = relObjProb / (relObjProb + relNonObjProb);
	  }

	  srcIterator1++;
	  srcIterator2++;
	  destIterator++;
	}
      }
    }
    
    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;
  }
  // 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;
    }
  };