bool brightRGB::getMax(const image& img,dvector& dest) const{

    // image empty?
    if (img.empty()) {
      setStatusString("image empty");
      dest.resize(0);
      return false;
    }

    const rgbPixel transColor = getParameters().transColor;
    ivector maxV(3,-1);
    image::const_iterator it = img.begin();
    if(getParameters().transparent) {
      while(it != img.end()) {
	if(*it != transColor) {
	  if((*it).getRed() > maxV.at(0))
	    maxV.at(0) = (*it).getRed();
	  if((*it).getGreen() > maxV.at(1))
	    maxV.at(1) = (*it).getGreen();
	  if((*it).getBlue() > maxV.at(2))
	    maxV.at(2) = (*it).getBlue();
	}
	it++;
      }
      // only transparent pixels?
      if (maxV.at(0)==-1) {
        setStatusString("only transparent pixels");
        dest.resize(0);
        return false;
      }
    } else { // no transparent color
      while(it != img.end()) {
	if((*it).getRed() > maxV.at(0))
	  maxV.at(0) = (*it).getRed();
	if((*it).getGreen() > maxV.at(1))
	  maxV.at(1) = (*it).getGreen();
	if((*it).getBlue() > maxV.at(2))
	  maxV.at(2) = (*it).getBlue();
	it++;
      }
    }
    if(maxV.at(0) == -1)
      return false;
    dest.castFrom(maxV);
    // normalize to 0..1
    dest.divide(255);
    return true;
  };
  bool brightRGB::getAverage(const image& img,dvector& dest) const{

    const rgbPixel transColor = getParameters().transColor;
    dvector avg(3,0.0);
    image::const_iterator it = img.begin();
    // check for empty image
    if (img.columns()==0 || img.rows()==0) {
      setStatusString("image empty");
      dest.resize(0);
      return false;
    }
    if(getParameters().transparent) {
      int counter = 0;
      while(it != img.end()) {
	if(*it != transColor) {
	  avg.at(0) += (*it).getRed();
	  avg.at(1) += (*it).getGreen();
	  avg.at(2) += (*it).getBlue();
	  ++counter;
	}
	it++;
      }
      // check for completely transparent image
      if (counter==0) {
        setStatusString("only transparent pixels");
        dest.resize(0);
        return false;
      }
      avg.divide(counter);
    } else { // no transparent color
      while(it != img.end()) {
	avg.at(0) += (*it).getRed();
	avg.at(1) += (*it).getGreen();
	avg.at(2) += (*it).getBlue();
	it++;
      }
      avg.divide(img.columns()*img.rows());
    }
    // values between 0 and 1
    dest.divide(avg, 255.);
    return true;
  };
  bool brightRGB::getMedian(const image& img,dvector& dest) const{


    // image empty?
    if (img.empty()) {
      setStatusString("image empty");
      dest.resize(0);
      return false;
    }

    const rgbPixel transColor = getParameters().transColor;
    dest.resize(3);
    ivector hist0(256,0);
    ivector hist1(256,0);
    ivector hist2(256,0);
    image::const_iterator it = img.begin();
    if(getParameters().transparent) {
      while(it != img.end()) {
  	if(*it != transColor) {
	  ++hist0.at((*it).getRed());
	  ++hist1.at((*it).getGreen());
	  ++hist2.at((*it).getBlue());
	}
	it++;
      }
      const int counterHalf = hist0.sumOfElements()/2;
      // check for complete image transparent
      if (counterHalf==0) {
        setStatusString("only transparent pixels");
        dest.resize(0);
        return false;
      }

      int i,s;
      i=-1,s=0;
      while(++i<256 && s<counterHalf) {
	s += hist0.at(i);
      }
      dest.at(0) = i-1;
      i=-1,s=0;
      while(++i<256 && s<counterHalf) {
	s += hist1.at(i);
      }
      dest.at(1) = i-1;
      i=-1,s=0;
      while(++i<256 && s<counterHalf) {
	s += hist2.at(i);
      }
      dest.at(2) = i-1;
    } else { // no transparent color
      while(it != img.end()) {
	  ++hist0.at((*it).getRed());
	  ++hist1.at((*it).getGreen());
	  ++hist2.at((*it).getBlue());
	it++;
      }
      const int counterHalf = img.columns()*img.rows()/2;
      int i,s;
      i=-1,s=0;
      while(++i<256 && s<counterHalf) {
	s += hist0.at(i);
      }
      dest.at(0) = i-1;
      i=-1,s=0;
      while(++i<256 && s<counterHalf) {
	s += hist1.at(i);
      }
      dest.at(1) = i-1;
      i=-1,s=0;
      while(++i<256 && s<counterHalf) {
	s += hist2.at(i);
      }
      dest.at(2) = i-1;
    }

    // normalize to 0..1
    dest.divide(255);

    return true;
  };
  // On copy apply for type image!
  bool histogramRGBL::apply(const image& src,dvector& dest) const {

    if (src.empty()) {
      dest.clear();
      setStatusString("input channel empty");
      return false;
    }

    const parameters& param = getParameters();

    int theMin(0),theMax(255);

    const int lastIdx = param.cells-1;

    const float m = float(lastIdx)/(theMax-theMin);
    int y,r,g,b,l;
    int idx;
    int entries;

    vector<rgbPixel>::const_iterator it,eit;

    dest.resize(4*param.cells,0.0,false,true); // initialize with 0
    dvector theR(param.cells,0.0);
    dvector theG(param.cells,0.0);
    dvector theB(param.cells,0.0);
    dvector theL(param.cells,0.0);

    entries = 0;

    // if b too small, it's possible to calculate everything faster...

    // check if the ignore value
    if (param.considerAllData) {
      for (y=0;y<src.rows();++y) {
        const vector<rgbPixel>& vct = src.getRow(y);
        for (it=vct.begin(),eit=vct.end();it!=eit;++it) {
          r = (*it).getRed();
          g = (*it).getGreen();
          b = (*it).getBlue();
          l = (min(r,g,b)+max(r,g,b))/2;

          idx = static_cast<int>(r*m);
          theR.at(idx)++;
          idx = static_cast<int>(g*m);
          theG.at(idx)++;
          idx = static_cast<int>(b*m);
          theB.at(idx)++;
          idx = static_cast<int>(l*m);
          theL.at(idx)++;

          entries++;
        }
      }
    } else {
      for (y=0;y<src.rows();++y) {
        const vector<rgbPixel>& vct = src.getRow(y);
        for (it=vct.begin(),eit=vct.end();it!=eit;++it) {
          if ((*it) != param.ignoreValue) {
            r = (*it).getRed();
            g = (*it).getGreen();
            b = (*it).getBlue();
            l = (min(r,g,b)+max(r,g,b))/2;

            idx = static_cast<int>(r*m);
            theR.at(idx)++;
            idx = static_cast<int>(g*m);
            theG.at(idx)++;
            idx = static_cast<int>(b*m);
            theB.at(idx)++;
            idx = static_cast<int>(l*m);
            theL.at(idx)++;

            entries++;
          }
        }
      }
    }

    if (param.smooth) {
      convolution convolver;
      convolution::parameters cpar;
      cpar.boundaryType = lti::Mirror;
      cpar.setKernel(param.kernel);
      convolver.setParameters(cpar);

      matrix<double> tmp;
      tmp.useExternData(4,param.cells,&dest.at(0));

      convolver.apply(theR,tmp.getRow(0));
      convolver.apply(theG,tmp.getRow(1));
      convolver.apply(theB,tmp.getRow(2));
      convolver.apply(theL,tmp.getRow(3));

    } else {
      dest.fill(theR,0);
      dest.fill(theG,param.cells);
      dest.fill(theB,2*param.cells);
      dest.fill(theL,3*param.cells);
    }

    if (param.normalize) {
      if (entries > 0) {
        dest.divide(entries);
      }
    }

    return true;

  };