import ij.*;
import ij.gui.*;
import java.awt.*;
import ij.plugin.filter.PlugInFilter;
import ij.process.*;

/** RISfromRGB
  *
  * Puts Log Complex Color Image into a 3-Slice FP Stack.
  *
  * This example adapted by pf from tutorial plugins named
  * ColorInverter & StackAverage found with the tutorial at
  * http://www.fh-hagenberg.at/mtd/depot/imaging/imagej
  * 
  */
public class RISfromRGB_ implements PlugInFilter {

	protected ImagePlus imp; // defines an instance variable, protected means what?	

	public int setup(String arg, ImagePlus imp) {
		if (arg.equals("about"))
			{showAbout(); return DONE;}
		this.imp=imp;
                return DOES_RGB+NO_CHANGES; // checks for RGB image as input
	}

	public void run(ImageProcessor ip) {

		//ImageStack stack=imp.getStack(); // sets up the image stack for access
		// get width, height and the region of interest
		int w = ip.getWidth();     
		int ht = ip.getHeight();    
		int dimension = ip.getWidth()*ip.getHeight();	
		int[] cpixels = (int[]) ip.getPixels(); // gets the first slice pixel array
	
		// create a new image with the same size and copy the pixels of the original image
		ImagePlus fpimage = NewImage.createFloatImage("Ampl-Phase-SatL stack",w,ht,3,NewImage.FILL_BLACK);
		ImageStack fpstack = fpimage.getStack();
		float[] rpixels = (float[]) fpstack.getPixels(1);
		float[] ipixels = (float[]) fpstack.getPixels(2);
		float[] spixels = (float[]) fpstack.getPixels(3);

		float r,g,b,h,s,v,satL,lightness,minc,maxc,delta;
		double amplitude, phase, real, imaginary;
		// r,g,b values are from 0 to 1
		// h = [0,360], s = [0,1], v = [0,1]
		// if s == 0, then h = -1 (undefined)
		for (int j=0;j<dimension;j++) {
			// first determine RGB pixel values from the stack images
			int c = cpixels[j];
		    	int rint = (c&0xff0000)>>16;
		    	int gint = (c&0x00ff00)>>8;
		    	int bint = (c&0x0000ff);
			r = (float) rint/(255); g= (float) gint/(255); b= (float) bint/255;
			// now get HSV parameters hue[0..360] satV[0..1] brightness[0..1]
			minc = Math.min( r, Math.min( g, b ));
			maxc = Math.max( r, Math.max( g, b ));
			v = maxc;  // brightness "v" in [0,1]
			delta = maxc - minc;
			if( delta != 0 ) {
				s = delta / maxc;  // saturation "s" in [0,1]
				if( r == maxc ) {
					h = ( g - b ) / delta;  // between yellow & magenta
				} else if( g == maxc ) {
					h = 2 + ( b - r ) / delta;	// between cyan & yellow
				} else { // it must be that b == maxc so that
					h = 4 + ( r - g ) / delta;	// between magenta & cyan
				}
				h *= 60;  // hue "h" in degrees
				if( h < 0 ) h += 360; // moved to the positive branch cut
			} else {
				// r = g = b = 0	// s = 0, v is undefined
				s = 0; h = 0; // here set all to zero
			}
			// next convert from HSV to HSL: hue[0..360] satL[0..1] lightness[0..1]
			lightness = v*(1- s/2);
			if (s==0) {
				satL = 0;
			} else {
				if (lightness < 0.5) {
					satL = s/(2-s);
				} else {
					satL = v*s/(2+v*(s-2));
				}
			}		
			// then convert from HSL to ATS: ampl[0..+Infinity] phase[0..2*Pi] satL[0..1]
			if (lightness<0.5) {
				if (lightness==0) {
					amplitude = 0;
				} else {
					amplitude = Math.exp(1-1/(2*lightness));
				}	
			} else {
				if (lightness == 1) {
					amplitude = Math.exp(+100);
				} else {
					amplitude = Math.exp(-1+1/(2-2*lightness));
				}
			}
			phase = h*Math.PI/180.;
			// and from ATS to XYS: XY[-Infinity..+Infinity] satL[0..1]
			real = amplitude*Math.cos(phase);
			imaginary = amplitude*Math.sin(phase);
			rpixels[j] = (float) real;
			ipixels[j] = (float) imaginary;
			spixels[j] = (float) satL;
		}

		fpimage.show();
		fpimage.updateAndDraw();

	}

	void showAbout() {
		// called by setup if the string argument is "about"
		IJ.showMessage("ATSfromRGB",
			"gets the amplitude phase satL stack from a log color image"
		);
	}

}