use of gdsc.smlm.results.filter.MultiPathFilter in project GDSC-SMLM by aherbert.
the class BenchmarkFilterAnalysis method getAssignments.
/**
* Score the filter using the results list and the configured fail count.
*
* @param filter
* the filter
* @param resultsList
* the results list
* @param allAssignments
* all the assignments
* @return The score
*/
private ArrayList<FractionalAssignment[]> getAssignments(DirectFilter filter) {
final MultiPathFilter multiPathFilter = createMPF(filter, minimalFilter);
ArrayList<FractionalAssignment[]> allAssignments = new ArrayList<FractionalAssignment[]>(resultsList.length);
multiPathFilter.fractionScoreSubset(resultsList, failCount, nActual, allAssignments, null, coordinateStore);
return allAssignments;
}
use of gdsc.smlm.results.filter.MultiPathFilter 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.results.filter.MultiPathFilter 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.results.filter.MultiPathFilter 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.results.filter.MultiPathFilter 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);
}
Aggregations