DicLidReconstruction_.java
package com.github.celldynamics.quimp.plugin.dic;
import java.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.github.celldynamics.quimp.plugin.IQuimpPluginFilter;
import com.github.celldynamics.quimp.plugin.ParamList;
import com.github.celldynamics.quimp.plugin.QuimpPluginException;
import com.github.celldynamics.quimp.registration.Registration;
import com.github.celldynamics.quimp.utils.QuimPArrayUtils;
import ij.IJ;
import ij.ImagePlus;
import ij.ImageStack;
import ij.gui.GenericDialog;
import ij.process.ImageProcessor;
import ij.process.ShortProcessor;
/**
* Main implementation of ImageJ plugin.
*
* <p>Currently supports only 8bit images and stacks.
*
* @author p.baniukiewicz
* @see LidReconstructor
*/
public class DicLidReconstruction_ implements IQuimpPluginFilter {
/**
* The Constant LOGGER.
*/
static final Logger LOGGER = LoggerFactory.getLogger(DicLidReconstruction_.class.getName());
private LidReconstructor dic;
private ImagePlus imp;
/**
* Filled by {@link #showUi(boolean)}.
*/
private double angle;
/**
* Filled by {@link #showUi(boolean)}.
*/
private double decay;
/**
* Filled by {@link #showUi(boolean)}.
*/
private int masksize;
/**
* Angle of filtering.
*
* <p>Filled by {@link #showUi(boolean)} as {@link #angle}+90.
*/
private String prefilterangle;
/**
* Output image inversion.
*
* <p>Filled by {@link #showUi(boolean)}
*/
private boolean invertOutput;
/*
* (non-Javadoc)
*
* @see ij.plugin.filter.PlugInFilter#setup(java.lang.String, ij.ImagePlus)
*/
@Override
public int setup(String arg, ImagePlus imp) {
this.imp = imp;
return DOES_8G + NO_CHANGES;
}
/*
* (non-Javadoc)
*
* @see com.github.celldynamics.quimp.plugin.IQuimpCorePlugin#setup()
*/
@Override
public int setup() {
return 0;
}
/**
* This method is run when current image was accepted and input data were correct.
*
* @param ip is the current slice
*/
@Override
public void run(ImageProcessor ip) {
// validate registered user
new Registration(IJ.getInstance(), "QuimP Registration");
ImageProcessor ret;
if (showUi(true) == 0) {
return; // if user clicked Cancel or data were not valid
}
try {
// create result as separate 16bit image
ImagePlus result = new ImagePlus("DIC_" + imp.getTitle(),
new ShortProcessor(ip.getWidth(), ip.getHeight()));
dic = new LidReconstructor(imp.getProcessor(), decay, angle, prefilterangle, masksize);
if (imp.getStack().getSize() == 1) { // if there is no stack we can avoid additional rotation
// here (see DICReconstruction documentation)
IJ.showProgress(0.0);
ret = dic.reconstructionDicLid();
if (invertOutput) {
ret.invert();
}
result.getProcessor().setPixels(ret.getPixels());
IJ.showProgress(1.0);
result.show();
} else { // we have stack. Process slice by slice
// create result stack
ImageStack resultstack = new ImageStack(imp.getWidth(), imp.getHeight());
ImageStack stack = imp.getStack();
for (int s = 1; s <= stack.getSize(); s++) {
IJ.showProgress(s / ((double) stack.getSize() + 1));
dic.setIp(stack.getProcessor(s));
ret = dic.reconstructionDicLid();
if (invertOutput) {
ret.invert();
}
resultstack.addSlice(ret);
}
IJ.showProgress(1.0);
// pack in ImagePlus
new ImagePlus("DIC_" + imp.getTitle(), resultstack).show();
}
} catch (DicException e) { // exception can be thrown if input image is 16-bit and saturated
IJ.log(e.getMessage());
LOGGER.debug(e.getMessage(), e);
LOGGER.error("Problem with DIC reconstruction: " + e.getMessage());
} finally {
imp.updateAndDraw();
}
}
/**
* Round given angle to closest full angle: 0, 45, 90, 135
*
* @param angle input angle in range <0;360)
* @return full anlge as string. Can be 0, 45, 90, 135
*/
String roundtofull(double angle) {
int anglei = (int) angle; // cut fractions
if (anglei >= 180) {
anglei -= 180;
}
// calculate distances between 0, 45, 90, 135, 180
Integer[] d = new Integer[5];
d[0] = Math.abs(0 - anglei);
d[1] = Math.abs(45 - anglei);
d[2] = Math.abs(90 - anglei);
d[3] = Math.abs(135 - anglei);
d[4] = Math.abs(180 - anglei);
// min distance
int i = QuimPArrayUtils.minListIndex(Arrays.asList(d));
i = i > 3 ? 0 : i; // deal with 180 that should be 0
return Integer.toString(i * 45);
}
/*
* (non-Javadoc)
*
* @see
* IQuimpCorePlugin#setPluginConfig(com.github.celldynamics.quimp.
* plugin.ParamList)
*/
@Override
public void setPluginConfig(ParamList par) throws QuimpPluginException {
}
/*
* (non-Javadoc)
*
* @see com.github.celldynamics.quimp.plugin.IQuimpCorePlugin#getPluginConfig()
*/
@Override
public ParamList getPluginConfig() {
return null;
}
/**
* Shows user dialog and check conditions.
*
* @return 1 if user clicked OK and input data are correct (they are numbers) or return 0
* otherwise
*/
@Override
public int showUi(boolean val) {
GenericDialog gd = new GenericDialog("DIC reconstruction");
gd.addMessage("Reconstruction of DIC image by Line Integrals.\n");
gd.addNumericField("Shear angle (measured counterclockwise)", 45.0, 0, 6, "[deg]");
gd.addNumericField("Decay factor (>0)", 0.0, 2, 6, "[-]");
// gd.addChoice("Angle perpendicular to shear", new String[] { "0", "45", "90", "135" },
// "45");
gd.addNumericField("Filter mask size (odd, 0 to switch filtering off)", 0, 0);
gd.addCheckbox("Invert output", false);
gd.setResizable(false);
gd.showDialog();
if (gd.wasCanceled()) {
return 0;
}
// read GUI elements and store results in private fields order as these
// methods are called should match to GUI build order
angle = Math.abs(gd.getNextNumber());
if (angle >= 360) {
angle -= 360;
}
decay = gd.getNextNumber();
prefilterangle = roundtofull(angle + 90); // filtering angle
masksize = (int) gd.getNextNumber();
invertOutput = gd.getNextBoolean();
if (gd.invalidNumber()) { // check if numbers in fields were correct
IJ.error("One of the numbers in dialog box is not valid");
return 0;
}
if (masksize != 0 && masksize % 2 == 0) {
IJ.error("Mask size must be uneven");
return 0;
}
return 1;
}
/*
* (non-Javadoc)
*
* @see com.github.celldynamics.quimp.plugin.IQuimpCorePlugin#getVersion()
*/
@Override
public String getVersion() {
return "See QuimP version";
}
/*
* (non-Javadoc)
*
* @see com.github.celldynamics.quimp.plugin.IQuimpCorePlugin#about()
*/
@Override
public String about() {
return "DIC plugin.\n" + "Author: Piotr Baniukiewicz\n" + "mail: p.baniukiewicz@warwick.ac.uk\n"
+ "This plugin supports macro parameters\n" + "Check macro recorder";
}
}