use of uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.PSFParameter in project GDSC-SMLM by aherbert.
the class PsfCreator method fitPsf.
/**
* Fit the new PSF image and show a graph of the amplitude/width.
*
* @param psfStack the psf stack
* @param loess the loess
* @param cz the cz
* @param averageRange the average range
* @param fitCom the fit com
* @return The width of the PSF in the z-centre
*/
private double fitPsf(ImageStack psfStack, LoessInterpolator loess, int cz, double averageRange, final double[][] fitCom) {
IJ.showStatus("Fitting final PSF");
// is not appropriate for a normalised PSF.
if (fitConfig.getFitSolver() != FitSolver.LVM_LSE) {
ImageJUtils.log(" " + FitProtosHelper.getName(fitConfig.getFitSolver()) + " is not appropriate for final PSF fitting.");
ImageJUtils.log(" Switching to Least Square Estimation");
fitConfig.setFitSolver(FitSolver.LVM_LSE);
if (settings.getInteractiveMode()) {
// This assumes the LVM does not need the calibration
PeakFit.configureFitSolver(config, null, null, 0);
}
}
// Update the box radius since this is used in the fitSpot method.
boxRadius = psfStack.getWidth() / 2;
final int x = boxRadius;
final int y = boxRadius;
final double shift = fitConfig.getCoordinateShiftFactor();
// Scale the PSF
final PSF.Builder localPsf = fitConfig.getPsf().toBuilder();
for (int i = 0; i < localPsf.getParametersCount(); i++) {
final PSFParameter param = localPsf.getParameters(i);
if (param.getUnit() == PSFParameterUnit.DISTANCE) {
final PSFParameter.Builder b = param.toBuilder();
b.setValue(b.getValue() * settings.getMagnification());
localPsf.setParameters(i, b);
}
}
fitConfig.setPsf(localPsf.build());
// Need to be updated after the widths have been set
fitConfig.setCoordinateShiftFactor(shift);
fitConfig.setBackgroundFitting(false);
// Since the PSF will be normalised remove the camera calibration
fitConfig.setCameraType(CameraType.CAMERA_TYPE_NA);
fitConfig.setMinPhotons(0);
fitConfig.setBias(0);
fitConfig.setGain(1);
// No complex filtering so we get a fit. It should be easy to fit anyway.
fitConfig.setPrecisionThreshold(0);
fitConfig.setDirectFilter(null);
// fitConfig.setDisableSimpleFilter(true);
// Use this for debugging the fit
// fitConfig.setLog(uk.ac.sussex.gdsc.core.ij.ImageJPluginLoggerHelper.getDefaultLogger());
final MemoryPeakResults results = fitSpot(psfStack, psfStack.getWidth(), psfStack.getHeight(), x, y);
if (results.size() < 5) {
ImageJUtils.log(" Final PSF: Not enough fit results %d", results.size());
return 0;
}
// Get the results for the spot centre and width
final double[] z = new double[results.size()];
final double[] xCoord = new double[z.length];
final double[] yCoord = new double[z.length];
final double[] sd = new double[z.length];
final double[] a = new double[z.length];
// Set limits for the fit
final float maxWidth = (float) (Math.max(fitConfig.getInitialXSd(), fitConfig.getInitialYSd()) * settings.getMagnification() * 4);
// PSF is normalised to 1
final float maxSignal = 2;
final WidthResultProcedure wp = new WidthResultProcedure(results, DistanceUnit.PIXEL);
wp.getWxWy();
final HeightResultProcedure hp = new HeightResultProcedure(results, IntensityUnit.COUNT);
hp.getH();
final Counter counter = new Counter();
final Counter counterOk = new Counter();
// We have fit the results so they will be in the preferred units
results.forEach((PeakResultProcedure) peak -> {
int index = counter.getAndIncrement();
final float w = Math.max(wp.wx[index], wp.wy[index]);
if (peak.getIntensity() > maxSignal || w > maxWidth) {
return;
}
index = counterOk.getAndIncrement();
z[index] = peak.getFrame();
fitCom[0][peak.getFrame() - 1] = xCoord[index] = peak.getXPosition() - x;
fitCom[1][peak.getFrame() - 1] = yCoord[index] = peak.getYPosition() - y;
sd[index] = w;
a[index] = hp.heights[index];
});
// Truncate
final double[] z2 = Arrays.copyOf(z, counter.getCount());
final double[] xCoord2 = Arrays.copyOf(xCoord, z2.length);
final double[] yCoord2 = Arrays.copyOf(yCoord, z2.length);
final double[] sd2 = Arrays.copyOf(sd, z2.length);
final double[] a2 = Arrays.copyOf(a, z2.length);
// Extract the average smoothed range from the individual fits
final int r = (int) Math.ceil(averageRange / 2);
int start = 0;
int stop = z2.length - 1;
for (int j = 0; j < z2.length; j++) {
if (z2[j] > cz - r) {
start = j;
break;
}
}
for (int j = z2.length; j-- > 0; ) {
if (z2[j] < cz + r) {
stop = j;
break;
}
}
// Extract xy centre coords and smooth
double[] smoothX = new double[stop - start + 1];
double[] smoothY = new double[smoothX.length];
double[] smoothSd = new double[smoothX.length];
double[] smoothA = new double[smoothX.length];
final double[] newZ = new double[smoothX.length];
int smoothCzIndex = 0;
for (int j = start, k = 0; j <= stop; j++, k++) {
smoothX[k] = xCoord2[j];
smoothY[k] = yCoord2[j];
smoothSd[k] = sd2[j];
smoothA[k] = a2[j];
newZ[k] = z2[j];
if (newZ[k] == cz) {
smoothCzIndex = k;
}
}
smoothX = loess.smooth(newZ, smoothX);
smoothY = loess.smooth(newZ, smoothY);
smoothSd = loess.smooth(newZ, smoothSd);
smoothA = loess.smooth(newZ, smoothA);
// Update the widths and positions using the magnification
final double scale = 1.0 / settings.getMagnification();
for (int j = 0; j < xCoord2.length; j++) {
xCoord2[j] *= scale;
yCoord2[j] *= scale;
sd2[j] *= scale;
}
for (int j = 0; j < smoothX.length; j++) {
smoothX[j] *= scale;
smoothY[j] *= scale;
smoothSd[j] *= scale;
}
showPlots(z2, a2, newZ, smoothA, xCoord2, yCoord2, sd2, newZ, smoothX, smoothY, smoothSd, cz);
// Store the data for replotting
this.z = z2;
this.amplitude = a2;
this.smoothAz = newZ;
this.smoothA = smoothA;
this.xCoord = xCoord2;
this.yCoord = yCoord2;
this.sd = sd2;
this.newZ = newZ;
this.smoothX = smoothX;
this.smoothY = smoothY;
this.smoothSd = smoothSd;
// maximumIndex = findMinimumIndex(smoothSd, maximumIndex - start);
return smoothSd[smoothCzIndex];
}
use of uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.PSFParameter in project GDSC-SMLM by aherbert.
the class PeakResultConversionHelper method getNames.
/**
* Gets the names for the peak results parameters. This includes the standard parameters and any
* additional parameters defined in the PSF. If a parameter name is undefined then unknown is
* returned.
*
* @return the converters
*/
public String[] getNames() {
final LocalList<String> list = new LocalList<>(5);
list.add("Background");
list.add("Intensity");
list.add("X");
list.add("Y");
list.add("Z");
if (psf != null) {
try {
for (final PSFParameter p : PsfHelper.getParameters(psf)) {
final String name = p.getName();
list.add(TextUtils.isNullOrEmpty(name) ? "unknown" : name);
}
} catch (final ConfigurationException ex) {
// Ignore
}
}
return list.toArray(new String[0]);
}
use of uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.PSFParameter in project GDSC-SMLM by aherbert.
the class PeakResultConversionHelper method getConverters.
/**
* Gets the converters for the peak results parameters. This includes the standard parameters and
* any additional parameters defined in the PSF. If a parameter unit type is undefined then an
* identity converter is created.
*
* @return the converters
*/
public Converter[] getConverters() {
final LocalList<Converter> list = new LocalList<>(5);
getIntensityConverter();
getDistanceConverter();
list.add(intensityConverter);
list.add(intensityConverter);
list.add(distanceConverter);
list.add(distanceConverter);
list.add(distanceConverter);
if (psf != null) {
try {
for (final PSFParameter p : PsfHelper.getParameters(psf)) {
switch(p.getUnit()) {
case DISTANCE:
list.add(distanceConverter);
break;
case INTENSITY:
list.add(intensityConverter);
break;
case ANGLE:
list.add(getAngleConverter());
break;
default:
list.add(new IdentityTypeConverter<>(p.getUnit()));
}
}
} catch (final ConfigurationException ex) {
// Ignore
}
}
return list.toArray(new Converter[0]);
}
use of uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.PSFParameter in project GDSC-SMLM by aherbert.
the class PeakResultConversionHelper method getUnitNames.
/**
* Gets the unit names for the peak results parameters. This includes the standard parameters and
* any additional parameters defined in the PSF. If a parameter unit is undefined then an empty
* string is returned.
*
* @return the converters
*/
public String[] getUnitNames() {
final LocalList<String> list = new LocalList<>(5);
getIntensityConverter();
getDistanceConverter();
final String safeIntensityUnit = (intensityConverter.to() != null) ? UnitHelper.getShortName(intensityConverter.to()) : "";
final String safeDistanceUnit = (distanceConverter.to() != null) ? UnitHelper.getShortName(distanceConverter.to()) : "";
String safeAngleUnit = null;
list.add(safeIntensityUnit);
list.add(safeIntensityUnit);
list.add(safeDistanceUnit);
list.add(safeDistanceUnit);
list.add(safeDistanceUnit);
if (psf != null) {
try {
for (final PSFParameter p : PsfHelper.getParameters(psf)) {
switch(p.getUnit()) {
case DISTANCE:
list.add(safeDistanceUnit);
break;
case INTENSITY:
list.add(safeIntensityUnit);
break;
case ANGLE:
safeAngleUnit = getOrCreateAngleUnit(safeAngleUnit);
list.add(safeAngleUnit);
break;
default:
list.add("");
}
}
} catch (final ConfigurationException ex) {
// Ignore
}
}
return list.toArray(new String[0]);
}
use of uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.PSFParameter in project GDSC-SMLM by aherbert.
the class PeakFit method addPsfOptions.
/**
* Adds the PSF options.
*
* <p>Note that if an astigmatic PSF is selected then the model must be created with
* {@link #configurePsfModel(FitEngineConfiguration, int)}.
*
* @param gd the dialog
* @param fitConfigurationProvider the fit configuration provider
*/
public static void addPsfOptions(final ExtendedGenericDialog gd, final FitConfigurationProvider fitConfigurationProvider) {
final FitConfiguration fitConfig = fitConfigurationProvider.getFitConfiguration();
gd.addChoice("PSF", getPsfTypeNames(), PsfProtosHelper.getName(fitConfig.getPsfType()), new OptionListener<Integer>() {
@Override
public boolean collectOptions(Integer field) {
final FitConfiguration fitConfig = fitConfigurationProvider.getFitConfiguration();
fitConfig.setPsfType(PeakFit.getPsfTypeValues()[field]);
return collectOptions(false);
}
@Override
public boolean collectOptions() {
return collectOptions(true);
}
private boolean collectOptions(boolean silent) {
final FitConfiguration localFitConfig = fitConfigurationProvider.getFitConfiguration();
final PSFType psfType = localFitConfig.getPsfType();
final ExtendedGenericDialog egd = new ExtendedGenericDialog("PSF Options", null);
PSF oldPsf = null;
if (psfType == PSFType.ASTIGMATIC_GAUSSIAN_2D) {
// The PSF is entirely defined in the model
String[] list = AstigmatismModelManager.listAstigmatismModels(false, localFitConfig.getCalibrationReader().getNmPerPixel(), 0.1);
// In case the calibration has not been updated
if (list.length == 0) {
list = AstigmatismModelManager.listAstigmatismModels(false, true);
}
egd.addChoice("Z-model", list, localFitConfig.getPsfModelName());
} else {
// Collect the PSF parameters
oldPsf = localFitConfig.getPsf();
for (int i = 0; i < oldPsf.getParametersCount(); i++) {
final PSFParameter p = oldPsf.getParameters(i);
egd.addNumericField(String.format("PSF_parameter_%d (%s)", i + 1, p.getName()), p.getValue(), 3);
}
if (psfType == PSFType.ONE_AXIS_GAUSSIAN_2D) {
egd.addCheckbox("Fixed", localFitConfig.isFixedPsf());
}
}
egd.setSilent(silent);
egd.showDialog(true, gd);
if (egd.wasCanceled()) {
return false;
}
if (psfType == PSFType.ASTIGMATIC_GAUSSIAN_2D) {
// The PSF is entirely defined in the model
localFitConfig.setPsfModelName(egd.getNextChoice());
return true;
}
@SuppressWarnings("null") final PSF.Builder b = oldPsf.toBuilder();
final int n = b.getParametersCount();
for (int i = 0; i < n; i++) {
b.getParametersBuilder(i).setValue(egd.getNextNumber());
}
final PSF newPsf = b.build();
localFitConfig.setPsf(newPsf);
boolean changed = !oldPsf.equals(newPsf);
if (psfType == PSFType.ONE_AXIS_GAUSSIAN_2D) {
final boolean newFixed = egd.getNextBoolean();
changed = changed || (newFixed != localFitConfig.isFixedPsf());
localFitConfig.setFixedPsf(newFixed);
}
return changed;
}
});
}
Aggregations