use of gdsc.smlm.results.PeakResult in project GDSC-SMLM by aherbert.
the class FilterAnalysis method showDialog.
private boolean showDialog(List<MemoryPeakResults> resultsList, boolean fileInput) {
GenericDialog gd = new GenericDialog(TITLE);
gd.addHelp(About.HELP_URL);
int total = 0;
int tp = 0;
for (MemoryPeakResults r : resultsList) {
total += r.size();
for (PeakResult p : r.getResults()) if (p.origValue != 0)
tp++;
}
gd.addMessage(String.format("%d files, %d results, %d True-Positives", resultsList.size(), total, tp));
if (!fileInput) {
gd.addCheckbox("SNR_filter", snrFilter);
gd.addNumericField("Min_SNR", minSnr, 0);
gd.addNumericField("Max_SNR", maxSnr, 0);
gd.addNumericField("Min_Width", minWidth, 2);
gd.addNumericField("Max_Width", maxWidth, 2);
gd.addNumericField("Increment_Width", incWidth, 2);
gd.addCheckbox("Precision_filter", precisionFilter);
gd.addNumericField("Min_Precision", minPrecision, 0);
gd.addNumericField("Max_Precision", maxPrecision, 0);
gd.addCheckbox("Trace_filter", traceFilter);
gd.addNumericField("Min_distance", minDistance, 2);
gd.addNumericField("Max_distance", maxDistance, 2);
gd.addNumericField("Increment_distance", incDistance, 2);
gd.addNumericField("Min_time", minTime, 0);
gd.addNumericField("Max_time", maxTime, 0);
gd.addNumericField("Increment_time", incTime, 0);
gd.addCheckbox("Hysteresis_SNR_filter", hysteresisSnrFilter);
gd.addNumericField("Min_SNR_gap", minSnrGap, 0);
gd.addNumericField("Max_SNR_gap", maxSnrGap, 0);
gd.addNumericField("Increment_SNR_gap", incSnrGap, 0);
gd.addCheckbox("Hysteresis_Precision_filter", hysteresisPrecisionFilter);
gd.addNumericField("Min_Precision_gap", minPrecisionGap, 0);
gd.addNumericField("Max_Precision_gap", maxPrecisionGap, 0);
gd.addNumericField("Increment_Precision_gap", incPrecisionGap, 0);
gd.addCheckbox("Save_filters", saveFilterSets);
}
gd.addCheckbox("Show_table", showResultsTable);
gd.addSlider("Plot_top_n", 0, 20, plotTopN);
gd.addCheckbox("Calculate_sensitivity", calculateSensitivity);
gd.addSlider("Delta", 0.01, 1, delta);
if (!fileInput) {
// Re-arrange to 2 columns
if (gd.getLayout() != null) {
GridBagLayout grid = (GridBagLayout) gd.getLayout();
Component splitLabel = (Component) gd.getCheckboxes().get(3);
int xOffset = 0, yOffset = 0;
int lastY = -1, rowCount = 0;
for (Component comp : gd.getComponents()) {
// Check if this should be the second major column
if (comp == splitLabel) {
xOffset += 2;
yOffset -= rowCount;
rowCount = 0;
}
// Reposition the field
GridBagConstraints c = grid.getConstraints(comp);
if (lastY != c.gridy)
rowCount++;
lastY = c.gridy;
c.gridx = c.gridx + xOffset;
c.gridy = c.gridy + yOffset;
c.insets.left = c.insets.left + 10 * xOffset;
c.insets.top = 0;
c.insets.bottom = 0;
grid.setConstraints(comp, c);
}
if (IJ.isLinux())
gd.setBackground(new Color(238, 238, 238));
}
}
gd.showDialog();
if (gd.wasCanceled() || !readDialog(gd, fileInput))
return false;
return true;
}
use of gdsc.smlm.results.PeakResult in project GDSC-SMLM by aherbert.
the class FIRE method calculatePrecisionHistogram.
/**
* Calculate a histogram of the precision. The precision can be either stored in the results or calculated using the
* Mortensen formula. If the precision method for Q estimation is not fixed then the histogram is fitted with a
* Gaussian to create an initial estimate.
*
* @param precisionMethod
* the precision method
* @return The precision histogram
*/
private PrecisionHistogram calculatePrecisionHistogram() {
boolean logFitParameters = false;
String title = results.getName() + " Precision Histogram";
// Check if the results has the precision already or if it can be computed.
boolean canUseStored = canUseStoredPrecision(results);
boolean canCalculatePrecision = canCalculatePrecision(results);
// Set the method to compute a histogram. Default to the user selected option.
PrecisionMethod m = null;
if (canUseStored && precisionMethod == PrecisionMethod.STORED)
m = precisionMethod;
else if (canCalculatePrecision && precisionMethod == PrecisionMethod.CALCULATE)
m = precisionMethod;
if (m == null) {
// We only have two choices so if one is available then select it.
if (canUseStored)
m = PrecisionMethod.STORED;
else if (canCalculatePrecision)
m = PrecisionMethod.CALCULATE;
// If the user selected a method not available then log a warning
if (m != null && precisionMethod != PrecisionMethod.FIXED) {
IJ.log(String.format("%s : Selected precision method '%s' not available, switching to '%s'", TITLE, precisionMethod, m.getName()));
}
if (m == null) {
// This does not matter if the user has provide a fixed input.
if (precisionMethod == PrecisionMethod.FIXED) {
PrecisionHistogram histogram = new PrecisionHistogram(title);
histogram.mean = mean;
histogram.sigma = sigma;
return histogram;
}
// No precision
return null;
}
}
// We get here if we can compute precision.
// Build the histogram
StoredDataStatistics precision = new StoredDataStatistics(results.size());
if (m == PrecisionMethod.STORED) {
for (PeakResult r : results.getResults()) {
precision.add(r.getPrecision());
}
} else {
final double nmPerPixel = results.getNmPerPixel();
final double gain = results.getGain();
final boolean emCCD = results.isEMCCD();
for (PeakResult r : results.getResults()) {
precision.add(r.getPrecision(nmPerPixel, gain, emCCD));
}
}
//System.out.printf("Raw p = %f\n", precision.getMean());
double yMin = Double.NEGATIVE_INFINITY, yMax = 0;
// Set the min and max y-values using 1.5 x IQR
DescriptiveStatistics stats = precision.getStatistics();
double lower = stats.getPercentile(25);
double upper = stats.getPercentile(75);
if (Double.isNaN(lower) || Double.isNaN(upper)) {
if (logFitParameters)
Utils.log("Error computing IQR: %f - %f", lower, upper);
} else {
double iqr = upper - lower;
yMin = FastMath.max(lower - iqr, stats.getMin());
yMax = FastMath.min(upper + iqr, stats.getMax());
if (logFitParameters)
Utils.log(" Data range: %f - %f. Plotting 1.5x IQR: %f - %f", stats.getMin(), stats.getMax(), yMin, yMax);
}
if (yMin == Double.NEGATIVE_INFINITY) {
int n = 5;
yMin = Math.max(stats.getMin(), stats.getMean() - n * stats.getStandardDeviation());
yMax = Math.min(stats.getMax(), stats.getMean() + n * stats.getStandardDeviation());
if (logFitParameters)
Utils.log(" Data range: %f - %f. Plotting mean +/- %dxSD: %f - %f", stats.getMin(), stats.getMax(), n, yMin, yMax);
}
// Get the data within the range
double[] data = precision.getValues();
precision = new StoredDataStatistics(data.length);
for (double d : data) {
if (d < yMin || d > yMax)
continue;
precision.add(d);
}
int histogramBins = Utils.getBins(precision, Utils.BinMethod.SCOTT);
float[][] hist = Utils.calcHistogram(precision.getFloatValues(), yMin, yMax, histogramBins);
PrecisionHistogram histogram = new PrecisionHistogram(hist, precision, title);
if (precisionMethod == PrecisionMethod.FIXED) {
histogram.mean = mean;
histogram.sigma = sigma;
return histogram;
}
// Fitting of the histogram to produce the initial estimate
// Extract non-zero data
float[] x = Arrays.copyOf(hist[0], hist[0].length);
float[] y = hist[1];
int count = 0;
float dx = (x[1] - x[0]) * 0.5f;
for (int i = 0; i < y.length; i++) if (y[i] > 0) {
x[count] = x[i] + dx;
y[count] = y[i];
count++;
}
x = Arrays.copyOf(x, count);
y = Arrays.copyOf(y, count);
// Sense check to fitted data. Get mean and SD of histogram
double[] stats2 = Utils.getHistogramStatistics(x, y);
if (logFitParameters)
Utils.log(" Initial Statistics: %f +/- %f", stats2[0], stats2[1]);
histogram.mean = stats2[0];
histogram.sigma = stats2[1];
// Standard Gaussian fit
double[] parameters = fitGaussian(x, y);
if (parameters == null) {
Utils.log(" Failed to fit initial Gaussian");
return histogram;
}
double newMean = parameters[1];
double error = Math.abs(stats2[0] - newMean) / stats2[1];
if (error > 3) {
Utils.log(" Failed to fit Gaussian: %f standard deviations from histogram mean", error);
return histogram;
}
if (newMean < yMin || newMean > yMax) {
Utils.log(" Failed to fit Gaussian: %f outside data range %f - %f", newMean, yMin, yMax);
return histogram;
}
if (logFitParameters)
Utils.log(" Initial Gaussian: %f @ %f +/- %f", parameters[0], parameters[1], parameters[2]);
histogram.mean = parameters[1];
histogram.sigma = parameters[2];
return histogram;
}
use of gdsc.smlm.results.PeakResult 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.results.PeakResult in project GDSC-SMLM by aherbert.
the class FitWorker method addSingleResult.
/**
* Add the result to the list. Only check for duplicates in the current results grid.
*
* @param candidateId
* the candidate id
* @param peakParams
* the peak params
* @param peakParamsDev
* the peak params dev
* @param error
* the error
* @param noise
* the noise
* @return true, if successful
*/
private boolean addSingleResult(int candidateId, float[] peakParams, float[] peakParamsDev, double error, float noise) {
int x = candidates.get(candidateId).x;
int y = candidates.get(candidateId).y;
float value = data[y * cc.dataBounds.width + x];
// This is obsolete as the multipathfilter now performs duplicate testing
//if (duplicateDistance2 > 0)
//{
// // Check for duplicates
// final PeakResult[] neighbours = gridManager.getPeakResultNeighbours(x, y);
// for (int i = 0; i < neighbours.length; i++)
// {
// if (distance2(neighbours[i].params, peakParams) < duplicateDistance2)
// {
// if (logger != null)
// logger.info("[%d] Ignoring duplicate peak @ %.2f,%.2f", slice,
// peakParams[Gaussian2DFunction.X_POSITION], peakParams[Gaussian2DFunction.Y_POSITION]);
// //System.out.printf("Duplicate [%d] %.2f,%.2f == %.2f,%.2f\n", candidateId,
// // peakParams[Gaussian2DFunction.X_POSITION], peakParams[Gaussian2DFunction.Y_POSITION],
// // neighbours[i].params[Gaussian2DFunction.X_POSITION], neighbours[i].params[Gaussian2DFunction.Y_POSITION]);
// return false;
// }
// }
//}
// Update to the global bounds.
// (Note the global bounds will be added to the params at the end of processing the frame
// so we leave those untouched)
x = cc.fromDataToGlobalX(x);
y = cc.fromDataToGlobalY(y);
// This was fit OK so add it to the grid of results (so we do not fit it again)
final PeakResult peakResult = createResult(x, y, value, error, noise, peakParams, peakParamsDev, candidateId);
queueToGrid(peakResult);
candidates.get(candidateId).fit = true;
// Check if the position is inside the border tolerance
if (insideBorder(peakParams[Gaussian2DFunction.X_POSITION], peakParams[Gaussian2DFunction.Y_POSITION])) {
sliceResults.add(peakResult);
fittedBackground += peakParams[Gaussian2DFunction.BACKGROUND];
} else if (logger != null) {
logger.info("[%d] Ignoring peak within image border @ %.2f,%.2f", slice, peakParams[Gaussian2DFunction.X_POSITION], peakParams[Gaussian2DFunction.Y_POSITION]);
}
return true;
}
use of gdsc.smlm.results.PeakResult in project GDSC-SMLM by aherbert.
the class FitWorker method add.
/*
* (non-Javadoc)
*
* @see gdsc.smlm.results.filter.MultiPathFilter.SelectedResultStore#add(gdsc.smlm.results.filter.MultiPathFilter.
* SelectedResult)
*/
public void add(SelectedResult selectedResult) {
// TODO - Print the current state of the dynamicMultiPathFitResult to file.
// This will allow debugging what is different between the benchmark fit and the PeakFit.
// Output:
// slice
// candidate Id
// Initial and final params for each fit result.
// Details of the selected result.
// Then try to figure out why the benchmark fit deviates from PeakFit.
// Add to the slice results.
final PreprocessedPeakResult[] results = selectedResult.results;
if (results == null)
return;
final int currrentSize = sliceResults.size();
final int candidateId = dynamicMultiPathFitResult.candidateId;
final FitResult fitResult = (FitResult) selectedResult.fitResult.data;
// The background for each result was the local background. We want the fitted global background
final float background = (float) fitResult.getParameters()[0];
final double[] dev = fitResult.getParameterStdDev();
if (queueSize != 0)
throw new RuntimeException("There are results queued already!");
for (int i = 0; i < results.length; i++) {
if (results[i].isExistingResult())
continue;
if (results[i].isNewResult()) {
final double[] p = results[i].toGaussian2DParameters();
// Store slice results relative to the data frame (not the global bounds)
// Convert back so that 0,0 is the top left of the data bounds
p[Gaussian2DFunction.X_POSITION] -= cc.dataBounds.x;
p[Gaussian2DFunction.Y_POSITION] -= cc.dataBounds.y;
final float[] params = new float[7];
params[Gaussian2DFunction.BACKGROUND] = background;
for (int j = 1; j < 7; j++) params[j] = (float) p[j];
final float[] paramsDev;
if (dev == null) {
paramsDev = null;
} else {
paramsDev = new float[7];
paramsDev[Gaussian2DFunction.BACKGROUND] = (float) dev[Gaussian2DFunction.BACKGROUND];
final int offset = results[i].getId() * 6;
for (int j = 1; j < 7; j++) paramsDev[j] = (float) dev[offset + j];
}
addSingleResult(results[i].getCandidateId(), params, paramsDev, fitResult.getError(), results[i].getNoise());
if (logger != null) {
// Show the shift, signal and width spread
PreprocessedPeakResult peak = results[i];
logger.info("Fit OK %d (%.1f,%.1f) [%d]: Shift = %.3f,%.3f : SNR = %.2f : Width = %.2f,%.2f", peak.getCandidateId(), peak.getX(), peak.getY(), peak.getId(), Math.sqrt(peak.getXRelativeShift2()), Math.sqrt(peak.getYRelativeShift2()), peak.getSNR(), peak.getXSDFactor(), peak.getYSDFactor());
}
} else {
// This is a candidate that passed validation. Store the estimate as passing the primary filter.
// We now do this is the pass() method.
//storeEstimate(results[i].getCandidateId(), results[i], FILTER_RANK_PRIMARY);
}
}
job.setFitResult(candidateId, fitResult);
// Reporting
if (this.counter != null) {
FitType fitType = dynamicMultiPathFitResult.fitType;
if (selectedResult.fitResult.getStatus() == 0) {
fitType.setOK(true);
if (dynamicMultiPathFitResult.getSuperMultiFitResult() == selectedResult.fitResult)
fitType.setMultiOK(true);
else if (dynamicMultiPathFitResult.getSuperMultiDoubletFitResult() == selectedResult.fitResult)
fitType.setMultiDoubletOK(true);
else if (dynamicMultiPathFitResult.getSuperDoubletFitResult() == selectedResult.fitResult)
fitType.setDoubletOK(true);
}
add(fitType);
}
if (logger != null) {
switch(fitResult.getStatus()) {
case OK:
// We log good results in the loop above.
break;
case BAD_PARAMETERS:
case FAILED_TO_ESTIMATE_WIDTH:
logger.info("Bad parameters: %s", Arrays.toString(fitResult.getInitialParameters()));
break;
default:
logger.info(fitResult.getStatus().toString());
break;
}
}
// Debugging
if (logger2 != null) {
double[] peakParams = fitResult.getParameters();
if (peakParams != null) {
// Parameters are the raw values from fitting the region. Convert for logging.
peakParams = Arrays.copyOf(peakParams, peakParams.length);
int npeaks = peakParams.length / 6;
for (int i = 0; i < npeaks; i++) {
peakParams[i * 6 + Gaussian2DFunction.X_POSITION] += cc.fromFitRegionToGlobalX();
peakParams[i * 6 + Gaussian2DFunction.Y_POSITION] += cc.fromFitRegionToGlobalY();
peakParams[i * 6 + Gaussian2DFunction.SHAPE] *= 180.0 / Math.PI;
}
}
final int x = candidates.get(candidateId).x;
final int y = candidates.get(candidateId).y;
logger2.debug("%d:%d [%d,%d] %s (%s) = %s\n", slice, candidateId, cc.fromDataToGlobalX(x), cc.fromDataToGlobalY(y), fitResult.getStatus(), fitResult.getStatusData(), Arrays.toString(peakParams));
}
// Check if there were any new results
int npeaks = sliceResults.size() - currrentSize;
if (npeaks != 0) {
success++;
// Support for post-processing filter
if (resultFilter != null) {
// Check all result peaks for the distance to the filter positions
PeakResult[] peakResults = new PeakResult[npeaks];
for (int i = sliceResults.size(); npeaks-- > 0; ) {
peakResults[npeaks] = sliceResults.get(--i);
}
resultFilter.filter(fitResult, candidateId, peakResults);
}
}
}
Aggregations