Search in sources :

Example 21 with FitEngineConfiguration

use of uk.ac.sussex.gdsc.smlm.engine.FitEngineConfiguration in project GDSC-SMLM by aherbert.

the class BenchmarkFit method showDialog.

private boolean showDialog() {
    final ExtendedGenericDialog gd = new ExtendedGenericDialog(TITLE);
    final double sa = getSa();
    ImageJUtils.addMessage(gd, "Fits the benchmark image created by CreateData plugin.\nPSF width = %s, adjusted = %s", MathUtils.rounded(benchmarkParameters.sd / benchmarkParameters.pixelPitch), MathUtils.rounded(sa));
    final FitEngineConfiguration config = SettingsManager.readFitEngineConfiguration(0);
    fitConfig = config.getFitConfiguration();
    fitConfig.setNmPerPixel(benchmarkParameters.pixelPitch);
    // For each new benchmark width, reset the PSF width to the square pixel adjustment
    if (lastId != benchmarkParameters.id) {
        lastId = benchmarkParameters.id;
        fitConfig.setInitialPeakStdDev(benchmarkParameters.sd / benchmarkParameters.pixelPitch);
        // The adjusted width is only relevant when using a single point approximation
        // for a Gaussian over the pixel. Using the ERF function computes the actual
        // integral over the pixel.
        // fitConfig.setInitialPeakStdDev(sa);
        // Set the PSF. This requires the CreateData plugin to store the most appropriate
        // PSF used for the simulation.
        fitConfig.setPsf(benchmarkParameters.psf);
    }
    gd.addSlider("Region_size", 2, 20, regionSize);
    PeakFit.addPsfOptions(gd, fitConfig);
    gd.addChoice("Fit_solver", SettingsManager.getFitSolverNames(), FitProtosHelper.getName(fitConfig.getFitSolver()));
    gd.addChoice("Origin_XY", ORIGIN_XY, originXY, new OptionListener<Integer>() {

        @Override
        public boolean collectOptions(Integer value) {
            originXY = value;
            return collectOptions(false);
        }

        @Override
        public boolean collectOptions() {
            return collectOptions(true);
        }

        private boolean collectOptions(boolean silent) {
            if (originXY != 2) {
                return false;
            }
            final ExtendedGenericDialog egd = new ExtendedGenericDialog("Origin XY");
            egd.addNumericField("Offset_X", offsetX, 2, 6, "nm");
            egd.addNumericField("Offset_Y", offsetY, 2, 6, "nm");
            egd.setSilent(silent);
            egd.showDialog(true, gd);
            if (egd.wasCanceled()) {
                return false;
            }
            offsetX = gd.getNextNumber();
            offsetY = gd.getNextNumber();
            return true;
        }
    });
    gd.addChoice("Origin_Z", ORIGIN_Z, originZ, new OptionListener<Integer>() {

        @Override
        public boolean collectOptions(Integer value) {
            originZ = value;
            return collectOptions(false);
        }

        @Override
        public boolean collectOptions() {
            return collectOptions(true);
        }

        private boolean collectOptions(boolean silent) {
            if (originZ != 2) {
                return false;
            }
            final ExtendedGenericDialog egd = new ExtendedGenericDialog("Origin Z");
            egd.addNumericField("Offset_Z", offsetZ, 2, 6, "nm");
            egd.setSilent(silent);
            egd.showDialog(true, gd);
            if (egd.wasCanceled()) {
                return false;
            }
            offsetZ = gd.getNextNumber();
            return true;
        }
    });
    gd.addCheckbox("Zero_offset", zeroOffset);
    gd.addNumericField("Offset_points", offsetPoints, 0, new OptionListener<Double>() {

        @Override
        public boolean collectOptions(Double value) {
            offsetPoints = Math.max(0, value);
            return collectOptions(false);
        }

        @Override
        public boolean collectOptions() {
            return collectOptions(true);
        }

        private boolean collectOptions(boolean silent) {
            if (offsetPoints == 0) {
                return false;
            }
            final ExtendedGenericDialog egd = new ExtendedGenericDialog("Offset range");
            egd.addSlider("Offset_range_x", 0, 2.5, offsetRangeX);
            egd.addSlider("Offset_range_y", 0, 2.5, offsetRangeY);
            egd.addSlider("Offset_range_z", 0, 2.5, offsetRangeZ);
            egd.setSilent(silent);
            egd.showDialog(true, gd);
            if (egd.wasCanceled()) {
                return false;
            }
            offsetRangeX = Math.max(0, egd.getNextNumber());
            offsetRangeY = Math.max(0, egd.getNextNumber());
            offsetRangeZ = Math.max(0, egd.getNextNumber());
            return true;
        }
    });
    gd.addCheckbox("Background_fitting", backgroundFitting, new OptionListener<Boolean>() {

        @Override
        public boolean collectOptions(Boolean value) {
            backgroundFitting = value;
            return collectOptions(false);
        }

        @Override
        public boolean collectOptions() {
            return collectOptions(true);
        }

        private boolean collectOptions(boolean silent) {
            if (!backgroundFitting) {
                return false;
            }
            final ExtendedGenericDialog egd = new ExtendedGenericDialog("Background fitting");
            egd.addCheckbox("Estimate_background", estimateBackground);
            egd.setSilent(silent);
            egd.showDialog(true, gd);
            if (egd.wasCanceled()) {
                return false;
            }
            estimateBackground = egd.getNextBoolean();
            return true;
        }
    });
    gd.addMessage("Signal fitting can be disabled for " + PsfProtosHelper.getName(PSFType.ONE_AXIS_GAUSSIAN_2D) + " function");
    gd.addCheckbox("Signal_fitting", signalFitting, new OptionListener<Boolean>() {

        @Override
        public boolean collectOptions(Boolean value) {
            signalFitting = value;
            return collectOptions(false);
        }

        @Override
        public boolean collectOptions() {
            return collectOptions(true);
        }

        private boolean collectOptions(boolean silent) {
            if (!signalFitting) {
                return false;
            }
            final ExtendedGenericDialog egd = new ExtendedGenericDialog("Signal fitting");
            egd.addCheckbox("Estimate_signal", estimateSignal);
            egd.setSilent(silent);
            egd.showDialog(true, gd);
            if (egd.wasCanceled()) {
                return false;
            }
            estimateSignal = egd.getNextBoolean();
            return true;
        }
    });
    gd.addCheckbox("Show_histograms", showHistograms);
    gd.addCheckbox("Save_raw_data", saveRawData);
    gd.addHelp(HelpUrls.getUrl("fit-benchmark-data"));
    gd.showDialog();
    if (gd.wasCanceled()) {
        return false;
    }
    regionSize = (int) Math.abs(gd.getNextNumber());
    fitConfig.setPsfType(PeakFit.getPsfTypeValues()[gd.getNextChoiceIndex()]);
    // Some enum values are not supported
    fitConfig.setFitSolver(SettingsManager.getFitSolverValues()[gd.getNextChoiceIndex()]);
    originXY = gd.getNextChoiceIndex();
    originZ = gd.getNextChoiceIndex();
    zeroOffset = gd.getNextBoolean();
    offsetPoints = Math.max(0, gd.getNextNumber());
    backgroundFitting = gd.getNextBoolean();
    signalFitting = gd.getNextBoolean();
    showHistograms = gd.getNextBoolean();
    saveRawData = gd.getNextBoolean();
    gd.collectOptions();
    // Do this before the call to is3D()
    if (!PeakFit.configurePsfModel(config)) {
        return false;
    }
    getStartPoints(fitConfig.is3D());
    if (startPoints.length == 0) {
        IJ.error(TITLE, "No initial fitting positions");
        return false;
    }
    if (regionSize < 1) {
        regionSize = 1;
    }
    if (gd.invalidNumber()) {
        return false;
    }
    // Initialise the correct calibration
    final CalibrationWriter calibration = new CalibrationWriter(fitConfig.getCalibration());
    calibration.setNmPerPixel(benchmarkParameters.pixelPitch);
    calibration.setCountPerPhoton(benchmarkParameters.gain);
    calibration.setQuantumEfficiency(benchmarkParameters.qe);
    calibration.setBias(benchmarkParameters.bias);
    calibration.setCameraType(benchmarkParameters.cameraType);
    calibration.setReadNoise(benchmarkParameters.readNoise);
    calibration.setExposureTime(1000);
    fitConfig.setCalibration(calibration.getCalibration());
    fitConfig.setCameraModelName(benchmarkParameters.cameraModelName);
    if (!PeakFit.configureFitSolver(config, IJImageSource.getBounds(imp), null, 0)) {
        return false;
    }
    if (showHistograms) {
        final ExtendedGenericDialog gd2 = new ExtendedGenericDialog(TITLE);
        gd2.addMessage("Select the histograms to display");
        gd2.addNumericField("Histogram_bins", histogramBins, 0);
        final double[] convert = getConversionFactors();
        for (int i = 0; i < displayHistograms.length; i++) {
            if (convert[i] != 0) {
                gd2.addCheckbox(NAMES[i].replace(' ', '_'), displayHistograms[i]);
            }
        }
        gd2.showDialog();
        if (gd2.wasCanceled()) {
            return false;
        }
        histogramBins = (int) Math.abs(gd2.getNextNumber());
        for (int i = 0; i < displayHistograms.length; i++) {
            if (convert[i] != 0) {
                displayHistograms[i] = gd2.getNextBoolean();
            }
        }
    }
    return true;
}
Also used : FitEngineConfiguration(uk.ac.sussex.gdsc.smlm.engine.FitEngineConfiguration) ExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) CalibrationWriter(uk.ac.sussex.gdsc.smlm.data.config.CalibrationWriter)

