package yi.iu.processor.channel;

import java.awt.*;
import yi.iu.processor.channel.ChannelMaker;
import yi.iu.CY_HSI;
import yi.iu.ui.*;

/**
 * The CY-HSI color space
 * [REFERENCE]
 *   A. R. Weeks, Color segmentation in the HSI color space using the K-means
 *   algorithm
 */
public class CYMaker extends ChannelMaker
{
    public int[] getProcessedPseudoColor(int[] source, Dimension d)
    {
        int[][] hsi= getProcessed_ex(source,d);
        (new InfoFrame("CY_HSI", source, d.width, d.height, hsi)).show();
        return null;
    }

    public int[] getProcessed(int rgb[], Dimension d)
    {
      return getLuminance(rgb, d);
    }

    public int[][] getProcessed_ex(int rgb[], Dimension d)
    {
      return getHSI(rgb, d);
    }


    public static int[][] getHSI(int rgb[], Dimension d)
    {
        int width=d.width, height=d.height;
            int size=width*height;
            int[][] hsi= new int[size][3];

            for (int i=0;i<size;i++) {
                int r=rgb[i]>>16&255;
                int g=rgb[i]>>8&255;
                int b=rgb[i]&255;
                rgb2hsi(r,g,b,hsi[i]);
            }
            return hsi;
    }

    public static int[] getHue(int rgb[], Dimension d)
    {
        int width=d.width, height=d.height;
            int size=width*height;
            int[] h= new int[size];

            int[] hsi= new int[3];
            for (int i=0;i<size;i++) {
                int r=rgb[i]>>16&255;
                int g=rgb[i]>>8&255;
                int b=rgb[i]&255;
                rgb2hsi(r,g,b,hsi);
                h[i]=hsi[0];
            }
            return h;
    }

    /**
     * Red component scale parameter when converting RGB to Luminance.
     */
    final static double RSCALE = 0.299;
    /**
     * Green component scale parameter when converting RGB to Luminance.
     */
    final static double GSCALE = 0.587;
    /**
     * Blue component scale parameter when converting RGB to Luminance.
     */
    final static double BSCALE = 0.114;

    /**
     * Converts RGB color to gray scale color according the YIQ color model or
     * CIM color model. The gray scale value is defined as the luminance
     * component in the CIM and YIQ model
     * @param rgb the rgb pixel values of the input image
     * @param d the dimension of the input image
     * @return the array of the lumninance (gray level)
     */
    public static int[] getLuminance(int rgb[], Dimension d)
    {
      int width=d.width, height=d.height;
      int size=width*height;
      int[] luminance= new int[size];

      for (int i=0;i<size;i++) {
        int r= rgb[i]>>16&0xff;
        int g= rgb[i]>>8 &0xff;
        int b= rgb[i]    &0xff;
        luminance[i]= (int)Math.round(RSCALE*r+GSCALE*g+BSCALE*b);
      }
      return luminance;
    }

    public static int[] makeNewImageFromHSI(int[][] hsi, Dimension d)
    {
        int width=d.width, height=d.height;
            int size=width*height;

            int[] rgb= new int[size];
            for (int i=0;i<size;i++) {
                rgb[i]=hsi2rgb(hsi[i][0],hsi[i][1],hsi[i][2]);
            }
            return rgb;
    }

    public static void makeImageFromHue(int[] hue, Dimension d)
    {
        int width=d.width, height=d.height;
            int size=width*height;

            int[] hsi= new int[3];
            for (int i=0;i<size;i++) {
                hue[i]=hsi2rgb(hue[i],255,255);
            }
    }

    static int HSCALE=256;
    //A. R. Weeks, Color segmentation in the HSI color space using the K-means algorithm
    public static CY_HSI rgb2hsi(int r, int g, int b)
    {
        double y=0.299*r+0.587*g+0.114*b;
            double ry= r-y;
            double by= b-y;
            int s=(int)Math.round(Math.sqrt(ry*ry+by*by));

            //hue= arc tan (ry/by)
            double hue= Math.atan2(ry,by);
            int h= (int)Math.round(hue*HSCALE/2/Math.PI);
            if (h<0) h+=HSCALE;
            return new CY_HSI(h, s, (int)Math.round(y));
    }

    public static void rgb2hsi(int r, int g, int b, int[] hsi)
    {
        CY_HSI cy= rgb2hsi(r,g,b);
        hsi[0]=cy.h;hsi[1]=cy.s;hsi[2]=cy.i;
    }

    public static int hsi2rgb(int h, int s, int y)
    {
        double sita=(double)h*2*Math.PI/HSCALE;
        int r=(int)Math.round(s*Math.sin(sita)+y);
        if (r<0) r=0;
        if (r>255) r=255;
        int b=(int)Math.round(s*Math.cos(sita)+y);
        if (b<0) b=0;
        if (b>255) b=255;
        int g=(int)Math.round(-0.51*(r-y)-0.19*(b-y)+y);
        if (g<0) g=0;
        if (g>255) g=255;
        int rgb=0xff<<24|r<<16|g<<8|b;
        return rgb;
    }
}