Package net.sourceforge.jiu.color.quantization

Source Code of net.sourceforge.jiu.color.quantization.ArbitraryPaletteQuantizer

/*
* ArbitraryPaletteQuantizer
*
* Copyright (c) 2001, 2002, 2003 Marco Schmidt.
* All rights reserved.
*/

package net.sourceforge.jiu.color.quantization;

import net.sourceforge.jiu.color.quantization.RGBQuantizer;
import net.sourceforge.jiu.data.MemoryPaletted8Image;
import net.sourceforge.jiu.data.Palette;
import net.sourceforge.jiu.data.Paletted8Image;
import net.sourceforge.jiu.data.PixelImage;
import net.sourceforge.jiu.data.RGB24Image;
import net.sourceforge.jiu.data.RGBIndex;
import net.sourceforge.jiu.ops.ImageToImageOperation;
import net.sourceforge.jiu.ops.MissingParameterException;
import net.sourceforge.jiu.ops.WrongParameterException;

/**
* A color quantizer that maps an {@link net.sourceforge.jiu.data.RGBImage}
* to any given palette.
* This operation is restricted to RGB24Image and palettes with up to 256 colors.
* It picks the color from the palette which is closest to the
* color to be quantized (with the minimum distance).
* This is a rather naive implementation which, for any given color
* to be quantized, computes the distance between it and each color
* in the palette (read: this operation is rather slow with a large palette and input image).
* <p>
* It uses <a target="_top" href="http://hissa.nist.gov/dads/HTML/manhttndstnc.html">Manhattan distance</a> (L<sub>1</sub>)
* instead of <a target="_top" href="http://hissa.nist.gov/dads/HTML/euclidndstnc.html">Euclidean distance</a> (L<sub>2</sub>).
* This saves a square root operation per distance computation.
* <p>
* There are more sophisticated <a target="_top"
* href="http://www.cs.sunysb.edu/~algorith/files/nearest-neighbor.shtml">nearest
* neighbor</a> algorithms available, left for future extensions.
*
* <h3>Usage example</h3>
* <p>This example maps an RGB truecolor image to some palette
* we create.</p>
* <pre>
* RGB24Image image = ...; // initialize this
* // create some Palette object that you want to map the image to
* Palette palette = new Palette(3); // create palette with three entries
* palette.put(0, 33, 00, 244); // set first color
* palette.put(1, 0, 240, 193); // set second color
* palette.put(2, 245, 126, 136); // set third color
* ArbitraryPaletteQuantizer quantizer = new ArbitraryPaletteQuantizer(palette);
* quantizer.setInputImage(image);
* quantizer.process();
* PixelImage quantizedImage = quantizer.getOutputImage();
* </pre>
*
* @author Marco Schmidt
* @since 0.5.0
*/
public class ArbitraryPaletteQuantizer extends ImageToImageOperation implements RGBIndex, RGBQuantizer
{
  private final int[] RED;
  private final int[] GREEN;
  private final int[] BLUE;
  private Palette palette;
  private int numEntries;

  /**
   * Creates a quantizer that will be able to map pixels (or a complete image)
   * to the argument palette.
   */
  public ArbitraryPaletteQuantizer(Palette palette)
  {
    this.palette = palette;
    numEntries = palette.getNumEntries();
    // create 1D lookup tables for the three components and fill them with
    // the palette entry data
    RED = new int[numEntries];
    GREEN = new int[numEntries];
    BLUE = new int[numEntries];
    for (int i = 0; i < numEntries; i++)
    {
      RED[i] = palette.getSample(INDEX_RED, i);
      GREEN[i] = palette.getSample(INDEX_GREEN, i);
      BLUE[i] = palette.getSample(INDEX_BLUE, i);
    }
  }

  /**
   * Returns a copy of the palette that was given to the
   * constructor of this class.
   * @return new copy of the palette this quantizer works on
   */
  public Palette createPalette()
  {
    return (Palette)palette.clone();
  }

  public int map(int[] origRgb, int[] quantizedRgb)
  {
    int r = origRgb[INDEX_RED];
    int g = origRgb[INDEX_GREEN];
    int b = origRgb[INDEX_BLUE];
    int minIndex = 0;
    int minDistance = Integer.MAX_VALUE;
    for (int index = 0; index < numEntries; index++)
    {
      int v = r - RED[index];
      int distance = v * v;
      v = g - GREEN[index];
      distance += v * v;
      v = b - BLUE[index];
      distance += v * v;
      if (distance < minDistance)
      {
        minDistance = distance;
        minIndex = index;
      }
    }
    quantizedRgb[INDEX_RED] = RED[minIndex];
    quantizedRgb[INDEX_GREEN] = GREEN[minIndex];
    quantizedRgb[INDEX_BLUE] = BLUE[minIndex];
    return minIndex;
  }

  /**
   * Finds the best match for the argument color in the palette and returns
   * its index.
   * Similar to {@link #map(int[], int[])}, the quantized color is not required
   * and thus a few assignemnts are saved by this method.
   * @param red red sample of the pixel to be quantized
   * @param green green sample of the pixel to be quantized
   * @param blue blue sample of the pixel to be quantized
   * @return index of the color in the palette that is closest to the argument color
   */
  public int map(int red, int green, int blue)
  {
    int minIndex = 0;
    int minDistance = Integer.MAX_VALUE;
    for (int index = 0; index < numEntries; index++)
    {
      int v = red - RED[index];
      int distance = v * v;
      v = green - GREEN[index];
      distance += v * v;
      v = blue - BLUE[index];
      distance += v * v;
      if (distance < minDistance)
      {
        minDistance = distance;
        minIndex = index;
      }
    }
    return minIndex;
  }

  private void process(RGB24Image in, Paletted8Image out)
  {
    final int WIDTH = in.getWidth();
    final int HEIGHT = in.getHeight();
    if (out == null)
    {
      out = new MemoryPaletted8Image(WIDTH, HEIGHT, createPalette());
    }
    for (int y = 0; y < HEIGHT; y++)
    {
      for (int x = 0; x < WIDTH; x++)
      {
        out.putSample(0, x, y, map(in.getSample(INDEX_RED, x, y), in.getSample(INDEX_GREEN, x, y), in.getSample(INDEX_BLUE, x, y)));
      }
      setProgress(y, HEIGHT);
    }
    setOutputImage(out);
  }

  /**
   * Maps the input image to an output image, using the palette given to the constructor.
   */
  public void process() throws
    MissingParameterException,
    WrongParameterException
  {
    ensureInputImageIsAvailable();
    PixelImage in = getInputImage();
    if (!(in instanceof RGB24Image))
    {
      throw new WrongParameterException("Input image must be of type RGB24Image.");
    }
    PixelImage out = getOutputImage();
    if (out != null && !(out instanceof Paletted8Image))
    {
      throw new WrongParameterException("Output image must be of type Paletted8Image.");
    }
    process((RGB24Image)in, (Paletted8Image)out);
  }
}
TOP

Related Classes of net.sourceforge.jiu.color.quantization.ArbitraryPaletteQuantizer

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.