use of uk.ac.sussex.gdsc.smlm.engine.FitConfiguration in project GDSC-SMLM by aherbert.
the class PeakFit method configureFitSolver.
/**
* Show a dialog to configure the fit solver. 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>The bounds are used to validate the camera model. The camera model must be large enough to
* cover the source bounds. If larger then it will be cropped. Optionally an internal region of
* the input image can be specified. This is relative to the width and height of the input image.
* If no camera model is present then the bounds can be null.
*
* @param config the configuration
* @param sourceBounds the source image bounds (used to validate the camera model dimensions)
* @param bounds the crop bounds (relative to the input image, used to validate the camera model
* dimensions)
* @param flags the flags
* @return True if the configuration succeeded
*/
public static boolean configureFitSolver(FitEngineConfiguration config, Rectangle sourceBounds, Rectangle bounds, int flags) {
final boolean extraOptions = BitFlagUtils.anySet(flags, FLAG_EXTRA_OPTIONS);
final boolean ignoreCalibration = BitFlagUtils.anySet(flags, FLAG_IGNORE_CALIBRATION);
final boolean saveSettings = BitFlagUtils.anyNotSet(flags, FLAG_NO_SAVE);
final FitConfiguration fitConfig = config.getFitConfiguration();
final CalibrationWriter calibration = fitConfig.getCalibrationWriter();
final FitSolver fitSolver = fitConfig.getFitSolver();
final boolean isLvm = fitSolver == FitSolver.LVM_LSE || fitSolver == FitSolver.LVM_WLSE || fitSolver == FitSolver.LVM_MLE;
// Support the deprecated backtracking FastMLE solver as a plain FastMLE solver
final boolean isFastMml = fitSolver == FitSolver.FAST_MLE || fitSolver == FitSolver.BACKTRACKING_FAST_MLE;
final boolean isSteppingFunctionSolver = isLvm || isFastMml;
if (fitSolver == FitSolver.MLE) {
final ExtendedGenericDialog gd = new ExtendedGenericDialog(TITLE);
if (!ignoreCalibration) {
gd.addMessage("Maximum Likelihood Estimation requires CCD-type camera parameters");
gd.addNumericField("Camera_bias", calibration.getBias(), 2, 6, "count");
gd.addCheckbox("Model_camera_noise", fitConfig.isModelCamera());
gd.addNumericField("Read_noise", calibration.getReadNoise(), 2, 6, "count");
gd.addNumericField("Quantum_efficiency", calibration.getQuantumEfficiency(), 2, 6, "electron/photon");
gd.addCheckbox("EM-CCD", calibration.isEmCcd());
} else {
gd.addMessage("Maximum Likelihood Estimation requires additional parameters");
}
final String[] searchNames = SettingsManager.getSearchMethodNames();
gd.addChoice("Search_method", searchNames, FitProtosHelper.getName(fitConfig.getSearchMethod()));
gd.addStringField("Relative_threshold", MathUtils.rounded(fitConfig.getRelativeThreshold()));
gd.addStringField("Absolute_threshold", MathUtils.rounded(fitConfig.getAbsoluteThreshold()));
gd.addNumericField("Max_iterations", fitConfig.getMaxIterations(), 0);
gd.addNumericField("Max_function_evaluations", fitConfig.getMaxFunctionEvaluations(), 0);
if (extraOptions) {
gd.addCheckbox("Gradient_line_minimisation", fitConfig.isGradientLineMinimisation());
}
gd.showDialog();
if (gd.wasCanceled()) {
return false;
}
if (!ignoreCalibration) {
calibration.setBias(Math.abs(gd.getNextNumber()));
fitConfig.setModelCamera(gd.getNextBoolean());
calibration.setReadNoise(Math.abs(gd.getNextNumber()));
calibration.setQuantumEfficiency(Math.abs(gd.getNextNumber()));
calibration.setCameraType((gd.getNextBoolean()) ? CameraType.EMCCD : CameraType.CCD);
fitConfig.setCalibration(calibration.getCalibration());
}
fitConfig.setSearchMethod(SettingsManager.getSearchMethodValues()[gd.getNextChoiceIndex()]);
fitConfig.setRelativeThreshold(getThresholdNumber(gd));
fitConfig.setAbsoluteThreshold(getThresholdNumber(gd));
fitConfig.setMaxIterations((int) gd.getNextNumber());
fitConfig.setMaxFunctionEvaluations((int) gd.getNextNumber());
if (extraOptions) {
fitConfig.setGradientLineMinimisation(gd.getNextBoolean());
} else {
// This option is for the Conjugate Gradient optimiser and makes it less stable
fitConfig.setGradientLineMinimisation(false);
}
if (saveSettings) {
saveFitEngineSettings(config);
}
try {
ParameterUtils.isAboveZero("Relative threshold", fitConfig.getRelativeThreshold());
ParameterUtils.isAboveZero("Absolute threshold", fitConfig.getAbsoluteThreshold());
ParameterUtils.isAboveZero("Max iterations", fitConfig.getMaxIterations());
ParameterUtils.isAboveZero("Max function evaluations", fitConfig.getMaxFunctionEvaluations());
fitConfig.getFunctionSolver();
} catch (final IllegalArgumentException | IllegalStateException ex) {
IJ.error(TITLE, ex.getMessage());
return false;
}
} else if (isSteppingFunctionSolver) {
final boolean requireCalibration = !ignoreCalibration && fitSolver != FitSolver.LVM_LSE;
// Collect options for LVM fitting
final ExtendedGenericDialog gd = new ExtendedGenericDialog(TITLE);
final String fitSolverName = FitProtosHelper.getName(fitSolver);
gd.addMessage(fitSolverName + " requires additional parameters");
gd.addStringField("Relative_threshold", MathUtils.rounded(fitConfig.getRelativeThreshold()));
gd.addStringField("Absolute_threshold", MathUtils.rounded(fitConfig.getAbsoluteThreshold()));
gd.addStringField("Parameter_relative_threshold", MathUtils.rounded(fitConfig.getParameterRelativeThreshold()));
gd.addStringField("Parameter_absolute_threshold", MathUtils.rounded(fitConfig.getParameterAbsoluteThreshold()));
gd.addNumericField("Max_iterations", fitConfig.getMaxIterations(), 0);
if (isLvm) {
gd.addNumericField("Lambda", fitConfig.getLambda(), 4);
}
if (isFastMml) {
gd.addCheckbox("Fixed_iterations", fitConfig.isFixedIterations());
// This works because the proto configuration enum matches the named enum
final String[] lineSearchNames = SettingsManager.getNames((Object[]) FastMleSteppingFunctionSolver.LineSearchMethod.values());
gd.addChoice("Line_search_method", lineSearchNames, lineSearchNames[fitConfig.getLineSearchMethod().getNumber()]);
}
gd.addCheckbox("Use_clamping", fitConfig.isUseClamping());
gd.addCheckbox("Dynamic_clamping", fitConfig.isUseDynamicClamping());
final PSF psf = fitConfig.getPsf();
final boolean isAstigmatism = psf.getPsfType() == PSFType.ASTIGMATIC_GAUSSIAN_2D;
final int nParams = PsfHelper.getParameterCount(psf);
if (extraOptions) {
gd.addNumericField("Clamp_background", fitConfig.getClampBackground(), 2);
gd.addNumericField("Clamp_signal", fitConfig.getClampSignal(), 2);
gd.addNumericField("Clamp_x", fitConfig.getClampX(), 2);
gd.addNumericField("Clamp_y", fitConfig.getClampY(), 2);
if (isAstigmatism) {
gd.addNumericField("Clamp_z", fitConfig.getClampZ(), 2);
} else {
if (nParams > 1 || !fitConfig.isFixedPsf()) {
gd.addNumericField("Clamp_sx", fitConfig.getClampXSd(), 2);
}
if (nParams > 1) {
gd.addNumericField("Clamp_sy", fitConfig.getClampYSd(), 2);
}
if (nParams > 2) {
gd.addNumericField("Clamp_angle", fitConfig.getClampAngle(), 2);
}
}
}
// Extra parameters are needed for calibrated fit solvers
if (requireCalibration) {
switch(calibration.getCameraType()) {
case CCD:
case EMCCD:
case SCMOS:
break;
default:
IJ.error(TITLE, fitSolverName + " requires camera calibration");
return false;
}
gd.addMessage(fitSolverName + " requires calibration for camera: " + CalibrationProtosHelper.getName(calibration.getCameraType()));
if (calibration.isScmos()) {
final String[] models = CameraModelManager.listCameraModels(true);
gd.addChoice("Camera_model_name", models, fitConfig.getCameraModelName());
} else {
gd.addNumericField("Camera_bias", calibration.getBias(), 2, 6, "Count");
gd.addNumericField("Gain", calibration.getCountPerPhoton(), 2, 6, "Count/photon");
gd.addNumericField("Read_noise", calibration.getReadNoise(), 2, 6, "Count");
}
}
gd.showDialog();
if (gd.wasCanceled()) {
return false;
}
fitConfig.setRelativeThreshold(getThresholdNumber(gd));
fitConfig.setAbsoluteThreshold(getThresholdNumber(gd));
fitConfig.setParameterRelativeThreshold(getThresholdNumber(gd));
fitConfig.setParameterAbsoluteThreshold(getThresholdNumber(gd));
fitConfig.setMaxIterations((int) gd.getNextNumber());
if (isLvm) {
fitConfig.setLambda(gd.getNextNumber());
}
if (isFastMml) {
fitConfig.setFixedIterations(gd.getNextBoolean());
fitConfig.setLineSearchMethod(gd.getNextChoiceIndex());
}
fitConfig.setUseClamping(gd.getNextBoolean());
fitConfig.setUseDynamicClamping(gd.getNextBoolean());
if (extraOptions) {
fitConfig.setClampBackground(Math.abs(gd.getNextNumber()));
fitConfig.setClampSignal(Math.abs(gd.getNextNumber()));
fitConfig.setClampX(Math.abs(gd.getNextNumber()));
fitConfig.setClampY(Math.abs(gd.getNextNumber()));
if (isAstigmatism) {
fitConfig.setClampZ(Math.abs(gd.getNextNumber()));
} else {
if (nParams > 1 || !fitConfig.isFixedPsf()) {
fitConfig.setClampXSd(Math.abs(gd.getNextNumber()));
}
if (nParams > 1) {
fitConfig.setClampYSd(Math.abs(gd.getNextNumber()));
}
if (nParams > 2) {
fitConfig.setClampAngle(Math.abs(gd.getNextNumber()));
}
}
}
if (requireCalibration) {
if (calibration.isScmos()) {
fitConfig.setCameraModelName(gd.getNextChoice());
} else {
calibration.setBias(Math.abs(gd.getNextNumber()));
calibration.setCountPerPhoton(Math.abs(gd.getNextNumber()));
calibration.setReadNoise(Math.abs(gd.getNextNumber()));
fitConfig.setCalibration(calibration.getCalibration());
}
}
// camera model is set.
if (calibration.isScmos()) {
fitConfig.setCameraModel(CameraModelManager.load(fitConfig.getCameraModelName()));
if (!checkCameraModel(fitConfig, sourceBounds, bounds, true)) {
return false;
}
}
if (saveSettings) {
saveFitEngineSettings(config);
}
try {
if (isLvm) {
ParameterUtils.isAboveZero("Lambda", fitConfig.getLambda());
}
// This call will check if the configuration is OK (including convergence criteria)
fitConfig.getFunctionSolver();
} catch (final IllegalArgumentException | IllegalStateException ex) {
IJ.error(TITLE, ex.getMessage());
return false;
}
} else {
IJ.error(TITLE, "Unknown fit solver: " + fitSolver);
return false;
}
if (config.isIncludeNeighbours() && !fitConfig.getFunctionSolver().isBounded()) {
IJ.error(TITLE, "Including neighbours requires a bounded fit solver");
return false;
}
return true;
}
use of uk.ac.sussex.gdsc.smlm.engine.FitConfiguration in project GDSC-SMLM by aherbert.
the class PeakFit method configureZFilter.
/**
* Show a dialog to configure the results z filter. The updated settings are saved to the settings
* file.
*
* <p>If the fit configuration PSF is not 3D or the simple filter is disabled then this method
* returns true. If it is enabled then a dialog is shown to input the configuration for the z
* filter.
*
* <p>Note: The PSF and any z-model must be correctly configured for fitting in pixel units.
*
* @param config the config
* @param flags the flags
* @return true, if successful
*/
public static boolean configureZFilter(FitEngineConfiguration config, int flags) {
final FitConfiguration fitConfig = config.getFitConfiguration();
if (fitConfig.isDisableSimpleFilter() || !fitConfig.is3D()) {
return true;
}
// Create a converter to map the model units in pixels to nm for the dialog.
// Note the output units of pixels may not yet be set in the calibration so we assume it is
// pixels.
final TypeConverter<DistanceUnit> c = UnitConverterUtils.createConverter(DistanceUnit.PIXEL, DistanceUnit.NM, fitConfig.getCalibrationReader().getNmPerPixel());
final ExtendedGenericDialog gd = new ExtendedGenericDialog(TITLE);
gd.addMessage("3D filter");
gd.addNumericField("Min_z", c.convert(fitConfig.getMinZ()), 0, 6, "nm");
gd.addNumericField("Max_z", c.convert(fitConfig.getMaxZ()), 0, 6, "nm");
gd.showDialog();
if (gd.wasCanceled()) {
return false;
}
final double minZ = gd.getNextNumber();
final double maxZ = gd.getNextNumber();
if (gd.invalidNumber() || minZ > maxZ) {
IJ.error(TITLE, "Min Z must be equal or below the max Z");
return false;
}
// Map back
fitConfig.setMinZ(c.convertBack(minZ));
fitConfig.setMaxZ(c.convertBack(maxZ));
if (BitFlagUtils.anyNotSet(flags, FLAG_NO_SAVE)) {
SettingsManager.writeSettings(config, 0);
}
return true;
}
use of uk.ac.sussex.gdsc.smlm.engine.FitConfiguration in project GDSC-SMLM by aherbert.
the class GaussianFit method runFinal.
/**
* Perform fitting using the chosen maxima. Update the overlay if successful.
*
* @param ip The input image
*/
private void runFinal(ImageProcessor ip) {
ip.reset();
final Rectangle bounds = ip.getRoi();
// Crop to the ROI
final float[] data = ImageJImageConverter.getData(ip);
final int width = bounds.width;
final int height = bounds.height;
// Sort the maxima
float[] smoothData = data;
if (getSmooth() > 0) {
// Smoothing destructively modifies the data so create a copy
smoothData = Arrays.copyOf(data, width * height);
final BlockMeanFilter filter = new BlockMeanFilter();
if (settings.smooth <= settings.border) {
filter.stripedBlockFilterInternal(smoothData, width, height, (float) settings.smooth);
} else {
filter.stripedBlockFilter(smoothData, width, height, (float) settings.smooth);
}
}
SortUtils.sortIndices(maxIndices, smoothData, true);
// Show the candidate peaks
if (maxIndices.length > 0) {
final String message = String.format("Identified %d peaks", maxIndices.length);
if (isLogProgress()) {
IJ.log(message);
for (final int index : maxIndices) {
IJ.log(String.format(" %.2f @ [%d,%d]", data[index], bounds.x + index % width, bounds.y + index / width));
}
}
// Check whether to run if the number of peaks is large
if (maxIndices.length > 10) {
final GenericDialog gd = new GenericDialog("Warning");
gd.addMessage(message + "\nDo you want to fit?");
gd.showDialog();
if (gd.wasCanceled()) {
return;
}
}
} else {
IJ.log("No maxima identified");
return;
}
results = new ImageJTablePeakResults(settings.showDeviations, imp.getTitle() + " [" + imp.getCurrentSlice() + "]");
final CalibrationWriter cw = new CalibrationWriter();
cw.setIntensityUnit(IntensityUnit.COUNT);
cw.setDistanceUnit(DistanceUnit.PIXEL);
cw.setAngleUnit(AngleUnit.RADIAN);
results.setCalibration(cw.getCalibration());
results.setPsf(PsfProtosHelper.getDefaultPsf(getPsfType()));
results.setShowFittingData(true);
results.setAngleUnit(AngleUnit.DEGREE);
results.begin();
// Perform the Gaussian fit
long ellapsed = 0;
final FloatProcessor renderedImage = settings.showFit ? new FloatProcessor(ip.getWidth(), ip.getHeight()) : null;
if (!settings.singleFit) {
if (isLogProgress()) {
IJ.log("Combined fit");
}
// Estimate height from smoothed data
final double[] estimatedHeights = new double[maxIndices.length];
for (int i = 0; i < estimatedHeights.length; i++) {
estimatedHeights[i] = smoothData[maxIndices[i]];
}
final FitConfiguration config = new FitConfiguration();
setupPeakFiltering(config);
final long time = System.nanoTime();
final double[] params = fitMultiple(data, width, height, maxIndices, estimatedHeights);
ellapsed = System.nanoTime() - time;
if (params != null) {
// Copy all the valid parameters into a new array
final double[] validParams = new double[params.length];
int count = 0;
int validPeaks = 0;
validParams[count++] = params[0];
final double[] initialParams = convertParameters(fitResult.getInitialParameters());
final double[] paramsDev = convertParameters(fitResult.getParameterDeviations());
final Rectangle regionBounds = new Rectangle();
final float[] xpoints = new float[maxIndices.length];
final float[] ypoints = new float[maxIndices.length];
int npoints = 0;
for (int i = 1, n = 0; i < params.length; i += Gaussian2DFunction.PARAMETERS_PER_PEAK, n++) {
final int y = maxIndices[n] / width;
final int x = maxIndices[n] % width;
// Check the peak is a good fit
if (settings.filterResults && config.validatePeak(n, initialParams, params, paramsDev) != FitStatus.OK) {
continue;
}
if (settings.showFit) {
// Copy the valid parameters before there are adjusted to global bounds
validPeaks++;
for (int ii = i, j = 0; j < Gaussian2DFunction.PARAMETERS_PER_PEAK; ii++, j++) {
validParams[count++] = params[ii];
}
}
final double[] peakParams = extractParams(params, i);
final double[] peakParamsDev = extractParams(paramsDev, i);
addResult(bounds, regionBounds, peakParams, peakParamsDev, npoints, x, y, data[maxIndices[n]]);
// Add fit result to the overlay - Coords are updated with the region offsets in addResult
final double xf = peakParams[Gaussian2DFunction.X_POSITION];
final double yf = peakParams[Gaussian2DFunction.Y_POSITION];
xpoints[npoints] = (float) xf;
ypoints[npoints] = (float) yf;
npoints++;
}
setOverlay(npoints, xpoints, ypoints);
// Draw the fit
if (validPeaks != 0) {
addToImage(bounds.x, bounds.y, renderedImage, validParams, validPeaks, width, height);
}
} else {
if (isLogProgress()) {
IJ.log("Failed to fit " + TextUtils.pleural(maxIndices.length, "peak") + ": " + getReason(fitResult));
}
imp.setOverlay(null);
}
} else {
if (isLogProgress()) {
IJ.log("Individual fit");
}
int npoints = 0;
final float[] xpoints = new float[maxIndices.length];
final float[] ypoints = new float[maxIndices.length];
// Extract each peak and fit individually
final ImageExtractor ie = ImageExtractor.wrap(data, width, height);
float[] region = null;
final Gaussian2DFitter gf = createGaussianFitter(settings.filterResults);
double[] validParams = null;
final ShortProcessor renderedImageCount = settings.showFit ? new ShortProcessor(ip.getWidth(), ip.getHeight()) : null;
for (int n = 0; n < maxIndices.length; n++) {
final int y = maxIndices[n] / width;
final int x = maxIndices[n] % width;
final long time = System.nanoTime();
final Rectangle regionBounds = ie.getBoxRegionBounds(x, y, settings.singleRegionSize);
region = ie.crop(regionBounds, region);
final int newIndex = (y - regionBounds.y) * regionBounds.width + x - regionBounds.x;
if (isLogProgress()) {
IJ.log("Fitting peak " + (n + 1));
}
final double[] peakParams = fitSingle(gf, region, regionBounds.width, regionBounds.height, newIndex, smoothData[maxIndices[n]]);
ellapsed += System.nanoTime() - time;
// Output fit result
if (peakParams != null) {
if (settings.showFit) {
// Copy the valid parameters before there are adjusted to global bounds
validParams = peakParams.clone();
}
double[] peakParamsDev = null;
if (settings.showDeviations) {
peakParamsDev = convertParameters(fitResult.getParameterDeviations());
}
addResult(bounds, regionBounds, peakParams, peakParamsDev, n, x, y, data[maxIndices[n]]);
// Add fit result to the overlay - Coords are updated with the region offsets in addResult
final double xf = peakParams[Gaussian2DFunction.X_POSITION];
final double yf = peakParams[Gaussian2DFunction.Y_POSITION];
xpoints[npoints] = (float) xf;
ypoints[npoints] = (float) yf;
npoints++;
// Draw the fit
if (settings.showDeviations) {
final int ox = bounds.x + regionBounds.x;
final int oy = bounds.y + regionBounds.y;
addToImage(ox, oy, renderedImage, validParams, 1, regionBounds.width, regionBounds.height);
addCount(ox, oy, renderedImageCount, regionBounds.width, regionBounds.height);
}
} else if (isLogProgress()) {
IJ.log("Failed to fit peak " + (n + 1) + ": " + getReason(fitResult));
}
}
// Update the overlay
if (npoints > 0) {
setOverlay(npoints, xpoints, ypoints);
} else {
imp.setOverlay(null);
}
// Create the mean
if (settings.showFit) {
for (int i = renderedImageCount.getPixelCount(); i-- > 0; ) {
final int count = renderedImageCount.get(i);
if (count > 1) {
renderedImage.setf(i, renderedImage.getf(i) / count);
}
}
}
}
results.end();
if (renderedImage != null) {
ImageJUtils.display(TITLE, renderedImage);
}
if (isLogProgress()) {
IJ.log("Time = " + (ellapsed / 1000000.0) + "ms");
}
}
use of uk.ac.sussex.gdsc.smlm.engine.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.
*
* <p>This calls {@link FitConfiguration#setDirectFilter(DirectFilter)} and sets the precision
* method using the method in the direct filter.
*
* @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) {
final BenchmarkFilterAnalysisResult lastResult = BenchmarkFilterAnalysisResult.lastResult.get();
if (lastResult.scores.isEmpty()) {
return false;
}
FilterResult best;
if (useLatest) {
best = lastResult.scores.get(lastResult.scores.size() - 1);
} else {
best = getBestResult(lastResult.scores);
}
// New smart filter support
final FitConfiguration fitConfig = config.getFitConfiguration();
fitConfig.setDirectFilter(best.getFilter());
// Set the precision method using the direct filter
fitConfig.setPrecisionMethod(fitConfig.getFilterPrecisionMethod());
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);
config.setDuplicateDistance(best.duplicateDistance);
config.setDuplicateDistanceAbsolute(best.duplicateDistanceAbsolute);
return true;
}
use of uk.ac.sussex.gdsc.smlm.engine.FitConfiguration in project GDSC-SMLM by aherbert.
the class SpotAnalysis method updateCurrentSlice.
private void updateCurrentSlice(int slice) {
if (slice != currentSlice) {
currentSlice = slice;
final double signal = getSignal(slice);
final double noise = smoothSd[slice - 1];
currentLabel.setText(String.format("Frame %d: Signal = %s, SNR = %s", slice, MathUtils.rounded(signal, 4), MathUtils.rounded(signal / noise, 3)));
drawProfiles();
// Fit the PSF using a Gaussian
final FitConfiguration fitConfiguration = new FitConfiguration();
fitConfiguration.setPsf(PsfProtosHelper.defaultOneAxisGaussian2DPSF);
fitConfiguration.setFixedPsf(true);
fitConfiguration.setBackgroundFitting(true);
fitConfiguration.setSignalStrength(0);
fitConfiguration.setCoordinateShift(rawImp.getWidth() / 4.0f);
fitConfiguration.setComputeResiduals(false);
fitConfiguration.setComputeDeviations(false);
final Gaussian2DFitter gf = new Gaussian2DFitter(fitConfiguration);
double[] params = new double[1 + Gaussian2DFunction.PARAMETERS_PER_PEAK];
final double psfWidth = Double.parseDouble(widthTextField.getText());
params[Gaussian2DFunction.BACKGROUND] = smoothMean[slice - 1];
params[Gaussian2DFunction.SIGNAL] = (gain * signal);
params[Gaussian2DFunction.X_POSITION] = rawImp.getWidth() / 2.0f;
params[Gaussian2DFunction.Y_POSITION] = rawImp.getHeight() / 2.0f;
params[Gaussian2DFunction.X_SD] = params[Gaussian2DFunction.Y_SD] = psfWidth;
float[] data = (float[]) rawImp.getImageStack().getProcessor(slice).getPixels();
FitResult fitResult = gf.fit(SimpleArrayUtils.toDouble(data), rawImp.getWidth(), rawImp.getHeight(), 1, params, new boolean[1]);
if (fitResult.getStatus() == FitStatus.OK) {
params = fitResult.getParameters();
final double spotSignal = params[Gaussian2DFunction.SIGNAL] / gain;
rawFittedLabel.setText(String.format("Raw fit: Signal = %s, SNR = %s", MathUtils.rounded(spotSignal, 4), MathUtils.rounded(spotSignal / noise, 3)));
ImageRoiPainter.addRoi(rawImp, slice, new OffsetPointRoi(params[Gaussian2DFunction.X_POSITION], params[Gaussian2DFunction.Y_POSITION]));
} else {
rawFittedLabel.setText("");
rawImp.setOverlay(null);
}
// Fit the PSF using a Gaussian
if (blurImp == null) {
return;
}
params = new double[1 + Gaussian2DFunction.PARAMETERS_PER_PEAK];
params[Gaussian2DFunction.BACKGROUND] = (float) smoothMean[slice - 1];
params[Gaussian2DFunction.SIGNAL] = (float) (gain * signal);
params[Gaussian2DFunction.X_POSITION] = rawImp.getWidth() / 2.0f;
params[Gaussian2DFunction.Y_POSITION] = rawImp.getHeight() / 2.0f;
params[Gaussian2DFunction.X_SD] = params[Gaussian2DFunction.Y_SD] = psfWidth;
data = (float[]) blurImp.getImageStack().getProcessor(slice).getPixels();
fitResult = gf.fit(SimpleArrayUtils.toDouble(data), rawImp.getWidth(), rawImp.getHeight(), 1, params, new boolean[1]);
if (fitResult.getStatus() == FitStatus.OK) {
params = fitResult.getParameters();
final double spotSignal = params[Gaussian2DFunction.SIGNAL] / gain;
blurFittedLabel.setText(String.format("Blur fit: Signal = %s, SNR = %s", MathUtils.rounded(spotSignal, 4), MathUtils.rounded(spotSignal / noise, 3)));
ImageRoiPainter.addRoi(blurImp, slice, new OffsetPointRoi(params[Gaussian2DFunction.X_POSITION], params[Gaussian2DFunction.Y_POSITION]));
} else {
blurFittedLabel.setText("");
blurImp.setOverlay(null);
}
}
}
Aggregations