Search in sources :

Example 11 with NonBlockingExtendedGenericDialog

use of uk.ac.sussex.gdsc.core.ij.gui.NonBlockingExtendedGenericDialog in project GDSC-SMLM by aherbert.

the class CameraModelFisherInformationAnalysis method showDialog.

private boolean showDialog() {
    settings = SettingsManager.readCameraModelFisherInformationAnalysisSettings(0).toBuilder();
    final NonBlockingExtendedGenericDialog gd = new NonBlockingExtendedGenericDialog(TITLE);
    gd.addHelp(HelpUrls.getUrl("camera-model-fisher-information-analysis"));
    // @formatter:off
    gd.addMessage(TextUtils.wrap("Compute Fisher information for a CCD/EM-CCD camera model. " + "Configure the range of photons using a log10 scale.", 80));
    // @formatter:on
    gd.addSlider("Min_exponent", -50, 4, settings.getMinExponent());
    gd.addSlider("Max_exponent", -10, 4, settings.getMaxExponent());
    gd.addSlider("Sub_divisions", 0, 10, settings.getSubDivisions());
    gd.addChoice("Camera_1_type", cameraTypes, settings.getCamera1Type());
    gd.addNumericField("Camera_1_gain", settings.getCamera1Gain(), 2);
    gd.addNumericField("Camera_1_noise", settings.getCamera1Noise(), 2);
    gd.addChoice("Camera_2_type", cameraTypes, settings.getCamera2Type());
    gd.addNumericField("Camera_2_gain", settings.getCamera2Gain(), 2);
    gd.addNumericField("Camera_2_noise", settings.getCamera2Noise(), 2);
    gd.addChoice("Plot_point", POINT_OPTION, settings.getPointOption());
    gd.showDialog();
    if (gd.wasCanceled()) {
        return false;
    }
    settings.setMinExponent((int) gd.getNextNumber());
    settings.setMaxExponent((int) gd.getNextNumber());
    settings.setSubDivisions((int) gd.getNextNumber());
    settings.setCamera1Type(gd.getNextChoiceIndex());
    settings.setCamera1Gain(gd.getNextNumber());
    settings.setCamera1Noise(gd.getNextNumber());
    settings.setCamera2Type(gd.getNextChoiceIndex());
    settings.setCamera2Gain(gd.getNextNumber());
    settings.setCamera2Noise(gd.getNextNumber());
    settings.setPointOption(gd.getNextChoiceIndex());
    SettingsManager.writeSettings(settings);
    if (settings.getMinExponent() > settings.getMaxExponent()) {
        IJ.error(TITLE, "Min exponent must be less or equal to max exponent");
        return false;
    }
    return true;
}
Also used : NonBlockingExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.NonBlockingExtendedGenericDialog)

Example 12 with NonBlockingExtendedGenericDialog

use of uk.ac.sussex.gdsc.core.ij.gui.NonBlockingExtendedGenericDialog in project GDSC-SMLM by aherbert.

the class Fire method showQEstimationDialog.

