/**
   * Scales the range of <code>image</code> to an arbitrary min/max in a Region of Interest. The
   * range used for all planes is the global max, min of the image.
   *
   * @param image RealColorImage to scale.
   * @param roi Region of Interest of <code>image</code>.
   * @return <code>image</code>.
   */
  protected Image apply(RealColorImage image, ROI roi) {
    RealGrayImage plane;

    float min = image.min(roi);
    float max = image.max(roi);
    float r = 0;
    float range = max - min;
    float value = 0;
    if (range == 0) range = 1; // to avoid divide by zero problems

    for (int i = 0; i < 3; i++) {
      plane = image.plane(i);

      for (int y = roi.uy(); y <= roi.ly(); y++) {
        for (int x = roi.ux(); x <= roi.lx(); x++) {
          r = plane.get(x, y);
          value = (((r - min) / (range) * (float_max - float_min)) + float_min);
          plane.set(x, y, value);
        }
      }

      image.setPlane(i, plane);
    }

    return image;
  }
  /**
   * Applies the palette to <code>image</code> using the KdTree to find the nearest neighbor.
   * Returned Image is a ColorImage. <code>image</code> is not modified.
   *
   * @param image ColorImage to apply palette to
   * @return ColorImage
   */
  protected Image apply(ColorImage image) {

    RealColorImage realImage = ImageConverter.toRealColor(image);
    ColorImage newImage = new ColorImage(realImage.X(), realImage.Y());

    float[] total = null;
    float[] best = null;
    int[] temp = new int[3];

    for (int x = 0; x < realImage.X(); x++) {
      for (int y = 0; y < realImage.Y(); y++) {
        tree2.getValues().removeAllElements();
        do {
          total = realImage.get(x, y);
          tree2.findNearest(total, tree2.getRoot(), threshold);
          threshold += 2;
        } while (tree2.getValues().size() == 0);

        threshold = 8;
        if (tree2.getValues().size() != 1) best = findBest(total);
        else best = (float[]) tree2.getValues().elementAt(0);
        temp[0] = (int) best[0];
        temp[1] = (int) best[1];
        temp[2] = (int) best[2];
        newImage.set(x, y, temp);
      }
    }
    System.out.println("Done with the apply");
    return newImage;
  }
  /**
   * Writes a RealColorImage to a file, byteSizing first
   *
   * @param im the RealColorImage
   */
  public void writeByteSized(RealColorImage im) throws IOException {

    X = im.X();
    Y = im.Y();
    float[] color = new float[3];

    // convert to byte size
    RealColorImage tmpim = (RealColorImage) im.copy();
    tmpim.byteSize();

    // write PPM in raw format

    writeRawPRCMHeader(X, Y);
    for (int y = 0; y < Y; y++) {
      for (int x = 0; x < X; x++) {
        color = tmpim.get(x, y);
        data.write((byte) color[0]);
        data.write((byte) color[1]);
        data.write((byte) color[2]);
      }
    }
  }
 /**
  * Scales the range of <code>image</code> to an arbitrary min/max. The range used for all planes
  * is the global max, min of the image.
  *
  * @param image RealColorImage to scale.
  * @return <code>image</code>.
  */
 protected Image apply(RealColorImage image) {
   return apply(image, new ROI(0, 0, image.X() - 1, image.Y() - 1));
 }