Search in sources :

Example 1 with WindowOrganiser

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

the class CreateData method showSummary.

private double showSummary(List<? extends FluorophoreSequenceModel> fluorophores, List<LocalisationModel> localisations) {
    IJ.showStatus("Calculating statistics ...");
    final Statistics[] stats = new Statistics[NAMES.length];
    for (int i = 0; i < stats.length; i++) {
        stats[i] = (settings.getShowHistograms() || alwaysRemoveOutliers[i]) ? new StoredDataStatistics() : new Statistics();
    }
    // Find the largest timepoint
    final ImagePlus outputImp = WindowManager.getImage(benchmarkImageId);
    int frameCount;
    if (outputImp == null) {
        sortLocalisationsByTime(localisations);
        frameCount = localisations.get(localisations.size() - 1).getTime();
    } else {
        frameCount = outputImp.getStackSize();
    }
    final int[] countHistogram = new int[frameCount + 1];
    // Use the localisations that were drawn to create the sampled on/off times
    rebuildNeighbours(localisations);
    // Assume that there is at least one localisation
    final LocalisationModel first = localisations.get(0);
    // The current localisation
    int currentId = first.getId();
    // The last time this localisation was on
    int lastT = first.getTime();
    // Number of blinks
    int blinks = 0;
    // On-time of current pulse
    int currentT = 0;
    double signal = 0;
    final double centreOffset = settings.getSize() * 0.5;
    // Used to convert the sampled times in frames into seconds
    final double framesPerSecond = 1000.0 / settings.getExposureTime();
    // final double gain = new CreateDataSettingsHelper(settings).getTotalGainSafe();
    for (final LocalisationModel l : localisations) {
        final double[] data = l.getData();
        if (data == null) {
            throw new IllegalStateException("No localisation data. This should not happen!");
        }
        final double noise = data[1];
        final double sx = data[2];
        final double sy = data[3];
        final double intensityInPhotons = data[4];
        // Q. What if the noise is zero, i.e. no background photon / read noise?
        // Just ignore it at current. This is only an approximation to the SNR estimate
        // if this is not a Gaussian spot.
        final double snr = Gaussian2DPeakResultHelper.getMeanSignalUsingP05(intensityInPhotons, sx, sy) / noise;
        stats[SIGNAL].add(intensityInPhotons);
        stats[NOISE].add(noise);
        if (noise != 0) {
            stats[SNR].add(snr);
        }
        // if (l.isContinuous())
        if (l.getNext() != null && l.getPrevious() != null) {
            stats[SIGNAL_CONTINUOUS].add(intensityInPhotons);
            if (noise != 0) {
                stats[SNR_CONTINUOUS].add(snr);
            }
        }
        final int id = l.getId();
        // Check if this a new fluorophore
        if (currentId != id) {
            // Add previous fluorophore
            stats[SAMPLED_BLINKS].add(blinks);
            stats[SAMPLED_T_ON].add(currentT / framesPerSecond);
            stats[TOTAL_SIGNAL].add(signal);
            // Reset
            blinks = 0;
            currentT = 1;
            currentId = id;
            signal = intensityInPhotons;
        } else {
            signal += intensityInPhotons;
            // Check if the current fluorophore pulse is broken (i.e. a blink)
            if (l.getTime() - 1 > lastT) {
                blinks++;
                stats[SAMPLED_T_ON].add(currentT / framesPerSecond);
                currentT = 1;
                stats[SAMPLED_T_OFF].add(((l.getTime() - 1) - lastT) / framesPerSecond);
            } else {
                // Continuous on-time
                currentT++;
            }
        }
        lastT = l.getTime();
        countHistogram[lastT]++;
        stats[X].add((l.getX() - centreOffset) * settings.getPixelPitch());
        stats[Y].add((l.getY() - centreOffset) * settings.getPixelPitch());
        stats[Z].add(l.getZ() * settings.getPixelPitch());
    }
    // Final fluorophore
    stats[SAMPLED_BLINKS].add(blinks);
    stats[SAMPLED_T_ON].add(currentT / framesPerSecond);
    stats[TOTAL_SIGNAL].add(signal);
    // Samples per frame
    for (int t = 1; t < countHistogram.length; t++) {
        stats[SAMPLES].add(countHistogram[t]);
    }
    if (fluorophores != null) {
        for (final FluorophoreSequenceModel f : fluorophores) {
            stats[BLINKS].add(f.getNumberOfBlinks());
            // On-time
            for (final double t : f.getOnTimes()) {
                stats[T_ON].add(t);
            }
            // Off-time
            for (final double t : f.getOffTimes()) {
                stats[T_OFF].add(t);
            }
        }
    } else {
        // show no blinks
        stats[BLINKS].add(0);
        stats[T_ON].add(1);
    }
    if (results != null) {
        // Convert depth-of-field to pixels
        final double depth = settings.getDepthOfField() / settings.getPixelPitch();
        try {
            // Get widths
            final WidthResultProcedure wp = new WidthResultProcedure(results, DistanceUnit.PIXEL);
            wp.getW();
            stats[WIDTH].add(wp.wx);
        } catch (final DataException ex) {
            ImageJUtils.log("Unable to compute width: " + ex.getMessage());
        }
        try {
            // Get z depth
            final StandardResultProcedure sp = new StandardResultProcedure(results, DistanceUnit.PIXEL);
            sp.getXyz();
            // Get precision
            final PrecisionResultProcedure pp = new PrecisionResultProcedure(results);
            pp.getPrecision();
            stats[PRECISION].add(pp.precisions);
            for (int i = 0; i < pp.size(); i++) {
                if (Math.abs(sp.z[i]) < depth) {
                    stats[PRECISION_IN_FOCUS].add(pp.precisions[i]);
                }
            }
        } catch (final DataException ex) {
            ImageJUtils.log("Unable to compute LSE precision: " + ex.getMessage());
        }
        // Compute density per frame. Multi-thread for speed
        if (settings.getDensityRadius() > 0) {
            final int threadCount = Prefs.getThreads();
            final Ticker ticker = ImageJUtils.createTicker(results.getLastFrame(), threadCount, "Calculating density ...");
            final ExecutorService threadPool = Executors.newFixedThreadPool(threadCount);
            final List<Future<?>> futures = new LinkedList<>();
            final TFloatArrayList coordsX = new TFloatArrayList();
            final TFloatArrayList coordsY = new TFloatArrayList();
            final Statistics densityStats = stats[DENSITY];
            final float radius = (float) (settings.getDensityRadius() * getHwhm());
            final Rectangle bounds = results.getBounds();
            final double area = (double) bounds.width * bounds.height;
            // Store the density for each result.
            final int[] allDensity = new int[results.size()];
            final FrameCounter counter = results.newFrameCounter();
            results.forEach((PeakResultProcedure) result -> {
                if (counter.advance(result.getFrame())) {
                    counter.increment(runDensityCalculation(threadPool, futures, coordsX, coordsY, densityStats, radius, area, allDensity, counter.getCount(), ticker));
                }
                coordsX.add(result.getXPosition());
                coordsY.add(result.getYPosition());
            });
            runDensityCalculation(threadPool, futures, coordsX, coordsY, densityStats, radius, area, allDensity, counter.getCount(), ticker);
            ConcurrencyUtils.waitForCompletionUnchecked(futures);
            threadPool.shutdown();
            ImageJUtils.finished();
            // Split results into singles (density = 0) and clustered (density > 0)
            final MemoryPeakResults singles = copyMemoryPeakResults("No Density");
            final MemoryPeakResults clustered = copyMemoryPeakResults("Density");
            counter.reset();
            results.forEach((PeakResultProcedure) result -> {
                final int density = allDensity[counter.getAndIncrement()];
                result.setOrigValue(density);
                if (density == 0) {
                    singles.add(result);
                } else {
                    clustered.add(result);
                }
            });
        }
    }
    final StringBuilder sb = new StringBuilder();
    sb.append(datasetNumber).append('\t');
    if (settings.getCameraType() == CameraType.SCMOS) {
        sb.append("sCMOS (").append(settings.getCameraModelName()).append(") ");
        final Rectangle bounds = cameraModel.getBounds();
        sb.append(" ").append(bounds.x).append(",").append(bounds.y);
        final int size = settings.getSize();
        sb.append(" ").append(size).append("x").append(size);
    } else if (CalibrationProtosHelper.isCcdCameraType(settings.getCameraType())) {
        sb.append(CalibrationProtosHelper.getName(settings.getCameraType()));
        final int size = settings.getSize();
        sb.append(" ").append(size).append("x").append(size);
        if (settings.getCameraType() == CameraType.EMCCD) {
            sb.append(" EM=").append(settings.getEmGain());
        }
        sb.append(" CG=").append(settings.getCameraGain());
        sb.append(" RN=").append(settings.getReadNoise());
        sb.append(" B=").append(settings.getBias());
    } else {
        throw new IllegalStateException();
    }
    sb.append(" QE=").append(settings.getQuantumEfficiency()).append('\t');
    sb.append(settings.getPsfModel());
    if (psfModelType == PSF_MODEL_IMAGE) {
        sb.append(" Image").append(settings.getPsfImageName());
    } else if (psfModelType == PSF_MODEL_ASTIGMATISM) {
        sb.append(" model=").append(settings.getAstigmatismModel());
    } else {
        sb.append(" DoF=").append(MathUtils.rounded(settings.getDepthOfFocus()));
        if (settings.getEnterWidth()) {
            sb.append(" SD=").append(MathUtils.rounded(settings.getPsfSd()));
        } else {
            sb.append(" λ=").append(MathUtils.rounded(settings.getWavelength()));
            sb.append(" NA=").append(MathUtils.rounded(settings.getNumericalAperture()));
        }
    }
    sb.append('\t');
    sb.append((fluorophores == null) ? localisations.size() : fluorophores.size()).append('\t');
    sb.append(stats[SAMPLED_BLINKS].getN() + (int) stats[SAMPLED_BLINKS].getSum()).append('\t');
    sb.append(localisations.size()).append('\t');
    sb.append(frameCount).append('\t');
    sb.append(MathUtils.rounded(areaInUm)).append('\t');
    sb.append(MathUtils.rounded(localisations.size() / (areaInUm * frameCount), 4)).append('\t');
    sb.append(MathUtils.rounded(getHwhm(), 4)).append('\t');
    double sd = getPsfSd();
    sb.append(MathUtils.rounded(sd, 4)).append('\t');
    sd *= settings.getPixelPitch();
    final double sa = PsfCalculator.squarePixelAdjustment(sd, settings.getPixelPitch()) / settings.getPixelPitch();
    sb.append(MathUtils.rounded(sa, 4)).append('\t');
    // Width not valid for the Image PSF.
    // Q. Is this true? We can approximate the FHWM for a spot-like image PSF.
    final int nStats = (psfModelType == PSF_MODEL_IMAGE) ? stats.length - 1 : stats.length;
    for (int i = 0; i < nStats; i++) {
        final double centre = (alwaysRemoveOutliers[i]) ? ((StoredDataStatistics) stats[i]).getStatistics().getPercentile(50) : stats[i].getMean();
        sb.append(MathUtils.rounded(centre, 4)).append('\t');
    }
    createSummaryTable().accept(sb.toString());
    // Show histograms
    if (settings.getShowHistograms() && !java.awt.GraphicsEnvironment.isHeadless()) {
        IJ.showStatus("Calculating histograms ...");
        final boolean[] chosenHistograms = getChoosenHistograms();
        final WindowOrganiser wo = new WindowOrganiser();
        final HistogramPlotBuilder builder = new HistogramPlotBuilder(TITLE);
        for (int i = 0; i < NAMES.length; i++) {
            if (chosenHistograms[i]) {
                builder.setData((StoredDataStatistics) stats[i]).setName(NAMES[i]).setIntegerBins(integerDisplay[i]).setRemoveOutliersOption((settings.getRemoveOutliers() || alwaysRemoveOutliers[i]) ? 2 : 0).setNumberOfBins(settings.getHistogramBins()).show(wo);
            }
        }
        wo.tile();
    }
    IJ.showStatus("");
    return stats[SIGNAL].getMean();
}
Also used : RandomUtils(uk.ac.sussex.gdsc.core.utils.rng.RandomUtils) LoadLocalisations(uk.ac.sussex.gdsc.smlm.ij.plugins.LoadLocalisations) Arrays(java.util.Arrays) PoissonSamplerUtils(uk.ac.sussex.gdsc.core.utils.rng.PoissonSamplerUtils) Molecule(uk.ac.sussex.gdsc.smlm.data.config.MoleculeProtos.Molecule) IdPeakResult(uk.ac.sussex.gdsc.smlm.results.IdPeakResult) ImageProcessor(ij.process.ImageProcessor) HistogramPlotBuilder(uk.ac.sussex.gdsc.core.ij.HistogramPlot.HistogramPlotBuilder) ConfigurationException(uk.ac.sussex.gdsc.smlm.data.config.ConfigurationException) AiryPsfModel(uk.ac.sussex.gdsc.smlm.model.AiryPsfModel) GaussianPsfModel(uk.ac.sussex.gdsc.smlm.model.GaussianPsfModel) MemoryUtils(uk.ac.sussex.gdsc.core.utils.MemoryUtils) PSFType(uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.PSFType) HelpUrls(uk.ac.sussex.gdsc.smlm.ij.plugins.HelpUrls) ResultsManager(uk.ac.sussex.gdsc.smlm.ij.plugins.ResultsManager) GammaDistribution(org.apache.commons.math3.distribution.GammaDistribution) Future(java.util.concurrent.Future) Vector(java.util.Vector) MemoryPeakResults(uk.ac.sussex.gdsc.smlm.results.MemoryPeakResults) Map(java.util.Map) DensityManager(uk.ac.sussex.gdsc.core.clustering.DensityManager) UnicodeReader(uk.ac.sussex.gdsc.core.utils.UnicodeReader) RadialFalloffIllumination(uk.ac.sussex.gdsc.smlm.model.RadialFalloffIllumination) DistanceUnit(uk.ac.sussex.gdsc.smlm.data.config.UnitProtos.DistanceUnit) RawResultProcedure(uk.ac.sussex.gdsc.smlm.results.procedures.RawResultProcedure) ConcurrencyUtils(uk.ac.sussex.gdsc.core.utils.concurrent.ConcurrencyUtils) TextUtils(uk.ac.sussex.gdsc.core.utils.TextUtils) Gaussian2DFunction(uk.ac.sussex.gdsc.smlm.function.gaussian.Gaussian2DFunction) Executors(java.util.concurrent.Executors) PeakFit(uk.ac.sussex.gdsc.smlm.ij.plugins.PeakFit) TIntHashSet(gnu.trove.set.hash.TIntHashSet) ImagePlus(ij.ImagePlus) LocalisationList(uk.ac.sussex.gdsc.smlm.ij.plugins.LoadLocalisations.LocalisationList) UniformDistribution(uk.ac.sussex.gdsc.smlm.model.UniformDistribution) ShortProcessor(ij.process.ShortProcessor) FileUtils(uk.ac.sussex.gdsc.core.utils.FileUtils) CameraModelFisherInformationAnalysis(uk.ac.sussex.gdsc.smlm.ij.plugins.CameraModelFisherInformationAnalysis) CalibrationProtosHelper(uk.ac.sussex.gdsc.smlm.data.config.CalibrationProtosHelper) PlugIn(ij.plugin.PlugIn) LocalisationModelSet(uk.ac.sussex.gdsc.smlm.model.LocalisationModelSet) AiryPattern(uk.ac.sussex.gdsc.smlm.model.AiryPattern) Prefs(ij.Prefs) FrameCounter(uk.ac.sussex.gdsc.smlm.results.count.FrameCounter) WindowManager(ij.WindowManager) PeakResult(uk.ac.sussex.gdsc.smlm.results.PeakResult) CreateDataSettings(uk.ac.sussex.gdsc.smlm.ij.settings.GUIProtos.CreateDataSettings) GridDistribution(uk.ac.sussex.gdsc.smlm.model.GridDistribution) ArrayList(java.util.ArrayList) Atom(uk.ac.sussex.gdsc.smlm.data.config.MoleculeProtos.Atom) AutoThreshold(uk.ac.sussex.gdsc.core.threshold.AutoThreshold) GenericDialog(ij.gui.GenericDialog) ImagePsfModel(uk.ac.sussex.gdsc.smlm.model.ImagePsfModel) PsfModel(uk.ac.sussex.gdsc.smlm.model.PsfModel) PeakResultProcedure(uk.ac.sussex.gdsc.smlm.results.procedures.PeakResultProcedure) PoissonGaussianFisherInformation(uk.ac.sussex.gdsc.smlm.function.PoissonGaussianFisherInformation) ImagePsfHelper(uk.ac.sussex.gdsc.smlm.ij.settings.ImagePsfHelper) UnivariateLikelihoodFisherInformationCalculator(uk.ac.sussex.gdsc.smlm.fitting.UnivariateLikelihoodFisherInformationCalculator) SpatialIllumination(uk.ac.sussex.gdsc.smlm.model.SpatialIllumination) PeakResultsReader(uk.ac.sussex.gdsc.smlm.results.PeakResultsReader) PsfCombiner(uk.ac.sussex.gdsc.smlm.ij.plugins.PsfCombiner) DiffusionType(uk.ac.sussex.gdsc.smlm.model.DiffusionType) Files(java.nio.file.Files) BufferedWriter(java.io.BufferedWriter) FitWorker(uk.ac.sussex.gdsc.smlm.engine.FitWorker) RandomGeneratorAdapter(uk.ac.sussex.gdsc.core.utils.rng.RandomGeneratorAdapter) AtomOrBuilder(uk.ac.sussex.gdsc.smlm.data.config.MoleculeProtos.AtomOrBuilder) IOException(java.io.IOException) SamplerUtils(uk.ac.sussex.gdsc.core.utils.rng.SamplerUtils) DiscreteUniformSampler(org.apache.commons.rng.sampling.distribution.DiscreteUniformSampler) File(java.io.File) SummaryStatistics(org.apache.commons.math3.stat.descriptive.SummaryStatistics) FloatProcessor(ij.process.FloatProcessor) BasePoissonFisherInformation(uk.ac.sussex.gdsc.smlm.function.BasePoissonFisherInformation) Paths(java.nio.file.Paths) AstigmatismZModel(uk.ac.sussex.gdsc.smlm.function.gaussian.AstigmatismZModel) TextFilePeakResults(uk.ac.sussex.gdsc.smlm.results.TextFilePeakResults) EmCcdCameraModel(uk.ac.sussex.gdsc.smlm.model.camera.EmCcdCameraModel) ImageStack(ij.ImageStack) PoissonSampler(org.apache.commons.rng.sampling.distribution.PoissonSampler) CameraModel(uk.ac.sussex.gdsc.smlm.model.camera.CameraModel) ExtendedPeakResult(uk.ac.sussex.gdsc.smlm.results.ExtendedPeakResult) PsfHelper(uk.ac.sussex.gdsc.smlm.data.config.PsfHelper) BufferedReader(java.io.BufferedReader) ImmutableMemoryPeakResults(uk.ac.sussex.gdsc.smlm.results.ImmutableMemoryPeakResults) DoubleEquality(uk.ac.sussex.gdsc.core.utils.DoubleEquality) StandardResultProcedure(uk.ac.sussex.gdsc.smlm.results.procedures.StandardResultProcedure) SphericalDistribution(uk.ac.sussex.gdsc.smlm.model.SphericalDistribution) TIntArrayList(gnu.trove.list.array.TIntArrayList) GaussianFilter(uk.ac.sussex.gdsc.smlm.filters.GaussianFilter) TextWindow(ij.text.TextWindow) StandardValueProcedure(uk.ac.sussex.gdsc.smlm.function.StandardValueProcedure) ImagePSF(uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.ImagePSF) Formatter(java.util.Formatter) FixedLifetimeImageModel(uk.ac.sussex.gdsc.smlm.model.FixedLifetimeImageModel) StoredDataStatistics(uk.ac.sussex.gdsc.core.utils.StoredDataStatistics) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) PeakResults(uk.ac.sussex.gdsc.smlm.results.PeakResults) DataException(uk.ac.sussex.gdsc.core.data.DataException) PsfCalculator(uk.ac.sussex.gdsc.smlm.ij.plugins.PsfCalculator) EmpiricalDistribution(org.apache.commons.math3.random.EmpiricalDistribution) MathUtils(uk.ac.sussex.gdsc.core.utils.MathUtils) BinomialDiscreteInverseCumulativeProbabilityFunction(uk.ac.sussex.gdsc.core.utils.rng.BinomialDiscreteInverseCumulativeProbabilityFunction) CalibrationWriter(uk.ac.sussex.gdsc.smlm.data.config.CalibrationWriter) Offset(uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.Offset) TextFormat(com.google.protobuf.TextFormat) PsfProtosHelper(uk.ac.sussex.gdsc.smlm.data.config.PsfProtosHelper) SettingsManager(uk.ac.sussex.gdsc.smlm.ij.settings.SettingsManager) ItemEvent(java.awt.event.ItemEvent) CameraType(uk.ac.sussex.gdsc.smlm.data.config.CalibrationProtos.CameraType) SpatialDistribution(uk.ac.sussex.gdsc.smlm.model.SpatialDistribution) ExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog) AstigmatismModelManager(uk.ac.sussex.gdsc.smlm.ij.plugins.AstigmatismModelManager) UniformRealDistribution(org.apache.commons.math3.distribution.UniformRealDistribution) MoleculeModel(uk.ac.sussex.gdsc.smlm.model.MoleculeModel) TIntIntHashMap(gnu.trove.map.hash.TIntIntHashMap) MarsagliaTsangGammaSampler(uk.ac.sussex.gdsc.core.utils.rng.MarsagliaTsangGammaSampler) WidthResultProcedure(uk.ac.sussex.gdsc.smlm.results.procedures.WidthResultProcedure) Gaussian2DPeakResultHelper(uk.ac.sussex.gdsc.smlm.results.Gaussian2DPeakResultHelper) List(java.util.List) FluorophoreSequenceModel(uk.ac.sussex.gdsc.smlm.model.FluorophoreSequenceModel) BirResultProcedure(uk.ac.sussex.gdsc.smlm.results.procedures.BirResultProcedure) Entry(java.util.Map.Entry) CompoundMoleculeModel(uk.ac.sussex.gdsc.smlm.model.CompoundMoleculeModel) RealDistribution(org.apache.commons.math3.distribution.RealDistribution) HoltzerAstigmatismZModel(uk.ac.sussex.gdsc.smlm.function.gaussian.HoltzerAstigmatismZModel) ImageModel(uk.ac.sussex.gdsc.smlm.model.ImageModel) MaskDistribution3D(uk.ac.sussex.gdsc.smlm.model.MaskDistribution3D) TypeConverter(uk.ac.sussex.gdsc.core.data.utils.TypeConverter) PrecisionResultProcedure(uk.ac.sussex.gdsc.smlm.results.procedures.PrecisionResultProcedure) Rectangle(java.awt.Rectangle) AtomicBoolean(java.util.concurrent.atomic.AtomicBoolean) PSF(uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.PSF) WindowOrganiser(uk.ac.sussex.gdsc.core.ij.plugin.WindowOrganiser) IntensityUnit(uk.ac.sussex.gdsc.smlm.data.config.UnitProtos.IntensityUnit) Mixture(uk.ac.sussex.gdsc.smlm.data.config.MoleculeProtos.Mixture) AtomicReference(java.util.concurrent.atomic.AtomicReference) SobolSequenceGenerator(org.apache.commons.math3.random.SobolSequenceGenerator) MaskDistribution(uk.ac.sussex.gdsc.smlm.model.MaskDistribution) OptionListener(uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog.OptionListener) OpenDialog(ij.io.OpenDialog) ParameterUtils(uk.ac.sussex.gdsc.smlm.ij.plugins.ParameterUtils) IJImageSource(uk.ac.sussex.gdsc.smlm.ij.IJImageSource) NoiseEstimatorMethod(uk.ac.sussex.gdsc.smlm.data.config.FitProtos.NoiseEstimatorMethod) ReadHint(uk.ac.sussex.gdsc.smlm.results.ImageSource.ReadHint) ExponentialDistribution(org.apache.commons.math3.distribution.ExponentialDistribution) FisherInformationMatrix(uk.ac.sussex.gdsc.smlm.fitting.FisherInformationMatrix) UnitHelper(uk.ac.sussex.gdsc.smlm.data.config.UnitHelper) LinkedList(java.util.LinkedList) CcdCameraModel(uk.ac.sussex.gdsc.smlm.model.camera.CcdCameraModel) FileSaver(ij.io.FileSaver) Statistics(uk.ac.sussex.gdsc.core.utils.Statistics) ExecutorService(java.util.concurrent.ExecutorService) CreateDataSettingsHelper(uk.ac.sussex.gdsc.smlm.ij.settings.CreateDataSettingsHelper) TFloatArrayList(gnu.trove.list.array.TFloatArrayList) FunctionHelper(uk.ac.sussex.gdsc.smlm.function.FunctionHelper) UniformRandomProvider(org.apache.commons.rng.UniformRandomProvider) PoissonSamplerCache(org.apache.commons.rng.sampling.distribution.PoissonSamplerCache) AstigmatismModel(uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.AstigmatismModel) ConversionException(uk.ac.sussex.gdsc.core.data.utils.ConversionException) SplitMix64(org.apache.commons.rng.core.source64.SplitMix64) Checkbox(java.awt.Checkbox) ActivationEnergyImageModel(uk.ac.sussex.gdsc.smlm.model.ActivationEnergyImageModel) LoadLocalisationsSettings(uk.ac.sussex.gdsc.smlm.ij.settings.GUIProtos.LoadLocalisationsSettings) FileInputStream(java.io.FileInputStream) Ticker(uk.ac.sussex.gdsc.core.logging.Ticker) PsfModelGradient1Function(uk.ac.sussex.gdsc.smlm.model.PsfModelGradient1Function) InterpolatedPoissonFisherInformation(uk.ac.sussex.gdsc.smlm.function.InterpolatedPoissonFisherInformation) Consumer(java.util.function.Consumer) CameraModelManager(uk.ac.sussex.gdsc.smlm.ij.plugins.CameraModelManager) LocalisationModel(uk.ac.sussex.gdsc.smlm.model.LocalisationModel) ImageJUtils(uk.ac.sussex.gdsc.core.ij.ImageJUtils) UniformIllumination(uk.ac.sussex.gdsc.smlm.model.UniformIllumination) SynchronizedPeakResults(uk.ac.sussex.gdsc.smlm.results.SynchronizedPeakResults) IJ(ij.IJ) NullArgumentException(org.apache.commons.math3.exception.NullArgumentException) SmlmUsageTracker(uk.ac.sussex.gdsc.smlm.ij.plugins.SmlmUsageTracker) InverseTransformDiscreteSampler(org.apache.commons.rng.sampling.distribution.InverseTransformDiscreteSampler) Comparator(java.util.Comparator) Collections(java.util.Collections) NormalizedGaussianSampler(org.apache.commons.rng.sampling.distribution.NormalizedGaussianSampler) LocalList(uk.ac.sussex.gdsc.core.utils.LocalList) UniformRandomProviders(uk.ac.sussex.gdsc.core.utils.rng.UniformRandomProviders) Rectangle(java.awt.Rectangle) HistogramPlotBuilder(uk.ac.sussex.gdsc.core.ij.HistogramPlot.HistogramPlotBuilder) MemoryPeakResults(uk.ac.sussex.gdsc.smlm.results.MemoryPeakResults) ImmutableMemoryPeakResults(uk.ac.sussex.gdsc.smlm.results.ImmutableMemoryPeakResults) Ticker(uk.ac.sussex.gdsc.core.logging.Ticker) FrameCounter(uk.ac.sussex.gdsc.smlm.results.count.FrameCounter) StoredDataStatistics(uk.ac.sussex.gdsc.core.utils.StoredDataStatistics) WidthResultProcedure(uk.ac.sussex.gdsc.smlm.results.procedures.WidthResultProcedure) WindowOrganiser(uk.ac.sussex.gdsc.core.ij.plugin.WindowOrganiser) PrecisionResultProcedure(uk.ac.sussex.gdsc.smlm.results.procedures.PrecisionResultProcedure) SummaryStatistics(org.apache.commons.math3.stat.descriptive.SummaryStatistics) StoredDataStatistics(uk.ac.sussex.gdsc.core.utils.StoredDataStatistics) Statistics(uk.ac.sussex.gdsc.core.utils.Statistics) ImagePlus(ij.ImagePlus) ReadHint(uk.ac.sussex.gdsc.smlm.results.ImageSource.ReadHint) LinkedList(java.util.LinkedList) TFloatArrayList(gnu.trove.list.array.TFloatArrayList) DataException(uk.ac.sussex.gdsc.core.data.DataException) LocalisationModel(uk.ac.sussex.gdsc.smlm.model.LocalisationModel) FluorophoreSequenceModel(uk.ac.sussex.gdsc.smlm.model.FluorophoreSequenceModel) ExecutorService(java.util.concurrent.ExecutorService) Future(java.util.concurrent.Future) StandardResultProcedure(uk.ac.sussex.gdsc.smlm.results.procedures.StandardResultProcedure)

