package yi.iu.processor.color.quan;

import java.awt.*;
import yi.iu.processor.color.reg.DPU_ColorRegion;
import yi.iu.processor.color.reg.ColorRegionUtil;
import yi.util.label.Label;
import yi.iu.processor.color.ColorUtil;
import yi.util.io.OutputResult;
import yi.util.io.ReadArgu;
import yi.util.config.*;
import yi.util.io.output.*;

/**
 * Implement the color quantization described in
 * J. R. Smith, VisualSEEk: a fully automated content-base image query system
 * Transformation from RGB to HSV and quantization gives 18 hues, 3 saturations,
 * 3 values and 4 grays = 166 colors
 */
public class SmithColorQuantization {
  final static float FIRST_SIXTH = (float)(1.0/6);
  public final static int MAX_LABEL = 165;
  public int[] m_labels;
  /**
   * In Smith's paper, how to quantize is not described in detail.  Here is what
   * I will do:
   * Using java.awt.Color.RGBtoHSB converts a RGB color to HSB color first, in
   * which H,S,and B are in the range of [0..1]
   * H will be divided equally to 18 section.  S will be divide to 4 parts:
   * [0,1/6),[1/6,1/2),[1/2,5/6),[5/6,1].  When S is fell into the first range,
   * the color will be quantized only according to its brightness; while
   * otherwise, its brightness will be divided to 3 equally-length ranges.
   *
   * @param r
   * @param g
   * @param b
   * @return
   */
  public static int quantize(int r, int g, int b) {
    int index;
    float[] hsb = Color.RGBtoHSB(r, g, b, null);
    float h=hsb[0],s=hsb[1],v=hsb[2];
    if (s < FIRST_SIXTH) {
      index = (int)(v/0.25);
      if (index >=4) index = 3;
      return index;
    }
    int index_h = (int)(h*18); if (index_h>=18) index_h = 17;
    int index_s = (int)((s-FIRST_SIXTH)*3); if (index_s>=3) index_s = 2;
    int index_v = (int)(v*3); if (index_v>=3) index_v = 2;
    return index_h*3*3 + index_s*3 + index_v + 4;
  }

  public static int quantize(int rgb) {
    int r = (rgb>>16)&0xff;
    int g = (rgb>>8)&0xff;
    int b = rgb&0xff;
    return quantize(r,g,b);
  }

  /**
   * Quantize an image (return the image map with labels)
   * @param rgbs
   * @param width
   * @param height
   * @param rst
   * @return
   */
  public int[] quantize(int[] rgbs, int width, int height, int[] rst) {
    if (rst == null) rst = new int[rgbs.length];
    for (int i=0; i<rst.length; i++) {
      int rgb = rgbs[i];
      int r = (rgb>>16)&0xff;
      int g = (rgb>>8)&0xff;
      int b = rgb&0xff;
      rst[i] = quantize(r,g,b);
    }
    m_labels = rst;
    return rst;
  }

  public int[] getLabels() {return m_labels;}

  public int[] getDemo(int[] pixels, int width, int height) {
    quantize(pixels, width, height, null);
    int[] labels = getLabels();
    int[] packed_means = ColorRegionUtil.getMeanColors(pixels, labels, 0, 0xffff0000);
    int[] demo = new int[pixels.length];
    for (int i=0;i<demo.length;i++) {
      if (labels[i] < 0) demo[i]=0xffff0000;
      else demo[i] = packed_means[labels[i]];
    }
    return demo;
  }

  public static class Test{
    public static void main(String[] args) {
      for (int r=0; r<256; r+=64)
        for (int g=0; g<256; g+=64)
          for (int b=0; b<256; b+=64) {
            int index = quantize(r,g,b);
            System.out.println("("+r+","+g+","+b+")->"+index);
          }
    }
  }

  public static void main(String[] args) {
    // init configuration
    Configuration.init(args);

    // get the image name
    String img_name = ReadArgu.getOption('i', args);
    if (img_name == null) {
      System.err.println("Usage: -i image_name");
      System.exit(1);
    }

    // read in image
    Image image = null;
    Dimension d = new Dimension();
    int[] pixels = null;
    try {
      image = yi.util.io.ImageReader.readImageFile(img_name);
      pixels = yi.util.io.ImageReader.getPixels(image, d);
    }
    catch (java.io.IOException e) {
      System.err.println("Can't read image " + img_name);
      e.printStackTrace();
      System.exit(2);
    }


    // process
    Configuration.setParameter("SOURCE_NAME", img_name);
    SmithColorQuantization quan = new SmithColorQuantization();
    int[] rst_img = quan.getDemo(pixels, d.width, d.height);

    // output result
    OutputResult.outputGIFImage(img_name + "." + DOU.shortName(quan.getClass().getName()) + ".gif", rst_img, d.width, d.height);

    System.exit(0);
  }}