use of org.apache.commons.math3.stat.descriptive.rank.Max in project GDSC-SMLM by aherbert.
the class PSFCreator method run.
/*
* (non-Javadoc)
*
* @see ij.plugin.filter.PlugInFilter#run(ij.process.ImageProcessor)
*/
public void run(ImageProcessor ip) {
loadConfiguration();
BasePoint[] spots = getSpots();
if (spots.length == 0) {
IJ.error(TITLE, "No spots without neighbours within " + (boxRadius * 2) + "px");
return;
}
ImageStack stack = getImageStack();
final int width = imp.getWidth();
final int height = imp.getHeight();
final int currentSlice = imp.getSlice();
// Adjust settings for a single maxima
config.setIncludeNeighbours(false);
fitConfig.setDuplicateDistance(0);
ArrayList<double[]> centres = new ArrayList<double[]>(spots.length);
int iterations = 1;
LoessInterpolator loess = new LoessInterpolator(smoothing, iterations);
// TODO - The fitting routine may not produce many points. In this instance the LOESS interpolator
// fails to smooth the data very well. A higher bandwidth helps this but perhaps
// try a different smoothing method.
// For each spot
Utils.log(TITLE + ": " + imp.getTitle());
Utils.log("Finding spot locations...");
Utils.log(" %d spot%s without neighbours within %dpx", spots.length, ((spots.length == 1) ? "" : "s"), (boxRadius * 2));
StoredDataStatistics averageSd = new StoredDataStatistics();
StoredDataStatistics averageA = new StoredDataStatistics();
Statistics averageRange = new Statistics();
MemoryPeakResults allResults = new MemoryPeakResults();
allResults.setName(TITLE);
allResults.setBounds(new Rectangle(0, 0, width, height));
MemoryPeakResults.addResults(allResults);
for (int n = 1; n <= spots.length; n++) {
BasePoint spot = spots[n - 1];
final int x = (int) spot.getX();
final int y = (int) spot.getY();
MemoryPeakResults results = fitSpot(stack, width, height, x, y);
allResults.addAllf(results.getResults());
if (results.size() < 5) {
Utils.log(" Spot %d: Not enough fit results %d", n, results.size());
continue;
}
// Get the results for the spot centre and width
double[] z = new double[results.size()];
double[] xCoord = new double[z.length];
double[] yCoord = new double[z.length];
double[] sd = new double[z.length];
double[] a = new double[z.length];
int i = 0;
for (PeakResult peak : results.getResults()) {
z[i] = peak.getFrame();
xCoord[i] = peak.getXPosition() - x;
yCoord[i] = peak.getYPosition() - y;
sd[i] = FastMath.max(peak.getXSD(), peak.getYSD());
a[i] = peak.getAmplitude();
i++;
}
// Smooth the amplitude plot
double[] smoothA = loess.smooth(z, a);
// Find the maximum amplitude
int maximumIndex = findMaximumIndex(smoothA);
// Find the range at a fraction of the max. This is smoothed to find the X/Y centre
int start = 0, stop = smoothA.length - 1;
double limit = smoothA[maximumIndex] * amplitudeFraction;
for (int j = 0; j < smoothA.length; j++) {
if (smoothA[j] > limit) {
start = j;
break;
}
}
for (int j = smoothA.length; j-- > 0; ) {
if (smoothA[j] > limit) {
stop = j;
break;
}
}
averageRange.add(stop - start + 1);
// 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[] newZ = new double[smoothX.length];
for (int j = start, k = 0; j <= stop; j++, k++) {
smoothX[k] = xCoord[j];
smoothY[k] = yCoord[j];
smoothSd[k] = sd[j];
newZ[k] = z[j];
}
smoothX = loess.smooth(newZ, smoothX);
smoothY = loess.smooth(newZ, smoothY);
smoothSd = loess.smooth(newZ, smoothSd);
// Since the amplitude is not very consistent move from this peak to the
// lowest width which is the in-focus spot.
maximumIndex = findMinimumIndex(smoothSd, maximumIndex - start);
// Find the centre at the amplitude peak
double cx = smoothX[maximumIndex] + x;
double cy = smoothY[maximumIndex] + y;
int cz = (int) newZ[maximumIndex];
double csd = smoothSd[maximumIndex];
double ca = smoothA[maximumIndex + start];
// The average should weight the SD using the signal for each spot
averageSd.add(smoothSd[maximumIndex]);
averageA.add(ca);
if (ignoreSpot(n, z, a, smoothA, xCoord, yCoord, sd, newZ, smoothX, smoothY, smoothSd, cx, cy, cz, csd)) {
Utils.log(" Spot %d was ignored", n);
continue;
}
// Store result - it may have been moved interactively
maximumIndex += this.slice - cz;
cz = (int) newZ[maximumIndex];
csd = smoothSd[maximumIndex];
ca = smoothA[maximumIndex + start];
Utils.log(" Spot %d => x=%.2f, y=%.2f, z=%d, sd=%.2f, A=%.2f\n", n, cx, cy, cz, csd, ca);
centres.add(new double[] { cx, cy, cz, csd, n });
}
if (interactiveMode) {
imp.setSlice(currentSlice);
imp.setOverlay(null);
// Hide the amplitude and spot plots
Utils.hide(TITLE_AMPLITUDE);
Utils.hide(TITLE_PSF_PARAMETERS);
}
if (centres.isEmpty()) {
String msg = "No suitable spots could be identified centres";
Utils.log(msg);
IJ.error(TITLE, msg);
return;
}
// Find the limits of the z-centre
int minz = (int) centres.get(0)[2];
int maxz = minz;
for (double[] centre : centres) {
if (minz > centre[2])
minz = (int) centre[2];
else if (maxz < centre[2])
maxz = (int) centre[2];
}
IJ.showStatus("Creating PSF image");
// Create a stack that can hold all the data.
ImageStack psf = createStack(stack, minz, maxz, magnification);
// For each spot
Statistics stats = new Statistics();
boolean ok = true;
for (int i = 0; ok && i < centres.size(); i++) {
double progress = (double) i / centres.size();
final double increment = 1.0 / (stack.getSize() * centres.size());
IJ.showProgress(progress);
double[] centre = centres.get(i);
// Extract the spot
float[][] spot = new float[stack.getSize()][];
Rectangle regionBounds = null;
for (int slice = 1; slice <= stack.getSize(); slice++) {
ImageExtractor ie = new ImageExtractor((float[]) stack.getPixels(slice), width, height);
if (regionBounds == null)
regionBounds = ie.getBoxRegionBounds((int) centre[0], (int) centre[1], boxRadius);
spot[slice - 1] = ie.crop(regionBounds);
}
int n = (int) centre[4];
final float b = getBackground(n, spot);
if (!subtractBackgroundAndWindow(spot, b, regionBounds.width, regionBounds.height, centre, loess)) {
Utils.log(" Spot %d was ignored", n);
continue;
}
stats.add(b);
// Adjust the centre using the crop
centre[0] -= regionBounds.x;
centre[1] -= regionBounds.y;
// This takes a long time so this should track progress
ok = addToPSF(maxz, magnification, psf, centre, spot, regionBounds, progress, increment, centreEachSlice);
}
if (interactiveMode) {
Utils.hide(TITLE_INTENSITY);
}
IJ.showProgress(1);
if (threadPool != null) {
threadPool.shutdownNow();
threadPool = null;
}
if (!ok || stats.getN() == 0)
return;
final double avSd = getAverage(averageSd, averageA, 2);
Utils.log(" Average background = %.2f, Av. SD = %s px", stats.getMean(), Utils.rounded(avSd, 4));
normalise(psf, maxz, avSd * magnification, false);
IJ.showProgress(1);
psfImp = Utils.display("PSF", psf);
psfImp.setSlice(maxz);
psfImp.resetDisplayRange();
psfImp.updateAndDraw();
double[][] fitCom = new double[2][psf.getSize()];
Arrays.fill(fitCom[0], Double.NaN);
Arrays.fill(fitCom[1], Double.NaN);
double fittedSd = fitPSF(psf, loess, maxz, averageRange.getMean(), fitCom);
// Compute the drift in the PSF:
// - Use fitted centre if available; otherwise find CoM for each frame
// - express relative to the average centre
double[][] com = calculateCentreOfMass(psf, fitCom, nmPerPixel / magnification);
double[] slice = Utils.newArray(psf.getSize(), 1, 1.0);
String title = TITLE + " CoM Drift";
Plot2 plot = new Plot2(title, "Slice", "Drift (nm)");
plot.addLabel(0, 0, "Red = X; Blue = Y");
//double[] limitsX = Maths.limits(com[0]);
//double[] limitsY = Maths.limits(com[1]);
double[] limitsX = getLimits(com[0]);
double[] limitsY = getLimits(com[1]);
plot.setLimits(1, psf.getSize(), Math.min(limitsX[0], limitsY[0]), Math.max(limitsX[1], limitsY[1]));
plot.setColor(Color.red);
plot.addPoints(slice, com[0], Plot.DOT);
plot.addPoints(slice, loess.smooth(slice, com[0]), Plot.LINE);
plot.setColor(Color.blue);
plot.addPoints(slice, com[1], Plot.DOT);
plot.addPoints(slice, loess.smooth(slice, com[1]), Plot.LINE);
Utils.display(title, plot);
// TODO - Redraw the PSF with drift correction applied.
// This means that the final image should have no drift.
// This is relevant when combining PSF images. It doesn't matter too much for simulations
// unless the drift is large.
// Add Image properties containing the PSF details
final double fwhm = getFWHM(psf, maxz);
psfImp.setProperty("Info", XmlUtils.toXML(new PSFSettings(maxz, nmPerPixel / magnification, nmPerSlice, stats.getN(), fwhm, createNote())));
Utils.log("%s : z-centre = %d, nm/Pixel = %s, nm/Slice = %s, %d images, PSF SD = %s nm, FWHM = %s px\n", psfImp.getTitle(), maxz, Utils.rounded(nmPerPixel / magnification, 3), Utils.rounded(nmPerSlice, 3), stats.getN(), Utils.rounded(fittedSd * nmPerPixel, 4), Utils.rounded(fwhm));
createInteractivePlots(psf, maxz, nmPerPixel / magnification, fittedSd * nmPerPixel);
IJ.showStatus("");
}
use of org.apache.commons.math3.stat.descriptive.rank.Max in project GDSC-SMLM by aherbert.
the class EMGainAnalysis method getFunction.
private MultivariateFunction getFunction(final int[] limits, final double[] y, final int max, final int maxEval) {
MultivariateFunction fun = new MultivariateFunction() {
int eval = 0;
public double value(double[] point) {
IJ.showProgress(++eval, maxEval);
if (Utils.isInterrupted())
throw new TooManyEvaluationsException(maxEval);
// Compute the sum of squares between the two functions
double photons = point[0];
double gain = point[1];
double noise = point[2];
int bias = (int) Math.round(point[3]);
//System.out.printf("[%d] = %s\n", eval, Arrays.toString(point));
final double[] g = pdf(max, photons, gain, noise, bias);
double ss = 0;
for (int c = limits[0]; c <= limits[1]; c++) {
final double d = g[c] - y[c];
ss += d * d;
}
return ss;
}
};
return fun;
}
use of org.apache.commons.math3.stat.descriptive.rank.Max in project GDSC-SMLM by aherbert.
the class EMGainAnalysis method fit.
/**
* Fit the EM-gain distribution (Gaussian * Gamma)
*
* @param h
* The distribution
*/
private void fit(int[] h) {
final int[] limits = limits(h);
final double[] x = getX(limits);
final double[] y = getY(h, limits);
Plot2 plot = new Plot2(TITLE, "ADU", "Frequency");
double yMax = Maths.max(y);
plot.setLimits(limits[0], limits[1], 0, yMax);
plot.setColor(Color.black);
plot.addPoints(x, y, Plot2.DOT);
Utils.display(TITLE, plot);
// Estimate remaining parameters.
// Assuming a gamma_distribution(shape,scale) then mean = shape * scale
// scale = gain
// shape = Photons = mean / gain
double mean = getMean(h) - bias;
// Note: if the bias is too high then the mean will be negative. Just move the bias.
while (mean < 0) {
bias -= 1;
mean += 1;
}
double photons = mean / gain;
if (simulate)
Utils.log("Simulated bias=%d, gain=%s, noise=%s, photons=%s", (int) _bias, Utils.rounded(_gain), Utils.rounded(_noise), Utils.rounded(_photons));
Utils.log("Estimate bias=%d, gain=%s, noise=%s, photons=%s", (int) bias, Utils.rounded(gain), Utils.rounded(noise), Utils.rounded(photons));
final int max = (int) x[x.length - 1];
double[] g = pdf(max, photons, gain, noise, (int) bias);
plot.setColor(Color.blue);
plot.addPoints(x, g, Plot2.LINE);
Utils.display(TITLE, plot);
// Perform a fit
CustomPowellOptimizer o = new CustomPowellOptimizer(1e-6, 1e-16, 1e-6, 1e-16);
double[] startPoint = new double[] { photons, gain, noise, bias };
int maxEval = 3000;
String[] paramNames = { "Photons", "Gain", "Noise", "Bias" };
// Set bounds
double[] lower = new double[] { 0, 0.5 * gain, 0, bias - noise };
double[] upper = new double[] { 2 * photons, 2 * gain, gain, bias + noise };
// Restart until converged.
// TODO - Maybe fix this with a better optimiser. This needs to be tested on real data.
PointValuePair solution = null;
for (int iter = 0; iter < 3; iter++) {
IJ.showStatus("Fitting histogram ... Iteration " + iter);
try {
// Basic Powell optimiser
MultivariateFunction fun = getFunction(limits, y, max, maxEval);
PointValuePair optimum = o.optimize(new MaxEval(maxEval), new ObjectiveFunction(fun), GoalType.MINIMIZE, new InitialGuess((solution == null) ? startPoint : solution.getPointRef()));
if (solution == null || optimum.getValue() < solution.getValue()) {
double[] point = optimum.getPointRef();
// Check the bounds
for (int i = 0; i < point.length; i++) {
if (point[i] < lower[i] || point[i] > upper[i]) {
throw new RuntimeException(String.format("Fit out of of estimated range: %s %f", paramNames[i], point[i]));
}
}
solution = optimum;
}
} catch (Exception e) {
IJ.log("Powell error: " + e.getMessage());
if (e instanceof TooManyEvaluationsException) {
maxEval = (int) (maxEval * 1.5);
}
}
try {
// Bounded Powell optimiser
MultivariateFunction fun = getFunction(limits, y, max, maxEval);
MultivariateFunctionMappingAdapter adapter = new MultivariateFunctionMappingAdapter(fun, lower, upper);
PointValuePair optimum = o.optimize(new MaxEval(maxEval), new ObjectiveFunction(adapter), GoalType.MINIMIZE, new InitialGuess(adapter.boundedToUnbounded((solution == null) ? startPoint : solution.getPointRef())));
double[] point = adapter.unboundedToBounded(optimum.getPointRef());
optimum = new PointValuePair(point, optimum.getValue());
if (solution == null || optimum.getValue() < solution.getValue()) {
solution = optimum;
}
} catch (Exception e) {
IJ.log("Bounded Powell error: " + e.getMessage());
if (e instanceof TooManyEvaluationsException) {
maxEval = (int) (maxEval * 1.5);
}
}
}
IJ.showStatus("");
IJ.showProgress(1);
if (solution == null) {
Utils.log("Failed to fit the distribution");
return;
}
double[] point = solution.getPointRef();
photons = point[0];
gain = point[1];
noise = point[2];
bias = (int) Math.round(point[3]);
String label = String.format("Fitted bias=%d, gain=%s, noise=%s, photons=%s", (int) bias, Utils.rounded(gain), Utils.rounded(noise), Utils.rounded(photons));
Utils.log(label);
if (simulate) {
Utils.log("Relative Error bias=%s, gain=%s, noise=%s, photons=%s", Utils.rounded(relativeError(bias, _bias)), Utils.rounded(relativeError(gain, _gain)), Utils.rounded(relativeError(noise, _noise)), Utils.rounded(relativeError(photons, _photons)));
}
// Show the PoissonGammaGaussian approximation
double[] f = null;
if (showApproximation) {
f = new double[x.length];
PoissonGammaGaussianFunction fun = new PoissonGammaGaussianFunction(1.0 / gain, noise);
final double expected = photons * gain;
for (int i = 0; i < f.length; i++) {
f[i] = fun.likelihood(x[i] - bias, expected);
//System.out.printf("x=%d, g=%f, f=%f, error=%f\n", (int) x[i], g[i], f[i],
// gdsc.smlm.fitting.utils.DoubleEquality.relativeError(g[i], f[i]));
}
yMax = Maths.maxDefault(yMax, f);
}
// Replot
g = pdf(max, photons, gain, noise, (int) bias);
plot = new Plot2(TITLE, "ADU", "Frequency");
plot.setLimits(limits[0], limits[1], 0, yMax * 1.05);
plot.setColor(Color.black);
plot.addPoints(x, y, Plot2.DOT);
plot.setColor(Color.red);
plot.addPoints(x, g, Plot2.LINE);
plot.addLabel(0, 0, label);
if (showApproximation) {
plot.setColor(Color.blue);
plot.addPoints(x, f, Plot2.LINE);
}
Utils.display(TITLE, plot);
}
use of org.apache.commons.math3.stat.descriptive.rank.Max in project GDSC-SMLM by aherbert.
the class DensityImage method computeRipleysPlot.
/**
* Compute the Ripley's L-function for user selected radii and show it on a plot.
*
* @param results
*/
private void computeRipleysPlot(MemoryPeakResults results) {
ExtendedGenericDialog gd = new ExtendedGenericDialog(TITLE);
gd.addMessage("Compute Ripley's L(r) - r plot");
gd.addNumericField("Min_radius", minR, 2);
gd.addNumericField("Max_radius", maxR, 2);
gd.addNumericField("Increment", incrementR, 2);
gd.addCheckbox("Confidence_intervals", confidenceIntervals);
gd.showDialog();
if (gd.wasCanceled())
return;
minR = gd.getNextNumber();
maxR = gd.getNextNumber();
incrementR = gd.getNextNumber();
confidenceIntervals = gd.getNextBoolean();
if (minR > maxR || incrementR < 0 || gd.invalidNumber()) {
IJ.error(TITLE, "Invalid radius parameters");
return;
}
DensityManager dm = createDensityManager(results);
double[][] values = calculateLScores(dm);
// 99% confidence intervals
final int iterations = (confidenceIntervals) ? 99 : 0;
double[] upper = null;
double[] lower = null;
Rectangle bounds = results.getBounds();
// Use a uniform distribution for the coordinates
HaltonSequenceGenerator dist = new HaltonSequenceGenerator(2);
dist.skipTo(new Well19937c(System.currentTimeMillis() + System.identityHashCode(this)).nextInt());
for (int i = 0; i < iterations; i++) {
IJ.showProgress(i, iterations);
IJ.showStatus(String.format("L-score confidence interval %d / %d", i + 1, iterations));
// Randomise coordinates
float[] x = new float[results.size()];
float[] y = new float[x.length];
for (int j = x.length; j-- > 0; ) {
final double[] d = dist.nextVector();
x[j] = (float) (d[0] * bounds.width);
y[j] = (float) (d[1] * bounds.height);
}
double[][] values2 = calculateLScores(new DensityManager(x, y, bounds));
if (upper == null) {
upper = values2[1];
lower = new double[upper.length];
System.arraycopy(upper, 0, lower, 0, upper.length);
} else {
for (int m = upper.length; m-- > 0; ) {
if (upper[m] < values2[1][m])
upper[m] = values2[1][m];
if (lower[m] > values2[1][m])
lower[m] = values2[1][m];
}
}
}
String title = results.getName() + " Ripley's (L(r) - r) / r";
Plot2 plot = new Plot2(title, "Radius", "(L(r) - r) / r", values[0], values[1]);
// Get the limits
double yMin = min(0, values[1]);
double yMax = max(0, values[1]);
if (iterations > 0) {
yMin = min(yMin, lower);
yMax = max(yMax, upper);
}
plot.setLimits(0, values[0][values[0].length - 1], yMin, yMax);
if (iterations > 0) {
plot.setColor(Color.BLUE);
plot.addPoints(values[0], upper, 1);
plot.setColor(Color.RED);
plot.addPoints(values[0], lower, 1);
plot.setColor(Color.BLACK);
}
Utils.display(title, plot);
}
use of org.apache.commons.math3.stat.descriptive.rank.Max in project GDSC-SMLM by aherbert.
the class JumpDistanceAnalysis method saveFitCurve.
private void saveFitCurve(double[] params, double[][] jdHistogram) {
if (curveLogger == null)
return;
final int nPoints = curveLogger.getNumberOfCurvePoints();
if (nPoints <= 1)
return;
Function function;
if (params.length == 1)
function = new JumpDistanceCumulFunction(null, null, 0);
else
function = new MixedJumpDistanceCumulFunction(null, null, 0, params.length / 2);
final double max = jdHistogram[0][jdHistogram[0].length - 1];
final double interval = max / nPoints;
final double[] x = new double[nPoints + 1];
final double[] y = new double[nPoints + 1];
for (int i = 0; i < nPoints; i++) {
x[i] = i * interval;
y[i] = function.evaluate(x[i], params);
}
x[nPoints] = max;
y[nPoints] = function.evaluate(max, params);
if (params.length == 1)
curveLogger.saveSinglePopulationCurve(new double[][] { x, y });
else
curveLogger.saveMixedPopulationCurve(new double[][] { x, y });
}
Aggregations