import java.awt.*;
import ij.plugin.*;
import ij.*;
import ij.gui.*;
import ij.plugin.filter.PlugInFilter;
import ij.process.*;

/**
 * MicroD Plugin for ImageJ
 * @author Martin Uria
 * Description: Runs a Micro Densitometry analysis 
 * on the selected region of an 8-bit grayscale image.
 * The region can be specified by user input or by 
 * ROI (region of interest) in the image itself. 
 * The aperture of the analysis must be specified on the 
 * input screen.  The default value (if unchanged) is 1.
 * 
 */


public class MicroDApr08_A implements PlugInFilter
{
	/**
	 * il ::	Width of the ROI. Specified by user or ROI selection.
	 * ih ::  	Height of the ROI. Specified by user or ROI selection.
	 * iXROI :: 	X coordinate of the ROI. Specified by user or ROI selection.
	 * iYROI ::	Y coordinate of the ROI. Specified by user or ROI selection.
	 * iw ::	Aperture of the Densitometry.  1 is default value.
	 */
	ImagePlus imgp;
	int il, ih, iw;			
	int k, i, j;			
	int iXROI, iYROI;		
	double sumx, sumMuSq, sumxsq;	
	double sigma, variance, mu, stdev, muavg;	
	boolean bAbort = false;


	public int setup(String arg, ImagePlus imgp)
	{
		this.imgp = imgp;
		//Specifies that this pluggin will only deal with 8-bit grayscale images.
		return DOES_8G+NO_CHANGES;
	}

	public void run(ImageProcessor imp)
	{
		Rectangle r = imp.getRoi();
		il = r.width;
		ih = r.height;
		iXROI = r.x;
		iYROI = r.y;
		iw = 1;

		//display a dialog box and collect the necessary data.
		GenericDialog gd = new GenericDialog("Specify ROI", IJ.getInstance());
		gd.addNumericField("Scan Length (l):", il, 0);
		gd.addNumericField("Aperture Height (h):", ih, 0);
		gd.addNumericField("Aperture Width (w):", iw, 0);
		gd.addNumericField("X Coordinate:", iXROI, 0);
		gd.addNumericField("Y Coordinate:", iYROI, 0);
		gd.showDialog();
        
		//if box is canceled do nothing.
		if (gd.wasCanceled()) 
		{
			bAbort = true;
			return;
		}
		
		//get the values from the dialog box.
		il = (int) gd.getNextNumber(); 
		ih = (int) gd.getNextNumber(); 
		iw = (int) gd.getNextNumber();
		iXROI = (int) gd.getNextNumber();
		iYROI = (int) gd.getNextNumber();
		
		//number of windows
		int asize = il - iw; 
		
		//set necessary arrays
		float [] muArray = new float[asize];
		float [] coArray = new float[asize];
		float [] stdevArray = new float[asize];

		//ImagePlus M = WindowManager.getCurrentImage();

		imgp.setRoi(iXROI, iYROI, il, ih);

		//Find the mean & stdev for each window
		for (k = 0; k<asize; k++)
		{
			sumx=0;
			sumxsq=0;
			for ( i = iXROI + k; i <(iXROI+iw+k); i++)
			{
				for( j= iYROI; j < iYROI+ih; j++)
				{
					sumx += imp.getPixel(i,j);	//M.getPixel(i,j)[0];		
					sumxsq += imp.getPixel(i,j) * imp.getPixel(i,j);	
				}
			}
			mu = sumx/(iw*ih); 
			muArray[k]=(float)mu;
			coArray[k]=k;
			stdev = Math.sqrt( (sumxsq - (sumx * sumx) / (double) (iw*ih) ) / (iw*ih - 1) ); 
			stdevArray[k]=(float)stdev;
		}

		//find the average mean
		sumx = 0;
		for (k = 0; k<asize; k++){
			sumx += muArray[k];			
		}
		muavg = sumx/asize;		

		//Find the standard deviation
		sigma = 0; variance = 0; sumMuSq = 0; stdev = 0;
		for (k = 0; k < asize; k++)
		{
			sigma += muArray[k];
			sumMuSq += muArray[k]*muArray[k];
		}
		variance = ( sumMuSq - ( sigma * sigma ) / (double) k ) / (double) (k-1) ;
		stdev = Math.sqrt(variance);

		IJ.write("Standard Deviation: " + stdev);
		IJ.write("Average mean: " + muavg);
		
		//draw stdev plot for debugging
		PlotWindow plot2 = new PlotWindow("Standard Deviation","i (x-axis)","Standard Deviation(y-axis)",coArray,stdevArray);
		plot2.setLimits(0,(il-iw-1), 0,255);
		plot2.setLineWidth(1);
		plot2.setColor(Color.red);
		plot2.draw();

		//draw the P vs. i plot 
		PlotWindow plot1 = new PlotWindow("P vs i","i (x-axis)","P (y-axis)",coArray,muArray);
		plot1.setLimits(0,(il-iw-1), 0,255);
		plot1.setLineWidth(1);
		plot1.setColor(Color.green);
		plot1.draw();
		
		//register plugin with ImageJ
		//so that it shows on the analysis pluggin menu.
		IJ.register(MicroDApr08_A.class);

	}
}