Example 2 with WindowOrganiser

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

the class BenchmarkSpotFilter method run.

@Override
public void run(String arg) {
    SmlmUsageTracker.recordPlugin(this.getClass(), arg);
    extraOptions = ImageJUtils.isExtraOptions();
    batchMode = "batch".equals(arg);
    simulationParameters = CreateData.getSimulationParameters();
    if (simulationParameters == null) {
        IJ.error(TITLE, "No benchmark spot parameters in memory");
        return;
    }
    imp = CreateData.getImage();
    if (imp == null) {
        IJ.error(TITLE, "No benchmark image");
        return;
    }
    results = CreateData.getResults();
    if (results == null) {
        IJ.error(TITLE, "No benchmark results in memory");
        return;
    }
    // Set-up for the simulation
    try {
        if (results.getCalibration() == null) {
            throw new ConfigurationException("Require calibrated results");
        }
        if (results.getCalibrationReader().getDistanceUnit() != DistanceUnit.PIXEL) {
            throw new ConfigurationException("Require results in pixel distance units");
        }
        if (results.getCalibrationReader().getIntensityUnit() != IntensityUnit.PHOTON) {
            throw new ConfigurationException("Require results in photon units");
        }
        // This plugin is heavily reliant on the results being represented as a
        // Gaussian2D function.
        final int flags = Gaussian2DPeakResultHelper.AMPLITUDE | Gaussian2DPeakResultHelper.PIXEL_AMPLITUDE;
        calculator = Gaussian2DPeakResultHelper.create(results.getPsf(), results.getCalibration(), flags);
        cameraModel = CreateData.getCameraModel(simulationParameters);
    } catch (final ConfigurationException ex) {
        IJ.error(TITLE, "Bad configuration: " + ex.getMessage());
        return;
    }
    if (!showDialog()) {
        return;
    }
    // Get the simulation results into a list per frame
    simulationCoords = getSimulationCoordinates();
    // Clear old results to free memory
    BenchmarkSpotFilterResult localFilterResult;
    filterResult.set(null);
    // For graphs
    windowOrganiser = new WindowOrganiser();
    if (batchMode) {
        // Clear the cached results if the setting changed
        final SettingsList settingList = new SettingsList(simulationParameters.id, settings.filterRelativeDistances, // search, maxSearch, // Ignore search distance for smart caching
        settings.border, settings.scoreRelativeDistances, settings.analysisBorder, settings.hardBorder, settings.matchingMethod, settings.upperDistance, settings.lowerDistance, settings.upperSignalFactor, settings.lowerSignalFactor, settings.recallFraction);
        final ArrayList<BatchResult[]> cachedResults = getCachedBatchResults(settingList);
        // Batch mode to test enumeration of filters
        final double sd = simulationParameters.sd / simulationParameters.pixelPitch;
        final int limit = (int) Math.floor(3 * sd);
        // This should be in integers otherwise we may repeat search box sizes
        final int[] searchParam = SimpleArrayUtils.newArray(settings.maxSearch - settings.minSearch + 1, settings.minSearch, 1);
        // Continuous parameters
        final double[] pEmpty = new double[0];
        final double[] mParam = (settings.batchMean) ? getRange(limit, 0.05) : pEmpty;
        final double[] gParam = (settings.batchGaussian) ? getRange(limit, 0.05) : pEmpty;
        // Less continuous parameters
        final double[] cParam = (settings.batchCircular) ? getRange(limit, 0.5) : pEmpty;
        // Discrete parameters
        final double[] medParam = (settings.batchMedian) ? getRange(limit, 1) : pEmpty;
        setupProgress((long) imp.getImageStackSize() * searchParam.length * (mParam.length + gParam.length + cParam.length + medParam.length), "Frame");
        ArrayList<BatchResult[]> batchResults = new ArrayList<>(cachedResults.size());
        double param2 = 0;
        if (settings.differenceFilter && settings.differenceSmooth > 0) {
            if (settings.filterRelativeDistances) {
                // Convert to absolute for batch run
                param2 = MathUtils.roundUsingDecimalPlaces(settings.differenceSmooth * config.getHwhmMin(), 3);
            } else {
                // Already an absolute value
                param2 = settings.differenceSmooth;
            }
            config.setDataFilterType(DataFilterType.DIFFERENCE);
        } else {
            config.setDataFilterType(DataFilterType.SINGLE);
        }
        for (final int search : searchParam) {
            // Batch runs use absolute distance
            config.setSearch(search, true);
            // Allow re-use of these if they are cached to allow quick reanalysis of results.
            if (settings.batchMean) {
                batchResults.add(getOrCompute(cachedResults, DataFilterMethod.MEAN, mParam, search, param2));
            }
            if (settings.batchGaussian) {
                batchResults.add(getOrCompute(cachedResults, DataFilterMethod.GAUSSIAN, gParam, search, param2));
            }
            if (settings.batchCircular) {
                batchResults.add(getOrCompute(cachedResults, DataFilterMethod.CIRCULAR_MEAN, cParam, search, param2));
            }
            if (settings.batchMean) {
                batchResults.add(getOrCompute(cachedResults, DataFilterMethod.MEDIAN, medParam, search, param2));
            }
        }
        IJ.showProgress(-1);
        IJ.showStatus("");
        if (ImageJUtils.isInterrupted()) {
            return;
        }
        // Save the results in a cache
        setCachedBatchResults(settingList, cachedResults);
        // Analysis options
        final ExtendedGenericDialog gd = new ExtendedGenericDialog(TITLE);
        final boolean haveCached = cachedResults.size() > batchResults.size();
        if (haveCached) {
            gd.addCheckbox("Use_cached_results", settings.useCached);
        }
        gd.addMessage("Choose performance plots:");
        for (int i = 0; i < settings.batchPlot.length; i++) {
            gd.addCheckbox(Settings.batchPlotNames[i], settings.batchPlot[i]);
        }
        gd.addChoice("Selection", Settings.SELECTION_METHOD, settings.selectionMethod);
        gd.addCheckbox("Show_plots", settings.showPlot);
        gd.addCheckbox("Plot_rank_by_intensity", settings.rankByIntensity);
        gd.addCheckbox("Show_failures_plots", settings.showFailuresPlot);
        gd.addCheckbox("Show_TP", settings.showTP);
        gd.addCheckbox("Show_FP", settings.showFP);
        gd.addCheckbox("Show_FN", settings.showFN);
        gd.addHelp(HelpUrls.getUrl("filter-spot-data-batch"));
        gd.showDialog();
        if (gd.wasCanceled()) {
            return;
        }
        if (haveCached) {
            settings.useCached = gd.getNextBoolean();
            if (settings.useCached) {
                batchResults = cachedResults;
            }
        }
        for (int i = 0; i < settings.batchPlot.length; i++) {
            settings.batchPlot[i] = gd.getNextBoolean();
        }
        settings.selectionMethod = gd.getNextChoiceIndex();
        settings.showPlot = gd.getNextBoolean();
        settings.rankByIntensity = gd.getNextBoolean();
        settings.showFailuresPlot = gd.getNextBoolean();
        settings.showTP = gd.getNextBoolean();
        settings.showFP = gd.getNextBoolean();
        settings.showFN = gd.getNextBoolean();
        // Plot charts
        for (int i = 0; i < settings.batchPlot.length; i++) {
            plot(i, batchResults);
        }
        // Store in global singleton
        localFilterResult = analyse(batchResults);
    } else {
        // Single filter mode
        setupProgress(imp.getImageStackSize(), "Frame");
        localFilterResult = runAnalysis(config);
    }
    ImageJUtils.clearSlowProgress();
    IJ.showStatus("");
    if (localFilterResult == null) {
        return;
    }
    // Store the latest result
    filterResult.set(localFilterResult);
    // Debugging the matches
    if (settings.debug) {
        addSpotsToMemory(localFilterResult.filterResults);
    }
    if (settings.showFailuresPlot) {
        showFailuresPlot(localFilterResult);
    }
    if (settings.showPlot) {
        showPlot(localFilterResult);
    }
    if (isShowOverlay()) {
        showOverlay(imp, localFilterResult);
    }
    windowOrganiser.tile();
}
Also used : SettingsList(uk.ac.sussex.gdsc.core.utils.SettingsList) ConfigurationException(uk.ac.sussex.gdsc.smlm.data.config.ConfigurationException) ArrayList(java.util.ArrayList) WindowOrganiser(uk.ac.sussex.gdsc.core.ij.plugin.WindowOrganiser) ExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog) PeakResultPoint(uk.ac.sussex.gdsc.smlm.results.PeakResultPoint) BasePoint(uk.ac.sussex.gdsc.core.match.BasePoint)

