scalespace.filter.ALoG_Filter_.java Source code

Java tutorial

Introduction

Here is the source code for scalespace.filter.ALoG_Filter_.java

Source

package scalespace.filter;

import ij.IJ;
import ij.ImageJ;
import ij.ImagePlus;
import ij.ImageStack;
import ij.Prefs;
import ij.gui.GenericDialog;
import ij.gui.DialogListener;
import ij.measure.Calibration;
import ij.plugin.filter.Convolver;
import ij.plugin.filter.ExtendedPlugInFilter;
import ij.plugin.filter.PlugInFilterRunner;
import ij.process.Blitter;
import ij.process.FloatProcessor;
import ij.process.ImageProcessor;
import ij.process.LUT;
import ijaux.scale.*;

import java.awt.*;
import java.awt.event.*;
import java.util.*;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.plot.PlotOrientation;
import org.jfree.data.xy.XYSeries;
import org.jfree.data.xy.XYSeriesCollection;

import activeSegmentation.IFilter;
import dsp.Conv;

/**
 * @version    1.2 23 Aug 2016
 *              1.1 27 Jun 2015
 *             1.0  6 Oct 2014 
 *             
 *   
 * 
 * @author Dimiter Prodanov, IMEC , Sumit Kumar Vohra 
 *
 *
 * @contents
 * The plugin performs anisotropic LoG filtering. The principle is based on Michael Broadhead
 * http://works.bepress.com/cgi/viewcontent.cgi?article=1017&context=michael_broadhead 
 * 
 * 
 * @license This library is free software; you can redistribute it and/or
 *      modify it under the terms of the GNU Lesser General Public
 *      License as published by the Free Software Foundation; either
 *      version 2.1 of the License, or (at your option) any later version.
 *
 *      This library 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
 *       Lesser General Public License for more details.
 *
 *      You should have received a copy of the GNU Lesser General Public
 *      License along with this library; if not, write to the Free Software
 *      Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

public class ALoG_Filter_ implements ExtendedPlugInFilter, DialogListener, IFilter {

    private PlugInFilterRunner pfr = null;

    final int flags = DOES_ALL + KEEP_PREVIEW + NO_CHANGES;
    private String version = "2.0";
    private int nPasses = 1;
    private int pass;

    public final static String SIGMA = "LOG_sigma", MAX_LEN = "G_MAX", FULL_OUTPUT = "Full_out", LEN = "G_len";

    private static int sz = Prefs.getInt(LEN, 2);
    private int max_sz = Prefs.getInt(MAX_LEN, 8);
    //private static float sigma=(float) Prefs.getDouble(SIGMA, 2.0f);
    private boolean isEnabled = true;

    private float[][] kernel = null;

    private ImagePlus image = null;
    public static boolean debug = IJ.debugMode;

    public boolean fulloutput = false;

    private boolean isFloat = false;

    private boolean hasRoi = false;

    /* NEW VARIABLES*/

    /** A string key identifying this factory. */
    private final String FILTER_KEY = "ALOG";

    /** The pretty name of the target detector. */
    private final String FILTER_NAME = "Anisotropic Laplace of Gaussian";

    private Map<String, String> settings = new HashMap<String, String>();

    private ImageStack imageStack;

    /**
     * 
     */
    /* (non-Javadoc)
     * @see ij.plugin.filter.PlugInFilter#setup(java.lang.String, ij.ImagePlus)
     */
    @Override
    public int setup(String arg, ImagePlus imp) {
        image = imp;
        isFloat = (image.getType() == ImagePlus.GRAY32);
        hasRoi = imp.getRoi() != null;
        cal = image.getCalibration();
        return flags;
    }

    final int Ox = 0, Oy = 1, Oz = 2;

    private boolean doCalib = false;
    private Calibration cal = null;

    /*
     * (non-Javadoc)
     * @see ij.plugin.filter.PlugInFilter#run(ij.process.ImageProcessor)
     */
    @Override
    public void run(ImageProcessor ip) {
        int r = (sz - 1) / 2;
        GScaleSpace sp = new GScaleSpace(r);

        imageStack = new ImageStack(ip.getWidth(), ip.getHeight());

        filter(ip, sp, sz);

        image = new ImagePlus("ALoG result hw=" + ((sz - 1) / 2), imageStack);
        image.show();
    }

    /**
     * Apply filter to input image (in place)
     * @param inputImage input image
     * @param size kernel size (it must be odd)
     * @param nAngles number of angles
     * @return false if error
     */
    public ImageStack applyFilter(ImageProcessor ip) {

        imageStack = new ImageStack(ip.getWidth(), ip.getHeight());
        for (int sigma = sz; sigma <= max_sz; sigma += 2) {
            GScaleSpace sp = new GScaleSpace(sigma);
            filter(ip.duplicate(), sp, sigma);
        }

        return imageStack;
    }

    public void filter(ImageProcessor ip, GScaleSpace sp, float sigma) {

        ip.snapshot();

        if (!isFloat)
            ip = ip.toFloat(0, null);

        pass++;

        //GScaleSpace sp=new GScaleSpace(sigma);
        float[] kernx = sp.gauss1D();
        System.out.println("kernx :" + kernx.length);
        GScaleSpace.flip(kernx);
        float[] kern_diff2 = sp.diff2Gauss1D();
        GScaleSpace.flip(kern_diff2);
        System.out.println("kernx2 :" + kern_diff2.length);
        float[] kern_diff1 = sp.diffGauss1D();
        System.out.println("kernx1:" + kern_diff1.length);
        GScaleSpace.flip(kern_diff1);

        kernel = new float[4][];
        kernel[0] = kernx;
        kernel[1] = kern_diff2;
        kernel[2] = kern_diff1;

        float[] kernel2 = sp.computeDiff2Kernel2D();
        kernel[3] = kernel2;
        GScaleSpace.flip(kernel2); // symmetric but this is the correct way

        int sz = sp.getSize();
        if (debug && pass == 1) {
            FloatProcessor fpkern2 = new FloatProcessor(sz, sz);

            float[][] disp = new float[2][];

            disp[0] = GScaleSpace.joinXY(kernel, 0, 1);
            disp[1] = GScaleSpace.joinXY(kernel, 1, 0);

            for (int i = 0; i < sz * sz; i++)
                fpkern2.setf(i, disp[0][i] + disp[1][i]);

            new ImagePlus("kernel sep", fpkern2).show();

        }

        FloatProcessor fpaux = (FloatProcessor) ip;

        Conv cnv = new Conv();

        FloatProcessor gradx = (FloatProcessor) fpaux.duplicate();
        FloatProcessor grady = (FloatProcessor) fpaux.duplicate();
        FloatProcessor lap_xx = (FloatProcessor) fpaux.duplicate();
        FloatProcessor lap_yy = (FloatProcessor) fpaux.duplicate();
        FloatProcessor lap_xy = (FloatProcessor) fpaux.duplicate();

        cnv.convolveFloat1D(gradx, kern_diff1, Ox);
        cnv.convolveFloat1D(gradx, kernx, Oy);

        cnv.convolveFloat1D(grady, kern_diff1, Oy);
        cnv.convolveFloat1D(grady, kernx, Ox);

        cnv.convolveFloat1D(lap_xx, kern_diff2, Ox);
        cnv.convolveFloat1D(lap_xx, kernx, Oy);

        cnv.convolveFloat1D(lap_yy, kern_diff2, Oy);
        cnv.convolveFloat1D(lap_yy, kernx, Ox);

        cnv.convolveFloat1D(lap_xy, kern_diff1, Oy);
        cnv.convolveFloat1D(lap_xy, kern_diff1, Ox);
        int width = ip.getWidth();
        int height = ip.getHeight();

        FloatProcessor lap_t = new FloatProcessor(width, height); // tangential component
        FloatProcessor lap_o = new FloatProcessor(width, height); // orthogonal component

        for (int i = 0; i < width * height; i++) {
            double gx = gradx.getf(i);
            double gy = grady.getf(i);

            double gxy = lap_xy.getf(i);

            double gxx = lap_xx.getf(i);
            double gyy = lap_yy.getf(i);

            double lx = 2.0f * gx * gy * gxy;

            gx *= gx;
            gy *= gy;
            double dt = gy * gxx + gx * gyy;
            double dx = gx * gxx + gy * gyy;
            //double amp=2.0*(gx+gy);         
            double amp = (gx + gy);

            float lt = (float) ((dt - lx) / amp);
            float ot = (float) ((dx + lx) / amp);
            lap_t.setf(i, lt);
            lap_o.setf(i, ot);

        }

        if (fulloutput) {
            imageStack.addSlice(FILTER_KEY + "X diff" + sigma, gradx);
            imageStack.addSlice(FILTER_KEY + "Y diff" + sigma, grady);
            imageStack.addSlice(FILTER_KEY + "XX diff" + sigma, lap_xx);
            imageStack.addSlice(FILTER_KEY + "YY diff" + sigma, lap_yy);
            imageStack.addSlice(FILTER_KEY + "XY diff" + sigma, lap_xy);
        }

        imageStack.addSlice(FILTER_KEY + "Lap T" + sigma, lap_t);
        lap_o.resetMinAndMax();
        imageStack.addSlice(FILTER_KEY + "Lap O" + sigma, lap_o);
        System.out.println("ALOG_FILTER");

    }

    /**
     * @param i
     * @return
     */
    public float[] getKernel(int i) {
        return kernel[i];
    }

    /* (non-Javadoc)
     * @see ij.plugin.filter.ExtendedPlugInFilter#showDialog(ij.ImagePlus, java.lang.String, ij.plugin.filter.PlugInFilterRunner)
     */
    @Override
    public int showDialog(ImagePlus imp, String command, PlugInFilterRunner pfr) {
        this.pfr = pfr;
        int r = (sz - 1) / 2;
        GenericDialog gd = new GenericDialog("Anisotropic LoG " + version);

        gd.addNumericField("half width", r, 2);
        //gd.addNumericField("sigma", sigma, 1);
        gd.addCheckbox("Show kernel", debug);
        gd.addCheckbox("Full output", fulloutput);
        if (cal != null) {
            if (!cal.getUnit().equals("pixel"))
                gd.addCheckbox("units ( " + cal.getUnit() + " )", doCalib);
        }

        gd.addPreviewCheckbox(pfr);
        gd.addDialogListener(this);
        gd.setResizable(false);
        gd.showDialog();

        //pixundo=imp.getProcessor().getPixelsCopy();
        if (gd.wasCanceled()) {
            return DONE;
        }

        return IJ.setupDialog(imp, flags);
    }

    // Called after modifications to the dialog. Returns true if valid input.
    /* (non-Javadoc)
     * @see ij.gui.DialogListener#dialogItemChanged(ij.gui.GenericDialog, java.awt.AWTEvent)
     */
    public boolean dialogItemChanged(GenericDialog gd, AWTEvent e) {
        double r = (int) (gd.getNextNumber());
        //sigma = (float) (gd.getNextNumber());
        debug = gd.getNextBoolean();
        fulloutput = gd.getNextBoolean();
        if (cal != null)
            doCalib = gd.getNextBoolean();

        if (doCalib) {
            r = (r / cal.pixelWidth);
        }
        sz = (2 * (int) r + 1);
        if (gd.wasCanceled()) {

            return false;
        }
        return r > 0;
        //return sigma>0;
    }

    /* (non-Javadoc)
     * @see ij.plugin.filter.ExtendedPlugInFilter#setNPasses(int)
     */
    @Override
    public void setNPasses(int nPasses) {
        this.nPasses = nPasses;
    }

    /* Saves the current settings of the plugin for further use
     * 
     *
     * @param prefs
     */
    public static void savePreferences(Properties prefs) {
        prefs.put(LEN, Integer.toString(sz));
        // prefs.put(SIGMA, Float.toString(sigma));

    }

    @Override
    public Map<String, String> getDefaultSettings() {

        settings.put(LEN, Integer.toString(sz));
        settings.put(MAX_LEN, Integer.toString(max_sz));
        settings.put(FULL_OUTPUT, Boolean.toString(fulloutput));

        return this.settings;
    }

    @Override
    public boolean reset() {
        // TODO Auto-generated method stub
        sz = Prefs.getInt(LEN, 2);
        max_sz = Prefs.getInt(MAX_LEN, 8);
        fulloutput = Prefs.getBoolean(FULL_OUTPUT, true);
        return true;
    }

    @Override
    public boolean updateSettings(Map<String, String> settingsMap) {
        sz = Integer.parseInt(settingsMap.get(LEN));
        max_sz = Integer.parseInt(settingsMap.get(MAX_LEN));
        fulloutput = Boolean.parseBoolean(settingsMap.get(FULL_OUTPUT));

        return true;
    }

    @Override
    public String getKey() {
        return this.FILTER_KEY;
    }

    @Override
    public String getName() {
        // TODO Auto-generated method stub
        return this.FILTER_NAME;
    }

    /**
     * Get stack size
     * @param sliceNum
     * @return number of slices in the stack
     */
    @Override
    public int getSize() {
        return imageStack.getSize();
    }

    /**
     * Get slice label
     * @param index slice index (from 1 to max size)
     * @return slice label
     */
    @Override
    public String getSliceLabel(int index) {
        return imageStack.getSliceLabel(index);
    }

    /**
     * Get stack height
     * @return stack height
     */
    @Override
    public int getHeight() {
        return imageStack.getHeight();
    }

    /**
     * Get stack width
     * @return stack width
     */
    @Override
    public int getWidth() {
        return imageStack.getWidth();
    }

    private Double log(double x) {

        return (x * x - 2) * Math.exp(-Math.pow(x, 2) / 2) / (2 * Math.sqrt(3.14));
    }

    @Override
    public Image getImage() {

        final XYSeries series = new XYSeries("Data");
        for (double i = -10; i <= 10; i = i + 0.5) {
            Double y = log(i);
            series.add(i, y);
        }
        final XYSeriesCollection data = new XYSeriesCollection(series);
        final JFreeChart chart = ChartFactory.createXYLineChart("", "", "", data, PlotOrientation.VERTICAL, false,
                false, false);

        return chart.createBufferedImage(200, 200);
    }

    @Override
    public boolean isEnabled() {
        // TODO Auto-generated method stub
        return isEnabled;
    }

    @Override
    public void setEnabled(boolean isEnabled) {
        // TODO Auto-generated method stub
        this.isEnabled = isEnabled;
    }

    @Override
    public ImageStack getImageStack() {
        return imageStack;
    }

    @Override
    public void setImageStack(ImageStack imageStack) {
        this.imageStack = imageStack;
    }
}