Example 22 with FitEngineConfiguration

use of uk.ac.sussex.gdsc.smlm.engine.FitEngineConfiguration in project GDSC-SMLM by aherbert.

the class BenchmarkSpotFilter method updateConfiguration.

/**
 * Updates the given configuration using the latest settings used in benchmarking.
 *
 * @param config the configuration
 * @return true, if successful
 */
public static boolean updateConfiguration(FitEngineConfiguration config) {
    final BenchmarkSpotFilterResult result = filterResult.get();
    if (result == null) {
        return false;
    }
    final FitEngineConfiguration latestConfig = result.config;
    config.setDataFilterType(latestConfig.getDataFilterType());
    final int nFilters = latestConfig.getNumberOfFilters();
    for (int n = 0; n < nFilters; n++) {
        final RelativeParameter p = latestConfig.getDataFilterParameter(n);
        config.setDataFilter(latestConfig.getDataFilterMethod(n), p.getValue(), p.getAbsolute(), n);
    }
    config.setSearch(latestConfig.getSearch(), latestConfig.getSearchAbsolute());
    config.setBorder(latestConfig.getBorder(), latestConfig.getBorderAbsolute());
    return true;
}
Also used : FitEngineConfiguration(uk.ac.sussex.gdsc.smlm.engine.FitEngineConfiguration) RelativeParameter(uk.ac.sussex.gdsc.smlm.data.config.FitProtos.RelativeParameter) PeakResultPoint(uk.ac.sussex.gdsc.smlm.results.PeakResultPoint) BasePoint(uk.ac.sussex.gdsc.core.match.BasePoint)