Example 3 with WindowOrganiser

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

the class SpotFinderPreview method run.

private void run(ImageProcessor ip, MaximaSpotFilter filter) {
    if (refreshing) {
        return;
    }
    currentSlice = imp.getCurrentSlice();
    final Rectangle bounds = ip.getRoi();
    // Crop to the ROI
    FloatProcessor fp = ip.crop().toFloat(0, null);
    float[] data = (float[]) fp.getPixels();
    final int width = fp.getWidth();
    final int height = fp.getHeight();
    // Store the mean bias and gain of the region data.
    // This is used to correctly overlay the filtered data on the original image.
    double bias = 0;
    double gain = 1;
    boolean adjust = false;
    // Set weights
    final CameraModel cameraModel = fitConfig.getCameraModel();
    if (!(cameraModel instanceof FakePerPixelCameraModel)) {
        // This should be done on the normalised data
        final float[] w = cameraModel.getNormalisedWeights(bounds);
        filter.setWeights(w, width, height);
        data = data.clone();
        if (data.length < ip.getPixelCount()) {
            adjust = true;
            bias = MathUtils.sum(cameraModel.getBias(bounds)) / data.length;
            gain = MathUtils.sum(cameraModel.getGain(bounds)) / data.length;
        }
        cameraModel.removeBiasAndGain(bounds, data);
    }
    final Spot[] spots = filter.rank(data, width, height);
    data = filter.getPreprocessedData();
    final int size = spots.length;
    if (topNScrollBar != null) {
        topNScrollBar.setMaximum(size);
        selectScrollBar.setMaximum(size);
    }
    fp = new FloatProcessor(width, height, data);
    final FloatProcessor out = new FloatProcessor(ip.getWidth(), ip.getHeight());
    out.copyBits(ip, 0, 0, Blitter.COPY);
    if (adjust) {
        fp.multiply(gain);
        fp.add(bias);
    }
    out.insert(fp, bounds.x, bounds.y);
    final double min = fp.getMin();
    final double max = fp.getMax();
    out.setMinAndMax(min, max);
    final Overlay o = new Overlay();
    o.add(new ImageRoi(0, 0, out));
    if (label != null) {
        // Get results for frame
        final Coordinate[] actual = ResultsMatchCalculator.getCoordinates(actualCoordinates, imp.getCurrentSlice());
        final Coordinate[] predicted = new Coordinate[size];
        for (int i = 0; i < size; i++) {
            predicted[i] = new BasePoint(spots[i].x + bounds.x, spots[i].y + bounds.y);
        }
        // Compute assignments
        final LocalList<FractionalAssignment> fractionalAssignments = new LocalList<>(3 * predicted.length);
        final double matchDistance = settings.distance * fitConfig.getInitialPeakStdDev();
        final RampedScore score = RampedScore.of(matchDistance, matchDistance * settings.lowerDistance / 100, false);
        final double dmin = matchDistance * matchDistance;
        final int nActual = actual.length;
        final int nPredicted = predicted.length;
        for (int j = 0; j < nPredicted; j++) {
            // Centre in the middle of the pixel
            final float x = predicted[j].getX() + 0.5f;
            final float y = predicted[j].getY() + 0.5f;
            // Any spots that match
            for (int i = 0; i < nActual; i++) {
                final double dx = (x - actual[i].getX());
                final double dy = (y - actual[i].getY());
                final double d2 = dx * dx + dy * dy;
                if (d2 <= dmin) {
                    final double d = Math.sqrt(d2);
                    final double s = score.score(d);
                    if (s == 0) {
                        continue;
                    }
                    double distance = 1 - s;
                    if (distance == 0) {
                        // In the case of a match below the distance thresholds
                        // the distance will be 0. To distinguish between candidates all below
                        // the thresholds just take the closest.
                        // We know d2 is below dmin so we subtract the delta.
                        distance -= (dmin - d2);
                    }
                    // Store the match
                    fractionalAssignments.add(new ImmutableFractionalAssignment(i, j, distance, s));
                }
            }
        }
        final FractionalAssignment[] assignments = fractionalAssignments.toArray(new FractionalAssignment[0]);
        // Compute matches
        final RankedScoreCalculator calc = RankedScoreCalculator.create(assignments, nActual - 1, nPredicted - 1);
        final boolean save = settings.showTP || settings.showFP;
        final double[] calcScore = calc.score(nPredicted, settings.multipleMatches, save);
        final ClassificationResult result = RankedScoreCalculator.toClassificationResult(calcScore, nActual);
        // Compute AUC and max jaccard (and plot)
        final double[][] curve = RankedScoreCalculator.getPrecisionRecallCurve(assignments, nActual, nPredicted);
        final double[] precision = curve[0];
        final double[] recall = curve[1];
        final double[] jaccard = curve[2];
        final double auc = AucCalculator.auc(precision, recall);
        // Show scores
        final String scoreLabel = String.format("Slice=%d, AUC=%s, R=%s, Max J=%s", imp.getCurrentSlice(), MathUtils.rounded(auc), MathUtils.rounded(result.getRecall()), MathUtils.rounded(MathUtils.maxDefault(0, jaccard)));
        setLabel(scoreLabel);
        // Plot
        String title = TITLE + " Performance";
        Plot plot = new Plot(title, "Spot Rank", "");
        final double[] rank = SimpleArrayUtils.newArray(precision.length, 0, 1.0);
        plot.setLimits(0, nPredicted, 0, 1.05);
        plot.setColor(Color.blue);
        plot.addPoints(rank, precision, Plot.LINE);
        plot.setColor(Color.red);
        plot.addPoints(rank, recall, Plot.LINE);
        plot.setColor(Color.black);
        plot.addPoints(rank, jaccard, Plot.LINE);
        plot.setColor(Color.black);
        plot.addLabel(0, 0, scoreLabel);
        final WindowOrganiser windowOrganiser = new WindowOrganiser();
        ImageJUtils.display(title, plot, 0, windowOrganiser);
        title = TITLE + " Precision-Recall";
        plot = new Plot(title, "Recall", "Precision");
        plot.setLimits(0, 1, 0, 1.05);
        plot.setColor(Color.red);
        plot.addPoints(recall, precision, Plot.LINE);
        plot.drawLine(recall[recall.length - 1], precision[recall.length - 1], recall[recall.length - 1], 0);
        plot.setColor(Color.black);
        plot.addLabel(0, 0, scoreLabel);
        ImageJUtils.display(title, plot, 0, windowOrganiser);
        windowOrganiser.tile();
        // Create Rois for TP and FP
        if (save) {
            final double[] matchScore = RankedScoreCalculator.getMatchScore(calc.getScoredAssignments(), nPredicted);
            int matches = 0;
            for (int i = 0; i < matchScore.length; i++) {
                if (matchScore[i] != 0) {
                    matches++;
                }
            }
            if (settings.showTP) {
                final float[] x = new float[matches];
                final float[] y = new float[x.length];
                int count = 0;
                for (int i = 0; i < matchScore.length; i++) {
                    if (matchScore[i] != 0) {
                        final BasePoint p = (BasePoint) predicted[i];
                        x[count] = p.getX() + 0.5f;
                        y[count] = p.getY() + 0.5f;
                        count++;
                    }
                }
                addRoi(0, o, x, y, count, Color.green);
            }
            if (settings.showFP) {
                final float[] x = new float[nPredicted - matches];
                final float[] y = new float[x.length];
                int count = 0;
                for (int i = 0; i < matchScore.length; i++) {
                    if (matchScore[i] == 0) {
                        final BasePoint p = (BasePoint) predicted[i];
                        x[count] = p.getX() + 0.5f;
                        y[count] = p.getY() + 0.5f;
                        count++;
                    }
                }
                addRoi(0, o, x, y, count, Color.red);
            }
        }
    } else {
        final WindowOrganiser wo = new WindowOrganiser();
        // Option to show the number of neighbours within a set pixel box radius
        final int[] count = spotFilterHelper.countNeighbours(spots, width, height, settings.neighbourRadius);
        // Show as histogram the totals...
        new HistogramPlotBuilder(TITLE, StoredData.create(count), "Neighbours").setIntegerBins(true).setPlotLabel("Radius = " + settings.neighbourRadius).show(wo);
        // TODO - Draw n=0, n=1 on the image overlay
        final LUT lut = LutHelper.createLut(LutColour.FIRE_LIGHT);
        // These are copied by the ROI
        final float[] x = new float[1];
        final float[] y = new float[1];
        // Plot the intensity
        final double[] intensity = new double[size];
        final double[] rank = SimpleArrayUtils.newArray(size, 1, 1.0);
        final int top = (settings.topN > 0) ? settings.topN : size;
        final int size_1 = size - 1;
        for (int i = 0; i < size; i++) {
            intensity[i] = spots[i].intensity;
            if (i < top) {
                x[0] = spots[i].x + bounds.x + 0.5f;
                y[0] = spots[i].y + bounds.y + 0.5f;
                final Color c = LutHelper.getColour(lut, size_1 - i, size);
                addRoi(0, o, x, y, 1, c, 2, 1);
            }
        }
        final String title = TITLE + " Intensity";
        final Plot plot = new Plot(title, "Rank", "Intensity");
        plot.setColor(Color.blue);
        plot.addPoints(rank, intensity, Plot.LINE);
        if (settings.topN > 0 && settings.topN < size) {
            plot.setColor(Color.magenta);
            plot.drawLine(settings.topN, 0, settings.topN, intensity[settings.topN - 1]);
        }
        if (settings.select > 0 && settings.select < size) {
            plot.setColor(Color.yellow);
            final int index = settings.select - 1;
            final double in = intensity[index];
            plot.drawLine(settings.select, 0, settings.select, in);
            x[0] = spots[index].x + bounds.x + 0.5f;
            y[0] = spots[index].y + bounds.y + 0.5f;
            final Color c = LutHelper.getColour(lut, size_1 - settings.select, size);
            addRoi(0, o, x, y, 1, c, 3, 3);
            plot.setColor(Color.black);
            plot.addLabel(0, 0, "Selected spot intensity = " + MathUtils.rounded(in));
        }
        ImageJUtils.display(title, plot, 0, wo);
        wo.tile();
    }
    imp.setOverlay(o);
}
Also used : FakePerPixelCameraModel(uk.ac.sussex.gdsc.smlm.model.camera.FakePerPixelCameraModel) CameraModel(uk.ac.sussex.gdsc.smlm.model.camera.CameraModel) Spot(uk.ac.sussex.gdsc.smlm.filters.Spot) BasePoint(uk.ac.sussex.gdsc.core.match.BasePoint) Rectangle(java.awt.Rectangle) HistogramPlotBuilder(uk.ac.sussex.gdsc.core.ij.HistogramPlot.HistogramPlotBuilder) RankedScoreCalculator(uk.ac.sussex.gdsc.core.match.RankedScoreCalculator) ImageRoi(ij.gui.ImageRoi) LocalList(uk.ac.sussex.gdsc.core.utils.LocalList) FractionalAssignment(uk.ac.sussex.gdsc.core.match.FractionalAssignment) ImmutableFractionalAssignment(uk.ac.sussex.gdsc.core.match.ImmutableFractionalAssignment) ImmutableFractionalAssignment(uk.ac.sussex.gdsc.core.match.ImmutableFractionalAssignment) Overlay(ij.gui.Overlay) FloatProcessor(ij.process.FloatProcessor) Plot(ij.gui.Plot) Color(java.awt.Color) ClassificationResult(uk.ac.sussex.gdsc.core.match.ClassificationResult) LUT(ij.process.LUT) WindowOrganiser(uk.ac.sussex.gdsc.core.ij.plugin.WindowOrganiser) BasePoint(uk.ac.sussex.gdsc.core.match.BasePoint) FakePerPixelCameraModel(uk.ac.sussex.gdsc.smlm.model.camera.FakePerPixelCameraModel) Coordinate(uk.ac.sussex.gdsc.core.match.Coordinate) RampedScore(uk.ac.sussex.gdsc.core.utils.RampedScore)