private boolean showQEstimationDialog(final PrecisionHistogram histogram, final QPlot qplot, final double nmPerPixel) {
    // This is used for the initial layout of windows
    final MyWindowOrganiser wo = new MyWindowOrganiser(2);
    // Use a simple workflow
    final Workflow<WorkSettings, Object> workflow = new Workflow<>();
    // Split the work to two children with a dummy initial worker
    final int previous = workflow.add(new BaseWorker(wo));
    workflow.add(new HistogramWorker(wo, histogram), previous);
    workflow.add(new QPlotWorker(wo, qplot), previous);
    workflow.start();
    final String macroOptions = Macro.getOptions();
    if (macroOptions != null) {
        // If inside a macro then just get the options and run the work
        final double mean = Double.parseDouble(Macro.getValue(macroOptions, KEY_MEAN, Double.toString(histogram.mean)));
        final double sigma = Double.parseDouble(Macro.getValue(macroOptions, KEY_SIGMA, Double.toString(histogram.sigma)));
        final double qvalue = Double.parseDouble(Macro.getValue(macroOptions, KEY_Q, Double.toString(qplot.qvalue)));
        workflow.run(new WorkSettings(mean, sigma, qvalue));
        workflow.shutdown(false);
    } else {
        // Draw the plots with the first set of work
        workflow.run(new WorkSettings(histogram.mean, histogram.sigma, qplot.qvalue));
        // Build the dialog
        final NonBlockingExtendedGenericDialog gd = new NonBlockingExtendedGenericDialog(pluginTitle);
        gd.addHelp(HelpUrls.getUrl("fourier-image-resolution"));
        final double mu = histogram.mean / nmPerPixel;
        final double sd = histogram.sigma / nmPerPixel;
        final double plateauness = qplot.computePlateauness(qplot.qvalue, mu, sd);
        ImageJUtils.addMessage(gd, "Estimate the blinking correction parameter Q for Fourier Ring Correlation\n \n" + "Initial estimate:\nPrecision = %.3f +/- %.3f\nQ = %s\nCost = %.3f", histogram.mean, histogram.sigma, MathUtils.rounded(qplot.qvalue), plateauness);
        final double mean10 = histogram.mean * 10;
        final double sd10 = histogram.sigma * 10;
        final double q10 = qplot.qvalue * 10;
        gd.addSlider("Mean (x10)", Math.max(0, mean10 - sd10 * 2), mean10 + sd10 * 2, mean10);
        gd.addSlider("Sigma (x10)", Math.max(0, sd10 / 2), sd10 * 2, sd10);
        gd.addSlider("Q (x10)", 0, Math.max(50, q10 * 2), q10);
        gd.addCheckbox("Reset_all", false);
        gd.addMessage("Double-click a slider to reset");
        gd.addDialogListener(new FireDialogListener(gd, histogram, qplot, workflow));
        // Show this when the workers have finished drawing the plots so it is on top
        try {
            final long timeout = System.currentTimeMillis() + 5000;
            while (!wo.isTiled()) {
                Thread.sleep(50);
                if (System.currentTimeMillis() > timeout) {
                    break;
                }
            }
        } catch (final InterruptedException ex) {
            // Propagate the interruption
            Thread.currentThread().interrupt();
        }
        gd.addHelp(HelpUrls.getUrl("fire-q-estimation"));
        gd.showDialog();
        // Finish the worker threads
        final boolean cancelled = gd.wasCanceled();
        workflow.shutdown(cancelled);
        if (cancelled) {
            return false;
        }
    }
    // Store the Q value and the mean and sigma
    settings.qvalue = qplot.qvalue;
    settings.mean = qplot.mean;
    settings.sigma = qplot.sigma;
    // Record the values for Macros since the NonBlockingDialog doesn't
    if (Recorder.record) {
        Recorder.recordOption(KEY_MEAN, Double.toString(settings.mean));
        Recorder.recordOption(KEY_SIGMA, Double.toString(settings.sigma));
        Recorder.recordOption(KEY_Q, Double.toString(settings.qvalue));
    }
    return true;
}
Also used : NonBlockingExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.NonBlockingExtendedGenericDialog) WeightedObservedPoint(org.apache.commons.math3.fitting.WeightedObservedPoint)

Example 13 with NonBlockingExtendedGenericDialog

use of uk.ac.sussex.gdsc.core.ij.gui.NonBlockingExtendedGenericDialog in project GDSC-SMLM by aherbert.

the class PsfDrift method showHwhm.

