use of uk.ac.sussex.gdsc.smlm.results.InterlacedImageSource in project GDSC-SMLM by aherbert.
the class PsfEstimator method calculateStatistics.
private boolean calculateStatistics(PeakFit fitter, double[] params, double[] paramsDev) {
debug(" Fitting PSF");
swapStatistics();
// Create the fit engine using the PeakFit plugin
final FitConfiguration fitConfig = config.getFitConfiguration();
fitConfig.setInitialPeakStdDev0((float) params[1]);
try {
fitConfig.setInitialPeakStdDev1((float) params[2]);
fitConfig.setInitialAngle((float) Math.toRadians(params[0]));
} catch (IllegalStateException ex) {
// Ignore this as the current PSF is not a 2 axis and theta Gaussian PSF
}
final ImageStack stack = imp.getImageStack();
final Rectangle roi = stack.getProcessor(1).getRoi();
ImageSource source = new IJImageSource(imp);
// Allow interlaced data by wrapping the image source
if (interlacedData) {
source = new InterlacedImageSource(source, dataStart, dataBlock, dataSkip);
}
// Allow frame aggregation by wrapping the image source
if (integrateFrames > 1) {
source = new AggregatedImageSource(source, integrateFrames);
}
fitter.initialiseImage(source, roi, true);
fitter.addPeakResults(this);
fitter.initialiseFitting();
final FitEngine engine = fitter.createFitEngine();
// Use random slices
final int[] slices = new int[stack.getSize()];
for (int i = 0; i < slices.length; i++) {
slices[i] = i + 1;
}
RandomUtils.shuffle(slices, UniformRandomProviders.create());
IJ.showStatus("Fitting ...");
// Use multi-threaded code for speed
int sliceIndex;
for (sliceIndex = 0; sliceIndex < slices.length; sliceIndex++) {
final int slice = slices[sliceIndex];
IJ.showProgress(size(), settings.getNumberOfPeaks());
final ImageProcessor ip = stack.getProcessor(slice);
// stack processor does not set the bounds required by ImageConverter
ip.setRoi(roi);
final FitJob job = new FitJob(slice, ImageJImageConverter.getData(ip), roi);
engine.run(job);
if (sampleSizeReached() || ImageJUtils.isInterrupted()) {
break;
}
}
if (ImageJUtils.isInterrupted()) {
IJ.showProgress(1);
engine.end(true);
return false;
}
// Wait until we have enough results
while (!sampleSizeReached() && !engine.isQueueEmpty()) {
IJ.showProgress(size(), settings.getNumberOfPeaks());
try {
Thread.sleep(50);
} catch (final InterruptedException ex) {
Thread.currentThread().interrupt();
throw new ConcurrentRuntimeException("Unexpected interruption", ex);
}
}
// End now if we have enough samples
engine.end(sampleSizeReached());
ImageJUtils.finished();
// This count will be an over-estimate given that the provider is ahead of the consumer
// in this multi-threaded system
debug(" Processed %d/%d slices (%d peaks)", sliceIndex, slices.length, size());
setParams(ANGLE, params, paramsDev, sampleNew[ANGLE]);
setParams(X, params, paramsDev, sampleNew[X]);
setParams(Y, params, paramsDev, sampleNew[Y]);
if (settings.getShowHistograms()) {
final HistogramPlotBuilder builder = new HistogramPlotBuilder(TITLE).setNumberOfBins(settings.getHistogramBins());
final WindowOrganiser wo = new WindowOrganiser();
for (int ii = 0; ii < 3; ii++) {
if (sampleNew[ii].getN() == 0) {
continue;
}
final StoredDataStatistics stats = StoredDataStatistics.create(sampleNew[ii].getValues());
builder.setData(stats).setName(NAMES[ii]).setPlotLabel("Mean = " + MathUtils.rounded(stats.getMean()) + ". Median = " + MathUtils.rounded(sampleNew[ii].getPercentile(50))).show(wo);
}
wo.tile();
}
if (size() < 2) {
log("ERROR: Insufficient number of fitted peaks, terminating ...");
return false;
}
return true;
}
use of uk.ac.sussex.gdsc.smlm.results.InterlacedImageSource in project GDSC-SMLM by aherbert.
the class PeakFit method showDialog.
private int showDialog(ImagePlus imp) {
// Executing as an ImageJ plugin.
// Load the settings
resultsSettings = SettingsManager.readResultsSettings(0).toBuilder();
// Settings are within the FitEngineSettings
config = SettingsManager.readFitEngineConfiguration(0);
fitConfig = config.getFitConfiguration();
settings = Settings.load();
if (simpleFit) {
return showSimpleDialog();
}
// Note: The bounds are not set when running in the fit maxima option (since all candidates
// have been identified already the crop is not required).
final boolean isCrop = (bounds != null && imp != null && (bounds.width < imp.getWidth() || bounds.height < imp.getHeight()));
// Some options are not always needed
if (extraOptions || isCrop) {
extraSettings = ExtraSettings.load();
ignoreBoundsForNoise = extraSettings.optionIgnoreBoundsForNoise;
}
if (!extraOptions) {
resultsSettings.getResultsImageSettingsBuilder().setRollingWindowSize(0);
fitConfig.setBackgroundFitting(true);
fitConfig.setNoise(0);
config.setNoiseMethod(NoiseEstimatorMethod.QUICK_RESIDUALS_LEAST_MEAN_OF_SQUARES);
}
final ExtendedGenericDialog gd = new ExtendedGenericDialog(TITLE);
String helpKey;
if (maximaIdentification) {
helpKey = "spot-finder";
gd.addMessage("Identify candidate maxima");
} else {
helpKey = "peak-fit";
gd.addMessage("Fit 2D Gaussian to identified maxima");
}
// Note: Currently is is not useful to append "-series" when running for a series image
// source since the params in this dialog do not concern the image input.
gd.addHelp(HelpUrls.getUrl(helpKey));
final String[] templates = ConfigurationTemplate.getTemplateNames(true);
gd.addChoice("Template", templates, templates[0]);
final CalibrationReader calibration = fitConfig.getCalibrationReader();
addCameraOptions(gd, 0, fitConfig);
gd.addNumericField("Calibration", calibration.getNmPerPixel(), 2, 6, "nm/px");
gd.addNumericField("Exposure_time", calibration.getExposureTime(), 2, 6, "ms");
if (isCrop) {
gd.addCheckbox("Ignore_bounds_for_noise", ignoreBoundsForNoise);
}
final FitConfigurationProvider fitConfigurationProvider = () -> fitConfig;
final FitEngineConfigurationProvider fitEngineConfigurationProvider = () -> config;
addPsfOptions(gd, fitConfigurationProvider);
addDataFilterOptions(gd, fitEngineConfigurationProvider);
addSearchOptions(gd, fitEngineConfigurationProvider);
addBorderOptions(gd, fitEngineConfigurationProvider);
addFittingOptions(gd, fitEngineConfigurationProvider);
if (extraOptions && !fitMaxima) {
gd.addCheckbox("Interlaced_data", extraSettings.interlacedData);
gd.addSlider("Integrate_frames", 1, 5, extraSettings.integrateFrames);
}
// Special case top get the slider since the GenericDialog does not provide access to this.
Scrollbar sliderCoordinateShiftFactor = null;
final boolean isShowGenericDialog = ImageJUtils.isShowGenericDialog();
if (!maximaIdentification) {
gd.addMessage("--- Gaussian fitting ---");
gd.addChoice("Fit_solver", SettingsManager.getFitSolverNames(), FitProtosHelper.getName(fitConfig.getFitSolver()));
if (extraOptions) {
gd.addCheckbox("Fit_background", fitConfig.isBackgroundFitting());
}
// Parameters specific to each Fit solver are collected in a second dialog
gd.addNumericField("Fail_limit", config.getFailuresLimit(), 0);
gd.addNumericField("Pass_rate", config.getPassRate(), 2);
gd.addCheckbox("Include_neighbours", config.isIncludeNeighbours());
gd.addSlider("Neighbour_height", 0.01, 1, config.getNeighbourHeightThreshold());
gd.addSlider("Residuals_threshold", 0.01, 1, config.getResidualsThreshold());
addDuplicateDistanceOptions(gd, fitEngineConfigurationProvider);
gd.addMessage("--- Peak filtering ---\nDiscard fits that shift; are too low; or expand/contract");
gd.addCheckbox("Smart_filter", fitConfig.isSmartFilter());
gd.addCheckbox("Disable_simple_filter", fitConfig.isDisableSimpleFilter());
gd.addSlider("Shift_factor", 0.0, 2.5, fitConfig.getCoordinateShiftFactor());
if (isShowGenericDialog) {
sliderCoordinateShiftFactor = gd.getLastScrollbar();
}
gd.addNumericField("Signal_strength", fitConfig.getSignalStrength(), 2);
gd.addNumericField("Min_photons", fitConfig.getMinPhotons(), 0);
if (extraOptions) {
gd.addNumericField("Noise", fitConfig.getNoise(), 2);
gd.addChoice("Noise_method", SettingsManager.getNoiseEstimatorMethodNames(), config.getNoiseMethod().ordinal());
}
gd.addSlider("Min_width_factor", 0, 0.99, fitConfig.getMinWidthFactor());
gd.addSlider("Width_factor", 1, 4.5, fitConfig.getMaxWidthFactor());
addPrecisionOptions(gd, fitConfigurationProvider);
// Q. Add dynamically displayed options for z-filtering here?
}
gd.addMessage("--- Results ---");
gd.addCheckbox("Log_progress", resultsSettings.getLogProgress());
if (!maximaIdentification) {
gd.addCheckbox("Show_deviations", resultsSettings.getShowDeviations());
}
ResultsManager.addTableResultsOptions(gd, resultsSettings);
ResultsManager.addImageResultsOptions(gd, resultsSettings, (extraOptions) ? ResultsManager.FLAG_EXTRA_OPTIONS : 0);
if (extraOptions) {
gd.addCheckbox("Show_processed_frames", extraSettings.showProcessedFrames);
}
ResultsManager.addFileResultsOptions(gd, resultsSettings, ResultsManager.FLAG_RESULTS_DIRECTORY);
ResultsManager.addInMemoryResultsOptions(gd, resultsSettings);
if (extraOptions) {
gd.addMessage("--- Misc ---");
gd.addSlider("Fraction_of_threads", 0.1, 1, settings.fractionOfThreads);
}
// Add a mouse listener to the config file field
if (isShowGenericDialog) {
new ItemDialogListener(sliderCoordinateShiftFactor).attach(gd, isCrop);
}
gd.showDialog();
if (gd.wasCanceled() || !readDialog(gd, isCrop)) {
return DONE;
}
if (imp != null) {
// Store whether the user selected to process all the images.
final int flags = IJ.setupDialog(imp, pluginFlags);
// Check if cancelled
if ((flags & DONE) != 0) {
return DONE;
}
if ((flags & DOES_STACKS) == 0) {
// Save the slice number for the overlay
singleFrame = imp.getCurrentSlice();
// Account for interlaced data
if (extraSettings.interlacedData) {
int start = singleFrame;
// Calculate the first frame that is not skipped
while (ignoreFrame(start) && start > extraSettings.dataStart) {
start--;
}
if (start < extraSettings.dataStart) {
log("The current frame (%d) is before the start of the interlaced data", singleFrame);
return DONE;
}
if (start != singleFrame) {
log("Updated the current frame (%d) to a valid interlaced data frame (%d)", singleFrame, start);
}
singleFrame = start;
}
// Account for integrated frames
int endFrame = singleFrame;
if (extraSettings.integrateFrames > 1) {
int totalFrames = 1;
while (totalFrames < extraSettings.integrateFrames) {
endFrame++;
if (!ignoreFrame(endFrame)) {
totalFrames++;
}
}
log("Updated the image end frame (%d) to %d allow %d integrated frames", singleFrame, endFrame, extraSettings.integrateFrames);
}
// Create a new image source with the correct frames
setSource(new IJImageSource(imp, singleFrame, endFrame - singleFrame));
// Store the image so the results can be added as an overlay
this.imp = imp;
this.imp.setOverlay(null);
}
}
// Allow interlaced data by wrapping the image source
if (extraSettings.interlacedData) {
setSource(new InterlacedImageSource(this.source, extraSettings.dataStart, extraSettings.dataBlock, extraSettings.dataSkip));
}
// Allow frame aggregation by wrapping the image source
if (extraSettings.integrateFrames > 1) {
setSource(new AggregatedImageSource(this.source, extraSettings.integrateFrames));
}
// Ask if the user wants to log progress on multiple frame images
if (resultsSettings.getLogProgress() && source.getFrames() > 1) {
final ExtendedGenericDialog egd = new ExtendedGenericDialog(TITLE);
egd.addMessage("Warning: Log progress on multiple-frame image will be slow");
egd.addCheckbox("Log_progress", true);
egd.showDialog();
if (egd.wasCanceled()) {
return DONE;
}
if (!egd.getNextBoolean()) {
resultsSettings.setLogProgress(false);
SettingsManager.writeSettings(resultsSettings.build());
}
}
// single call to be made.
return pluginFlags;
}
Aggregations