use of ij.gui.GenericDialog in project GDSC-SMLM by aherbert.
the class PSFDrift method computeDrift.
private void computeDrift() {
// Create a grid of XY offset positions between 0-1 for PSF insert
final double[] grid = new double[gridSize];
for (int i = 0; i < grid.length; i++) grid[i] = (double) i / gridSize;
// Configure fitting region
final int w = 2 * regionSize + 1;
centrePixel = w / 2;
// Check region size using the image PSF
double newPsfWidth = (double) imp.getWidth() / scale;
if (Math.ceil(newPsfWidth) > w)
Utils.log(TITLE + ": Fitted region size (%d) is smaller than the scaled PSF (%.1f)", w, newPsfWidth);
// Create robust PSF fitting settings
final double a = psfSettings.nmPerPixel * scale;
final double sa = PSFCalculator.squarePixelAdjustment(psfSettings.nmPerPixel * (psfSettings.fwhm / Gaussian2DFunction.SD_TO_FWHM_FACTOR), a);
fitConfig.setInitialPeakStdDev(sa / a);
fitConfig.setBackgroundFitting(backgroundFitting);
fitConfig.setNotSignalFitting(false);
fitConfig.setComputeDeviations(false);
fitConfig.setDisableSimpleFilter(true);
// Create the PSF over the desired z-depth
int depth = (int) Math.round(zDepth / psfSettings.nmPerSlice);
int startSlice = psfSettings.zCentre - depth;
int endSlice = psfSettings.zCentre + depth;
int nSlices = imp.getStackSize();
startSlice = (startSlice < 1) ? 1 : (startSlice > nSlices) ? nSlices : startSlice;
endSlice = (endSlice < 1) ? 1 : (endSlice > nSlices) ? nSlices : endSlice;
ImagePSFModel psf = createImagePSF(startSlice, endSlice);
int minz = startSlice - psfSettings.zCentre;
int maxz = endSlice - psfSettings.zCentre;
final int nZ = maxz - minz + 1;
final int gridSize2 = grid.length * grid.length;
total = nZ * gridSize2;
// Store all the fitting results
int nStartPoints = getNumberOfStartPoints();
results = new double[total * nStartPoints][];
// TODO - Add ability to iterate this, adjusting the current offset in the PSF
// each iteration
// Create a pool of workers
int nThreads = Prefs.getThreads();
BlockingQueue<Job> jobs = new ArrayBlockingQueue<Job>(nThreads * 2);
List<Worker> workers = new LinkedList<Worker>();
List<Thread> threads = new LinkedList<Thread>();
for (int i = 0; i < nThreads; i++) {
Worker worker = new Worker(jobs, psf, w, fitConfig);
Thread t = new Thread(worker);
workers.add(worker);
threads.add(t);
t.start();
}
// Fit
Utils.showStatus("Fitting ...");
final int step = Utils.getProgressInterval(total);
outer: for (int z = minz, i = 0; z <= maxz; z++) {
for (int x = 0; x < grid.length; x++) for (int y = 0; y < grid.length; y++, i++) {
if (IJ.escapePressed()) {
break outer;
}
put(jobs, new Job(z, grid[x], grid[y], i));
if (i % step == 0) {
IJ.showProgress(i, total);
}
}
}
// If escaped pressed then do not need to stop the workers, just return
if (Utils.isInterrupted()) {
IJ.showProgress(1);
return;
}
// Finish all the worker threads by passing in a null job
for (int i = 0; i < threads.size(); i++) {
put(jobs, new Job());
}
// Wait for all to finish
for (int i = 0; i < threads.size(); i++) {
try {
threads.get(i).join();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
threads.clear();
IJ.showProgress(1);
IJ.showStatus("");
// Plot the average and SE for the drift curve
// Plot the recall
double[] zPosition = new double[nZ];
double[] avX = new double[nZ];
double[] seX = new double[nZ];
double[] avY = new double[nZ];
double[] seY = new double[nZ];
double[] recall = new double[nZ];
for (int z = minz, i = 0; z <= maxz; z++, i++) {
Statistics statsX = new Statistics();
Statistics statsY = new Statistics();
for (int s = 0; s < nStartPoints; s++) {
int resultPosition = i * gridSize2 + s * total;
final int endResultPosition = resultPosition + gridSize2;
while (resultPosition < endResultPosition) {
if (results[resultPosition] != null) {
statsX.add(results[resultPosition][0]);
statsY.add(results[resultPosition][1]);
}
resultPosition++;
}
}
zPosition[i] = z * psfSettings.nmPerSlice;
avX[i] = statsX.getMean();
seX[i] = statsX.getStandardError();
avY[i] = statsY.getMean();
seY[i] = statsY.getStandardError();
recall[i] = (double) statsX.getN() / (nStartPoints * gridSize2);
}
// Find the range from the z-centre above the recall limit
int centre = 0;
for (int slice = startSlice, i = 0; slice <= endSlice; slice++, i++) {
if (slice == psfSettings.zCentre) {
centre = i;
break;
}
}
if (recall[centre] < recallLimit)
return;
int start = centre, end = centre;
for (int i = centre; i-- > 0; ) {
if (recall[i] < recallLimit)
break;
start = i;
}
for (int i = centre; ++i < recall.length; ) {
if (recall[i] < recallLimit)
break;
end = i;
}
int iterations = 1;
LoessInterpolator loess = null;
if (smoothing > 0)
loess = new LoessInterpolator(smoothing, iterations);
double[][] smoothx = displayPlot("Drift X", "X (nm)", zPosition, avX, seX, loess, start, end);
double[][] smoothy = displayPlot("Drift Y", "Y (nm)", zPosition, avY, seY, loess, start, end);
displayPlot("Recall", "Recall", zPosition, recall, null, null, start, end);
WindowOrganiser wo = new WindowOrganiser();
wo.tileWindows(idList);
// Ask the user if they would like to store them in the image
GenericDialog gd = new GenericDialog(TITLE);
gd.enableYesNoCancel();
gd.hideCancelButton();
startSlice = psfSettings.zCentre - (centre - start);
endSlice = psfSettings.zCentre + (end - centre);
gd.addMessage(String.format("Save the drift to the PSF?\n \nSlices %d (%s nm) - %d (%s nm) above recall limit", startSlice, Utils.rounded(zPosition[start]), endSlice, Utils.rounded(zPosition[end])));
gd.addMessage("Optionally average the end points to set drift outside the limits.\n(Select zero to ignore)");
gd.addSlider("Number_of_points", 0, 10, positionsToAverage);
gd.showDialog();
if (gd.wasOKed()) {
positionsToAverage = Math.abs((int) gd.getNextNumber());
ArrayList<PSFOffset> offset = new ArrayList<PSFOffset>();
final double pitch = psfSettings.nmPerPixel;
int j = 0, jj = 0;
for (int i = start, slice = startSlice; i <= end; slice++, i++) {
j = findCentre(zPosition[i], smoothx, j);
if (j == -1) {
Utils.log("Failed to find the offset for depth %.2f", zPosition[i]);
continue;
}
// The offset should store the difference to the centre in pixels so divide by the pixel pitch
double cx = smoothx[1][j] / pitch;
double cy = smoothy[1][j] / pitch;
jj = findOffset(slice, jj);
if (jj != -1) {
cx += psfSettings.offset[jj].cx;
cy += psfSettings.offset[jj].cy;
}
offset.add(new PSFOffset(slice, cx, cy));
}
addMissingOffsets(startSlice, endSlice, nSlices, offset);
psfSettings.offset = offset.toArray(new PSFOffset[offset.size()]);
psfSettings.addNote(TITLE, String.format("Solver=%s, Region=%d", PeakFit.getSolverName(fitConfig), regionSize));
imp.setProperty("Info", XmlUtils.toXML(psfSettings));
}
}
use of ij.gui.GenericDialog in project GDSC-SMLM by aherbert.
the class PSFDrift method run.
/*
* (non-Javadoc)
*
* @see ij.plugin.PlugIn#run(java.lang.String)
*/
public void run(String arg) {
SMLMUsageTracker.recordPlugin(this.getClass(), arg);
// Build a list of suitable images
List<String> titles = createImageList();
if (titles.isEmpty()) {
IJ.error(TITLE, "No suitable PSF images");
return;
}
if ("hwhm".equals(arg)) {
showHWHM(titles);
return;
}
GenericDialog gd = new GenericDialog(TITLE);
gd.addMessage("Select the input PSF image");
gd.addChoice("PSF", titles.toArray(new String[titles.size()]), title);
gd.addCheckbox("Use_offset", useOffset);
gd.addNumericField("Scale", scale, 2);
gd.addNumericField("z_depth", zDepth, 2, 6, "nm");
gd.addNumericField("Grid_size", gridSize, 0);
gd.addSlider("Recall_limit", 0.01, 1, recallLimit);
gd.addSlider("Region_size", 2, 20, regionSize);
gd.addCheckbox("Background_fitting", backgroundFitting);
String[] solverNames = SettingsManager.getNames((Object[]) FitSolver.values());
gd.addChoice("Fit_solver", solverNames, solverNames[fitConfig.getFitSolver().ordinal()]);
String[] functionNames = SettingsManager.getNames((Object[]) FitFunction.values());
gd.addChoice("Fit_function", functionNames, functionNames[fitConfig.getFitFunction().ordinal()]);
// We need these to set bounds for any bounded fitters
gd.addSlider("Min_width_factor", 0, 0.99, fitConfig.getMinWidthFactor());
gd.addSlider("Width_factor", 1.01, 5, fitConfig.getWidthFactor());
gd.addCheckbox("Offset_fit", offsetFitting);
gd.addNumericField("Start_offset", startOffset, 3);
gd.addCheckbox("Include_CoM_fit", comFitting);
gd.addCheckbox("Use_sampling", useSampling);
gd.addNumericField("Photons", photons, 0);
gd.addSlider("Photon_limit", 0, 1, photonLimit);
gd.addSlider("Smoothing", 0, 0.5, smoothing);
gd.showDialog();
if (gd.wasCanceled())
return;
title = gd.getNextChoice();
useOffset = gd.getNextBoolean();
scale = gd.getNextNumber();
zDepth = gd.getNextNumber();
gridSize = (int) gd.getNextNumber();
recallLimit = gd.getNextNumber();
regionSize = (int) Math.abs(gd.getNextNumber());
backgroundFitting = gd.getNextBoolean();
fitConfig.setFitSolver(gd.getNextChoiceIndex());
fitConfig.setFitFunction(gd.getNextChoiceIndex());
fitConfig.setMinWidthFactor(gd.getNextNumber());
fitConfig.setWidthFactor(gd.getNextNumber());
offsetFitting = gd.getNextBoolean();
startOffset = Math.abs(gd.getNextNumber());
comFitting = gd.getNextBoolean();
useSampling = gd.getNextBoolean();
photons = Math.abs(gd.getNextNumber());
photonLimit = Math.abs(gd.getNextNumber());
smoothing = Math.abs(gd.getNextNumber());
if (!comFitting && !offsetFitting) {
IJ.error(TITLE, "No initial fitting positions");
return;
}
if (regionSize < 1)
regionSize = 1;
if (gd.invalidNumber())
return;
GlobalSettings settings = new GlobalSettings();
settings.setFitEngineConfiguration(new FitEngineConfiguration(fitConfig));
if (!PeakFit.configureFitSolver(settings, null, false, true))
return;
imp = WindowManager.getImage(title);
if (imp == null) {
IJ.error(TITLE, "No PSF image for image: " + title);
return;
}
psfSettings = getPSFSettings(imp);
if (psfSettings == null) {
IJ.error(TITLE, "No PSF settings for image: " + title);
return;
}
computeDrift();
}
use of ij.gui.GenericDialog in project GDSC-SMLM by aherbert.
the class OverlayImage method addImage.
/**
* Adapted from ij.plugins.OverlayCommands#addImage(boolean) with the additional option for setting the zero pixels
* to transparent.
*/
void addImage() {
ImagePlus imp = IJ.getImage();
int[] wList = WindowManager.getIDList();
if (wList == null || wList.length < 2) {
IJ.error("Add Image...", "The command requires at least two open images.");
return;
}
String[] titles = new String[wList.length];
int count = 0;
for (int i = 0; i < wList.length; i++) {
ImagePlus imp2 = WindowManager.getImage(wList[i]);
if (imp2 != null && imp2 != imp && imp.getWidth() >= imp2.getWidth() && imp.getHeight() >= imp2.getHeight())
titles[count++] = imp2.getTitle();
}
if (count < 1) {
IJ.error("Add Image...", "The command requires at least one valid overlay image.");
return;
}
titles = Arrays.copyOf(titles, count);
int x = 0, y = 0;
Roi roi = imp.getRoi();
if (roi != null && roi.isArea()) {
Rectangle r = roi.getBounds();
x = r.x;
y = r.y;
}
GenericDialog gd = new GenericDialog("Add Image...");
gd.addChoice("Image to add:", titles, title);
gd.addNumericField("X location:", x, 0);
gd.addNumericField("Y location:", y, 0);
gd.addNumericField("Opacity (0-100%):", opacity, 0);
gd.addCheckbox("Transparent background", transparent);
gd.addCheckbox("Replace overlay", replace);
gd.showDialog();
if (gd.wasCanceled())
return;
title = gd.getNextChoice();
x = (int) gd.getNextNumber();
y = (int) gd.getNextNumber();
opacity = (int) gd.getNextNumber();
transparent = gd.getNextBoolean();
replace = gd.getNextBoolean();
ImagePlus overlay = WindowManager.getImage(title);
if (overlay == imp) {
IJ.error("Add Image...", "Image to be added cannot be the same as\n\"" + imp.getTitle() + "\".");
return;
}
if (overlay.getWidth() > imp.getWidth() && overlay.getHeight() > imp.getHeight()) {
IJ.error("Add Image...", "Image to be added cannnot be larger than\n\"" + imp.getTitle() + "\".");
return;
}
ImageRoi roi2 = new ImageRoi(x, y, overlay.getProcessor());
roi2.setZeroTransparent(transparent);
roi2.setName(overlay.getShortTitle());
if (opacity != 100)
roi2.setOpacity(opacity / 100.0);
Overlay overlayList = imp.getOverlay();
if (overlayList == null || replace)
overlayList = new Overlay();
overlayList.add(roi2);
imp.setOverlay(overlayList);
Undo.setup(Undo.OVERLAY_ADDITION, imp);
}
use of ij.gui.GenericDialog in project GDSC-SMLM by aherbert.
the class PSFCreator method subtractBackgroundAndWindow.
/**
* Subtract the background from the spot, compute the intensity within half the box region distance from the centre
* and smooth the intensity profile. In interactive mode the user must choose to accept the profile or reject.
* If accepted the smoothed profile is user to normalise the image and then the image is rolled off to zero
* using a Tukey window function.
*
* @param spot
* @param background
* The minimum level, all below this is background and set to zero
* @param spotWidth
* @param spotHeight
* @param n
* The spot number
* @param loess
* The smoothing interpolator
* @return True if accepted
*/
private boolean subtractBackgroundAndWindow(float[][] spot, final float background, final int spotWidth, final int spotHeight, double[] centre, LoessInterpolator loess) {
//ImageWindow imageWindow = new ImageWindow();
for (int i = 0; i < spot.length; i++) {
for (int j = 0; j < spot[i].length; j++) spot[i][j] = FastMath.max(spot[i][j] - background, 0);
}
// Create a distance map from the centre
if (lastWidth != spotWidth || lastHeight != spotHeight) {
final double cx = spotWidth * 0.5;
final double cy = spotHeight * 0.5;
minx = FastMath.max(0, (int) (cx - boxRadius * 0.5));
maxx = FastMath.min(spotWidth, (int) Math.ceil(cx + boxRadius * 0.5));
miny = FastMath.max(0, (int) (cy - boxRadius * 0.5));
maxy = FastMath.min(spotHeight, (int) Math.ceil(cy + boxRadius * 0.5));
// Precompute square distances
double[] dx2 = new double[maxx - minx + 1];
for (int x = minx, i = 0; x < maxx; x++, i++) {
// Use pixel centres with 0.5 offset
final double dx = x + 0.5 - cx;
dx2[i] = dx * dx;
}
dmap = new boolean[dx2.length * (maxy - miny + 1)];
final double d2 = boxRadius * boxRadius / 4;
for (int y = miny, j = 0; y < maxy; y++) {
final double dy = (y + 0.5 - cy);
final double dy2 = dy * dy;
final double limit = d2 - dy2;
for (int x = minx, i = 0; x < maxx; x++, i++, j++) {
dmap[j] = (dx2[i] < limit);
}
}
lastWidth = spotWidth;
lastHeight = spotHeight;
}
// Calculate the intensity profile within half the box radius from the centre
double[] xValues = new double[spot.length];
double[] yValues = new double[spot.length];
for (int i = 0; i < spot.length; i++) {
xValues[i] = i + 1;
double sum = 0;
for (int y = miny, j = 0; y < maxy; y++) {
int index = y * spotWidth + minx;
for (int x = minx; x < maxx; x++, index++, j++) if (dmap[j])
sum += spot[i][index];
}
yValues[i] = sum;
}
double[] newY = loess.smooth(xValues, yValues);
// falls towards zero at the ends)
for (int i = 0; i < newY.length; i++) if (newY[i] < 0)
newY[i] = yValues[i];
if (interactiveMode) {
Utils.hide(TITLE_AMPLITUDE);
Utils.hide(TITLE_PSF_PARAMETERS);
final int n = (int) centre[4];
String title = TITLE_INTENSITY;
Plot plot = new Plot(title, "Slice", "Sum", xValues, yValues);
plot.setColor(Color.red);
plot.addPoints(xValues, newY, Plot.LINE);
plot.setColor(Color.green);
double[] limits = Maths.limits(yValues);
plot.drawLine(centre[2], limits[0], centre[2], limits[1]);
plot.setColor(Color.black);
plot.addLabel(0, 0, "Spot " + n);
Utils.display(title, plot);
GenericDialog gd = new GenericDialog(TITLE);
gd.enableYesNoCancel();
gd.hideCancelButton();
gd.addMessage(String.format("Add spot %d to the PSF?\n(The intensity profile is the sum within half the box region)", n));
if (yesNoPosition != null) {
gd.centerDialog(false);
gd.setLocation(yesNoPosition);
}
gd.showDialog();
yesNoPosition = gd.getLocation();
if (!gd.wasOKed())
return false;
}
for (int i = 0; i < spot.length; i++) {
// Normalise
final float scale = (float) (newY[i] / yValues[i]);
for (int j = 0; j < spot[i].length; j++) spot[i][j] *= scale;
// Use a Tukey window to roll-off the image edges
//spot[i] = imageWindow.applySeperable(spot[i], spotWidth, spotHeight, ImageWindow.WindowFunction.Tukey);
spot[i] = ImageWindow.applyWindow(spot[i], spotWidth, spotHeight, ImageWindow.WindowFunction.TUKEY);
}
return true;
}
use of ij.gui.GenericDialog in project GDSC-SMLM by aherbert.
the class ImageBackground method showDialog.
private int showDialog() {
GenericDialog gd = new GenericDialog(TITLE);
gd.addHelp(About.HELP_URL);
gd.addMessage("Creates a background and mask image from a sample input stack\nusing a median projection");
gd.addNumericField("Bias", bias, 0);
gd.addSlider("Blur", 0, 20, sigma);
gd.showDialog();
if (gd.wasCanceled())
return DONE;
bias = (float) gd.getNextNumber();
sigma = gd.getNextNumber();
// Check arguments
try {
Parameters.isPositive("Bias", bias);
} catch (IllegalArgumentException e) {
IJ.error(TITLE, e.getMessage());
return DONE;
}
return flags;
}
Aggregations