private void showHwhm() {
    // Build a list of suitable images
    final List<String> titles = createImageList(false);
    if (titles.isEmpty()) {
        IJ.error(TITLE, "No suitable PSF images");
        return;
    }
    final GenericDialog gd = new GenericDialog(TITLE);
    gd.addMessage("Approximate the volume of the PSF as a Gaussian and\n" + "compute the equivalent Gaussian width.");
    settings = Settings.load();
    gd.addChoice("PSF", titles.toArray(new String[0]), settings.title);
    gd.addCheckbox("Use_offset", settings.useOffset);
    gd.addSlider("Smoothing", 0, 0.5, settings.smoothing);
    gd.addHelp(HelpUrls.getUrl("psf-hwhm"));
    gd.showDialog();
    if (gd.wasCanceled()) {
        return;
    }
    settings.title = gd.getNextChoice();
    settings.useOffset = gd.getNextBoolean();
    settings.smoothing = gd.getNextNumber();
    settings.save();
    imp = WindowManager.getImage(settings.title);
    if (imp == null) {
        IJ.error(TITLE, "No PSF image for image: " + settings.title);
        return;
    }
    psfSettings = getPsfSettings(imp);
    if (psfSettings == null) {
        IJ.error(TITLE, "No PSF settings for image: " + settings.title);
        return;
    }
    final int size = imp.getStackSize();
    final ImagePsfModel psf = createImagePsf(1, size, 1);
    final double[] w0 = psf.getAllHwhm0();
    final double[] w1 = psf.getAllHwhm1();
    // Get current centre
    final int centre = psfSettings.getCentreImage();
    // Extract valid values (some can be NaN)
    double[] sw0 = new double[w0.length];
    double[] sw1 = new double[w1.length];
    final TDoubleArrayList s0 = new TDoubleArrayList(w0.length);
    final TDoubleArrayList s1 = new TDoubleArrayList(w0.length);
    int c0 = 0;
    int c1 = 0;
    for (int i = 0; i < w0.length; i++) {
        if (Double.isFinite(w0[i])) {
            s0.add(i + 1);
            sw0[c0++] = w0[i];
        }
        if (Double.isFinite(w1[i])) {
            s1.add(i + 1);
            sw1[c1++] = w1[i];
        }
    }
    if (c0 == 0 && c1 == 0) {
        IJ.error(TITLE, "No computed HWHM for image: " + settings.title);
        return;
    }
    double[] slice0 = s0.toArray();
    sw0 = Arrays.copyOf(sw0, c0);
    double[] slice1 = s1.toArray();
    sw1 = Arrays.copyOf(sw1, c1);
    // Smooth
    if (settings.smoothing > 0) {
        final LoessInterpolator loess = new LoessInterpolator(settings.smoothing, 1);
        sw0 = loess.smooth(slice0, sw0);
        sw1 = loess.smooth(slice1, sw1);
    }
    final TDoubleArrayList minWx = new TDoubleArrayList();
    final TDoubleArrayList minWy = new TDoubleArrayList();
    for (int i = 0; i < w0.length; i++) {
        double weight = 0;
        if (Double.isFinite(w0[i])) {
            if (Double.isFinite(w1[i])) {
                weight = w0[i] * w1[i];
            } else {
                weight = w0[i] * w0[i];
            }
        } else if (Double.isFinite(w1[i])) {
            weight = w1[i] * w1[i];
        }
        if (weight != 0) {
            minWx.add(i + 1);
            minWy.add(Math.sqrt(weight));
        }
    }
    // Smooth the combined line
    final double[] cx = minWx.toArray();
    double[] cy = minWy.toArray();
    if (settings.smoothing > 0) {
        final LoessInterpolator loess = new LoessInterpolator(settings.smoothing, 1);
        cy = loess.smooth(cx, cy);
    }
    final int newCentre = SimpleArrayUtils.findMinIndex(cy);
    // Convert to FWHM
    final double fwhm = psfSettings.getFwhm();
    // Widths are in pixels
    final String title = TITLE + " HWHM";
    final Plot plot = new Plot(title, "Slice", "HWHM (px)");
    double[] limits = MathUtils.limits(sw0);
    limits = MathUtils.limits(limits, sw1);
    final double maxY = limits[1] * 1.05;
    plot.setLimits(1, size, 0, maxY);
    plot.setColor(Color.red);
    plot.addPoints(slice0, sw0, Plot.LINE);
    plot.setColor(Color.blue);
    plot.addPoints(slice1, sw1, Plot.LINE);
    plot.setColor(Color.magenta);
    plot.addPoints(cx, cy, Plot.LINE);
    plot.setColor(Color.black);
    plot.addLabel(0, 0, "X=red; Y=blue, Combined=Magenta");
    final PlotWindow pw = ImageJUtils.display(title, plot);
    // Show a non-blocking dialog to allow the centre to be updated ...
    // Add a label and dynamically update when the centre is moved.
    final NonBlockingExtendedGenericDialog gd2 = new NonBlockingExtendedGenericDialog(TITLE);
    final double scale = psfSettings.getPixelSize();
    // @formatter:off
    ImageJUtils.addMessage(gd2, "Update the PSF information?\n \n" + "Current z-centre = %d, FHWM = %s px (%s nm)\n", centre, MathUtils.rounded(fwhm), MathUtils.rounded(fwhm * scale));
    // @formatter:on
    gd2.addSlider("z-centre", cx[0], cx[cx.length - 1], newCentre);
    final TextField tf = gd2.getLastTextField();
    gd2.addMessage("");
    gd2.addAndGetButton("Reset", event -> tf.setText(Integer.toString(newCentre)));
    final Label label = gd2.getLastLabel();
    gd2.addCheckbox("Update_centre", settings.updateCentre);
    gd2.addCheckbox("Update_HWHM", settings.updateHwhm);
    gd2.enableYesNoCancel();
    gd2.hideCancelButton();
    final UpdateDialogListener dl = new UpdateDialogListener(cx, cy, maxY, newCentre, scale, pw, label);
    gd2.addDialogListener(dl);
    gd.addHelp(HelpUrls.getUrl("psf-hwhm"));
    gd2.showDialog();
    if (gd2.wasOKed() && (settings.updateCentre || settings.updateHwhm)) {
        final ImagePSF.Builder b = psfSettings.toBuilder();
        if (settings.updateCentre) {
            b.setCentreImage(dl.centre);
        }
        if (settings.updateHwhm) {
            b.setFwhm(dl.getFwhm());
        }
        imp.setProperty("Info", ImagePsfHelper.toString(b));
    }
}
Also used : Plot(ij.gui.Plot) NonBlockingExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.NonBlockingExtendedGenericDialog) Label(java.awt.Label) PlotWindow(ij.gui.PlotWindow) LoessInterpolator(org.apache.commons.math3.analysis.interpolation.LoessInterpolator) TDoubleArrayList(gnu.trove.list.array.TDoubleArrayList) ImagePSF(uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.ImagePSF) NonBlockingExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.NonBlockingExtendedGenericDialog) ExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog) GenericDialog(ij.gui.GenericDialog) TextField(java.awt.TextField) ImagePsfModel(uk.ac.sussex.gdsc.smlm.model.ImagePsfModel)

Example 14 with NonBlockingExtendedGenericDialog

use of uk.ac.sussex.gdsc.core.ij.gui.NonBlockingExtendedGenericDialog in project GDSC-SMLM by aherbert.

the class PsfCreator method runUsingAlignment.

