use of gdsc.smlm.fitting.FitConfiguration in project GDSC-SMLM by aherbert.
the class FitWorker method run.
/**
* Locate all the peaks in the image specified by the fit job
* <p>
* WARNING: The FitWorker fits a sub-region of the data for each maxima. It then updates the FitResult parameters
* with an offset reflecting the position. The initialParameters are not updated with this offset unless configured.
*
* @param job
* The fit job
*/
public void run(FitJob job) {
final long start = System.nanoTime();
job.start();
this.job = job;
benchmarking = false;
this.slice = job.slice;
// Used for debugging
//if (logger == null) logger = new gdsc.fitting.logging.ConsoleLogger();
// Crop to the ROI
cc = new CoordinateConverter(job.bounds);
final int width = cc.dataBounds.width;
final int height = cc.dataBounds.height;
borderLimitX = width - border;
borderLimitY = height - border;
data = job.data;
FitParameters params = job.getFitParameters();
this.endT = (params != null) ? params.endT : -1;
candidates = indentifySpots(job, width, height, params);
if (candidates.size == 0) {
finish(job, start);
return;
}
fittedBackground = 0;
// Always get the noise and store it with the results.
if (params != null && !Float.isNaN(params.noise)) {
noise = params.noise;
fitConfig.setNoise(noise);
} else if (calculateNoise) {
noise = estimateNoise(width, height);
fitConfig.setNoise(noise);
}
//System.out.printf("Slice %d : Noise = %g\n", slice, noise);
if (logger != null)
logger.info("Slice %d: Noise = %f", slice, noise);
final ImageExtractor ie = new ImageExtractor(data, width, height);
double[] region = null;
if (params != null && params.fitTask == FitTask.MAXIMA_IDENITIFICATION) {
final float sd0 = (float) fitConfig.getInitialPeakStdDev0();
final float sd1 = (float) fitConfig.getInitialPeakStdDev1();
for (int n = 0; n < candidates.getSize(); n++) {
// Find the background using the perimeter of the data.
// TODO - Perhaps the Gaussian Fitter should be used to produce the initial estimates but no actual fit done.
// This would produce coords using the centre-of-mass.
final Candidate candidate = candidates.get(n);
final int x = candidate.x;
final int y = candidate.y;
final Rectangle regionBounds = ie.getBoxRegionBounds(x, y, fitting);
region = ie.crop(regionBounds, region);
final float b = (float) Gaussian2DFitter.getBackground(region, regionBounds.width, regionBounds.height, 1);
// Offset the coords to the centre of the pixel. Note the bounds will be added later.
// Subtract the background to get the amplitude estimate then convert to signal.
final float amplitude = candidate.intensity - ((relativeIntensity) ? 0 : b);
final float signal = (float) (amplitude * 2.0 * Math.PI * sd0 * sd1);
final float[] peakParams = new float[] { b, signal, 0, x + 0.5f, y + 0.5f, sd0, sd1 };
final int index = y * width + x;
sliceResults.add(createResult(cc.fromDataToGlobalX(x), cc.fromDataToGlobalY(y), data[index], 0, noise, peakParams, null, n));
}
} else {
initialiseFitting();
// Smooth the data to provide initial background estimates
final BlockAverageDataProcessor processor = new BlockAverageDataProcessor(1, 1);
final float[] smoothedData = processor.process(data, width, height);
final ImageExtractor ie2 = new ImageExtractor(smoothedData, width, height);
// Allow the results to be filtered for certain peaks
if (params != null && params.filter != null) {
resultFilter = new DistanceResultFilter(params.filter, params.distanceThreshold, candidates.getlength());
//filter = new OptimumDistanceResultFilter(params.filter, params.distanceThreshold, maxIndices.length);
}
// The SpotFitter is used to create a dynamic MultiPathFitResult object.
// This is then passed to a multi-path filter. Thus the same fitting decision process
// is used when benchmarking and when running on actual data.
// Note: The SpotFitter labels each PreprocessedFitResult using the offset in the FitResult object.
// The initial params and deviations can then be extracted for the results that pass the filter.
MultiPathFilter filter;
IMultiPathFitResults multiPathResults = this;
SelectedResultStore store = this;
coordinateStore = coordinateStore.resize(width, height);
if (params != null && params.fitTask == FitTask.BENCHMARKING) {
// Run filtering as normal. However in the event that a candidate is missed or some
// results are not generated we must generate them. This is done in the complete(int)
// method if we set the benchmarking flag.
benchmarking = true;
// Filter using the benchmark filter
filter = params.benchmarkFilter;
if (filter == null) {
// Create a default filter using the standard FitConfiguration to ensure sensible fits
// are stored as the current slice results.
// Note the current fit configuration for benchmarking may have minimal filtering settings
// so we do not use that object.
final FitConfiguration tmp = new FitConfiguration();
final double residualsThreshold = 0.4;
filter = new MultiPathFilter(tmp, createMinimalFilter(), residualsThreshold);
}
} else {
// Filter using the configuration
filter = new MultiPathFilter(fitConfig, createMinimalFilter(), config.getResidualsThreshold());
}
// If we are benchmarking then do not generate results dynamically since we will store all
// results in the fit job
dynamicMultiPathFitResult = new DynamicMultiPathFitResult(ie, ie2, !benchmarking);
// Debug where the fit config may be different between benchmarking and fitting
if (slice == -1) {
SettingsManager.saveFitEngineConfiguration(config, String.format("/tmp/config.%b.xml", benchmarking));
Utils.write(String.format("/tmp/filter.%b.xml", benchmarking), filter.toXML());
//filter.setDebugFile(String.format("/tmp/fitWorker.%b.txt", benchmarking));
StringBuilder sb = new StringBuilder();
sb.append((benchmarking) ? ((gdsc.smlm.results.filter.Filter) filter.getFilter()).toXML() : fitConfig.getSmartFilter().toXML()).append("\n");
sb.append(((gdsc.smlm.results.filter.Filter) filter.getMinimalFilter()).toXML()).append("\n");
sb.append(filter.residualsThreshold).append("\n");
sb.append(config.getFailuresLimit()).append("\n");
sb.append(fitConfig.getDuplicateDistance()).append("\n");
if (spotFilter != null)
sb.append(spotFilter.getDescription()).append("\n");
sb.append("MaxCandidate = ").append(candidates.getSize()).append("\n");
for (int i = 0; i < candidates.list.length; i++) {
sb.append(String.format("Fit %d [%d,%d = %.1f]\n", i, candidates.get(i).x, candidates.get(i).y, candidates.get(i).intensity));
}
Utils.write(String.format("/tmp/candidates.%b.xml", benchmarking), sb.toString());
}
filter.select(multiPathResults, config.getFailuresLimit(), true, store, coordinateStore);
if (logger != null)
logger.info("Slice %d: %d / %d", slice, success, candidates.getSize());
// Result filter post-processing
if (resultFilter != null) {
resultFilter.finalise();
job.setResults(resultFilter.getResults());
job.setIndices(resultFilter.getMaxIndices());
for (int i = 0; i < resultFilter.getFilteredCount(); i++) {
job.setFitResult(i, resultFilter.getFitResults()[i]);
}
sliceResults.clear();
sliceResults.addAll(resultFilter.getResults());
}
}
// Add the ROI bounds to the fitted peaks
final float offsetx = cc.dataBounds.x;
final float offsety = cc.dataBounds.y;
for (int i = 0; i < sliceResults.size(); i++) {
final PeakResult result = sliceResults.get(i);
result.params[Gaussian2DFunction.X_POSITION] += offsetx;
result.params[Gaussian2DFunction.Y_POSITION] += offsety;
}
this.results.addAll(sliceResults);
finish(job, start);
}
use of gdsc.smlm.fitting.FitConfiguration in project GDSC-SMLM by aherbert.
the class DoubletAnalysis method saveTemplate.
/**
* Save PeakFit configuration template using the current benchmark settings.
*
* @param summary
*/
private void saveTemplate(String summary) {
if (!saveTemplate)
return;
// Start with a clone of the filter settings
FitConfiguration fitConfig = filterFitConfig.clone();
FitEngineConfiguration config = new FitEngineConfiguration(fitConfig);
// 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 (useBenchmarkSettings) {
FitEngineConfiguration pConfig = new FitEngineConfiguration(new FitConfiguration());
// 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]);
String filename = BenchmarkFilterAnalysis.getFilename("Template_File", templateFilename);
if (filename != null) {
templateFilename = filename;
GlobalSettings settings = new GlobalSettings();
settings.setNotes(getNotes(summary));
settings.setFitEngineConfiguration(config);
if (!SettingsManager.saveSettings(settings, filename, true))
IJ.log("Unable to save the template configuration");
}
}
use of gdsc.smlm.fitting.FitConfiguration in project GDSC-SMLM by aherbert.
the class BenchmarkFilterAnalysis method updateConfiguration.
/**
* Updates the given configuration using the latest settings used in benchmarking filtering. The residuals threshold
* will be copied only if the input FitConfiguration has isComputeResiduals() set to true.
*
* @param config
* the configuration
* @param useLatest
* Use the latest best filter. Otherwise use the highest scoring.
* @return true, if successful
*/
public static boolean updateConfiguration(FitEngineConfiguration config, boolean useLatest) {
if (scores.isEmpty())
return false;
FilterResult best;
if (useLatest) {
best = scores.get(scores.size() - 1);
} else {
best = getBestResult();
}
// New smart filter support
final FitConfiguration fitConfig = config.getFitConfiguration();
fitConfig.setDirectFilter(best.getFilter());
if (fitConfig.isComputeResiduals()) {
config.setResidualsThreshold(best.residualsThreshold);
fitConfig.setComputeResiduals(true);
} else {
config.setResidualsThreshold(1);
fitConfig.setComputeResiduals(false);
}
// Note:
// We leave the simple filter settings alone. These may be enabled as well, e.g. by the BenchmarkSpotFit plugin
// We could set the fail count range dynamically using a window around the best filter
config.setFailuresLimit(best.failCount);
fitConfig.setDuplicateDistance(best.duplicateDistance);
return true;
}
use of gdsc.smlm.fitting.FitConfiguration in project GDSC-SMLM by aherbert.
the class BenchmarkFilterAnalysis method saveTemplate.
/**
* Save PeakFit configuration template using the current benchmark settings.
*
* @param topFilterSummary
*/
private void saveTemplate(String topFilterSummary) {
FitEngineConfiguration config = new FitEngineConfiguration(new FitConfiguration());
if (!updateAllConfiguration(config, true)) {
IJ.log("Unable to create the template configuration");
return;
}
// Remove the PSF width to make the template generic
config.getFitConfiguration().setInitialPeakStdDev(0);
String filename = getFilename("Template_File", templateFilename);
if (filename != null) {
templateFilename = filename;
Prefs.set(KEY_TEMPLATE_FILENAME, filename);
GlobalSettings settings = new GlobalSettings();
settings.setNotes(getNotes(topFilterSummary));
settings.setFitEngineConfiguration(config);
if (!SettingsManager.saveSettings(settings, filename, true)) {
IJ.log("Unable to save the template configuration");
return;
}
// Save some random frames from the test image data
ImagePlus imp = CreateData.getImage();
if (imp == null)
return;
// Get the number of frames
final ImageStack stack = imp.getImageStack();
if (sampler == null || sampler.getResults() != results) {
sampler = new ResultsImageSampler(results, stack, 32);
sampler.analyse();
}
if (!sampler.isValid())
return;
// Iteratively show the example until the user is happy.
// Yes = OK, No = Repeat, Cancel = Do not save
String keyNo = "nNo";
String keyLow = "nLower";
String keyHigh = "nHigher";
if (Utils.isMacro()) {
// Collect the options if running in a macro
String options = Macro.getOptions();
nNo = Integer.parseInt(Macro.getValue(options, keyNo, Integer.toString(nNo)));
nLow = Integer.parseInt(Macro.getValue(options, keyLow, Integer.toString(nLow)));
nHigh = Integer.parseInt(Macro.getValue(options, keyHigh, Integer.toString(nHigh)));
} else {
if (nLow + nHigh == 0)
nLow = nHigh = 1;
}
final ImagePlus[] out = new ImagePlus[1];
out[0] = sampler.getSample(nNo, nLow, nHigh);
if (!Utils.isMacro()) {
// Show the template results
final ConfigurationTemplate configTemplate = new ConfigurationTemplate();
// Interactively show the sample image data
final boolean[] close = new boolean[1];
final ImagePlus[] outImp = new ImagePlus[1];
if (out[0] != null) {
outImp[0] = display(out[0]);
if (Utils.isNewWindow()) {
close[0] = true;
// Zoom a bit
ImageWindow iw = outImp[0].getWindow();
for (int i = 7; i-- > 0 && Math.max(iw.getWidth(), iw.getHeight()) < 512; ) {
iw.getCanvas().zoomIn(0, 0);
}
}
configTemplate.createResults(outImp[0]);
}
// TODO - fix this when a second sample is made as the results are not updated.
ImageListener listener = new ImageListener() {
public void imageOpened(ImagePlus imp) {
}
public void imageClosed(ImagePlus imp) {
}
public void imageUpdated(ImagePlus imp) {
if (imp != null && imp == outImp[0]) {
configTemplate.updateResults(imp.getCurrentSlice());
}
}
};
ImagePlus.addImageListener(listener);
// For the dialog
String msg = String.format("Showing image data for the template example.\n \nSample Frames:\nEmpty = %d\nLower density = %d\nHigher density = %d\n", sampler.getNumberOfEmptySamples(), sampler.getNumberOfLowDensitySamples(), sampler.getNumberOfHighDensitySamples());
// Turn off the recorder when the dialog is showing
boolean record = Recorder.record;
Recorder.record = false;
NonBlockingGenericDialog gd = new NonBlockingGenericDialog(TITLE);
gd.addMessage(msg);
//gd.enableYesNoCancel(" Save ", " Resample ");
gd.addSlider(keyNo, 0, 10, nNo);
gd.addSlider(keyLow, 0, 10, nLow);
gd.addSlider(keyHigh, 0, 10, nHigh);
gd.addDialogListener(new DialogListener() {
public boolean dialogItemChanged(GenericDialog gd, AWTEvent e) {
// image the user has not seen.
if (e == null)
return true;
nNo = (int) gd.getNextNumber();
nLow = (int) gd.getNextNumber();
nHigh = (int) gd.getNextNumber();
out[0] = sampler.getSample(nNo, nLow, nHigh);
if (out[0] != null) {
outImp[0] = display(out[0]);
if (Utils.isNewWindow()) {
close[0] = true;
// Zoom a bit
ImageWindow iw = outImp[0].getWindow();
for (int i = 7; i-- > 0 && Math.max(iw.getWidth(), iw.getHeight()) < 512; ) {
iw.getCanvas().zoomIn(0, 0);
}
}
configTemplate.createResults(outImp[0]);
}
return true;
}
});
gd.showDialog();
if (gd.wasCanceled()) {
out[0] = null;
// For the recorder
nNo = nLow = nHigh = 0;
}
if (close[0]) {
// Because closing the image sets the stack pixels array to null
if (out[0] != null)
out[0] = out[0].duplicate();
outImp[0].close();
}
configTemplate.closeResults();
ImagePlus.removeImageListener(listener);
if (record) {
Recorder.record = true;
Recorder.recordOption(keyNo, Integer.toString(nNo));
Recorder.recordOption(keyLow, Integer.toString(nLow));
Recorder.recordOption(keyHigh, Integer.toString(nHigh));
}
}
if (out[0] == null)
return;
ImagePlus example = out[0];
filename = Utils.replaceExtension(filename, ".tif");
IJ.save(example, filename);
}
}
use of gdsc.smlm.fitting.FitConfiguration in project GDSC-SMLM by aherbert.
the class BenchmarkSpotFit method updateConfiguration.
/**
* Updates the given configuration using the latest settings used in benchmarking.
*
* @param pConfig
* the configuration
* @return true, if successful
*/
public static boolean updateConfiguration(FitEngineConfiguration pConfig) {
final FitConfiguration pFitConfig = pConfig.getFitConfiguration();
pFitConfig.setInitialPeakStdDev(fitConfig.getInitialPeakStdDev0());
pConfig.setFitting(config.getFitting());
pFitConfig.setFitSolver(fitConfig.getFitSolver());
pFitConfig.setFitFunction(fitConfig.getFitFunction());
pConfig.setIncludeNeighbours(config.isIncludeNeighbours());
pConfig.setNeighbourHeightThreshold(config.getNeighbourHeightThreshold());
pFitConfig.setDuplicateDistance(fitConfig.getDuplicateDistance());
if (computeDoublets) {
//config.setComputeResiduals(true);
pConfig.setResidualsThreshold(0);
pFitConfig.setComputeResiduals(true);
} else {
pConfig.setResidualsThreshold(1);
pFitConfig.setComputeResiduals(false);
}
pFitConfig.setMaxIterations(fitConfig.getMaxIterations());
pFitConfig.setMaxFunctionEvaluations(fitConfig.getMaxFunctionEvaluations());
// MLE settings
pFitConfig.setModelCamera(fitConfig.isModelCamera());
pFitConfig.setBias(0);
pFitConfig.setReadNoise(0);
pFitConfig.setAmplification(0);
pFitConfig.setEmCCD(fitConfig.isEmCCD());
pFitConfig.setSearchMethod(fitConfig.getSearchMethod());
pFitConfig.setRelativeThreshold(fitConfig.getRelativeThreshold());
pFitConfig.setAbsoluteThreshold(fitConfig.getAbsoluteThreshold());
pFitConfig.setGradientLineMinimisation(fitConfig.isGradientLineMinimisation());
// LSE settings
pFitConfig.setFitCriteria(fitConfig.getFitCriteria());
pFitConfig.setSignificantDigits(fitConfig.getSignificantDigits());
pFitConfig.setDelta(fitConfig.getDelta());
pFitConfig.setLambda(fitConfig.getLambda());
pFitConfig.setSmartFilter(false);
// We used simple filtering. Also we must set the width factors as these are used
// during fitting to set the bounds.
pFitConfig.setDisableSimpleFilter(fitConfig.isDisableSimpleFilter());
pFitConfig.setCoordinateShiftFactor(fitConfig.getCoordinateShiftFactor());
pFitConfig.setSignalStrength(fitConfig.getSignalStrength());
pFitConfig.setMinPhotons(fitConfig.getMinPhotons());
pFitConfig.setMinWidthFactor(fitConfig.getMinWidthFactor());
pFitConfig.setWidthFactor(fitConfig.getWidthFactor());
pFitConfig.setPrecisionThreshold(fitConfig.getPrecisionThreshold());
pFitConfig.setPrecisionUsingBackground(fitConfig.isPrecisionUsingBackground());
return true;
}
Aggregations