Example 4 with WindowOrganiser

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

the class EmGainAnalysis method plotPmf.

@SuppressWarnings("unused")
private void plotPmf() {
    if (!showPmfDialog()) {
        return;
    }
    final double step = getStepSize(settings.settingPhotons, settings.settingGain, settings.settingNoise);
    final Pdf pdf = pdf(0, step, settings.settingPhotons, settings.settingGain, settings.settingNoise);
    double[] pmf = pdf.probability;
    double yMax = MathUtils.max(pmf);
    // Get the approximation
    LikelihoodFunction fun;
    switch(settings.approximationType) {
        case 3:
            fun = new PoissonFunction(1.0 / settings.settingGain);
            break;
        case 2:
            // Use adaptive normalisation
            fun = PoissonGaussianFunction2.createWithStandardDeviation(1.0 / settings.settingGain, settings.settingNoise);
            break;
        case 1:
            // Create Poisson-Gamma (no Gaussian noise)
            fun = createPoissonGammaGaussianFunction(0);
            break;
        case 0:
        default:
            fun = createPoissonGammaGaussianFunction(settings.settingNoise);
    }
    double expected = settings.settingPhotons;
    if (settings.settingOffset != 0) {
        expected += settings.settingOffset * expected / 100.0;
    }
    // Normalise
    final boolean normalise = false;
    if (normalise) {
        final double sum = MathUtils.sum(pmf);
        for (int i = pmf.length; i-- > 0; ) {
            pmf[i] /= sum;
        }
    }
    // Get CDF
    double sum = 0;
    double sum2 = 0;
    double[] x = pdf.x;
    double[] fvalues = new double[x.length];
    double[] cdf1 = new double[pmf.length];
    double[] cdf2 = new double[pmf.length];
    for (int i = 0; i < cdf1.length; i++) {
        sum += pmf[i] * step;
        cdf1[i] = sum;
        fvalues[i] = fun.likelihood(x[i], expected);
        sum2 += fvalues[i] * step;
        cdf2[i] = sum2;
    }
    // Truncate x for plotting
    int max = 0;
    double plimit = 1 - settings.tail;
    while (sum < plimit && max < pmf.length) {
        sum += pmf[max] * step;
        if (sum > 0.5 && pmf[max] == 0) {
            break;
        }
        max++;
    }
    int min = pmf.length;
    sum = 0;
    plimit = 1 - settings.head;
    while (sum < plimit && min > 0) {
        min--;
        sum += pmf[min] * step;
        if (sum > 0.5 && pmf[min] == 0) {
            break;
        }
    }
    pmf = Arrays.copyOfRange(pmf, min, max);
    x = Arrays.copyOfRange(x, min, max);
    fvalues = Arrays.copyOfRange(fvalues, min, max);
    if (settings.showApproximation) {
        yMax = MathUtils.maxDefault(yMax, fvalues);
    }
    final String label = String.format("Gain=%s, noise=%s, photons=%s", MathUtils.rounded(settings.settingGain), MathUtils.rounded(settings.settingNoise), MathUtils.rounded(settings.settingPhotons));
    final Plot plot = new Plot("PMF", "ADUs", "p");
    plot.setLimits(x[0], x[x.length - 1], 0, yMax);
    plot.setColor(Color.red);
    plot.addPoints(x, pmf, Plot.LINE);
    if (settings.showApproximation) {
        plot.setColor(Color.blue);
        plot.addPoints(x, fvalues, Plot.LINE);
    }
    plot.setColor(Color.magenta);
    plot.drawLine(settings.settingPhotons * settings.settingGain, 0, settings.settingPhotons * settings.settingGain, yMax);
    plot.setColor(Color.black);
    plot.addLabel(0, 0, label);
    final PlotWindow win1 = ImageJUtils.display("PMF", plot);
    // Plot the difference between the actual and approximation
    final double[] delta = new double[fvalues.length];
    for (int i = 0; i < fvalues.length; i++) {
        if (pmf[i] == 0 && fvalues[i] == 0) {
            continue;
        }
        if (settings.relativeDelta) {
            delta[i] = DoubleEquality.relativeError(fvalues[i], pmf[i]) * Math.signum(fvalues[i] - pmf[i]);
        } else {
            delta[i] = fvalues[i] - pmf[i];
        }
    }
    final Plot plot2 = new Plot("PMF delta", "ADUs", (settings.relativeDelta) ? "Relative delta" : "delta");
    final double[] limits = MathUtils.limits(delta);
    plot2.setLimits(x[0], x[x.length - 1], limits[0], limits[1]);
    plot2.setColor(Color.red);
    plot2.addPoints(x, delta, Plot.LINE);
    plot2.setColor(Color.magenta);
    plot2.drawLine(settings.settingPhotons * settings.settingGain, limits[0], settings.settingPhotons * settings.settingGain, limits[1]);
    plot2.setColor(Color.black);
    plot2.addLabel(0, 0, label + ((settings.settingOffset == 0) ? "" : ", expected = " + MathUtils.rounded(expected / settings.settingGain)));
    final WindowOrganiser wo = new WindowOrganiser();
    final PlotWindow win2 = ImageJUtils.display("PMF delta", plot2, wo);
    if (wo.isNotEmpty()) {
        final Point p2 = win1.getLocation();
        p2.y += win1.getHeight();
        win2.setLocation(p2);
    }
    // Plot the CDF of each distribution.
    // Compute the Kolmogorov distance as the supremum (maximum)
    // difference between the two cumulative probability distributions.
    // https://en.wikipedia.org/wiki/Kolmogorov%E2%80%93Smirnov_test
    double kolmogorovDistance = 0;
    double xd = x[0];
    for (int i = 0; i < cdf1.length; i++) {
        final double dist = Math.abs(cdf1[i] - cdf2[i]);
        if (kolmogorovDistance < dist) {
            kolmogorovDistance = dist;
            xd = pdf.x[i];
        }
    }
    cdf1 = Arrays.copyOfRange(cdf1, min, max);
    cdf2 = Arrays.copyOfRange(cdf2, min, max);
    final Plot plot3 = new Plot("CDF", "ADUs", "p");
    yMax = 1.05;
    plot3.setLimits(x[0], x[x.length - 1], 0, yMax);
    plot3.setColor(Color.red);
    plot3.addPoints(x, cdf1, Plot.LINE);
    plot3.setColor(Color.blue);
    plot3.addPoints(x, cdf2, Plot.LINE);
    plot3.setColor(Color.magenta);
    plot3.drawLine(settings.settingPhotons * settings.settingGain, 0, settings.settingPhotons * settings.settingGain, yMax);
    plot3.drawDottedLine(xd, 0, xd, yMax, 2);
    plot3.setColor(Color.black);
    plot3.addLabel(0, 0, label + ", Kolmogorov distance = " + MathUtils.rounded(kolmogorovDistance) + " @ " + xd);
    plot3.addLegend("CDF\nApprox");
    final int size = wo.size();
    final PlotWindow win3 = ImageJUtils.display("CDF", plot3, wo);
    if (size != wo.size()) {
        final Point p2 = win1.getLocation();
        p2.x += win1.getWidth();
        win3.setLocation(p2);
    }
}
Also used : Plot(ij.gui.Plot) PlotWindow(ij.gui.PlotWindow) WindowOrganiser(uk.ac.sussex.gdsc.core.ij.plugin.WindowOrganiser) Point(java.awt.Point) LikelihoodFunction(uk.ac.sussex.gdsc.smlm.function.LikelihoodFunction) PoissonFunction(uk.ac.sussex.gdsc.smlm.function.PoissonFunction) Point(java.awt.Point)