private void runUsingAlignment() {
    if (!showAlignmentDialog()) {
        return;
    }
    boxRadius = (int) Math.ceil(settings.getRadius());
    final CalibrationReader calibration = new CalibrationReader(settings.getCalibration());
    // Limit this
    final int halfBoxRadius = boxRadius / 2;
    settings.setAnalysisWindow(Math.min(settings.getAnalysisWindow(), halfBoxRadius));
    // Find the selected PSF spots x,y,z centre
    // We offset the centre to the middle of pixel.
    BasePoint[] centres = getSpots(0.5f, false);
    if (centres.length == 0) {
        IJ.error(TITLE, "No PSFs");
        return;
    }
    CameraModel cameraModel = null;
    if (calibration.isScmos()) {
        cameraModel = CameraModelManager.load(calibration.getCameraModelName());
        if (cameraModel == null) {
            IJ.error(TITLE, "No camera model");
            return;
        }
        cameraModel = PeakFit.cropCameraModel(cameraModel, IJImageSource.getBounds(imp), null, true);
    } else {
        cameraModel = new CcdCameraModel(calibration.getBias(), 1);
    }
    // Extract the image data for processing as float
    final float[][] image = CreateData.extractImageStack(imp, 0, imp.getStackSize() - 1);
    for (final float[] data : image) {
        cameraModel.removeBiasAndGain(data);
    }
    zSelector = new PsfCentreSelector();
    // Relocate the initial centres
    ImageJUtils.showStatus("Relocating initial centres");
    centres = relocateCentres(image, centres);
    if (centres == null) {
        return;
    }
    zRadius = (int) Math.ceil(settings.getAlignmentZRadius());
    // Check the region overlap in 3D and exclude overlapping PSFs
    boolean[] bad = findSpotOverlap(centres, null);
    centres = getNonBadSpots(centres, bad);
    if (centres.length == 0) {
        IJ.error(TITLE, "No PSFs without neighbours within the box region");
        return;
    }
    // Multi-thread for speed
    if (threadPool == null) {
        threadPool = Executors.newFixedThreadPool(Prefs.getThreads());
    }
    // Extract each PSF into a scaled PSF
    ImageJUtils.showStatus(String.format("[%d] Extracting PSFs", 0));
    ExtractedPsf[] psfs = extractPsfs(image, centres);
    Point location = null;
    // Iterate until centres have converged
    boolean converged = false;
    for (int iter = 0; !converged && iter < settings.getMaxIterations(); iter++) {
        if (ImageJUtils.isInterrupted()) {
            return;
        }
        // Combine all PSFs
        ImageJUtils.showStatus(String.format("[%d] Aligning PSFs", iter + 1));
        final ExtractedPsf combined = combine(psfs);
        combined.createProjections();
        // Get the current combined z-centre.
        // This is used to get the centre of mass for repositioning.
        // It also effects the alignment so do it for the first iteration.
        zSelector.setPsf(combined);
        if (iter == 0) {
            // TODO - check if the z-centre should be guessed here.
            // We assume that the combined PSF may be easier to guess if the initial
            // guess for each individual PSF was OK. It may not be necessary since all
            // the PSFs are combined around their z-centres. Once alignment has
            // started we skip this step.
            zSelector.analyse();
            zSelector.guessZCentre();
        }
        if (settings.getInteractiveMode()) {
            if (iter != 0) {
                zSelector.analyse();
            }
            // zSelector.guessZCentre();
            final double dz = zSelector.run("Update combined PSF z-centre", true, false, false, null);
            if (dz < 0) {
                return;
            }
        }
        // Align each to the combined PSF
        final float[][] translation = align(combined, psfs);
        if (ImageJUtils.isInterrupted()) {
            return;
        }
        // Find the new centre using the old centre plus the alignment shift
        for (int j = 0; j < psfs.length; j++) {
            centres[j] = psfs[j].updateCentre(translation[j]);
            // Update to get the correct scale
            translation[j][0] = centres[j].getX() - psfs[j].centre.getX();
            translation[j][1] = centres[j].getY() - psfs[j].centre.getY();
            translation[j][2] = centres[j].getZ() - psfs[j].centre.getZ();
            ImageJUtils.log("[%d] Centre %d : Shift X = %s : Shift Y = %s : Shift Z = %s", iter, j + 1, rounder.toString(translation[j][0]), rounder.toString(translation[j][1]), rounder.toString(translation[j][2]));
        }
        final boolean[] excluded = new boolean[psfs.length];
        if (checkAlignments) {
            combined.show(TITLE_PSF);
            // Ask about each centre in turn.
            // Update Point ROI using float coordinates and set image slice to
            // correct z-centre.
            // imp.saveRoi();
            imp.killRoi();
            final ImageCanvas ic = imp.getCanvas();
            // ic.setMagnification(16);
            int reject = 0;
            final float box = boxRadius + 0.5f;
            final int n = imp.getStackSize();
            for (int j = 0; j < centres.length; j++) {
                psfs[j].show(TITLE_SPOT_PSF);
                final Overlay o = new Overlay();
                o.add(createRoi(psfs[j].centre.getX(), psfs[j].centre.getY(), Color.RED));
                final float cx = centres[j].getX();
                final float cy = centres[j].getY();
                o.add(createRoi(cx, cy, Color.GREEN));
                final Roi roi = new Roi(cx - box, cy - box, 2 * box, 2 * box);
                o.add(roi);
                // The centre is absolute within the original stack
                imp.setSlice(MathUtils.clip(1, n, Math.round(centres[j].getZ())));
                final Rectangle r = ic.getSrcRect();
                final int x = centres[j].getXint();
                final int y = centres[j].getYint();
                if (!r.contains(x, y)) {
                    r.x = x - r.width / 2;
                    r.y = y - r.height / 2;
                    ic.setSourceRect(r);
                }
                imp.setOverlay(o);
                imp.updateAndDraw();
                final NonBlockingExtendedGenericDialog gd = new NonBlockingExtendedGenericDialog(TITLE);
                ImageJUtils.addMessage(gd, "Shift X = %s\nShift Y = %s\nShift Z = %s", rounder.toString(translation[j][0]), rounder.toString(translation[j][1]), rounder.toString(translation[j][2]));
                final int spotIndex = j;
                gd.addAndGetButton("Exclude spot", event -> {
                    if (excluded[spotIndex]) {
                        ImageJUtils.log("Included spot %d", spotIndex + 1);
                        excluded[spotIndex] = false;
                    } else {
                        ImageJUtils.log("Excluded spot %d", spotIndex + 1);
                        excluded[spotIndex] = true;
                    }
                });
                gd.enableYesNoCancel("Accept", "Reject");
                if (location != null) {
                    gd.setLocation(location.x, location.y);
                }
                gd.showDialog();
                if (gd.wasCanceled()) {
                    resetImp();
                    return;
                }
                final boolean failed = excluded[spotIndex] || !gd.wasOKed();
                if (failed) {
                    reject++;
                    centres[j] = psfs[j].centre;
                    // For RMSD computation
                    Arrays.fill(translation[j], 0f);
                }
                location = gd.getLocation();
            }
            resetImp();
            if (reject == psfs.length) {
                IJ.error(TITLE, "No PSF translations were accepted");
                return;
            }
        }
        bad = findSpotOverlap(centres, excluded);
        final int badCount = count(bad);
        final int excludedCount = count(excluded);
        int ok = bad.length - badCount - excludedCount;
        if (ok < bad.length) {
            if (badCount != 0 && settings.getInteractiveMode()) {
                final ExtendedGenericDialog gd = new ExtendedGenericDialog(TITLE);
                gd.addMessage("Warning: Regions now overlap!");
                gd.addMessage("OK = " + TextUtils.pleural(ok, "PSF"));
                gd.addMessage("Overlapping = " + TextUtils.pleural(badCount, "PSF"));
                // gd.addMessage("Excluded = " + TextUtils.pleural(excludedCount, "PSF"));
                gd.enableYesNoCancel("Exclude", "Include");
                if (location != null) {
                    gd.setLocation(location.x, location.y);
                }
                gd.showDialog();
                if (gd.wasCanceled()) {
                    resetImp();
                    return;
                }
                if (!gd.wasOKed()) {
                    // allow bad spots
                    Arrays.fill(bad, false);
                    ok = bad.length;
                }
                location = gd.getLocation();
            }
            if (ok == 0) {
                IJ.error(TITLE, "No PSFs remaining");
                resetImp();
                return;
            }
        }
        // Merge bad and excluded to get new centres
        for (int i = 0; i < bad.length; i++) {
            if (excluded[i]) {
                bad[i] = true;
            }
        }
        ok = bad.length - count(bad);
        final BasePoint[] newCentres = getNonBadSpots(centres, bad);
        // Find the change in centres
        final double[] rmsd = new double[2];
        for (int j = 0; j < psfs.length; j++) {
            if (bad[j]) {
                continue;
            }
            rmsd[0] += MathUtils.pow2(translation[j][0]) + MathUtils.pow2(translation[j][1]);
            rmsd[1] += MathUtils.pow2(translation[j][2]);
        }
        for (int j = 0; j < 2; j++) {
            rmsd[j] = Math.sqrt(rmsd[j] / ok);
        }
        ImageJUtils.showStatus(String.format("[%d] Checking combined PSF", iter + 1));
        // Compute CoM shift using the current z-centre and z-window
        final double[] shift = combined.getCentreOfMassXyShift(zSelector.getCentreSlice());
        final double shiftd = Math.sqrt(shift[0] * shift[0] + shift[1] * shift[1]);
        ImageJUtils.log("[%d] RMSD XY = %s : RMSD Z = %s : Combined CoM shift = %s,%s (%s)", iter, rounder.toString(rmsd[0]), rounder.toString(rmsd[1]), rounder.toString(shift[0]), rounder.toString(shift[1]), rounder.toString(shiftd));
        if (settings.getInteractiveMode()) {
            // Ask if OK to continue?
            final GenericDialog gd = new GenericDialog(TITLE);
            ImageJUtils.addMessage(gd, "RMSD XY = %s\nRMSD Z = %s\nCombined CoM shift = %s,%s (%s)", rounder.toString(rmsd[0]), rounder.toString(rmsd[1]), rounder.toString(shift[0]), rounder.toString(shift[1]), rounder.toString(shiftd));
            // Check if we can do more iterations
            if (iter + 1 < settings.getMaxIterations()) {
                gd.enableYesNoCancel("Continue", "Converged");
            } else {
                gd.setOKLabel("Converged");
            }
            gd.showDialog();
            if (gd.wasCanceled()) {
                return;
            }
            converged = !gd.wasOKed();
        } else {
            // Check convergence thresholds
            converged = rmsd[0] < settings.getRmsdXyThreshold() && rmsd[1] < settings.getRmsdZThreshold() && shiftd < settings.getComShiftThreshold();
        }
        // For the next round we move to the non-overlapping spots
        centres = newCentres;
        // Update the centres using the centre-of-mass of the combined PSF
        centres = updateUsingCentreOfMassXyShift(shift, shiftd, combined, centres);
        // Extract each PSF into a scaled PSF
        ImageJUtils.showStatus(String.format("[%d] Extracting PSFs", iter + 1));
        psfs = extractPsfs(image, centres);
    }
    // Combine all
    ExtractedPsf combined = combine(psfs);
    // Show an interactive dialog for cropping the PSF and choosing the
    // final output
    final PsfOutputSelector cropSelector = new PsfOutputSelector(combined);
    combined = cropSelector.run();
    if (combined == null) {
        return;
    }
    if (settings.getUpdateRoi()) {
        final float[] ox = new float[centres.length];
        final float[] oy = new float[centres.length];
        for (int i = 0; i < centres.length; i++) {
            ox[i] = centres[i].getX();
            oy[i] = centres[i].getY();
        }
        imp.setRoi(new OffsetPointRoi(ox, oy));
    }
    // For an image PSF we can just enlarge the PSF and window.
    // For a CSpline then we already have the 3D cubic spline function.
    // However we want to post-process the function to allow windowing and
    // normalisation. So we enlarge by 3 in each dimension.
    // The CSpline can be created by solving the coefficients for the
    // 4x4x4 (64) sampled points on each node.
    int magnification;
    if (settings.getOutputType() == OUTPUT_TYPE_IMAGE_PSF) {
        magnification = settings.getPsfMagnification();
    } else {
        magnification = 3;
    }
    // Enlarge the combined PSF for final processing
    ExtractedPsf finalPsf = combined.enlarge(magnification, threadPool);
    // Show a dialog to collect final z-centre interactively
    ImageJUtils.showStatus("Analysing PSF");
    zSelector.setPsf(finalPsf);
    zSelector.analyse();
    // zSelector.guessZCentre(); // No need to guess the centre
    final double dz = zSelector.run("Finalise PSF", true, true, true, null);
    if (dz < 0) {
        return;
    }
    zCentre = zSelector.getCentreSlice();
    if (settings.getCropToZCentre()) {
        finalPsf = finalPsf.cropToZCentre(zCentre);
        // Back to 1-based index
        zCentre = finalPsf.stackZCentre + 1;
    }
    // When click ok the background is subtracted from the PSF
    // All pixels below the background are set to zero
    // Apply a Tukey window to roll-off to zero at the outer pixels
    ImageJUtils.showStatus("Windowing PSF");
    final double[] wx = ImageWindow.tukeyEdge(finalPsf.maxx, settings.getWindow());
    final double[] wz = ImageWindow.tukeyEdge(finalPsf.psf.length, settings.getWindow());
    // Normalisation so the max intensity frame is one
    final float[][] psf = finalPsf.psf;
    final int maxz = psf.length;
    final double[] sum = new double[maxz];
    for (int z = 0; z < maxz; z++) {
        sum[z] = applyWindow(psf[z], z, wx, wz, zSelector.background);
    }
    // Smooth the intensity
    ImageJUtils.showStatus("Normalising PSF");
    final Smoother smoother = zSelector.ssmoother;
    final double[] ssum = smoother.smooth(sum).getDSmooth();
    // Compute normalisation and apply.
    SimpleArrayUtils.multiply(ssum, 1.0 / MathUtils.max(ssum));
    for (int z = 0; z < psf.length; z++) {
        if (sum[z] != 0) {
            SimpleArrayUtils.multiply(psf[z], ssum[z] / sum[z]);
        }
        sum[z] = MathUtils.sum(psf[z]);
    }
    // Show the final intensity profile
    final double[] slice = SimpleArrayUtils.newArray(maxz, 1, 1.0);
    final Plot plot = new Plot(TITLE_SIGNAL, "Slice", "Signal");
    final double[] range = MathUtils.limits(sum);
    plot.setLimits(1, maxz, range[0], range[1]);
    plot.setColor(Color.black);
    plot.addPoints(slice, sum, Plot.LINE);
    ImageJUtils.display(TITLE_SIGNAL, plot);
    // Create a new extracted PSF and show
    ImageJUtils.showStatus("Displaying PSF");
    magnification = finalPsf.magnification;
    finalPsf = new ExtractedPsf(psf, finalPsf.maxx, finalPsf.centre, magnification);
    finalPsf.createProjections();
    psfOut = finalPsf.show(TITLE_PSF, zCentre);
    psfImp = psfOut[0];
    // Add image info
    final int imageCount = centres.length;
    final ImagePSF.Builder imagePsf = ImagePsfHelper.create(zCentre, nmPerPixel / magnification, settings.getNmPerSlice() / magnification, imageCount, 0, createNote()).toBuilder();
    // Add the CoM
    // Find the XY centre around the z centre
    final double[] com = getCentreOfMassXy(finalPsf.psf, finalPsf.maxx, finalPsf.maxy, zCentre - 1, settings.getComWindow(), getComXyBorder(finalPsf.maxx, finalPsf.maxy));
    imagePsf.setXCentre(com[0]);
    imagePsf.setYCentre(com[1]);
    imagePsf.setZCentre(zCentre - 1);
    psfImp.setProperty("Info", ImagePsfHelper.toString(imagePsf));
    psfImp.setRoi(new OffsetPointRoi(com[0], com[1]));
    psfImp.setSlice(zCentre);
    psfImp.resetDisplayRange();
    psfImp.updateAndDraw();
    ImageJUtils.log("Final Centre-of-mass = %s,%s\n", rounder.toString(com[0]), rounder.toString(com[1]));
    ImageJUtils.log("%s : z-centre = %d, nm/Pixel = %s, nm/Slice = %s, %d images\n", psfImp.getTitle(), zCentre, MathUtils.rounded(imagePsf.getPixelSize(), 3), MathUtils.rounded(imagePsf.getPixelDepth(), 3), imageCount);
    if (settings.getOutputType() == OUTPUT_TYPE_CSPLINE) {
        // Ask this again as it is important
        // if (TextUtils.isNullOrEmpty(settings.getSplineFilename()))
        // {
        final ExtendedGenericDialog gd = new ExtendedGenericDialog(TITLE);
        gd.addFilenameField("Spline_filename", settings.getSplineFilename());
        gd.showDialog(true);
        if (gd.wasCanceled()) {
            return;
        }
        settings.setSplineFilename(gd.getNextString());
        // }
        if (!TextUtils.isNullOrEmpty(settings.getSplineFilename())) {
            // Save the result ...
            IJ.showStatus("Creating cubic spline");
            final CubicSplinePsf cubicSplinePsf = CubicSplineManager.createCubicSpline(imagePsf, psfImp.getImageStack(), settings.getSinglePrecision());
            IJ.showStatus("Saving cubic spline");
            CubicSplineManager.save(cubicSplinePsf, settings.getSplineFilename());
            final String msg = "Spline saved to " + settings.getSplineFilename();
            IJ.showStatus(msg);
            IJ.log(msg);
            // To leave the status message
            return;
        }
    }
    IJ.showStatus("");
}
Also used : CameraModel(uk.ac.sussex.gdsc.smlm.model.camera.CameraModel) CcdCameraModel(uk.ac.sussex.gdsc.smlm.model.camera.CcdCameraModel) CcdCameraModel(uk.ac.sussex.gdsc.smlm.model.camera.CcdCameraModel) BasePoint(uk.ac.sussex.gdsc.core.match.BasePoint) Rectangle(java.awt.Rectangle) CubicSplinePsf(uk.ac.sussex.gdsc.smlm.ij.plugins.CubicSplineManager.CubicSplinePsf) ImageCanvas(ij.gui.ImageCanvas) ImagePSF(uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.ImagePSF) GenericDialog(ij.gui.GenericDialog) NonBlockingExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.NonBlockingExtendedGenericDialog) ExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog) Overlay(ij.gui.Overlay) OffsetPointRoi(uk.ac.sussex.gdsc.core.ij.gui.OffsetPointRoi) Plot(ij.gui.Plot) NonBlockingExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.NonBlockingExtendedGenericDialog) Point(java.awt.Point) BasePoint(uk.ac.sussex.gdsc.core.match.BasePoint) NonBlockingExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.NonBlockingExtendedGenericDialog) ExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog) CalibrationReader(uk.ac.sussex.gdsc.smlm.data.config.CalibrationReader) OffsetPointRoi(uk.ac.sussex.gdsc.core.ij.gui.OffsetPointRoi) Roi(ij.gui.Roi) Point(java.awt.Point) BasePoint(uk.ac.sussex.gdsc.core.match.BasePoint)

