use of ij.gui.GenericDialog in project GDSC-SMLM by aherbert.
the class PsfCombiner method combineImages.
private void combineImages() {
final double nmPerPixel = getNmPerPixel();
if (nmPerPixel <= 0) {
return;
}
final double nmPerSlice = getNmPerSlice();
if (nmPerPixel <= 0) {
return;
}
// Find the lowest & highest dimensions
int minStart = Integer.MAX_VALUE;
int maxStart = Integer.MIN_VALUE;
int minEnd = Integer.MAX_VALUE;
int maxEnd = Integer.MIN_VALUE;
int minSize = Integer.MAX_VALUE;
int maxSize = 0;
for (final Psf psf : input) {
if (minStart > psf.start) {
minStart = psf.start;
}
if (maxStart < psf.start) {
maxStart = psf.start;
}
if (maxEnd < psf.getEnd()) {
maxEnd = psf.getEnd();
}
if (minEnd > psf.getEnd()) {
minEnd = psf.getEnd();
}
if (maxSize < psf.getSize()) {
maxSize = psf.getSize();
}
if (minSize > psf.getSize()) {
minSize = psf.getSize();
}
}
int size = maxSize;
int shift = -minStart;
int depth = maxEnd - minStart + 1;
// Option to crop. Do this before processing as it will make the plugin faster
if (minStart < maxStart || minEnd < maxEnd || minSize < maxSize) {
boolean crop;
if (ImageJUtils.isMacro()) {
final String options = Macro.getOptions();
crop = options.contains(" crop");
} else {
final GenericDialog gd = new GenericDialog(TITLE);
ImageJUtils.addMessage(gd, "The range of the PSFs is different:\nStart %d to %d\nEnd %d to %d\n" + "Size %d to %d\n \nCrop to the smallest?", minStart, maxStart, minEnd, maxEnd, minSize, maxSize);
gd.enableYesNoCancel();
gd.addHelp(HelpUrls.getUrl("psf-combiner"));
gd.showDialog();
if (gd.wasCanceled()) {
return;
}
crop = gd.wasOKed();
}
if (crop) {
Recorder.recordOption("crop");
for (final Psf psf : input) {
psf.crop(maxStart, minEnd, minSize);
}
size = minSize;
shift = -maxStart;
depth = minEnd - maxStart + 1;
}
}
// Shift all stacks
int totalImages = 0;
for (final Psf psf : input) {
psf.start += shift;
totalImages += psf.psfSettings.getImageCount();
}
// Create a stack to hold all the images
// Create a stack to hold the sum of the weights
final ImageStack stack = new ImageStack(size, size, depth);
final ImageStack stackW = new ImageStack(size, size, depth);
for (int n = 1; n <= depth; n++) {
stack.setPixels(new float[size * size], n);
stackW.setPixels(new float[size * size], n);
}
// Insert all the PSFs
IJ.showStatus("Creating combined image ...");
int imageNo = 0;
final double fraction = 1.0 / input.size();
for (final Psf psf : input) {
double progress = imageNo * fraction;
final ImageStack psfStack = psf.psfStack;
final int w = psf.getSize();
final int offsetXy = (size - w) / 2;
final int offsetZ = psf.start;
final double weight = (1.0 * psf.psfSettings.getImageCount()) / totalImages;
final FloatProcessor wp = new FloatProcessor(w, w, SimpleArrayUtils.newFloatArray(psfStack.getWidth() * psfStack.getHeight(), (float) weight));
final double increment = fraction / psfStack.getSize();
for (int n = 1; n <= psfStack.getSize(); n++) {
progress += increment;
IJ.showProgress(progress);
// Get the data and adjust using the weight
final float[] psfData = ImageJImageConverter.getData(psfStack.getProcessor(n));
for (int i = 0; i < psfData.length; i++) {
psfData[i] *= weight;
}
// Insert into the combined PSF
final int slice = n + offsetZ;
ImageProcessor ip = stack.getProcessor(slice);
ip.copyBits(new FloatProcessor(w, w, psfData), offsetXy, offsetXy, Blitter.ADD);
// Insert the weights
ip = stackW.getProcessor(slice);
ip.copyBits(wp, offsetXy, offsetXy, Blitter.ADD);
}
imageNo++;
}
// Normalise
for (int n = 1; n <= depth; n++) {
stack.getProcessor(n).copyBits(stackW.getProcessor(n), 0, 0, Blitter.DIVIDE);
}
ImageJUtils.finished();
final ImagePlus imp = ImageJUtils.display("Combined PSF", stack);
imp.setSlice(1 + shift);
imp.resetDisplayRange();
imp.updateAndDraw();
final double fwhm = getFwhm();
imp.setProperty("Info", ImagePsfHelper.toString(ImagePsfHelper.create(imp.getSlice(), nmPerPixel, nmPerSlice, totalImages, fwhm)));
ImageJUtils.log("%s : z-centre = %d, nm/Pixel = %s, nm/Slice = %s, %d images, FWHM = %s\n", imp.getTitle(), imp.getSlice(), MathUtils.rounded(nmPerPixel), MathUtils.rounded(nmPerSlice), totalImages, MathUtils.rounded(fwhm));
}
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 the spot
* @param background The minimum level, all below this is background and set to zero
* @param spotWidth the spot width
* @param spotHeight the spot height
* @param centre the centre
* @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] = Math.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 = Math.max(0, (int) (cx - boxRadius * 0.5));
maxx = Math.min(spotWidth, (int) Math.ceil(cx + boxRadius * 0.5));
miny = Math.max(0, (int) (cy - boxRadius * 0.5));
maxy = Math.min(spotHeight, (int) Math.ceil(cy + boxRadius * 0.5));
// Precompute square distances
final 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 int halfBoxRadius = boxRadius / 2;
final double d2 = halfBoxRadius * halfBoxRadius;
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
final double[] xValues = new double[spot.length];
final 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;
}
final 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 (settings.getInteractiveMode()) {
ImageJUtils.hide(TITLE_AMPLITUDE);
ImageJUtils.hide(TITLE_PSF_PARAMETERS);
final int n = (int) centre[4];
final String title = TITLE_INTENSITY;
final Plot plot = new Plot(title, "Slice", "Sum");
plot.addPoints(xValues, yValues, Plot.LINE);
plot.setColor(Color.red);
plot.addPoints(xValues, newY, Plot.LINE);
plot.setColor(Color.green);
final double[] limits = MathUtils.limits(yValues);
plot.drawLine(centre[2], limits[0], centre[2], limits[1]);
plot.setColor(Color.black);
plot.addLabel(0, 0, "Spot " + n);
ImageJUtils.display(title, plot);
final GenericDialog gd = new GenericDialog(TITLE);
gd.enableYesNoCancel();
gd.hideCancelButton();
ImageJUtils.addMessage(gd, "Add spot %d to the PSF?\n(The intensity profile is the sum within half the box region)", n);
final Point previousPoint = yesNoPosition.get();
if (previousPoint != null) {
gd.centerDialog(false);
gd.setLocation(previousPoint);
}
gd.showDialog();
yesNoPosition.set(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.WindowMethod.TUKEY);
}
return true;
}
use of ij.gui.GenericDialog in project GDSC-SMLM by aherbert.
the class PixelFilter method showDialog.
@Override
public int showDialog(ImagePlus imp, String command, PlugInFilterRunner pfr) {
this.pfr = pfr;
preview = true;
final GenericDialog gd = new GenericDialog(TITLE);
gd.addHelp(HelpUrls.getUrl("pixel-filter"));
gd.addMessage("Replace pixels with mean if they are N StdDevs from the mean");
settings = Settings.load();
settings.save();
gd.addSlider("Radius", 1, 5, settings.radius);
gd.addSlider("Error (SD units)", 2.5, 7, settings.error);
gd.addPreviewCheckbox(pfr);
gd.addDialogListener(this);
gd.addMessage("");
label = (Label) gd.getMessage();
gd.showDialog();
if (gd.wasCanceled() || !dialogItemChanged(gd, null)) {
return DONE;
}
preview = false;
cachedRollingSum = cachedRollingSumSq = null;
label = null;
return IJ.setupDialog(imp, FLAGS);
}
use of ij.gui.GenericDialog in project GDSC-SMLM by aherbert.
the class TcPalmAnalysis method analyseRois.
/**
* Analyses all the ROIs in the ROI manager.
*
* @param event the event
*/
private void analyseRois(ActionEvent event) {
final RoiManager manager = RoiManager.getInstance();
if (manager == null) {
IJ.error(TITLE, "ROI manager is not open");
return;
}
final LocalList<Roi> rois = Arrays.stream(manager.getRoisAsArray()).filter(Roi::isArea).collect(LocalCollectors.toLocalList());
if (rois.isEmpty()) {
IJ.error(TITLE, "No area ROIs");
return;
}
// Check for overlaps.
if (!settings.getDisableOverlapCheck() && anyOverlap(rois)) {
final GenericDialog gd = new GenericDialog(TITLE);
gd.addMessage(TextUtils.wrap("WARNING - Bounding rectangles of ROIs overlap. You can verify " + "the ROIs on the image using the ROI manager 'Show all' function.", 80));
gd.setOKLabel("Continue");
gd.showDialog();
if (gd.wasCanceled()) {
return;
}
}
// For each ROI:
// - Extract the current groups
// - Build the cumulative count plot
// - Identify the bursts
// - Extract ClusterData for each burst
final TcPalmAnalysisSettings settings = this.settings.build();
final LocalList<ClusterData> allClusters = rois.parallelStream().map(roi -> {
final Rectangle2D scaledBounds = createScaledBounds(roi);
final BiPredicate<ClusterData, Rectangle2D> filter = createSelectionFilter(roi, settings);
// Filter all cluster groups
final LocalList<ClusterData> clusters = new LocalList<>();
clusterData.forEach(c -> {
if (filter.test(c, scaledBounds)) {
clusters.add(c);
}
});
// Extract activation bursts
final CumulativeCountData countData = createCumulativeCountData(clusters, false);
final LocalList<int[]> bursts = runBurstAnalysis(settings, countData);
final LocalList<LocalList<PeakResult>> burstLocalisations = createBurstLocalisations(clusters, bursts);
clusters.clear();
burstLocalisations.forEach(list -> {
final ClusterData d = new ClusterData(clusters.size() + 1, list);
// Save this for analysis
d.sourceRoi = roi;
d.getArea();
clusters.add(d);
});
return clusters;
}).collect(LocalList::new, LocalList::addAll, LocalList::addAll);
// Reorder
final Counter count = new Counter();
allClusters.forEach(c -> c.id = count.incrementAndGet());
// Display in a table
final ClusterDataTableModelFrame frame = createAllClustersTable();
frame.getModel().setData(allClusters, dataCalibration);
// Allow the results to be repeated
frame.selectedAction = clusters -> {
// Expecting a single cluster. No clusters occurs when the table (and selection) is cleared.
if (clusters.size() == 1) {
final ClusterData c = clusters.get(0);
// Push the correct ROI and settings to the analysis action.
// We do not directly update the ROI or dialog settings as
// these trigger events that are processed to add work with a delay.
// Updating them at the end should generate events that are
// ignored when finally executed as the ROI/settings should be the same.
addWork(0, c.sourceRoi, settings, () -> {
// When analysis has finished update the settings and image ROI.
image.getImagePlus().setRoi(c.sourceRoi);
darkTimeToleranceTextField.setText(Integer.toString(settings.getDarkTimeTolerance()));
minClusterSizeTextField.setText(Integer.toString(settings.getMinClusterSize()));
// When analysis has finished the cluster should be selected in the
// current clusters table.
final ClusterDataTableModelFrame currentClusters = currentClustersTable.get();
if (currentClusters != null) {
currentClusters.select(c);
}
});
}
};
// Show histogram of cluster size/duration
reportAnalysis(settings, allClusters, dataCalibration);
// Save clusters to memory
final Trace[] traces = allClusters.stream().map(c -> {
final Trace t = new Trace();
t.setId(c.id);
c.results.forEach(t::add);
return t;
}).toArray(Trace[]::new);
TraceMolecules.saveResults(results, traces, "TC PALM");
IJ.showStatus(TITLE + ": " + TextUtils.pleural(allClusters.size(), "cluster"));
}
use of ij.gui.GenericDialog in project GDSC-SMLM by aherbert.
the class PulseActivationAnalysis method isSimulation.
private int isSimulation() {
if (ImageJUtils.isExtraOptions()) {
final GenericDialog gd = new GenericDialog(title);
gd.addMessage("Perform a crosstalk simulation?");
gd.enableYesNoCancel();
gd.addHelp(HelpUrls.getUrl(helpKey));
gd.showDialog();
if (gd.wasOKed()) {
return 1;
}
if (gd.wasCanceled()) {
return -1;
}
}
return 0;
}
Aggregations