use of uk.ac.sussex.gdsc.smlm.engine.FitEngineConfiguration in project gdsc-smlm by aherbert.
the class PsfDrift method run.
@Override
public void run(String arg) {
SmlmUsageTracker.recordPlugin(this.getClass(), arg);
if ("hwhm".equals(arg)) {
showHwhm();
return;
}
// Build a list of suitable images
final List<String> titles = createImageList(true);
if (titles.isEmpty()) {
IJ.error(TITLE, "No suitable PSF images");
return;
}
final ExtendedGenericDialog gd = new ExtendedGenericDialog(TITLE);
settings = Settings.load();
fitConfig = fitConfigRef.get().createCopy();
gd.addMessage("Select the input PSF image");
gd.addChoice("PSF", titles.toArray(new String[0]), settings.title);
gd.addCheckbox("Use_offset", settings.useOffset);
gd.addNumericField("Scale", settings.scale, 2);
gd.addNumericField("z_depth", settings.zDepth, 2, 6, "nm");
gd.addNumericField("Grid_size", settings.gridSize, 0);
gd.addSlider("Recall_limit", 0.01, 1, settings.recallLimit);
gd.addSlider("Region_size", 2, 20, settings.regionSize);
gd.addCheckbox("Background_fitting", settings.backgroundFitting);
PeakFit.addPsfOptions(gd, fitConfig);
gd.addChoice("Fit_solver", SettingsManager.getFitSolverNames(), FitProtosHelper.getName(fitConfig.getFitSolver()));
// We need these to set bounds for any bounded fitters
gd.addSlider("Min_width_factor", 0, 0.99, fitConfig.getMinWidthFactor());
gd.addSlider("Width_factor", 1, 4.5, fitConfig.getMaxWidthFactor());
gd.addCheckbox("Offset_fit", settings.offsetFitting);
gd.addNumericField("Start_offset", settings.startOffset, 3);
gd.addCheckbox("Include_CoM_fit", settings.comFitting);
gd.addCheckbox("Use_sampling", settings.useSampling);
gd.addNumericField("Photons", settings.photons, 0);
gd.addSlider("Photon_limit", 0, 1, settings.photonLimit);
gd.addSlider("Smoothing", 0, 0.5, settings.smoothing);
gd.addHelp(HelpUrls.getUrl("psf-drift"));
gd.showDialog();
if (gd.wasCanceled()) {
return;
}
settings.title = gd.getNextChoice();
settings.useOffset = gd.getNextBoolean();
settings.scale = gd.getNextNumber();
settings.zDepth = gd.getNextNumber();
settings.gridSize = (int) gd.getNextNumber();
settings.recallLimit = gd.getNextNumber();
settings.regionSize = (int) Math.abs(gd.getNextNumber());
settings.backgroundFitting = gd.getNextBoolean();
fitConfig.setPsfType(PeakFit.getPsfTypeValues()[gd.getNextChoiceIndex()]);
// Some enum values are not supported
fitConfig.setFitSolver(SettingsManager.getFitSolverValues()[gd.getNextChoiceIndex()]);
fitConfig.setMinWidthFactor(gd.getNextNumber());
fitConfig.setMaxWidthFactor(gd.getNextNumber());
settings.offsetFitting = gd.getNextBoolean();
settings.startOffset = Math.abs(gd.getNextNumber());
settings.comFitting = gd.getNextBoolean();
settings.useSampling = gd.getNextBoolean();
settings.photons = Math.abs(gd.getNextNumber());
settings.photonLimit = Math.abs(gd.getNextNumber());
settings.smoothing = Math.abs(gd.getNextNumber());
settings.save();
fitConfigRef.set(fitConfig);
gd.collectOptions();
if (!settings.comFitting && !settings.offsetFitting) {
IJ.error(TITLE, "No initial fitting positions");
return;
}
if (settings.regionSize < 1) {
settings.regionSize = 1;
}
if (gd.invalidNumber()) {
return;
}
imp = WindowManager.getImage(settings.title);
if (imp == null) {
IJ.error(TITLE, "No PSF image for image: " + settings.title);
return;
}
psfSettings = getPsfSettings(imp);
if (psfSettings == null) {
IJ.error(TITLE, "No PSF settings for image: " + settings.title);
return;
}
// Configure the fit solver. We must wrap the settings with a
// FitEngineConfiguration to pass to the PeakFit method
final FitEngineSettings fitEngineSettings = FitProtosHelper.DefaultFitEngineSettings.INSTANCE;
final FitEngineConfiguration config = FitEngineConfiguration.create(fitEngineSettings, SettingsManager.readCalibration(0), PsfProtosHelper.DefaultOneAxisGaussian2dPsf.INSTANCE);
config.getFitConfiguration().setFitSettings(fitConfig.getFitSettings());
if (!PeakFit.configurePsfModel(config)) {
return;
}
if (!PeakFit.configureFitSolver(config, IJImageSource.getBounds(imp), null, PeakFit.FLAG_NO_SAVE)) {
return;
}
// Update configuration
fitConfig = config.getFitConfiguration();
fitConfigRef.set(fitConfig);
computeDrift();
}
use of uk.ac.sussex.gdsc.smlm.engine.FitEngineConfiguration in project gdsc-smlm by aherbert.
the class FailCountManager method createData.
/**
* Creates the fail count data by running fitting on the current image.
*/
private void createData() {
final ImagePlus imp = WindowManager.getCurrentImage();
if (imp == null) {
IJ.error(TITLE, "No image for fitting");
return;
}
if (!showCreateDataDialog(imp)) {
return;
}
// Get the current fit configuration
final Configuration c = new Configuration();
if (!c.showDialog(false)) {
return;
}
final FitEngineConfiguration fitConfig = c.getFitEngineConfiguration();
// Update stopping criteria.
fitConfig.resetFailCounter();
fitConfig.setFailuresLimit(settings.getFailCountLimit());
final ImageSource source = new IJImageSource(imp);
final PeakFit peakFit = new PeakFit(fitConfig, ResultsSettings.getDefaultInstance());
peakFit.setResultsSuffix("(FailCountAnalysis)");
if (!peakFit.initialise(source, null, false)) {
IJ.error(TITLE, "Failed to initialise the fit engine");
return;
}
final FitEngine engine = peakFit.createFitEngine();
final Rectangle bounds = new Rectangle(source.getWidth(), source.getHeight());
// Run
final int totalFrames = Math.min(source.getFrames(), settings.getMaxFrames());
final int step = ImageJUtils.getProgressInterval(totalFrames);
IJ.showProgress(0);
boolean shutdown = false;
int slice = 0;
final LocalList<ParameterisedFitJob> jobs = new LocalList<>(totalFrames);
while (!shutdown && slice < totalFrames) {
final float[] data = source.next();
if (data == null) {
break;
}
if (slice++ % step == 0) {
final int frames = slice;
if (ImageJUtils.showStatus(() -> "Fitting slice: " + frames + " / " + totalFrames)) {
IJ.showProgress(slice, totalFrames);
}
}
final ParameterisedFitJob job = createJob(source.getStartFrameNumber(), data, bounds);
jobs.push(job);
engine.run(job);
shutdown = escapePressed();
}
ImageJUtils.showStatus("Extracting fail count data");
engine.end(shutdown);
IJ.showProgress(1);
source.close();
// Extract the fail count data
final LocalList<FailCountData> failCountData = new LocalList<>(jobs.size());
for (int i = 0; i < jobs.size(); i++) {
final ParameterisedFitJob job = jobs.unsafeGet(i);
if (job.getStatus() == Status.FINISHED) {
final FitParameters fitParams = job.getFitParameters();
// Find the last success
boolean[] results = fitParams.pass;
int end = results.length - 1;
while (end > 0 && !results[end]) {
end--;
}
// Add on the configured fail count limit
end = Math.min(end + 1 + settings.getFailCountLimit(), results.length);
results = Arrays.copyOf(results, end);
failCountData.add(new FailCountData(job.getSlice(), results));
}
}
failCountDataRef.set(failCountData);
ImageJUtils.showStatus("");
// Save for the future
if (settings.getSaveAfterFitting()) {
saveData();
}
}
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) {
// Check we have at least the first filter.
if (config.getDataFiltersCount() == 0) {
throw new IllegalStateException("No primary filter is configured");
}
int filterCount;
switch(config.getDataFilterType()) {
case JURY:
filterCount = Integer.MAX_VALUE;
break;
case DIFFERENCE:
filterCount = 2;
break;
case SINGLE:
default:
filterCount = 1;
break;
}
int numberOfFilters = 1;
final String[] filterNames = SettingsManager.getDataFilterMethodNames();
final DataFilterMethod[] filterValues = SettingsManager.getDataFilterMethodValues();
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.FitEngineConfiguration in project gdsc-smlm by aherbert.
the class PsfCalculator method run.
@Override
public void run(String arg) {
SmlmUsageTracker.recordPlugin(this.getClass(), arg);
final PSFCalculatorSettings settings = SettingsManager.readPsfCalculatorSettings(0);
final double sd = calculate(settings, false);
if (sd < 0) {
return;
}
SettingsManager.writeSettings(this.settingsBuilder);
final FitEngineConfiguration config = SettingsManager.readFitEngineConfiguration(0);
final FitConfiguration fitConfig = config.getFitConfiguration();
fitConfig.setNmPerPixel(getPixelPitch());
fitConfig.setPsfType(PSFType.ONE_AXIS_GAUSSIAN_2D);
fitConfig.setInitialPeakStdDev(sd);
SettingsManager.writeSettings(config, 0);
}
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 < DISPLAY_HISTOGRAMS.length; i++) {
if (convert[i] != 0) {
gd2.addCheckbox(NAMES[i].replace(' ', '_'), DISPLAY_HISTOGRAMS[i]);
}
}
gd2.showDialog();
if (gd2.wasCanceled()) {
return false;
}
histogramBins = (int) Math.abs(gd2.getNextNumber());
for (int i = 0; i < DISPLAY_HISTOGRAMS.length; i++) {
if (convert[i] != 0) {
DISPLAY_HISTOGRAMS[i] = gd2.getNextBoolean();
}
}
}
return true;
}
Aggregations