Example 15 with NonBlockingExtendedGenericDialog

use of uk.ac.sussex.gdsc.core.ij.gui.NonBlockingExtendedGenericDialog in project GDSC-SMLM by aherbert.

the class NucleusMask method createMask.

private void createMask() {
    diameter = settings.getDiameter();
    nmPerPixel = settings.getNmPerPixel();
    nmPerSlice = settings.getNmPerSlice();
    // Create the dimensions using the scale.
    // Scale diameter in um to nm
    final int radius = (int) Math.ceil(diameter * 500 / nmPerPixel);
    final int radiusz = (int) Math.ceil(diameter * 500 / nmPerSlice);
    final int inc = 2 * radius + 1;
    final int incz = 2 * radiusz + 1;
    final int maxx = settings.getFieldWidth();
    final int maxy = maxx;
    final int ditherHeight = (settings.getYDither() > 0) ? (int) Math.ceil(settings.getYDither() * 1000 / nmPerPixel) : 0;
    final int ditherDepth = (settings.getZDither() > 0) ? (int) Math.ceil(settings.getZDither() * 1000 / nmPerSlice) : 0;
    final int maxz = ditherDepth + incz;
    final ImageStack stack = new ImageStack(maxx, maxy, maxz);
    byte[] mask = new byte[maxx * maxy];
    for (int z = 0; z < maxz; z++) {
        mask = (z == 0) ? mask : mask.clone();
        stack.setPixels(mask, z + 1);
    }
    if (settings.getMode() == 0) {
        final ImageStack stack2 = createEllipsoid(inc, inc, incz);
        // Dither
        int cx = radius;
        final int lowerz = (maxz - ditherDepth) / 2;
        final int upperz = (maxz + ditherDepth) / 2;
        final UniformRandomProvider rng = UniformRandomProviders.create();
        final DiscreteUniformSampler ditherSampler = new DiscreteUniformSampler(rng, 0, ditherHeight);
        final DiscreteUniformSampler zSampler = new DiscreteUniformSampler(rng, lowerz, upperz);
        while (cx < maxx) {
            final int xloc = cx - radius;
            int cy = radius + ditherSampler.sample();
            while (cy < maxy) {
                final int yloc = cy - radius;
                final int offset = zSampler.sample() - radiusz;
                for (int slice = 1; slice <= stack2.getSize(); slice++) {
                    final int i = slice + offset;
                    if (i < 1 || i > maxz) {
                        continue;
                    }
                    final ImageProcessor ip = stack.getProcessor(i);
                    final ImageProcessor ip2 = stack2.getProcessor(slice);
                    ip.copyBits(ip2, xloc, yloc, Blitter.MAX);
                }
                cy += inc + 1 + ditherSampler.sample();
            }
            cx += inc + 1;
        }
    }
    // The final image will have a scale added to it.
    imp = ImageJUtils.display(TITLE, stack);
    calibrate(imp);
    imp.setSlice(maxz / 2);
    if (settings.getMode() == 1) {
        // Allow mouse click to draw spheres
        final MouseAdapter ml = createMouseAdapter();
        imp.getCanvas().addMouseListener(ml);
        final NonBlockingExtendedGenericDialog gd = new NonBlockingExtendedGenericDialog(TITLE);
        gd.addHelp(HelpUrls.getUrl("nucleus-mask"));
        gd.addMessage("Click the image to add a sphere");
        gd.addNumericField("Diameter", diameter, 2, 6, "um");
        gd.addDialogListener(this::dialogItemChanged);
        gd.hideCancelButton();
        gd.setOKLabel("Close");
        gd.addHelp(HelpUrls.getUrl("nucleus-mask"));
        gd.showDialog();
        imp.getCanvas().removeMouseListener(ml);
        if (diameter != settings.getDiameter()) {
            settings.setDiameter(diameter);
            SettingsManager.writeSettings(settings);
        }
    }
}
Also used : DiscreteUniformSampler(org.apache.commons.rng.sampling.distribution.DiscreteUniformSampler) ImageProcessor(ij.process.ImageProcessor) ImageStack(ij.ImageStack) MouseAdapter(java.awt.event.MouseAdapter) NonBlockingExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.NonBlockingExtendedGenericDialog) UniformRandomProvider(org.apache.commons.rng.UniformRandomProvider)

Aggregations

NonBlockingExtendedGenericDialog (uk.ac.sussex.gdsc.core.ij.gui.NonBlockingExtendedGenericDialog)15 ExtendedGenericDialog (uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog)4 GenericDialog (ij.gui.GenericDialog)2 Plot (ij.gui.Plot)2 TextField (java.awt.TextField)2 ImagePSF (uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.ImagePSF)2 MemoryPeakResults (uk.ac.sussex.gdsc.smlm.results.MemoryPeakResults)2 TDoubleArrayList (gnu.trove.list.array.TDoubleArrayList)1 ImageListener (ij.ImageListener)1 ImagePlus (ij.ImagePlus)1 ImageStack (ij.ImageStack)1 ImageCanvas (ij.gui.ImageCanvas)1 Overlay (ij.gui.Overlay)1 PlotWindow (ij.gui.PlotWindow)1 Roi (ij.gui.Roi)1 ImageProcessor (ij.process.ImageProcessor)1 Checkbox (java.awt.Checkbox)1 Choice (java.awt.Choice)1 Label (java.awt.Label)1 Point (java.awt.Point)1