/*
 * Otsu Thresholding algorithm
 *
 * Copyright (c) 2003 by Christopher Mei (christopher.mei@sophia.inria.fr)
 *                    and Maxime Dauphin
 *
 * This plugin is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2 
 * as published by the Free Software Foundation.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this plugin; if not, write to the Free Software
 * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 */

package thresholding;
import ij.*;
import ij.plugin.filter.PlugInFilter;
import ij.process.*;
import ij.gui.*;

import GUI.internalFrame;
import GUI.mainWindow;
import GUI.FileChooser;

/**
 *  This algorithm is an implementation of Otsu thresholding technique 
 *  based on the minimization of inter-class variance [otsu79].
 *
 *  @Article{otsu79,
 *    author =       "N. Otsu",
 *    title =        "A threshold selection method from gray level
 *                    histograms",
 *    journal =      "{IEEE} Trans. Systems, Man and Cybernetics",
 *    year =         "1979",
 *    volume =       "9",
 *    pages =        "62--66",
 *    month =        mar,
 *    keywords =     "threshold selection",
 *    note =         "minimize inter class variance",
 *  }
 *  
 **/

public class OtsuThresholding_ implements PlugInFilter {
    private int threshold;
    final static int HMIN = 0;
    final static int HMAX = 256;
    private ImagePlus imp;
    private ImageProcessor nip;
	int numberResult;
	boolean draw;
	boolean setSelected;
    
    private String title;
    
    public OtsuThresholding_(String title, int numberResult, boolean draw, boolean setSelected) {
		this.title = title;
		this.numberResult = numberResult;
		this.draw = draw;
		this.setSelected = setSelected;
	}

    public int setup(String arg, ImagePlus imp) {
	if (arg.equals("about"))
	    {showAbout(); return DONE;}
	return DOES_8G+DOES_STACKS+SUPPORTS_MASKING+NO_CHANGES;
    }
    
    public void run(ImageProcessor ip) {
	boolean debug = false;
	
	int width =  ip.getWidth();
	int height = ip.getHeight();

	GrayLevelClass.N = width*height;
	GrayLevelClass.probabilityHistogramDone = false;
	GrayLevelClass C1 = new GrayLevelClass((ByteProcessor) ip, true);
	GrayLevelClass C2 = new GrayLevelClass((ByteProcessor) ip, false);

	//IJ.showStatus("Iterating...");
	
	float fullMu = C1.getOmega()*C1.getMu()+C2.getOmega()*C2.getMu();
	//IJ.write("Full Omega : "+fullMu);
	double sigmaMax = 0;
	int threshold = 0;

	/** Start  **/
	for(int i=0 ; i<255 ; i++) {
	    //IJ.showStatus("Iteration "+i+"/"+256+"...");
	    //IJ.showProgress(i/256);

	    double sigma = C1.getOmega()*(Math.pow(C1.getMu()-fullMu,2))+C2.getOmega()*(Math.pow(C2.getMu()-fullMu,2));
	    
	    if(sigma>sigmaMax) {
		sigmaMax = sigma;
		threshold = C1.getThreshold();
	    }

	    C1.addToEnd();
	    C2.removeFromBeginning();
	}
	//NewImage.createByteImage(title, width, height, slices, options)
	
	imp = NewImage.createImage ("Threshold", width, height, 1, 8, NewImage.FILL_WHITE);

	nip = imp.getProcessor();
	
/*	byte[] pixels = (byte[]) ((ByteProcessor) ip).getPixels();

	int offset = 0;*/

/*	for (int y=0; y<height; y++) {
	    offset = y*width;
	    for (int x=0; x<width; x++) {
		if ((pixels[offset + x] & 0xff) <= threshold)
		    nip.putPixel(x, y, 0);
	    }
        }*/
	
	for (int i = 0; i < ip.getWidth(); i++) {
		for (int j = 0; j < ip.getHeight(); j++) {
			if (ip.getPixelValue(i, j) <= threshold)
				nip.putPixelValue(i, j, 0);
		}
	}
	//imp.show();
	IJ.showMessage("Found threshold : "+threshold);
	//System.out.println("numberResult otsu"+numberResult);
	
/*	if (draw) {
		mainWindow.intFrame[FileChooser.number] = new internalFrame("Otsu Thresholding", imp, FileChooser.number, numberResult, 1, true);
		try {
			mainWindow.intFrame[FileChooser.number].setSelected(true);
		} catch(Exception e){
			System.out.println("Chyba");
		}	
		++FileChooser.number;
	}*/
	
	if (draw) {
		internalFrame inFr = new internalFrame("Otsu Thresholding", imp, FileChooser.number, numberResult, 1, true);
		mainWindow.intFrameArrayList.add(inFr);
		try {
			((internalFrame)(mainWindow.intFrameArrayList.get(FileChooser.number))).setSelected(setSelected);
		} catch(Exception e){
			System.out.println("Chyba");
		}	
		++FileChooser.number;
	}
	
	//System.out.println("Found threshold : "+threshold);
    }
    
	public ImagePlus getImg(){
		return imp;
	}
	
	public ImageProcessor getIp(){
		return nip;
	}
	
    
    void showAbout() {
	IJ.showMessage("About OtsuThresholding_...",
		       "This plug-in filter calculates the OtsuThresholding of a 8-bit image.\n"
		       );
    }
    
    
	protected void finalize() throws Throwable {
	    try {
	        //close();        // close open files
	    } finally {
	        super.finalize();
	        System.out.println("otsu has been finalized.");
	    }
	}
}

