use of uk.ac.sussex.gdsc.core.utils.Statistics in project GDSC-SMLM by aherbert.
the class CreateData method setNoise.
/**
* Sets the noise in the results if missing.
*
* @param results the results
* @param imp the imp
*/
private static void setNoise(MemoryPeakResults results, ImagePlus imp) {
// Loaded results do not have noise
if (results.hasNoise()) {
return;
}
IJ.showStatus("Estimating noise ...");
// Compute noise per frame
final ImageStack stack = imp.getImageStack();
final int width = stack.getWidth();
final int height = stack.getHeight();
final IJImageSource source = new IJImageSource(imp);
final float[] noise = new float[source.getFrames() + 1];
source.setReadHint(ReadHint.SEQUENTIAL);
source.open();
for (int slice = 1; slice < noise.length; slice++) {
final float[] data = source.next();
// Use the trimmed method as there may be a lot of spots in the frame
noise[slice] = FitWorker.estimateNoise(data, width, height, NoiseEstimatorMethod.QUICK_RESIDUALS_LEAST_TRIMMED_OF_SQUARES);
}
// Statistics stats = Statistics.create(Arrays.copyOfRange(noise, 1, noise.length));
// System.out.printf("Noise = %.3f +/- %.3f (%d)\n", stats.getMean(),
// stats.getStandardDeviation(), stats.getN());
// Convert noise units from counts to the result format
final TypeConverter<IntensityUnit> c = results.getIntensityConverter(IntensityUnit.COUNT);
for (int i = 0; i < noise.length; i++) {
noise[i] = c.convertBack(noise[i]);
}
results.forEach((PeakResultProcedure) result -> {
if (result.getFrame() < noise.length) {
result.setNoise(noise[result.getFrame()]);
}
});
}
use of uk.ac.sussex.gdsc.core.utils.Statistics in project GDSC-SMLM by aherbert.
the class CreateData method showSummary.
private double showSummary(List<? extends FluorophoreSequenceModel> fluorophores, List<LocalisationModel> localisations) {
IJ.showStatus("Calculating statistics ...");
final Statistics[] stats = new Statistics[NAMES.length];
for (int i = 0; i < stats.length; i++) {
stats[i] = (settings.getShowHistograms() || alwaysRemoveOutliers[i]) ? new StoredDataStatistics() : new Statistics();
}
// Find the largest timepoint
final ImagePlus outputImp = WindowManager.getImage(benchmarkImageId);
int frameCount;
if (outputImp == null) {
sortLocalisationsByTime(localisations);
frameCount = localisations.get(localisations.size() - 1).getTime();
} else {
frameCount = outputImp.getStackSize();
}
final int[] countHistogram = new int[frameCount + 1];
// Use the localisations that were drawn to create the sampled on/off times
rebuildNeighbours(localisations);
// Assume that there is at least one localisation
final LocalisationModel first = localisations.get(0);
// The current localisation
int currentId = first.getId();
// The last time this localisation was on
int lastT = first.getTime();
// Number of blinks
int blinks = 0;
// On-time of current pulse
int currentT = 0;
double signal = 0;
final double centreOffset = settings.getSize() * 0.5;
// Used to convert the sampled times in frames into seconds
final double framesPerSecond = 1000.0 / settings.getExposureTime();
// final double gain = new CreateDataSettingsHelper(settings).getTotalGainSafe();
for (final LocalisationModel l : localisations) {
final double[] data = l.getData();
if (data == null) {
throw new IllegalStateException("No localisation data. This should not happen!");
}
final double noise = data[1];
final double sx = data[2];
final double sy = data[3];
final double intensityInPhotons = data[4];
// Q. What if the noise is zero, i.e. no background photon / read noise?
// Just ignore it at current. This is only an approximation to the SNR estimate
// if this is not a Gaussian spot.
final double snr = Gaussian2DPeakResultHelper.getMeanSignalUsingP05(intensityInPhotons, sx, sy) / noise;
stats[SIGNAL].add(intensityInPhotons);
stats[NOISE].add(noise);
if (noise != 0) {
stats[SNR].add(snr);
}
// if (l.isContinuous())
if (l.getNext() != null && l.getPrevious() != null) {
stats[SIGNAL_CONTINUOUS].add(intensityInPhotons);
if (noise != 0) {
stats[SNR_CONTINUOUS].add(snr);
}
}
final int id = l.getId();
// Check if this a new fluorophore
if (currentId != id) {
// Add previous fluorophore
stats[SAMPLED_BLINKS].add(blinks);
stats[SAMPLED_T_ON].add(currentT / framesPerSecond);
stats[TOTAL_SIGNAL].add(signal);
// Reset
blinks = 0;
currentT = 1;
currentId = id;
signal = intensityInPhotons;
} else {
signal += intensityInPhotons;
// Check if the current fluorophore pulse is broken (i.e. a blink)
if (l.getTime() - 1 > lastT) {
blinks++;
stats[SAMPLED_T_ON].add(currentT / framesPerSecond);
currentT = 1;
stats[SAMPLED_T_OFF].add(((l.getTime() - 1) - lastT) / framesPerSecond);
} else {
// Continuous on-time
currentT++;
}
}
lastT = l.getTime();
countHistogram[lastT]++;
stats[X].add((l.getX() - centreOffset) * settings.getPixelPitch());
stats[Y].add((l.getY() - centreOffset) * settings.getPixelPitch());
stats[Z].add(l.getZ() * settings.getPixelPitch());
}
// Final fluorophore
stats[SAMPLED_BLINKS].add(blinks);
stats[SAMPLED_T_ON].add(currentT / framesPerSecond);
stats[TOTAL_SIGNAL].add(signal);
// Samples per frame
for (int t = 1; t < countHistogram.length; t++) {
stats[SAMPLES].add(countHistogram[t]);
}
if (fluorophores != null) {
for (final FluorophoreSequenceModel f : fluorophores) {
stats[BLINKS].add(f.getNumberOfBlinks());
// On-time
for (final double t : f.getOnTimes()) {
stats[T_ON].add(t);
}
// Off-time
for (final double t : f.getOffTimes()) {
stats[T_OFF].add(t);
}
}
} else {
// show no blinks
stats[BLINKS].add(0);
stats[T_ON].add(1);
}
if (results != null) {
// Convert depth-of-field to pixels
final double depth = settings.getDepthOfField() / settings.getPixelPitch();
try {
// Get widths
final WidthResultProcedure wp = new WidthResultProcedure(results, DistanceUnit.PIXEL);
wp.getW();
stats[WIDTH].add(wp.wx);
} catch (final DataException ex) {
ImageJUtils.log("Unable to compute width: " + ex.getMessage());
}
try {
// Get z depth
final StandardResultProcedure sp = new StandardResultProcedure(results, DistanceUnit.PIXEL);
sp.getXyz();
// Get precision
final PrecisionResultProcedure pp = new PrecisionResultProcedure(results);
pp.getPrecision();
stats[PRECISION].add(pp.precisions);
for (int i = 0; i < pp.size(); i++) {
if (Math.abs(sp.z[i]) < depth) {
stats[PRECISION_IN_FOCUS].add(pp.precisions[i]);
}
}
} catch (final DataException ex) {
ImageJUtils.log("Unable to compute LSE precision: " + ex.getMessage());
}
// Compute density per frame. Multi-thread for speed
if (settings.getDensityRadius() > 0) {
final int threadCount = Prefs.getThreads();
final Ticker ticker = ImageJUtils.createTicker(results.getLastFrame(), threadCount, "Calculating density ...");
final ExecutorService threadPool = Executors.newFixedThreadPool(threadCount);
final List<Future<?>> futures = new LinkedList<>();
final TFloatArrayList coordsX = new TFloatArrayList();
final TFloatArrayList coordsY = new TFloatArrayList();
final Statistics densityStats = stats[DENSITY];
final float radius = (float) (settings.getDensityRadius() * getHwhm());
final Rectangle bounds = results.getBounds();
final double area = (double) bounds.width * bounds.height;
// Store the density for each result.
final int[] allDensity = new int[results.size()];
final FrameCounter counter = results.newFrameCounter();
results.forEach((PeakResultProcedure) result -> {
if (counter.advance(result.getFrame())) {
counter.increment(runDensityCalculation(threadPool, futures, coordsX, coordsY, densityStats, radius, area, allDensity, counter.getCount(), ticker));
}
coordsX.add(result.getXPosition());
coordsY.add(result.getYPosition());
});
runDensityCalculation(threadPool, futures, coordsX, coordsY, densityStats, radius, area, allDensity, counter.getCount(), ticker);
ConcurrencyUtils.waitForCompletionUnchecked(futures);
threadPool.shutdown();
ImageJUtils.finished();
// Split results into singles (density = 0) and clustered (density > 0)
final MemoryPeakResults singles = copyMemoryPeakResults("No Density");
final MemoryPeakResults clustered = copyMemoryPeakResults("Density");
counter.reset();
results.forEach((PeakResultProcedure) result -> {
final int density = allDensity[counter.getAndIncrement()];
result.setOrigValue(density);
if (density == 0) {
singles.add(result);
} else {
clustered.add(result);
}
});
}
}
final StringBuilder sb = new StringBuilder();
sb.append(datasetNumber).append('\t');
if (settings.getCameraType() == CameraType.SCMOS) {
sb.append("sCMOS (").append(settings.getCameraModelName()).append(") ");
final Rectangle bounds = cameraModel.getBounds();
sb.append(" ").append(bounds.x).append(",").append(bounds.y);
final int size = settings.getSize();
sb.append(" ").append(size).append("x").append(size);
} else if (CalibrationProtosHelper.isCcdCameraType(settings.getCameraType())) {
sb.append(CalibrationProtosHelper.getName(settings.getCameraType()));
final int size = settings.getSize();
sb.append(" ").append(size).append("x").append(size);
if (settings.getCameraType() == CameraType.EMCCD) {
sb.append(" EM=").append(settings.getEmGain());
}
sb.append(" CG=").append(settings.getCameraGain());
sb.append(" RN=").append(settings.getReadNoise());
sb.append(" B=").append(settings.getBias());
} else {
throw new IllegalStateException();
}
sb.append(" QE=").append(settings.getQuantumEfficiency()).append('\t');
sb.append(settings.getPsfModel());
if (psfModelType == PSF_MODEL_IMAGE) {
sb.append(" Image").append(settings.getPsfImageName());
} else if (psfModelType == PSF_MODEL_ASTIGMATISM) {
sb.append(" model=").append(settings.getAstigmatismModel());
} else {
sb.append(" DoF=").append(MathUtils.rounded(settings.getDepthOfFocus()));
if (settings.getEnterWidth()) {
sb.append(" SD=").append(MathUtils.rounded(settings.getPsfSd()));
} else {
sb.append(" λ=").append(MathUtils.rounded(settings.getWavelength()));
sb.append(" NA=").append(MathUtils.rounded(settings.getNumericalAperture()));
}
}
sb.append('\t');
sb.append((fluorophores == null) ? localisations.size() : fluorophores.size()).append('\t');
sb.append(stats[SAMPLED_BLINKS].getN() + (int) stats[SAMPLED_BLINKS].getSum()).append('\t');
sb.append(localisations.size()).append('\t');
sb.append(frameCount).append('\t');
sb.append(MathUtils.rounded(areaInUm)).append('\t');
sb.append(MathUtils.rounded(localisations.size() / (areaInUm * frameCount), 4)).append('\t');
sb.append(MathUtils.rounded(getHwhm(), 4)).append('\t');
double sd = getPsfSd();
sb.append(MathUtils.rounded(sd, 4)).append('\t');
sd *= settings.getPixelPitch();
final double sa = PsfCalculator.squarePixelAdjustment(sd, settings.getPixelPitch()) / settings.getPixelPitch();
sb.append(MathUtils.rounded(sa, 4)).append('\t');
// Width not valid for the Image PSF.
// Q. Is this true? We can approximate the FHWM for a spot-like image PSF.
final int nStats = (psfModelType == PSF_MODEL_IMAGE) ? stats.length - 1 : stats.length;
for (int i = 0; i < nStats; i++) {
final double centre = (alwaysRemoveOutliers[i]) ? ((StoredDataStatistics) stats[i]).getStatistics().getPercentile(50) : stats[i].getMean();
sb.append(MathUtils.rounded(centre, 4)).append('\t');
}
createSummaryTable().accept(sb.toString());
// Show histograms
if (settings.getShowHistograms() && !java.awt.GraphicsEnvironment.isHeadless()) {
IJ.showStatus("Calculating histograms ...");
final boolean[] chosenHistograms = getChoosenHistograms();
final WindowOrganiser wo = new WindowOrganiser();
final HistogramPlotBuilder builder = new HistogramPlotBuilder(TITLE);
for (int i = 0; i < NAMES.length; i++) {
if (chosenHistograms[i]) {
builder.setData((StoredDataStatistics) stats[i]).setName(NAMES[i]).setIntegerBins(integerDisplay[i]).setRemoveOutliersOption((settings.getRemoveOutliers() || alwaysRemoveOutliers[i]) ? 2 : 0).setNumberOfBins(settings.getHistogramBins()).show(wo);
}
}
wo.tile();
}
IJ.showStatus("");
return stats[SIGNAL].getMean();
}
use of uk.ac.sussex.gdsc.core.utils.Statistics in project GDSC-SMLM by aherbert.
the class PcPalmFitting method combineCurves.
private static double[][] combineCurves(ArrayList<CorrelationResult> results, int maxSize) {
final double[][] gr = new double[3][maxSize];
final Statistics[] grStats = new Statistics[maxSize];
for (int i = 0; i < maxSize; i++) {
grStats[i] = new Statistics();
}
for (final CorrelationResult r : results) {
for (int i = 0; i < r.gr[0].length; i++) {
// All scales should be the same so over-write is OK
gr[0][i] = r.gr[0][i];
// NaN values can be generated so ignore them
if (!Double.isNaN(r.gr[1][i])) {
grStats[i].add(r.gr[1][i]);
}
}
}
for (int i = 0; i < maxSize; i++) {
gr[1][i] = grStats[i].getMean();
gr[2][i] = grStats[i].getStandardError();
}
return gr;
}
use of uk.ac.sussex.gdsc.core.utils.Statistics in project GDSC-SMLM by aherbert.
the class BlinkEstimatorTest method estimateBlinking.
private TIntHashSet estimateBlinking(UniformRandomProvider rg, double blinkingRate, double ton, double toff, int particles, double fixedFraction, boolean timeAtLowerBound, boolean doAssert) {
Assumptions.assumeTrue(TestSettings.allow(TestComplexity.MAXIMUM));
final SpatialIllumination activationIllumination = new UniformIllumination(100);
int totalSteps = 100;
final double eAct = totalSteps * 0.3 * activationIllumination.getAveragePhotons();
final ImageModel imageModel = new ActivationEnergyImageModel(eAct, activationIllumination, ton, 0, toff, 0, blinkingRate, rg);
final double[] max = new double[] { 256, 256, 32 };
final double[] min = new double[3];
final SpatialDistribution distribution = new UniformDistribution(min, max, rg.nextInt());
final List<CompoundMoleculeModel> compounds = new ArrayList<>(1);
final CompoundMoleculeModel c = new CompoundMoleculeModel(1, 0, 0, 0, Arrays.asList(new MoleculeModel(0, 0, 0, 0)));
c.setDiffusionRate(diffusionRate);
c.setDiffusionType(DiffusionType.RANDOM_WALK);
compounds.add(c);
final List<CompoundMoleculeModel> molecules = imageModel.createMolecules(compounds, particles, distribution, false);
// Activate fluorophores
final List<? extends FluorophoreSequenceModel> fluorophores = imageModel.createFluorophores(molecules, totalSteps);
totalSteps = checkTotalSteps(totalSteps, fluorophores);
final List<LocalisationModel> localisations = imageModel.createImage(molecules, fixedFraction, totalSteps, photons, 0.5, false);
// // Remove localisations to simulate missed counts.
// List<LocalisationModel> newLocalisations = new
// ArrayList<LocalisationModel>(localisations.size());
// boolean[] id = new boolean[fluorophores.size() + 1];
// Statistics photonStats = new Statistics();
// for (LocalisationModel l : localisations)
// {
// photonStats.add(l.getIntensity());
// // Remove by intensity threshold and optionally at random.
// if (l.getIntensity() < minPhotons || rand.nextDouble() < pDelete)
// continue;
// newLocalisations.add(l);
// id[l.getId()] = true;
// }
// localisations = newLocalisations;
// logger.info("Photons = %f", photonStats.getMean());
//
// List<FluorophoreSequenceModel> newFluorophores = new
// ArrayList<FluorophoreSequenceModel>(fluorophores.size());
// for (FluorophoreSequenceModel f : fluorophores)
// {
// if (id[f.getId()])
// newFluorophores.add(f);
// }
// fluorophores = newFluorophores;
final MemoryPeakResults results = new MemoryPeakResults();
final CalibrationWriter calibration = new CalibrationWriter();
calibration.setNmPerPixel(pixelPitch);
calibration.setExposureTime(msPerFrame);
calibration.setCountPerPhoton(1);
results.setCalibration(calibration.getCalibration());
results.setPsf(PsfHelper.create(PSFType.ONE_AXIS_GAUSSIAN_2D));
final float b = 0;
float intensity;
final float z = 0;
for (final LocalisationModel l : localisations) {
// Remove by intensity threshold and optionally at random.
if (l.getIntensity() < minPhotons || rg.nextDouble() < probabilityDelete) {
continue;
}
final int frame = l.getTime();
intensity = (float) l.getIntensity();
final float x = (float) l.getX();
final float y = (float) l.getY();
final float[] params = Gaussian2DPeakResultHelper.createParams(b, intensity, x, y, z, psfWidth);
results.add(frame, 0, 0, 0, 0, 0, 0, params, null);
}
// Add random localisations
// Intensity doesn't matter at the moment for tracing
intensity = (float) photons;
for (int i = (int) (localisations.size() * probabilityAdd); i-- > 0; ) {
final int frame = 1 + rg.nextInt(totalSteps);
final float x = (float) (rg.nextDouble() * max[0]);
final float y = (float) (rg.nextDouble() * max[1]);
final float[] params = Gaussian2DPeakResultHelper.createParams(b, intensity, x, y, z, psfWidth);
results.add(frame, 0, 0, 0, 0, 0, 0, params, null);
}
// Get actual simulated stats ...
final Statistics statsNBlinks = new Statistics();
final Statistics statsTOn = new Statistics();
final Statistics statsTOff = new Statistics();
final Statistics statsSampledNBlinks = new Statistics();
final Statistics statsSampledTOn = new Statistics();
final StoredDataStatistics statsSampledTOff = new StoredDataStatistics();
for (final FluorophoreSequenceModel f : fluorophores) {
statsNBlinks.add(f.getNumberOfBlinks());
statsTOn.add(f.getOnTimes());
statsTOff.add(f.getOffTimes());
final int[] on = f.getSampledOnTimes();
statsSampledNBlinks.add(on.length);
statsSampledTOn.add(on);
statsSampledTOff.add(f.getSampledOffTimes());
}
logger.info(FunctionUtils.getSupplier("N = %d (%d), N-blinks = %f, tOn = %f, tOff = %f, Fixed = %f", fluorophores.size(), localisations.size(), blinkingRate, ton, toff, fixedFraction));
logger.info(FunctionUtils.getSupplier("Actual N-blinks = %f (%f), tOn = %f (%f), tOff = %f (%f), 95%% = %f, max = %f", statsNBlinks.getMean(), statsSampledNBlinks.getMean(), statsTOn.getMean(), statsSampledTOn.getMean(), statsTOff.getMean(), statsSampledTOff.getMean(), statsSampledTOff.getStatistics().getPercentile(95), statsSampledTOff.getStatistics().getMax()));
logger.info("-=-=--=-");
final BlinkEstimator be = new BlinkEstimator();
be.setMaxDarkTime((int) (toff * 10));
be.setMsPerFrame(msPerFrame);
be.setRelativeDistance(false);
final double d = ImageModel.getRandomMoveDistance(diffusionRate);
be.setSearchDistance((fixedFraction < 1) ? Math.sqrt(2 * d * d) * 3 : 0);
be.setTimeAtLowerBound(timeAtLowerBound);
// Assertions.assertTrue("Max dark time must exceed the dark time of the data (otherwise no
// plateau)",
// be.maxDarkTime > statsSampledTOff.getStatistics().getMax());
final int nMolecules = fluorophores.size();
if (usePopulationStatistics) {
blinkingRate = statsNBlinks.getMean();
toff = statsTOff.getMean();
} else {
blinkingRate = statsSampledNBlinks.getMean();
toff = statsSampledTOff.getMean();
}
// See if any fitting regime gets a correct answer
final TIntHashSet ok = new TIntHashSet();
for (int numberOfFittedPoints = MIN_FITTED_POINTS; numberOfFittedPoints <= MAX_FITTED_POINTS; numberOfFittedPoints++) {
be.setNumberOfFittedPoints(numberOfFittedPoints);
be.computeBlinkingRate(results, true);
final double moleculesError = DoubleEquality.relativeError(nMolecules, be.getNMolecules());
final double blinksError = DoubleEquality.relativeError(blinkingRate, be.getNBlinks());
final double offError = DoubleEquality.relativeError(toff * msPerFrame, be.getTOff());
logger.info(FunctionUtils.getSupplier("Error %d: N = %f, blinks = %f, tOff = %f : %f", numberOfFittedPoints, moleculesError, blinksError, offError, (moleculesError + blinksError + offError) / 3));
if (moleculesError < relativeError && blinksError < relativeError && offError < relativeError) {
ok.add(numberOfFittedPoints);
logger.info("-=-=--=-");
logger.info(FunctionUtils.getSupplier("*** Correct at %d fitted points ***", numberOfFittedPoints));
if (doAssert) {
break;
}
}
// if (!be.isIncreaseNFittedPoints())
// break;
}
logger.info("-=-=--=-");
if (doAssert) {
Assertions.assertFalse(ok.isEmpty());
}
// relativeError);
return ok;
}
use of uk.ac.sussex.gdsc.core.utils.Statistics in project GDSC-SMLM by aherbert.
the class ResultsImageSampler method createResultSamples.
/**
* Creates the result samples. Do this by storing the coordinates at the region index.
*/
private void createResultSamples() {
final TLongObjectHashMap<ResultsSample> map = new TLongObjectHashMap<>(results.size());
ResultsSample next = ResultsSample.create(-1);
// For SNR computation
Object[] pixelArray = stack.getImageArray();
int width = stack.getWidth();
int height = stack.getHeight();
float[] buffer = null;
// Use a null float[] as this is not used for the getBoxRegionBounds method
ImageExtractor ie = ImageExtractor.wrap(null, width, height);
for (final PeakResult p : results.toArray()) {
// Avoid invalid slices
if (p.getFrame() < 1 || p.getFrame() > stack.getSize()) {
continue;
}
// Avoid low SNR results. Get the SNR using a 3x3 region around the spot.
final Rectangle bounds = ie.getBoxRegionBounds((int) p.getXPosition(), (int) p.getYPosition(), 1);
buffer = ImageJImageConverter.getData(pixelArray[p.getFrame()], width, height, bounds, buffer);
final Statistics stats = new Statistics();
stats.add(buffer, 0, bounds.width * bounds.height);
// SNR will be NaN if the region has no size
final double snr = stats.getMean() / stats.getStandardDeviation();
if (snr > 3) {
final long index = getIndex(p.getXPosition(), p.getYPosition(), p.getFrame());
ResultsSample current = map.putIfAbsent(index, next);
if (current == null) {
// If the return value is null then this is a new insertion.
// Set the current value as the one we just added and create the next insertion object.
current = next;
current.index = index;
next = ResultsSample.create(-1);
}
current.add(p);
}
}
// Create an array of all the sample entries.
// This is used to sample regions by density.
data = map.values(new ResultsSample[map.size()]);
}
Aggregations