use of uk.ac.sussex.gdsc.smlm.engine.FitConfiguration 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.engine.FitConfiguration in project GDSC-SMLM by aherbert.
the class PsfEstimator method showDialog.
/**
* Show dialog.
*
* @param imp the imp
* @return the int
*/
private int showDialog(ImagePlus imp) {
// Keep class variables for the parameters we are fitting
final FitConfiguration fitConfig = config.getFitConfiguration();
initialPeakStdDev0 = 1;
initialPeakStdDev1 = 1;
initialPeakAngle = 0;
try {
initialPeakStdDev0 = fitConfig.getInitialXSd();
initialPeakStdDev1 = fitConfig.getInitialYSd();
initialPeakAngle = fitConfig.getInitialAngle();
} catch (final IllegalStateException | ConfigurationException ex) {
// Ignore this as the current PSF is not a 2 axis and theta Gaussian PSF
}
if (!extraOptions) {
interlacedData = false;
integrateFrames = 1;
}
this.imp = imp;
final ExtendedGenericDialog gd = new ExtendedGenericDialog(TITLE);
gd.addHelp(HelpUrls.getUrl("psf-estimator"));
gd.addMessage("Estimate 2D Gaussian to fit maxima");
gd.addNumericField("Initial_StdDev0", initialPeakStdDev0, 3);
gd.addNumericField("Initial_StdDev1", initialPeakStdDev1, 3);
gd.addNumericField("Initial_Angle", initialPeakAngle, 3);
gd.addNumericField("Number_of_peaks", settings.getNumberOfPeaks(), 0);
// pValue sets the smallest significance level probability level at which they are said to be
// different.
// i.e. p <= pValue they are different
// lower pValue means harder to be found different.
// lower pValue means easier to be found the same.
gd.addNumericField("p-Value", settings.getPValue(), 4);
gd.addCheckbox("Update_preferences", settings.getUpdatePreferences());
gd.addCheckbox("Log_progress", settings.getDebugPsfEstimator());
gd.addCheckbox("Iterate", settings.getIterate());
gd.addCheckbox("Show_histograms", settings.getShowHistograms());
gd.addNumericField("Histogram_bins", settings.getHistogramBins(), 0);
PeakFit.addCameraOptions(gd, fitConfig);
PeakFit.addPsfOptions(gd, fitConfig);
final PeakFit.SimpleFitEngineConfigurationProvider provider = new PeakFit.SimpleFitEngineConfigurationProvider(config);
PeakFit.addDataFilterOptions(gd, provider);
PeakFit.addSearchOptions(gd, provider);
PeakFit.addBorderOptions(gd, provider);
PeakFit.addFittingOptions(gd, provider);
if (extraOptions) {
pluginSettings = Settings.load();
gd.addCheckbox("Interlaced_data", pluginSettings.interlacedData);
gd.addSlider("Integrate_frames", 1, 5, pluginSettings.integrateFrames);
}
gd.addMessage("--- Gaussian fitting ---");
gd.addChoice("Fit_solver", SettingsManager.getFitSolverNames(), FitProtosHelper.getName(fitConfig.getFitSolver()));
// 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());
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.01, 2, fitConfig.getCoordinateShiftFactor());
gd.addNumericField("Signal_strength", fitConfig.getSignalStrength(), 2);
gd.addNumericField("Min_photons", fitConfig.getMinPhotons(), 0);
gd.addSlider("Min_width_factor", 0, 0.99, fitConfig.getMinWidthFactor());
gd.addSlider("Width_factor", 1, 4.5, fitConfig.getMaxWidthFactor());
PeakFit.addPrecisionOptions(gd, new PeakFit.SimpleFitConfigurationProvider(fitConfig));
gd.showDialog();
if (gd.wasCanceled() || !readDialog(gd)) {
return DONE;
}
return FLAGS;
}
use of uk.ac.sussex.gdsc.smlm.engine.FitConfiguration in project GDSC-SMLM by aherbert.
the class PeakFit method addPsfOptions.
/**
* Adds the PSF options.
*
* <p>Note that if an astigmatic PSF is selected then the model must be created with
* {@link #configurePsfModel(FitEngineConfiguration, int)}.
*
* @param gd the dialog
* @param fitConfigurationProvider the fit configuration provider
*/
public static void addPsfOptions(final ExtendedGenericDialog gd, final FitConfigurationProvider fitConfigurationProvider) {
final FitConfiguration fitConfig = fitConfigurationProvider.getFitConfiguration();
gd.addChoice("PSF", getPsfTypeNames(), PsfProtosHelper.getName(fitConfig.getPsfType()), new OptionListener<Integer>() {
@Override
public boolean collectOptions(Integer field) {
final FitConfiguration fitConfig = fitConfigurationProvider.getFitConfiguration();
fitConfig.setPsfType(PeakFit.getPsfTypeValues()[field]);
return collectOptions(false);
}
@Override
public boolean collectOptions() {
return collectOptions(true);
}
private boolean collectOptions(boolean silent) {
final FitConfiguration localFitConfig = fitConfigurationProvider.getFitConfiguration();
final PSFType psfType = localFitConfig.getPsfType();
final ExtendedGenericDialog egd = new ExtendedGenericDialog("PSF Options", null);
PSF oldPsf = null;
if (psfType == PSFType.ASTIGMATIC_GAUSSIAN_2D) {
// The PSF is entirely defined in the model
String[] list = AstigmatismModelManager.listAstigmatismModels(false, localFitConfig.getCalibrationReader().getNmPerPixel(), 0.1);
// In case the calibration has not been updated
if (list.length == 0) {
list = AstigmatismModelManager.listAstigmatismModels(false, true);
}
egd.addChoice("Z-model", list, localFitConfig.getPsfModelName());
} else {
// Collect the PSF parameters
oldPsf = localFitConfig.getPsf();
for (int i = 0; i < oldPsf.getParametersCount(); i++) {
final PSFParameter p = oldPsf.getParameters(i);
egd.addNumericField(String.format("PSF_parameter_%d (%s)", i + 1, p.getName()), p.getValue(), 3);
}
if (psfType == PSFType.ONE_AXIS_GAUSSIAN_2D) {
egd.addCheckbox("Fixed", localFitConfig.isFixedPsf());
}
}
egd.setSilent(silent);
egd.showDialog(true, gd);
if (egd.wasCanceled()) {
return false;
}
if (psfType == PSFType.ASTIGMATIC_GAUSSIAN_2D) {
// The PSF is entirely defined in the model
localFitConfig.setPsfModelName(egd.getNextChoice());
return true;
}
@SuppressWarnings("null") final PSF.Builder b = oldPsf.toBuilder();
final int n = b.getParametersCount();
for (int i = 0; i < n; i++) {
b.getParametersBuilder(i).setValue(egd.getNextNumber());
}
final PSF newPsf = b.build();
localFitConfig.setPsf(newPsf);
boolean changed = !oldPsf.equals(newPsf);
if (psfType == PSFType.ONE_AXIS_GAUSSIAN_2D) {
final boolean newFixed = egd.getNextBoolean();
changed = changed || (newFixed != localFitConfig.isFixedPsf());
localFitConfig.setFixedPsf(newFixed);
}
return changed;
}
});
}
use of uk.ac.sussex.gdsc.smlm.engine.FitConfiguration 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;
}
use of uk.ac.sussex.gdsc.smlm.engine.FitConfiguration in project GDSC-SMLM by aherbert.
the class PsfCreator method fitSpot.
private MemoryPeakResults fitSpot(ImageStack stack, final int width, final int height, final int x, final int y) {
Rectangle regionBounds = null;
// Create a fit engine
final MemoryPeakResults results = new MemoryPeakResults();
final FitConfiguration fitConfig = config.getFitConfiguration();
results.setCalibration(fitConfig.getCalibration());
results.setPsf(fitConfig.getPsf());
results.setSortAfterEnd(true);
results.begin();
final int threadCount = Prefs.getThreads();
final FitEngine engine = FitEngine.create(config, SynchronizedPeakResults.create(results, threadCount), threadCount, FitQueue.BLOCKING);
for (int slice = 1; slice <= stack.getSize(); slice++) {
// Extract the region from each frame
final ImageExtractor ie = ImageExtractor.wrap((float[]) stack.getPixels(slice), width, height);
if (regionBounds == null) {
regionBounds = ie.getBoxRegionBounds(x, y, boxRadius);
}
final float[] region = ie.crop(regionBounds);
// Fit only a spot in the centre
final FitParameters params = new FitParameters();
params.maxIndices = new int[] { boxRadius * regionBounds.width + boxRadius };
final ParameterisedFitJob job = new ParameterisedFitJob(slice, params, slice, region, regionBounds);
// jobItems.add(job);
engine.run(job);
}
engine.end(false);
results.end();
return results;
}
Aggregations