Example 5 with WindowOrganiser

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

the class CmosAnalysis method runAnalysis.

private void runAnalysis() {
    final long start = System.currentTimeMillis();
    // Create thread pool and workers. The system is likely to be IO limited
    // so reduce the computation threads to allow the reading thread in the
    // SeriesImageSource to run.
    // If the images are small enough to fit into memory then 3 threads are used,
    // otherwise it is 1.
    final int nThreads = Math.max(1, getThreads() - 3);
    final ExecutorService executor = Executors.newFixedThreadPool(nThreads);
    final LocalList<Future<?>> futures = new LocalList<>(nThreads);
    final LocalList<ImageWorker> workers = new LocalList<>(nThreads);
    final double[][] data = new double[subDirs.size() * 2][];
    double[] pixelOffset = null;
    double[] pixelVariance = null;
    Statistics statsOffset = null;
    Statistics statsVariance = null;
    // For each sub-directory compute the mean and variance
    final int nSubDirs = subDirs.size();
    boolean error = false;
    int width = 0;
    int height = 0;
    for (int n = 0; n < nSubDirs; n++) {
        ImageJUtils.showSlowProgress(n, nSubDirs);
        final SubDir sd = subDirs.unsafeGet(n);
        ImageJUtils.showStatus(() -> "Analysing " + sd.name);
        final StopWatch sw = StopWatch.createStarted();
        // Option to reuse data
        final File file = new File(settings.directory, "perPixel" + sd.name + ".tif");
        boolean found = false;
        if (settings.reuseProcessedData && file.exists()) {
            final Opener opener = new Opener();
            opener.setSilentMode(true);
            final ImagePlus imp = opener.openImage(file.getPath());
            if (imp != null && imp.getStackSize() == 2 && imp.getBitDepth() == 32) {
                if (n == 0) {
                    width = imp.getWidth();
                    height = imp.getHeight();
                } else if (width != imp.getWidth() || height != imp.getHeight()) {
                    error = true;
                    IJ.error(TITLE, "Image width/height mismatch in image series: " + file.getPath() + String.format("\n \nExpected %dx%d, Found %dx%d", width, height, imp.getWidth(), imp.getHeight()));
                    break;
                }
                final ImageStack stack = imp.getImageStack();
                data[2 * n] = SimpleArrayUtils.toDouble((float[]) stack.getPixels(1));
                data[2 * n + 1] = SimpleArrayUtils.toDouble((float[]) stack.getPixels(2));
                found = true;
            }
        }
        if (!found) {
            // Open the series
            final SeriesImageSource source = new SeriesImageSource(sd.name, sd.path.getPath());
            if (!source.open()) {
                error = true;
                IJ.error(TITLE, "Failed to open image series: " + sd.path.getPath());
                break;
            }
            if (n == 0) {
                width = source.getWidth();
                height = source.getHeight();
            } else if (width != source.getWidth() || height != source.getHeight()) {
                error = true;
                IJ.error(TITLE, "Image width/height mismatch in image series: " + sd.path.getPath() + String.format("\n \nExpected %dx%d, Found %dx%d", width, height, source.getWidth(), source.getHeight()));
                break;
            }
            // So the bar remains at 99% when workers have finished use frames + 1
            final Ticker ticker = ImageJUtils.createTicker(source.getFrames() + 1L, nThreads);
            // Open the first frame to get the bit depth.
            // Assume the first pixels are not empty as the source is open.
            Object pixels = source.nextRaw();
            final int bitDepth = ImageJUtils.getBitDepth(pixels);
            ArrayMoment moment;
            if (settings.rollingAlgorithm) {
                moment = new RollingArrayMoment();
            // We assume 16-bit camera at the maximum
            } else if (bitDepth <= 16 && IntegerArrayMoment.isValid(IntegerType.UNSIGNED_16, source.getFrames())) {
                moment = new IntegerArrayMoment();
            } else {
                moment = new SimpleArrayMoment();
            }
            final BlockingQueue<Object> jobs = new ArrayBlockingQueue<>(nThreads * 2);
            for (int i = 0; i < nThreads; i++) {
                final ImageWorker worker = new ImageWorker(ticker, jobs, moment);
                workers.add(worker);
                futures.add(executor.submit(worker));
            }
            // Process the raw pixel data
            long lastTime = 0;
            while (pixels != null) {
                final long time = System.currentTimeMillis();
                if (time - lastTime > 150) {
                    if (ImageJUtils.isInterrupted()) {
                        error = true;
                        break;
                    }
                    lastTime = time;
                    IJ.showStatus("Analysing " + sd.name + " Frame " + source.getStartFrameNumber());
                }
                put(jobs, pixels);
                pixels = source.nextRaw();
            }
            source.close();
            if (error) {
                // Kill the workers
                workers.stream().forEach(worker -> worker.finished = true);
                // Clear the queue
                jobs.clear();
                // Signal any waiting workers
                workers.stream().forEach(worker -> jobs.add(ImageWorker.STOP_SIGNAL));
                // Cancel by interruption. We set the finished flag so the ImageWorker should
                // ignore the interrupt.
                futures.stream().forEach(future -> future.cancel(true));
                break;
            }
            // Finish all the worker threads cleanly
            workers.stream().forEach(worker -> jobs.add(ImageWorker.STOP_SIGNAL));
            // Wait for all to finish
            ConcurrencyUtils.waitForCompletionUnchecked(futures);
            // Create the final aggregate statistics
            for (final ImageWorker w : workers) {
                moment.add(w.moment);
            }
            data[2 * n] = moment.getMean();
            data[2 * n + 1] = moment.getVariance();
            // Get the processing speed.
            sw.stop();
            // ticker holds the number of number of frames processed
            final double bits = (double) bitDepth * source.getFrames() * source.getWidth() * source.getHeight();
            final double bps = bits / sw.getTime(TimeUnit.SECONDS);
            final SiPrefix prefix = SiPrefix.getSiPrefix(bps);
            ImageJUtils.log("Processed %d frames. Time = %s. Rate = %s %sbits/s", moment.getN(), sw.toString(), MathUtils.rounded(prefix.convert(bps)), prefix.getPrefix());
            // Reset
            futures.clear();
            workers.clear();
            final ImageStack stack = new ImageStack(width, height);
            stack.addSlice("Mean", SimpleArrayUtils.toFloat(data[2 * n]));
            stack.addSlice("Variance", SimpleArrayUtils.toFloat(data[2 * n + 1]));
            IJ.save(new ImagePlus("PerPixel", stack), file.getPath());
        }
        final Statistics s = Statistics.create(data[2 * n]);
        if (pixelOffset != null) {
            // Compute mean ADU
            final Statistics signal = new Statistics();
            final double[] mean = data[2 * n];
            for (int i = 0; i < pixelOffset.length; i++) {
                signal.add(mean[i] - pixelOffset[i]);
            }
            ImageJUtils.log("%s Mean = %s +/- %s. Signal = %s +/- %s ADU", sd.name, MathUtils.rounded(s.getMean()), MathUtils.rounded(s.getStandardDeviation()), MathUtils.rounded(signal.getMean()), MathUtils.rounded(signal.getStandardDeviation()));
        } else {
            // Set the offset assuming the first sub-directory is the bias image
            pixelOffset = data[0];
            pixelVariance = data[1];
            statsOffset = s;
            statsVariance = Statistics.create(pixelVariance);
            ImageJUtils.log("%s Offset = %s +/- %s. Variance = %s +/- %s", sd.name, MathUtils.rounded(s.getMean()), MathUtils.rounded(s.getStandardDeviation()), MathUtils.rounded(statsVariance.getMean()), MathUtils.rounded(statsVariance.getStandardDeviation()));
        }
        IJ.showProgress(1);
    }
    ImageJUtils.clearSlowProgress();
    if (error) {
        executor.shutdownNow();
        IJ.showStatus(TITLE + " cancelled");
        return;
    }
    executor.shutdown();
    if (pixelOffset == null || pixelVariance == null) {
        IJ.showStatus(TITLE + " error: no bias image");
        return;
    }
    // Compute the gain
    ImageJUtils.showStatus("Computing gain");
    final double[] pixelGain = new double[pixelOffset.length];
    final double[] bibiT = new double[pixelGain.length];
    final double[] biaiT = new double[pixelGain.length];
    // Ignore first as this is the 0 exposure image
    for (int n = 1; n < nSubDirs; n++) {
        // Use equation 2.5 from the Huang et al paper.
        final double[] b = data[2 * n];
        final double[] a = data[2 * n + 1];
        for (int i = 0; i < pixelGain.length; i++) {
            final double bi = b[i] - pixelOffset[i];
            final double ai = a[i] - pixelVariance[i];
            bibiT[i] += bi * bi;
            biaiT[i] += bi * ai;
        }
    }
    for (int i = 0; i < pixelGain.length; i++) {
        pixelGain[i] = biaiT[i] / bibiT[i];
    }
    final Statistics statsGain = Statistics.create(pixelGain);
    ImageJUtils.log("Gain Mean = %s +/- %s", MathUtils.rounded(statsGain.getMean()), MathUtils.rounded(statsGain.getStandardDeviation()));
    // Histogram of offset, variance and gain
    final int bins = 2 * HistogramPlot.getBinsSturgesRule(pixelGain.length);
    final WindowOrganiser wo = new WindowOrganiser();
    showHistogram("Offset (ADU)", pixelOffset, bins, statsOffset, wo);
    showHistogram("Variance (ADU^2)", pixelVariance, bins, statsVariance, wo);
    showHistogram("Gain (ADU/e)", pixelGain, bins, statsGain, wo);
    wo.tile();
    // Save
    final float[] bias = SimpleArrayUtils.toFloat(pixelOffset);
    final float[] variance = SimpleArrayUtils.toFloat(pixelVariance);
    final float[] gain = SimpleArrayUtils.toFloat(pixelGain);
    measuredStack = new ImageStack(width, height);
    measuredStack.addSlice("Offset", bias);
    measuredStack.addSlice("Variance", variance);
    measuredStack.addSlice("Gain", gain);
    final ExtendedGenericDialog egd = new ExtendedGenericDialog(TITLE);
    egd.addMessage("Save the sCMOS camera model?");
    if (settings.modelDirectory == null) {
        settings.modelDirectory = settings.directory;
        settings.modelName = "sCMOS Camera";
    }
    egd.addStringField("Model_name", settings.modelName, 30);
    egd.addDirectoryField("Model_directory", settings.modelDirectory);
    egd.showDialog();
    if (!egd.wasCanceled()) {
        settings.modelName = egd.getNextString();
        settings.modelDirectory = egd.getNextString();
        saveCameraModel(width, height, bias, gain, variance);
    }
    // Remove the status from the ij.io.ImageWriter class
    IJ.showStatus("");
    ImageJUtils.log("Analysis time = " + TextUtils.millisToString(System.currentTimeMillis() - start));
}
Also used : SiPrefix(uk.ac.sussex.gdsc.core.data.SiPrefix) RollingArrayMoment(uk.ac.sussex.gdsc.core.math.RollingArrayMoment) RollingArrayMoment(uk.ac.sussex.gdsc.core.math.RollingArrayMoment) ArrayMoment(uk.ac.sussex.gdsc.core.math.ArrayMoment) IntegerArrayMoment(uk.ac.sussex.gdsc.core.math.IntegerArrayMoment) SimpleArrayMoment(uk.ac.sussex.gdsc.core.math.SimpleArrayMoment) LocalList(uk.ac.sussex.gdsc.core.utils.LocalList) ArrayBlockingQueue(java.util.concurrent.ArrayBlockingQueue) SimpleArrayMoment(uk.ac.sussex.gdsc.core.math.SimpleArrayMoment) IntegerArrayMoment(uk.ac.sussex.gdsc.core.math.IntegerArrayMoment) ImageStack(ij.ImageStack) SeriesImageSource(uk.ac.sussex.gdsc.smlm.ij.SeriesImageSource) Ticker(uk.ac.sussex.gdsc.core.logging.Ticker) WindowOrganiser(uk.ac.sussex.gdsc.core.ij.plugin.WindowOrganiser) ExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog) Statistics(uk.ac.sussex.gdsc.core.utils.Statistics) ImagePlus(ij.ImagePlus) StopWatch(org.apache.commons.lang3.time.StopWatch) ExecutorService(java.util.concurrent.ExecutorService) Future(java.util.concurrent.Future) File(java.io.File) Opener(ij.io.Opener)

