scalespace.filter.BoG_Filter_.java Source code

Java tutorial

Introduction

Here is the source code for scalespace.filter.BoG_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.gui.Roi;
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.GScaleSpace;

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.6    23 Aug 2016
 *              1.5      date 23 Sept 2013
 *            - isotropic correction
 *             1.0      date 23 Jul 2013 
 *             Based on Mexican_Hat_Filter v 2.2
 *             - common functionality is refactored in a library class
 *             
 *   
 * 
 * @author Dimiter Prodanov IMEC  & Sumit Kumar Vohra
 *
 *
 * @contents
 * This pluign convolves an image with a Bi-Laplacian of Gaussian (BoG) filter
 * 
 * 
 * @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 BoG_Filter_ implements ExtendedPlugInFilter, DialogListener, IFilter {

    private PlugInFilterRunner pfr = null;

    final int flags = DOES_ALL + SUPPORTS_MASKING + KEEP_PREVIEW;
    private String version = "1.5";
    private int nPasses = 1;
    private int pass;

    public final static String SIGMA = "LOG_sigma", LEN = "G_len", MAX_LEN = "G_MAX", ISO = "G_iso",
            ISSEP = "G_SEP";

    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 float[][] kernel = null;

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

    public static boolean sep = Prefs.getBoolean(ISSEP, false);
    private static boolean isiso = Prefs.getBoolean(ISO, true);
    private boolean isEnabled = true;

    public boolean isFloat = false;

    private boolean hasRoi = false;

    /* NEW VARIABLES*/

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

    /** The pretty name of the target detector. */
    private final String FILTER_NAME = "Bi-Laplacian 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;
        return flags;
    }

    /*
     * (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);
        GScaleSpace sp = new GScaleSpace(r, 3.0f);
        FloatProcessor fp = filter(ip, sp, sep, isiso);
        image.setProcessor(fp);
        image.updateAndDraw();
    }

    /**
     * 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);
            ImageProcessor fp = filter(ip.duplicate(), sp, sep, isiso);
            imageStack.addSlice(FILTER_KEY + "_" + sigma, fp);
        }

        return imageStack;
    }

    public FloatProcessor filter(ImageProcessor ip, GScaleSpace sp, final boolean seperable,
            final boolean isotropic) {

        ip.snapshot();

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

        pass++;

        float[] kernx = sp.gauss1D();
        GScaleSpace.flip(kernx);

        float[] kern_diff_4 = sp.diffNGauss1D(4);
        GScaleSpace.flip(kern_diff_4);

        float[] kern_diff_2 = sp.diffNGauss1D(2);
        GScaleSpace.flip(kern_diff_2);

        kernel = new float[4][];
        kernel[0] = kernx;
        kernel[1] = kern_diff_4;
        kernel[2] = kern_diff_2;
        float[] kernel2 = sp.computeLapNKernel2D(2); // 2D kernel computation
        kernel[3] = kernel2;

        int sz = sp.getSize();

        if (debug)
            System.out.println("sz " + sz);

        float[][] disp = new float[3][];

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

        if (debug && pass == 1) {
            FloatProcessor fp = new FloatProcessor(sz, sz);
            if (isotropic) {
                disp[2] = GScaleSpace.joinXY(kernel, 2, 2);
                for (int i = 0; i < sz * sz; i++)
                    fp.setf(i, disp[0][i] + disp[1][i] + 2 * disp[2][i]);

            } else {
                for (int i = 0; i < sz * sz; i++)
                    fp.setf(i, disp[0][i] + disp[1][i]);
            }
            new ImagePlus("kernel sep", fp).show();
            if (!seperable) {
                FloatProcessor fp2 = new FloatProcessor(sz, sz, kernel2);
                new ImagePlus("kernel 2D", fp2).show();
            }
        }
        long time = -System.nanoTime();

        FloatProcessor fpaux = (FloatProcessor) ip;

        Conv cnv = new Conv();
        if (seperable) {
            if (isotropic) {
                FloatProcessor fpauxiso = (FloatProcessor) fpaux.duplicate();

                cnv.convolveSemiSep(fpaux, kernx, kern_diff_4);
                for (int i = 0; i < kern_diff_2.length; i++)
                    kern_diff_2[i] *= Math.sqrt(2.0);
                cnv.convolveFloat1D(fpauxiso, kern_diff_2, 0); //Ox
                cnv.convolveFloat1D(fpauxiso, kern_diff_2, 1); //Oy

                fpaux.copyBits(fpauxiso, 0, 0, Blitter.ADD);
                System.out.println("separable & isotropic computation");
            } else {
                cnv.convolveSemiSep(fpaux, kernx, kern_diff_4);
                System.out.println("separable & non-isotropic computation");
            }
        } else {
            if (isotropic) {
                System.out.println("non-separable & isotropic computation");
            } else {
                for (int i = 0; i < sz * sz; i++)
                    kernel2[i] = disp[0][i] + disp[1][i];
                System.out.println("non-separable & non-isotropic computation");
            } // end else
            cnv.convolveFloat(fpaux, kernel2, sz, sz);
        } // end else

        time += System.nanoTime();
        time /= 1000.0f;
        System.out.println("elapsed time: " + time + " us");
        fpaux.resetMinAndMax();

        /*if (convert) {
           float[] minmax=findMinAndMax(fpaux);
           final double d1 = -(fmin* minmax[1] - fmax* minmax[0])/(fmin - fmax);
           dr = dr/ (minmax[1] - minmax[0]);
           System.out.println("contrast adjustment y=ax+b \n " +
           " b " +d1 +" a " + dr);
            
           contrastAdjust(fpaux, dr, d1);
        }*/

        return fpaux;

    }

    /**
     * @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("Bi-LoG (BoG) " + version);
        gd.addNumericField("half width", r, 1);
        //gd.addNumericField("sigma", sigma, 1);
        gd.addCheckbox("Show kernel", debug);
        gd.addCheckbox("Separable", sep);
        gd.addCheckbox("isotropic", isiso);
        /*if (hasRoi)
           gd.addCheckbox("Brightness correct", true);*/

        gd.addPreviewCheckbox(pfr);
        gd.addDialogListener(this);
        gd.showDialog();
        pixundo = imp.getProcessor().getPixelsCopy();
        if (gd.wasCanceled()) {
            //image.repaintWindow();
            return DONE;
        }
        /*if (!IJ.isMacro())
           staticSZ = sz;*/
        return IJ.setupDialog(imp, flags);
    }

    private Object pixundo;
    //private boolean convert=false;

    // 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) {
        int r = (int) (gd.getNextNumber());
        //sigma = (float) (gd.getNextNumber());
        debug = gd.getNextBoolean();
        sep = gd.getNextBoolean();
        isiso = gd.getNextBoolean();
        //convert=gd.getNextBoolean();

        sz = 2 * r + 1;
        if (gd.wasCanceled()) {
            ImageProcessor proc = image.getProcessor();
            proc.setPixels(pixundo);
            proc.resetMinAndMax();
            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(ISO, Boolean.toString(isiso));
        prefs.put(ISSEP, Boolean.toString(sep));
        // 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(ISSEP, Boolean.toString(sep));
        settings.put(ISO, Boolean.toString(isiso));

        return this.settings;
    }

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

        return true;
    }

    @Override
    public boolean reset() {
        // TODO Auto-generated method stub
        sz = Prefs.getInt(LEN, 2);
        max_sz = Prefs.getInt(MAX_LEN, 8);
        sep = Prefs.getBoolean(ISSEP, true);
        isiso = Prefs.getBoolean(ISO, true);
        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 bog(double x) {

        return (Math.pow(x, 4) - 8 * (x * x) + 8) * 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 = bog(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;
    }

}