Example 23 with FitEngineConfiguration

use of uk.ac.sussex.gdsc.smlm.engine.FitEngineConfiguration in project GDSC-SMLM by aherbert.

the class DoubletAnalysis method saveTemplate.

/**
 * Save PeakFit configuration template using the current benchmark settings.
 *
 * @param summary the summary
 */
private void saveTemplate(String summary) {
    if (!settings.saveTemplate) {
        return;
    }
    // Start with a clone of the filter settings
    final FitEngineConfiguration config = new FitEngineConfiguration();
    final FitConfiguration fitConfig = config.getFitConfiguration();
    fitConfig.setFitSettings(filterFitConfig.getFitSettings());
    // Copy settings used during fitting
    updateConfiguration(config);
    // Remove the PSF width to make the template generic
    fitConfig.setInitialPeakStdDev(0);
    fitConfig.setNmPerPixel(0);
    fitConfig.setGain(0);
    fitConfig.setNoise(0);
    // This was done fitting all the results
    config.setFailuresLimit(-1);
    if (settings.useBenchmarkSettings) {
        final FitEngineConfiguration pConfig = new FitEngineConfiguration();
        // TODO - add option to use latest or the best
        if (BenchmarkFilterAnalysis.updateConfiguration(pConfig, false)) {
            config.setFailuresLimit(pConfig.getFailuresLimit());
        }
    }
    // Set the residuals
    fitConfig.setComputeResiduals(true);
    // TODO - make the choice of the best residuals configurable
    config.setResidualsThreshold(residualsScore.bestResiduals[2]);
    final String filename = BenchmarkFilterAnalysis.getFilename("Template_File", settings.templateFilename);
    if (filename != null) {
        settings.templateFilename = filename;
        final TemplateSettings.Builder settings = TemplateSettings.newBuilder();
        getNotes(settings, summary);
        settings.setFitEngineSettings(config.getFitEngineSettings());
        if (!SettingsManager.toJson(settings.build(), filename, SettingsManager.FLAG_SILENT)) {
            IJ.log("Unable to save the template configuration");
        }
    }
}
Also used : TemplateSettings(uk.ac.sussex.gdsc.smlm.data.config.TemplateProtos.TemplateSettings) FitEngineConfiguration(uk.ac.sussex.gdsc.smlm.engine.FitEngineConfiguration) FitConfiguration(uk.ac.sussex.gdsc.smlm.engine.FitConfiguration)