Aggregations

WindowOrganiser (uk.ac.sussex.gdsc.core.ij.plugin.WindowOrganiser)25 Plot (ij.gui.Plot)12 HistogramPlotBuilder (uk.ac.sussex.gdsc.core.ij.HistogramPlot.HistogramPlotBuilder)10 ImagePlus (ij.ImagePlus)8 Rectangle (java.awt.Rectangle)8 Statistics (uk.ac.sussex.gdsc.core.utils.Statistics)8 ImageStack (ij.ImageStack)7 Point (java.awt.Point)7 LocalList (uk.ac.sussex.gdsc.core.utils.LocalList)7 PlotWindow (ij.gui.PlotWindow)6 ExtendedGenericDialog (uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog)6 StoredDataStatistics (uk.ac.sussex.gdsc.core.utils.StoredDataStatistics)6 MemoryPeakResults (uk.ac.sussex.gdsc.smlm.results.MemoryPeakResults)6 Color (java.awt.Color)5 ExecutorService (java.util.concurrent.ExecutorService)5 IJ (ij.IJ)4 PlugIn (ij.plugin.PlugIn)4 LUT (ij.process.LUT)4 Future (java.util.concurrent.Future)4 HistogramPlot (uk.ac.sussex.gdsc.core.ij.HistogramPlot)4