use of gdsc.smlm.engine.FitEngineConfiguration in project GDSC-SMLM by aherbert.
the class PSFEstimator method setup.
/*
* (non-Javadoc)
*
* @see ij.plugin.filter.PlugInFilter#setup(java.lang.String, ij.ImagePlus)
*/
public int setup(String arg, ImagePlus imp) {
SMLMUsageTracker.recordPlugin(this.getClass(), arg);
extraOptions = Utils.isExtraOptions();
if (imp == null) {
IJ.noImage();
return DONE;
}
globalSettings = SettingsManager.loadSettings();
settings = globalSettings.getPsfEstimatorSettings();
// Reset
if (IJ.controlKeyDown()) {
config = new FitEngineConfiguration(new FitConfiguration());
globalSettings.setFitEngineConfiguration(config);
} else {
config = globalSettings.getFitEngineConfiguration();
}
Roi roi = imp.getRoi();
if (roi != null && roi.getType() != Roi.RECTANGLE) {
IJ.error("Rectangular ROI required");
return DONE;
}
return showDialog(imp);
}
use of gdsc.smlm.engine.FitEngineConfiguration in project GDSC-SMLM by aherbert.
the class BenchmarkFilterAnalysis method createResults.
/**
* Create peak results.
*
* @param filterResults
* The results from running the filter (or null)
* @param filter
* the filter
*/
private MemoryPeakResults createResults(PreprocessedPeakResult[] filterResults, DirectFilter filter, boolean withBorder) {
if (filterResults == null) {
final MultiPathFilter multiPathFilter = createMPF(filter, minimalFilter);
//multiPathFilter.setDebugFile("/tmp/filter.txt");
filterResults = filterResults(multiPathFilter);
}
MemoryPeakResults results = new MemoryPeakResults();
results.copySettings(this.results);
results.setName(TITLE);
if (withBorder) {
// To produce the same results as the PeakFit plugin we must implement the border
// functionality used in the FitWorker. This respects the border of the spot filter.
FitEngineConfiguration config = new FitEngineConfiguration(new FitConfiguration());
updateAllConfiguration(config);
MaximaSpotFilter spotFilter = config.createSpotFilter(true);
final int border = spotFilter.getBorder();
int[] bounds = getBounds();
final int borderLimitX = bounds[0] - border;
final int borderLimitY = bounds[1] - border;
for (PreprocessedPeakResult spot : filterResults) {
if (spot.getX() > border && spot.getX() < borderLimitX && spot.getY() > border && spot.getY() < borderLimitY) {
double[] p = spot.toGaussian2DParameters();
float[] params = new float[p.length];
for (int j = 0; j < p.length; j++) params[j] = (float) p[j];
int frame = spot.getFrame();
int origX = (int) p[Gaussian2DFunction.X_POSITION];
int origY = (int) p[Gaussian2DFunction.Y_POSITION];
results.addf(frame, origX, origY, 0, 0, spot.getNoise(), params, null);
}
}
} else {
for (PreprocessedPeakResult spot : filterResults) {
double[] p = spot.toGaussian2DParameters();
float[] params = new float[p.length];
for (int j = 0; j < p.length; j++) params[j] = (float) p[j];
int frame = spot.getFrame();
int origX = (int) p[Gaussian2DFunction.X_POSITION];
int origY = (int) p[Gaussian2DFunction.Y_POSITION];
results.addf(frame, origX, origY, 0, 0, spot.getNoise(), params, null);
}
}
return results;
}
use of gdsc.smlm.engine.FitEngineConfiguration in project GDSC-SMLM by aherbert.
the class BenchmarkSpotFit method showDialog.
@SuppressWarnings("unchecked")
private boolean showDialog() {
GenericDialog gd = new GenericDialog(TITLE);
gd.addHelp(About.HELP_URL);
gd.addMessage(String.format("Fit candidate spots in the benchmark image created by " + CreateData.TITLE + " plugin\nand identified by the " + BenchmarkSpotFilter.TITLE + " plugin.\nPSF width = %s nm (Square pixel adjustment = %s nm)\n \nConfigure the fitting:", Utils.rounded(simulationParameters.s), Utils.rounded(getSa())));
gd.addSlider("Fraction_positives", 50, 100, fractionPositives);
gd.addSlider("Fraction_negatives_after_positives", 0, 100, fractionNegativesAfterAllPositives);
gd.addSlider("Min_negatives_after_positives", 0, 10, negativesAfterAllPositives);
gd.addSlider("Match_distance", 0.5, 3.5, distance);
gd.addSlider("Lower_distance", 0, 3.5, lowerDistance);
gd.addSlider("Match_signal", 0, 3.5, signalFactor);
gd.addSlider("Lower_signal", 0, 3.5, lowerSignalFactor);
// Collect options for fitting
final double sa = getSa();
gd.addNumericField("Initial_StdDev", Maths.round(sa / simulationParameters.a), 3);
gd.addSlider("Fitting_width", 2, 4.5, config.getFitting());
String[] solverNames = SettingsManager.getNames((Object[]) FitSolver.values());
gd.addChoice("Fit_solver", solverNames, solverNames[fitConfig.getFitSolver().ordinal()]);
String[] functionNames = SettingsManager.getNames((Object[]) FitFunction.values());
gd.addChoice("Fit_function", functionNames, functionNames[fitConfig.getFitFunction().ordinal()]);
gd.addMessage("Multi-path filter (used to pick optimum results during fitting)");
// Allow loading the best filter fot these results
boolean benchmarkSettingsCheckbox = fitResultsId == BenchmarkFilterAnalysis.lastId;
// This should always be an opt-in decision. Otherwise the user cannot use the previous settings
useBenchmarkSettings = false;
if (benchmarkSettingsCheckbox)
gd.addCheckbox("Benchmark_settings", useBenchmarkSettings);
gd.addTextAreas(XmlUtils.convertQuotes(multiFilter.toXML()), null, 6, 60);
gd.addNumericField("Fail_limit", config.getFailuresLimit(), 0);
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.addCheckbox("Compute_doublets", computeDoublets);
gd.addNumericField("Duplicate_distance", fitConfig.getDuplicateDistance(), 2);
gd.addCheckbox("Show_score_histograms", showFilterScoreHistograms);
gd.addCheckbox("Show_correlation", showCorrelation);
gd.addCheckbox("Plot_rank_by_intensity", rankByIntensity);
gd.addCheckbox("Save_filter_range", saveFilterRange);
if (extraOptions) {
}
// Add a mouse listener to the config file field
if (benchmarkSettingsCheckbox && Utils.isShowGenericDialog()) {
Vector<TextField> numerics = (Vector<TextField>) gd.getNumericFields();
Vector<Checkbox> checkboxes = (Vector<Checkbox>) gd.getCheckboxes();
taFilterXml = gd.getTextArea1();
Checkbox b = checkboxes.get(0);
b.addItemListener(this);
textFailLimit = numerics.get(9);
cbIncludeNeighbours = checkboxes.get(1);
textNeighbourHeight = numerics.get(10);
cbComputeDoublets = checkboxes.get(2);
if (useBenchmarkSettings) {
FitConfiguration tmpFitConfig = new FitConfiguration();
FitEngineConfiguration tmp = new FitEngineConfiguration(tmpFitConfig);
// Collect the residuals threshold
tmpFitConfig.setComputeResiduals(true);
if (BenchmarkFilterAnalysis.updateConfiguration(tmp, false)) {
textFailLimit.setText("" + tmp.getFailuresLimit());
cbIncludeNeighbours.setState(tmp.isIncludeNeighbours());
textNeighbourHeight.setText(Utils.rounded(tmp.getNeighbourHeightThreshold()));
cbComputeDoublets.setState(tmp.getResidualsThreshold() < 1);
final DirectFilter primaryFilter = tmpFitConfig.getSmartFilter();
final double residualsThreshold = tmp.getResidualsThreshold();
taFilterXml.setText(new MultiPathFilter(primaryFilter, minimalFilter, residualsThreshold).toXML());
}
}
}
gd.showDialog();
if (gd.wasCanceled())
return false;
fractionPositives = Math.abs(gd.getNextNumber());
fractionNegativesAfterAllPositives = Math.abs(gd.getNextNumber());
negativesAfterAllPositives = (int) Math.abs(gd.getNextNumber());
distance = Math.abs(gd.getNextNumber());
lowerDistance = Math.abs(gd.getNextNumber());
signalFactor = Math.abs(gd.getNextNumber());
lowerSignalFactor = Math.abs(gd.getNextNumber());
fitConfig.setInitialPeakStdDev(gd.getNextNumber());
config.setFitting(gd.getNextNumber());
fitConfig.setFitSolver(gd.getNextChoiceIndex());
fitConfig.setFitFunction(gd.getNextChoiceIndex());
boolean myUseBenchmarkSettings = false;
if (benchmarkSettingsCheckbox)
//useBenchmarkSettings =
myUseBenchmarkSettings = gd.getNextBoolean();
// Read dialog settings
String xml = gd.getNextText();
int failLimit = (int) gd.getNextNumber();
boolean includeNeighbours = gd.getNextBoolean();
double neighbourHeightThreshold = gd.getNextNumber();
boolean myComputeDoublets = gd.getNextBoolean();
double myDuplicateDistance = gd.getNextNumber();
MultiPathFilter myMultiFilter = null;
if (myUseBenchmarkSettings && !Utils.isShowGenericDialog()) {
// Only copy the benchmark settings if not interactive
FitConfiguration tmpFitConfig = new FitConfiguration();
FitEngineConfiguration tmp = new FitEngineConfiguration(tmpFitConfig);
// Collect the residuals threshold
tmpFitConfig.setComputeResiduals(true);
if (BenchmarkFilterAnalysis.updateConfiguration(tmp, false)) {
config.setFailuresLimit(tmp.getFailuresLimit());
config.setIncludeNeighbours(tmp.isIncludeNeighbours());
config.setNeighbourHeightThreshold(tmp.getNeighbourHeightThreshold());
computeDoublets = (tmp.getResidualsThreshold() < 1);
fitConfig.setDuplicateDistance(tmpFitConfig.getDuplicateDistance());
final DirectFilter primaryFilter = tmpFitConfig.getSmartFilter();
final double residualsThreshold = tmp.getResidualsThreshold();
myMultiFilter = new MultiPathFilter(primaryFilter, minimalFilter, residualsThreshold);
}
} else {
myMultiFilter = MultiPathFilter.fromXML(xml);
config.setFailuresLimit(failLimit);
config.setIncludeNeighbours(includeNeighbours);
config.setNeighbourHeightThreshold(neighbourHeightThreshold);
computeDoublets = myComputeDoublets;
fitConfig.setDuplicateDistance(myDuplicateDistance);
}
if (myMultiFilter == null) {
gd = new GenericDialog(TITLE);
gd.addMessage("The multi-path filter was invalid.\n \nContinue with a default filter?");
gd.enableYesNoCancel();
gd.hideCancelButton();
gd.showDialog();
if (!gd.wasOKed())
return false;
} else {
multiFilter = myMultiFilter;
}
if (computeDoublets) {
//config.setComputeResiduals(true);
config.setResidualsThreshold(0);
fitConfig.setComputeResiduals(true);
} else {
config.setResidualsThreshold(1);
fitConfig.setComputeResiduals(false);
}
showFilterScoreHistograms = gd.getNextBoolean();
showCorrelation = gd.getNextBoolean();
rankByIntensity = gd.getNextBoolean();
saveFilterRange = gd.getNextBoolean();
// Avoid stupidness, i.e. things that move outside the fit window and are bad widths
// TODO - Fix this for simple or smart filter...
fitConfig.setDisableSimpleFilter(false);
// Realistically we cannot fit lower than this
fitConfig.setMinPhotons(15);
// Disable shift as candidates may be re-mapped to alternative candidates so the initial position is wrong.
fitConfig.setCoordinateShiftFactor(0);
fitConfig.setMinWidthFactor(1.0 / 5);
fitConfig.setWidthFactor(5);
// Disable the direct filter
fitConfig.setDirectFilter(null);
if (extraOptions) {
}
if (gd.invalidNumber())
return false;
if (lowerDistance > distance)
lowerDistance = distance;
if (lowerSignalFactor > signalFactor)
lowerSignalFactor = signalFactor;
// Distances relative to sa (not s) as this is the same as the BenchmarkSpotFilter plugin
distanceInPixels = distance * sa / simulationParameters.a;
lowerDistanceInPixels = lowerDistance * sa / simulationParameters.a;
GlobalSettings settings = new GlobalSettings();
settings.setFitEngineConfiguration(config);
settings.setCalibration(cal);
// Copy simulation defaults if a new simulation
if (lastId != simulationParameters.id) {
cal.setNmPerPixel(simulationParameters.a);
cal.setGain(simulationParameters.gain);
cal.setAmplification(simulationParameters.amplification);
cal.setExposureTime(100);
cal.setReadNoise(simulationParameters.readNoise);
cal.setBias(simulationParameters.bias);
cal.setEmCCD(simulationParameters.emCCD);
// This is needed to configure the fit solver
fitConfig.setNmPerPixel(Maths.round(cal.getNmPerPixel()));
fitConfig.setGain(Maths.round(cal.getGain()));
fitConfig.setBias(Maths.round(cal.getBias()));
fitConfig.setReadNoise(Maths.round(cal.getReadNoise()));
fitConfig.setAmplification(Maths.round(cal.getAmplification()));
fitConfig.setEmCCD(cal.isEmCCD());
}
if (!PeakFit.configureFitSolver(settings, null, extraOptions))
return false;
return true;
}
use of gdsc.smlm.engine.FitEngineConfiguration in project GDSC-SMLM by aherbert.
the class BenchmarkSpotFit method itemStateChanged.
public void itemStateChanged(ItemEvent e) {
if (e.getSource() instanceof Checkbox) {
Checkbox checkbox = (Checkbox) e.getSource();
int failLimit;
boolean includeNeighbours;
double neighbourHeightThrehsold;
boolean computeDoublets;
MultiPathFilter myMultiFilter;
if (checkbox.getState()) {
FitConfiguration tmpFitConfig = new FitConfiguration();
FitEngineConfiguration tmp = new FitEngineConfiguration(tmpFitConfig);
// Collect residuals threshold
tmpFitConfig.setComputeResiduals(true);
if (BenchmarkFilterAnalysis.updateConfiguration(tmp, false)) {
failLimit = tmp.getFailuresLimit();
includeNeighbours = tmp.isIncludeNeighbours();
neighbourHeightThrehsold = tmp.getNeighbourHeightThreshold();
computeDoublets = tmp.getResidualsThreshold() < 1;
final DirectFilter primaryFilter = tmpFitConfig.getSmartFilter();
final double residualsThreshold = tmp.getResidualsThreshold();
myMultiFilter = new MultiPathFilter(primaryFilter, minimalFilter, residualsThreshold);
} else {
IJ.log("Failed to update settings using the filter analysis");
checkbox.setState(false);
return;
}
} else {
failLimit = config.getFailuresLimit();
includeNeighbours = config.isIncludeNeighbours();
neighbourHeightThrehsold = config.getNeighbourHeightThreshold();
computeDoublets = BenchmarkSpotFit.computeDoublets;
myMultiFilter = multiFilter;
}
// Update the dialog
taFilterXml.setText(myMultiFilter.toXML());
textFailLimit.setText("" + failLimit);
cbIncludeNeighbours.setState(includeNeighbours);
textNeighbourHeight.setText(Utils.rounded(neighbourHeightThrehsold));
cbComputeDoublets.setState(computeDoublets);
}
}
use of gdsc.smlm.engine.FitEngineConfiguration in project GDSC-SMLM by aherbert.
the class TraceMolecules method fitTraces.
private void fitTraces(MemoryPeakResults results, Trace[] traces) {
// Check if the original image is open and the fit configuration can be extracted
ImageSource source = results.getSource();
if (source == null)
return;
if (!source.open())
return;
FitEngineConfiguration config = (FitEngineConfiguration) XmlUtils.fromXML(results.getConfiguration());
if (config == null)
return;
// Show a dialog asking if the traces should be refit
ExtendedGenericDialog gd = new ExtendedGenericDialog(TITLE);
gd.addMessage("Do you want to fit the traces as a single peak using a combined image?");
gd.addCheckbox("Fit_closest_to_centroid", !fitOnlyCentroid);
gd.addSlider("Distance_threshold", 0.01, 3, distanceThreshold);
gd.addSlider("Expansion_factor", 1, 4.5, expansionFactor);
// Allow fitting settings to be adjusted
FitConfiguration fitConfig = config.getFitConfiguration();
gd.addMessage("--- Gaussian fitting ---");
String[] filterTypes = SettingsManager.getNames((Object[]) DataFilterType.values());
gd.addChoice("Spot_filter_type", filterTypes, filterTypes[config.getDataFilterType().ordinal()]);
String[] filterNames = SettingsManager.getNames((Object[]) DataFilter.values());
gd.addChoice("Spot_filter", filterNames, filterNames[config.getDataFilter(0).ordinal()]);
gd.addSlider("Smoothing", 0, 2.5, config.getSmooth(0));
gd.addSlider("Search_width", 0.5, 2.5, config.getSearch());
gd.addSlider("Border", 0.5, 2.5, config.getBorder());
gd.addSlider("Fitting_width", 2, 4.5, config.getFitting());
String[] solverNames = SettingsManager.getNames((Object[]) FitSolver.values());
gd.addChoice("Fit_solver", solverNames, solverNames[fitConfig.getFitSolver().ordinal()]);
String[] functionNames = SettingsManager.getNames((Object[]) FitFunction.values());
gd.addChoice("Fit_function", functionNames, functionNames[fitConfig.getFitFunction().ordinal()]);
String[] criteriaNames = SettingsManager.getNames((Object[]) FitCriteria.values());
gd.addChoice("Fit_criteria", criteriaNames, criteriaNames[fitConfig.getFitCriteria().ordinal()]);
gd.addNumericField("Significant_digits", fitConfig.getSignificantDigits(), 0);
gd.addNumericField("Coord_delta", fitConfig.getDelta(), 4);
gd.addNumericField("Lambda", fitConfig.getLambda(), 4);
gd.addNumericField("Max_iterations", fitConfig.getMaxIterations(), 0);
gd.addNumericField("Fail_limit", config.getFailuresLimit(), 0);
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.addSlider("Duplicate_distance", 0, 1.5, fitConfig.getDuplicateDistance());
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.01, 5, fitConfig.getWidthFactor());
gd.addNumericField("Precision", fitConfig.getPrecisionThreshold(), 2);
gd.addCheckbox("Debug_failures", debugFailures);
gd.showDialog();
if (!gd.wasOKed()) {
source.close();
return;
}
// Get parameters for the fit
fitOnlyCentroid = !gd.getNextBoolean();
distanceThreshold = (float) gd.getNextNumber();
expansionFactor = (float) gd.getNextNumber();
config.setDataFilterType(gd.getNextChoiceIndex());
config.setDataFilter(gd.getNextChoiceIndex(), Math.abs(gd.getNextNumber()), 0);
config.setSearch(gd.getNextNumber());
config.setBorder(gd.getNextNumber());
config.setFitting(gd.getNextNumber());
fitConfig.setFitSolver(gd.getNextChoiceIndex());
fitConfig.setFitFunction(gd.getNextChoiceIndex());
fitConfig.setFitCriteria(gd.getNextChoiceIndex());
fitConfig.setSignificantDigits((int) gd.getNextNumber());
fitConfig.setDelta(gd.getNextNumber());
fitConfig.setLambda(gd.getNextNumber());
fitConfig.setMaxIterations((int) gd.getNextNumber());
config.setFailuresLimit((int) gd.getNextNumber());
config.setIncludeNeighbours(gd.getNextBoolean());
config.setNeighbourHeightThreshold(gd.getNextNumber());
config.setResidualsThreshold(gd.getNextNumber());
fitConfig.setSmartFilter(gd.getNextBoolean());
fitConfig.setDisableSimpleFilter(gd.getNextBoolean());
fitConfig.setCoordinateShiftFactor(gd.getNextNumber());
fitConfig.setSignalStrength(gd.getNextNumber());
fitConfig.setMinPhotons(gd.getNextNumber());
fitConfig.setMinWidthFactor(gd.getNextNumber());
fitConfig.setWidthFactor(gd.getNextNumber());
fitConfig.setPrecisionThreshold(gd.getNextNumber());
// Check arguments
try {
Parameters.isAboveZero("Distance threshold", distanceThreshold);
Parameters.isAbove("Expansion factor", expansionFactor, 1);
Parameters.isAboveZero("Search_width", config.getSearch());
Parameters.isAboveZero("Fitting_width", config.getFitting());
Parameters.isAboveZero("Significant digits", fitConfig.getSignificantDigits());
Parameters.isAboveZero("Delta", fitConfig.getDelta());
Parameters.isAboveZero("Lambda", fitConfig.getLambda());
Parameters.isAboveZero("Max iterations", fitConfig.getMaxIterations());
Parameters.isPositive("Failures limit", config.getFailuresLimit());
Parameters.isPositive("Neighbour height threshold", config.getNeighbourHeightThreshold());
Parameters.isPositive("Residuals threshold", config.getResidualsThreshold());
Parameters.isPositive("Coordinate Shift factor", fitConfig.getCoordinateShiftFactor());
Parameters.isPositive("Signal strength", fitConfig.getSignalStrength());
Parameters.isPositive("Min photons", fitConfig.getMinPhotons());
Parameters.isPositive("Min width factor", fitConfig.getMinWidthFactor());
Parameters.isPositive("Width factor", fitConfig.getWidthFactor());
Parameters.isPositive("Precision threshold", fitConfig.getPrecisionThreshold());
} catch (IllegalArgumentException e) {
IJ.error(TITLE, e.getMessage());
source.close();
return;
}
debugFailures = gd.getNextBoolean();
if (!PeakFit.configureSmartFilter(globalSettings, filename))
return;
if (!PeakFit.configureDataFilter(globalSettings, filename, false))
return;
if (!PeakFit.configureFitSolver(globalSettings, filename, false))
return;
// Adjust settings for a single maxima
config.setIncludeNeighbours(false);
fitConfig.setDuplicateDistance(0);
// Create a fit engine
MemoryPeakResults refitResults = new MemoryPeakResults();
refitResults.copySettings(results);
refitResults.setName(results.getName() + " Trace Fit");
refitResults.setSortAfterEnd(true);
refitResults.begin();
// No border since we know where the peaks are and we must not miss them due to truncated searching
FitEngine engine = new FitEngine(config, refitResults, Prefs.getThreads(), FitQueue.BLOCKING);
// Either : Only fit the centroid
// or : Extract a bigger region, allowing all fits to run as normal and then
// find the correct spot using Euclidian distance.
// Set up the limits
final double stdDev = FastMath.max(fitConfig.getInitialPeakStdDev0(), fitConfig.getInitialPeakStdDev1());
float fitWidth = (float) (stdDev * config.getFitting() * ((fitOnlyCentroid) ? 1 : expansionFactor));
IJ.showStatus("Refitting traces ...");
List<JobItem> jobItems = new ArrayList<JobItem>(traces.length);
int singles = 0;
int fitted = 0;
for (int n = 0; n < traces.length; n++) {
Trace trace = traces[n];
if (n % 32 == 0)
IJ.showProgress(n, traces.length);
// Skip traces with one peak
if (trace.size() == 1) {
singles++;
// Use the synchronized method to avoid thread clashes with the FitEngine
refitResults.addSync(trace.getHead());
continue;
}
Rectangle bounds = new Rectangle();
double[] combinedNoise = new double[1];
float[] data = buildCombinedImage(source, trace, fitWidth, bounds, combinedNoise, false);
if (data == null)
continue;
// Fit the combined image
FitParameters params = new FitParameters();
params.noise = (float) combinedNoise[0];
float[] centre = trace.getCentroid();
if (fitOnlyCentroid) {
int newX = (int) Math.round(centre[0]) - bounds.x;
int newY = (int) Math.round(centre[1]) - bounds.y;
params.maxIndices = new int[] { newY * bounds.width + newX };
} else {
params.filter = new ArrayList<float[]>();
params.filter.add(new float[] { centre[0] - bounds.x, centre[1] - bounds.y });
params.distanceThreshold = distanceThreshold;
}
// This is not needed since the bounds are passed using the FitJob
//params.setOffset(new float[] { bounds.x, bounds.y });
int startT = trace.getHead().getFrame();
params.endT = trace.getTail().getFrame();
ParameterisedFitJob job = new ParameterisedFitJob(n, params, startT, data, bounds);
jobItems.add(new JobItem(job, trace, centre));
engine.run(job);
fitted++;
}
engine.end(false);
IJ.showStatus("");
IJ.showProgress(1);
// Check the success ...
FitStatus[] values = FitStatus.values();
int[] statusCount = new int[values.length + 1];
ArrayList<String> names = new ArrayList<String>(Arrays.asList(SettingsManager.getNames((Object[]) values)));
names.add(String.format("No maxima within %.2f of centroid", distanceThreshold));
int separated = 0;
int success = 0;
final int debugLimit = 3;
for (JobItem jobItem : jobItems) {
int id = jobItem.getId();
ParameterisedFitJob job = jobItem.job;
Trace trace = jobItem.trace;
int[] indices = job.getIndices();
FitResult fitResult = null;
int status;
if (indices.length < 1) {
status = values.length;
} else if (indices.length > 1) {
// Choose the first OK result. This is all that matters for the success reporting
for (int n = 0; n < indices.length; n++) {
if (job.getFitResult(n).getStatus() == FitStatus.OK) {
fitResult = job.getFitResult(n);
break;
}
}
// Otherwise use the closest failure.
if (fitResult == null) {
final float[] centre = traces[id].getCentroid();
double minD = Double.POSITIVE_INFINITY;
for (int n = 0; n < indices.length; n++) {
// Since the fit has failed we use the initial parameters
final double[] params = job.getFitResult(n).getInitialParameters();
final double dx = params[Gaussian2DFunction.X_POSITION] - centre[0];
final double dy = params[Gaussian2DFunction.Y_POSITION] - centre[1];
final double d = dx * dx + dy * dy;
if (minD > d) {
minD = d;
fitResult = job.getFitResult(n);
}
}
}
status = fitResult.getStatus().ordinal();
} else {
fitResult = job.getFitResult(0);
status = fitResult.getStatus().ordinal();
}
// All jobs have only one peak
statusCount[status]++;
// Debug why any fits failed
if (fitResult == null || fitResult.getStatus() != FitStatus.OK) {
refitResults.addAll(trace.getPoints());
separated += trace.size();
if (debugFailures) {
FitStatus s = (fitResult == null) ? FitStatus.UNKNOWN : fitResult.getStatus();
// Only display the first n per category to limit the number of images
double[] noise = new double[1];
if (statusCount[status] <= debugLimit) {
Rectangle bounds = new Rectangle();
buildCombinedImage(source, trace, fitWidth, bounds, noise, true);
float[] centre = trace.getCentroid();
Utils.display(String.format("Trace %d (n=%d) : x=%f,y=%f", id, trace.size(), centre[0], centre[1]), slices);
switch(s) {
case INSUFFICIENT_PRECISION:
float precision = (Float) fitResult.getStatusData();
IJ.log(String.format("Trace %d (n=%d) : %s = %f", id, trace.size(), names.get(status), precision));
break;
case INSUFFICIENT_SIGNAL:
if (noise[0] == 0)
noise[0] = getCombinedNoise(trace);
float snr = (Float) fitResult.getStatusData();
IJ.log(String.format("Trace %d (n=%d) : %s = %f (noise=%.2f)", id, trace.size(), names.get(status), snr, noise[0]));
break;
case COORDINATES_MOVED:
case OUTSIDE_FIT_REGION:
case WIDTH_DIVERGED:
float[] shift = (float[]) fitResult.getStatusData();
IJ.log(String.format("Trace %d (n=%d) : %s = %.3f,%.3f", id, trace.size(), names.get(status), shift[0], shift[1]));
break;
default:
IJ.log(String.format("Trace %d (n=%d) : %s", id, trace.size(), names.get(status)));
break;
}
}
}
} else {
success++;
if (debugFailures) {
// Only display the first n per category to limit the number of images
double[] noise = new double[1];
if (statusCount[status] <= debugLimit) {
Rectangle bounds = new Rectangle();
buildCombinedImage(source, trace, fitWidth, bounds, noise, true);
float[] centre = trace.getCentroid();
Utils.display(String.format("Trace %d (n=%d) : x=%f,y=%f", id, trace.size(), centre[0], centre[1]), slices);
}
}
}
}
IJ.log(String.format("Trace fitting : %d singles : %d / %d fitted : %d separated", singles, success, fitted, separated));
if (separated > 0) {
IJ.log("Reasons for fit failure :");
// Start at i=1 to skip FitStatus.OK
for (int i = 1; i < statusCount.length; i++) {
if (statusCount[i] != 0)
IJ.log(" " + names.get(i) + " = " + statusCount[i]);
}
}
refitResults.end();
MemoryPeakResults.addResults(refitResults);
source.close();
}
Aggregations