Example 24 with FitEngineConfiguration

use of uk.ac.sussex.gdsc.smlm.engine.FitEngineConfiguration in project GDSC-SMLM by aherbert.

the class PeakFit method configureDataFilter.

/**
 * Show a dialog to configure the data filter. The data filter type and the first data filter must
 * ALREADY be set in the configuration. The subsequent filters are then configured, e.g. for
 * difference and jury filters.
 *
 * <p>The updated settings are saved to the settings file. An error message is shown if the dialog
 * is cancelled or the configuration is invalid.
 *
 * <p>If the configuration is for a per-pixel camera type (e.g. sCMOS) then the camera model will
 * be loaded using the configured camera model name. This will be used to validate the filter to
 * check the filter supports the per-pixel camera type.
 *
 * @param config the config
 * @param flags the flags
 * @return True if the configuration succeeded
 */
public static boolean configureDataFilter(final FitEngineConfiguration config, int flags) {
    int numberOfFilters = 1;
    int filterCount;
    switch(config.getDataFilterType()) {
        case JURY:
            filterCount = Integer.MAX_VALUE;
            break;
        case DIFFERENCE:
            filterCount = 2;
            break;
        case SINGLE:
        default:
            filterCount = 1;
    }
    final String[] filterNames = SettingsManager.getDataFilterMethodNames();
    final DataFilterMethod[] filterValues = SettingsManager.getDataFilterMethodValues();
    // Check we have at least the first filter.
    if (config.getDataFiltersCount() == 0) {
        throw new IllegalStateException("No primary filter is configured");
    }
    final FitEngineConfigurationProvider fitEngineConfigurationProvider = () -> config;
    for (int i = 1; i < filterCount; i++) {
        final int filter = i + 1;
        final int ii = i;
        final ExtendedGenericDialog gd = new ExtendedGenericDialog(TITLE);
        if (filter == filterCount) {
            // This is maximum filter count so no continue option
            ImageJUtils.addMessage(gd, "Configure the %s filter.", FitProtosHelper.getName(config.getDataFilterType()));
        } else {
            gd.enableYesNoCancel("Add", "Continue");
            ImageJUtils.addMessage(gd, "Configure the %s filter.\nClick continue to proceed with the current set of %d.", FitProtosHelper.getName(config.getDataFilterType()), i);
        }
        final String fieldName = "Spot_filter" + filter;
        if (IJ.isMacro()) {
            // Use blank default value so bad macro parameters return nothing
            gd.addStringField(fieldName, "");
        } else {
            gd.addChoice(fieldName, filterNames, filterNames[config.getDataFilterMethod(ii, config.getDataFilterMethod(ii - 1)).ordinal()]);
        }
        addRelativeParameterOptions(gd, new RelativeParameterProvider(0, 4.5, "Smoothing" + filter, fitEngineConfigurationProvider, true) {

            @Override
            void setAbsolute(boolean absolute) {
                // Get the current settings
                final FitEngineConfiguration c = fitEngineConfigurationProvider.getFitEngineConfiguration();
                final DataFilterMethod m = c.getDataFilterMethod(ii);
                final double smooth = c.getDataFilterParameter(ii).getValue();
                // Reset with the new absolute value
                c.setDataFilter(m, smooth, absolute, ii);
            }

            @Override
            boolean isAbsolute() {
                final FitEngineConfiguration c = fitEngineConfigurationProvider.getFitEngineConfiguration();
                return c.getDataFilterParameterAbsolute(ii, c.getDataFilterParameterAbsolute(ii - 1));
            }

            @Override
            double getValue() {
                final FitEngineConfiguration c = fitEngineConfigurationProvider.getFitEngineConfiguration();
                return c.getDataFilterParameterValue(ii, c.getDataFilterParameterValue(ii - 1));
            }
        });
        gd.showDialog();
        if (gd.wasCanceled()) {
            return false;
        }
        if (gd.wasOKed()) {
            int filterIndex = -1;
            if (IJ.isMacro()) {
                final String filterName = gd.getNextString();
                for (int j = 0; j < filterNames.length; j++) {
                    if (filterNames[j].equals(filterName)) {
                        filterIndex = j;
                        break;
                    }
                }
                if (filterIndex < 0) {
                    break;
                }
            } else {
                filterIndex = gd.getNextChoiceIndex();
            }
            // Note: The absolute flag is set in extra options
            config.setDataFilter(filterValues[filterIndex], Math.abs(gd.getNextNumber()), i);
            gd.collectOptions();
            numberOfFilters++;
        } else {
            break;
        }
    }
    config.setNumberOfFilters(numberOfFilters);
    if (BitFlagUtils.anyNotSet(flags, FLAG_NO_SAVE)) {
        saveFitEngineSettings(config);
    }
    final FitConfiguration fitConfig = config.getFitConfiguration();
    final CalibrationReader calibration = fitConfig.getCalibrationReader();
    if (calibration.isScmos()) {
        fitConfig.setCameraModel(CameraModelManager.load(fitConfig.getCameraModelName()));
    }
    try {
        config.createSpotFilter();
    } catch (final IllegalStateException ex) {
        IJ.error(TITLE, ex.getMessage());
        return false;
    }
    return true;
}
Also used : FitEngineConfiguration(uk.ac.sussex.gdsc.smlm.engine.FitEngineConfiguration) ExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog) CalibrationReader(uk.ac.sussex.gdsc.smlm.data.config.CalibrationReader) DataFilterMethod(uk.ac.sussex.gdsc.smlm.data.config.FitProtos.DataFilterMethod) FitConfiguration(uk.ac.sussex.gdsc.smlm.engine.FitConfiguration)

Example 25 with FitEngineConfiguration

use of uk.ac.sussex.gdsc.smlm.engine.FitEngineConfiguration in project GDSC-SMLM by aherbert.

the class PeakFit method showSimpleDialog.

private int showSimpleDialog() {
    // Just support circular fitting
    fitConfig.setPsf(PsfProtosHelper.defaultOneAxisGaussian2DPSF);
    fitConfig.setFixedPsf(false);
    // TODO - Support sCMOS camera. This may be 'too difficult' as the
    // user will need to have created a per-pixel calibration image
    final CalibrationWriter calibration = fitConfig.getCalibrationWriter();
    final boolean requireCalibration = requireCalibration(calibration);
    if (requireCalibration && !showCalibrationWizard(calibration, true)) {
        return DONE;
    }
    // Present dialog with simple output options: Image, Table
    final ExtendedGenericDialog gd = new ExtendedGenericDialog(TITLE);
    gd.addHelp(HelpUrls.getUrl("simple-fit"));
    gd.addMessage("Fit single-molecule localisations");
    if (!requireCalibration) {
        gd.addCheckbox("Use_current_calibration", true);
    }
    gd.addCheckbox("Show_table", settings.showTable);
    gd.addCheckbox("Show_image", settings.showImage);
    gd.showDialog();
    if (gd.wasCanceled()) {
        return DONE;
    }
    boolean useCurrentCalibration = true;
    if (!requireCalibration) {
        useCurrentCalibration = gd.getNextBoolean();
    }
    settings.showTable = gd.getNextBoolean();
    settings.showImage = gd.getNextBoolean();
    if (!useCurrentCalibration && !showCalibrationWizard(calibration, false)) {
        return DONE;
    }
    // Restore fitting to default settings but maintain the calibrated width
    final double sd = fitConfig.getInitialXSd();
    config = new FitEngineConfiguration();
    fitConfig = config.getFitConfiguration();
    fitConfig.setInitialPeakStdDev(sd);
    // Allow to move 1 SD
    fitConfig.setCoordinateShiftFactor(1);
    resultsSettings = ResultsSettings.newBuilder();
    // Do simple results output. We only need to set non-default values.
    resultsSettings.getResultsInMemorySettingsBuilder().setInMemory(true);
    if (settings.showTable) {
        final ResultsTableSettings.Builder tableSettings = resultsSettings.getResultsTableSettingsBuilder();
        tableSettings.setShowTable(true);
    }
    if (settings.showImage) {
        final ResultsImageSettings.Builder imageSettings = resultsSettings.getResultsImageSettingsBuilder();
        imageSettings.setImageType(ResultsImageType.DRAW_INTENSITY);
        imageSettings.setScale(Math.ceil(1024.0 / Math.max(bounds.width, bounds.height)));
        imageSettings.setWeighted(true);
        imageSettings.setEqualised(true);
    }
    // Log the settings we care about:
    IJ.log(LOG_SPACER);
    IJ.log("Peak Fit");
    IJ.log(LOG_SPACER);
    ImageJUtils.log("Pixel pitch = %s", MathUtils.rounded(calibration.getNmPerPixel(), 4));
    ImageJUtils.log("Exposure Time = %s", MathUtils.rounded(calibration.getExposureTime(), 4));
    ImageJUtils.log("PSF width = %s", MathUtils.rounded(fitConfig.getInitialXSd(), 4));
    // Save
    fitConfig.setCalibration(calibration.getCalibration());
    saveFitEngineSettings();
    SettingsManager.writeSettings(resultsSettings.build());
    return FLAGS;
}
Also used : FitEngineConfiguration(uk.ac.sussex.gdsc.smlm.engine.FitEngineConfiguration) CalibrationWriter(uk.ac.sussex.gdsc.smlm.data.config.CalibrationWriter) ExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog) ResultsImageSettings(uk.ac.sussex.gdsc.smlm.data.config.ResultsProtos.ResultsImageSettings) ResultsTableSettings(uk.ac.sussex.gdsc.smlm.data.config.ResultsProtos.ResultsTableSettings)

Aggregations

FitEngineConfiguration (uk.ac.sussex.gdsc.smlm.engine.FitEngineConfiguration)26 FitConfiguration (uk.ac.sussex.gdsc.smlm.engine.FitConfiguration)9 ExtendedGenericDialog (uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog)6 TemplateSettings (uk.ac.sussex.gdsc.smlm.data.config.TemplateProtos.TemplateSettings)4 ImagePlus (ij.ImagePlus)3 Checkbox (java.awt.Checkbox)3 BasePoint (uk.ac.sussex.gdsc.core.match.BasePoint)3 DataFilterMethod (uk.ac.sussex.gdsc.smlm.data.config.FitProtos.DataFilterMethod)3 PeakResultPoint (uk.ac.sussex.gdsc.smlm.results.PeakResultPoint)3 MultiPathFilter (uk.ac.sussex.gdsc.smlm.results.filter.MultiPathFilter)3 ImageListener (ij.ImageListener)2 Choice (java.awt.Choice)2 Rectangle (java.awt.Rectangle)2 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)2 NonBlockingExtendedGenericDialog (uk.ac.sussex.gdsc.core.ij.gui.NonBlockingExtendedGenericDialog)2 Calibration (uk.ac.sussex.gdsc.smlm.data.config.CalibrationProtos.Calibration)2 CalibrationWriter (uk.ac.sussex.gdsc.smlm.data.config.CalibrationWriter)2 FitEngineSettings (uk.ac.sussex.gdsc.smlm.data.config.FitProtos.FitEngineSettings)2 MemoryPeakResults (uk.ac.sussex.gdsc.smlm.results.MemoryPeakResults)2 DirectFilter (uk.ac.sussex.gdsc.smlm.results.filter.DirectFilter)2