use of uk.ac.sussex.gdsc.core.logging.Ticker 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.logging.Ticker in project GDSC-SMLM by aherbert.
the class BenchmarkSpotFilter method getSimulationCoordinates.
/**
* Gets the coordinates for the current simulation. This extract all the results in memory into a
* list per frame and is cached for the simulation Id.
*
* @return the coordinates
*/
private TIntObjectHashMap<PsfSpot[]> getSimulationCoordinates() {
Pair<Integer, TIntObjectHashMap<PsfSpot[]>> coords = coordinateCache.get();
if (coords.getKey() != simulationParameters.id) {
// Always use float coordinates.
// The Worker adds a pixel offset for the spot coordinates.
final TIntObjectHashMap<List<Coordinate>> coordinates = ResultsMatchCalculator.getCoordinates(results, false);
// Spot PSFs may overlap so we must determine the amount of signal overlap and amplitude
// effect for each spot...
final int nThreads = Prefs.getThreads();
final BlockingQueue<Integer> jobs = new ArrayBlockingQueue<>(nThreads * 2);
final List<OverlapWorker> workers = new LinkedList<>();
final List<Thread> threads = new LinkedList<>();
final Ticker overlapTicker = ImageJUtils.createTicker(coordinates.size(), nThreads, "Computing PSF overlap ...");
for (int i = 0; i < nThreads; i++) {
final OverlapWorker worker = new OverlapWorker(jobs, coordinates, overlapTicker);
final Thread t = new Thread(worker);
workers.add(worker);
threads.add(t);
t.start();
}
// Process the frames
coordinates.forEachKey(value -> {
put(jobs, value);
return true;
});
// Finish all the worker threads by passing in a null job
for (int i = 0; i < threads.size(); i++) {
put(jobs, -1);
}
// Wait for all to finish
final TIntObjectHashMap<PsfSpot[]> actualCoordinates = new TIntObjectHashMap<>();
for (int i = 0; i < threads.size(); i++) {
try {
threads.get(i).join();
} catch (final InterruptedException ex) {
Thread.currentThread().interrupt();
throw new ConcurrentRuntimeException("Unexpected interrupt", ex);
}
actualCoordinates.putAll(workers.get(i).coordinates);
}
threads.clear();
// For testing
final SimpleRegression regression = new SimpleRegression(false);
for (final PsfSpot[] spots : actualCoordinates.valueCollection()) {
for (final PsfSpot spot : spots) {
regression.addData(spot.getAmplitude(), calculator.getAmplitude(spot.getPeakResult().getParameters()));
}
}
ImageJUtils.log("PixelAmplitude vs Amplitude = %f, slope=%f, n=%d", regression.getR(), regression.getSlope(), regression.getN());
ImageJUtils.finished();
coords = Pair.of(simulationParameters.id, actualCoordinates);
coordinateCache.set(coords);
}
return coords.getRight();
}
use of uk.ac.sussex.gdsc.core.logging.Ticker in project GDSC-SMLM by aherbert.
the class DoubletAnalysis method runFitting.
private void runFitting() {
referenceResults.set(null);
final ImageStack stack = imp.getImageStack();
// Get the coordinates per frame
final TIntObjectHashMap<List<Coordinate>> actualCoordinates = ResultsMatchCalculator.getCoordinates(results, false);
final long[] sumCount = new long[1];
actualCoordinates.forEachValue(list -> {
sumCount[0] += list.size();
return true;
});
final double density = 1e6 * sumCount[0] / (simulationParameters.pixelPitch * simulationParameters.pixelPitch * results.getBounds().getWidth() * results.getBounds().getHeight() * actualCoordinates.size());
// Create a pool of workers
final int nThreads = Prefs.getThreads();
final BlockingQueue<Integer> jobs = new ArrayBlockingQueue<>(nThreads * 2);
final Ticker ticker = ImageJUtils.createTicker(actualCoordinates.size(), nThreads, "Computing results ...");
final List<Worker> workers = new LinkedList<>();
final List<Thread> threads = new LinkedList<>();
final Overlay overlay = (settings.showOverlay) ? new Overlay() : null;
for (int i = 0; i < nThreads; i++) {
final Worker worker = new Worker(jobs, stack, actualCoordinates, config, overlay, ticker);
final Thread t = new Thread(worker);
workers.add(worker);
threads.add(t);
t.start();
}
// Fit the frames
final long startTime = System.nanoTime();
actualCoordinates.forEachKey(frame -> {
put(jobs, frame);
return true;
});
// Finish all the worker threads by passing in a null job
for (int i = 0; i < threads.size(); i++) {
put(jobs, -1);
}
// Wait for all to finish
for (int i = 0; i < threads.size(); i++) {
try {
threads.get(i).join();
} catch (final InterruptedException ex) {
Thread.currentThread().interrupt();
throw new ConcurrentRuntimeException(ex);
}
}
threads.clear();
ImageJUtils.finished("Collecting results ...");
final long runTime = System.nanoTime() - startTime;
// Collect the results
int cic = 0;
int daic = 0;
int dbic = 0;
ArrayList<DoubletResult> results = null;
int maxH = 0;
int maxH2 = 0;
int maxH3 = 0;
for (final Worker worker : workers) {
if (results == null) {
results = worker.results;
} else {
results.addAll(worker.results);
}
cic += worker.cic;
daic += worker.daic;
dbic += worker.dbic;
maxH = MathUtils.max(maxH, worker.spotHistogram.length);
for (int k = 0; k < 3; k++) {
maxH2 = MathUtils.max(maxH2, worker.neighbourHistogram[k].length);
maxH3 = MathUtils.max(maxH3, worker.almostNeighbourHistogram[k].length);
}
}
if (cic > 0) {
ImageJUtils.log("Difference AIC %d, BIC %d, Total %d", daic, dbic, cic);
}
if (settings.showHistograms) {
final double[] spotHistogram = new double[maxH];
final double[] resultHistogram = new double[maxH];
final double[][] neighbourHistogram = new double[3][maxH2];
final double[][] almostNeighbourHistogram = new double[3][maxH3];
for (final Worker worker : workers) {
final int[] h1a = worker.spotHistogram;
final int[] h1b = worker.resultHistogram;
for (int j = 0; j < h1a.length; j++) {
spotHistogram[j] += h1a[j];
resultHistogram[j] += h1b[j];
}
final int[][] h2 = worker.neighbourHistogram;
final int[][] h3 = worker.almostNeighbourHistogram;
for (int k = 0; k < 3; k++) {
for (int j = 0; j < h2[k].length; j++) {
neighbourHistogram[k][j] += h2[k][j];
}
for (int j = 0; j < h3[k].length; j++) {
almostNeighbourHistogram[k][j] += h3[k][j];
}
}
}
showHistogram(0, spotHistogram);
showHistogram(1, resultHistogram);
showHistogram(2, neighbourHistogram[0]);
showHistogram(3, neighbourHistogram[1]);
showHistogram(4, neighbourHistogram[2]);
showHistogram(5, almostNeighbourHistogram[0]);
showHistogram(6, almostNeighbourHistogram[1]);
showHistogram(7, almostNeighbourHistogram[2]);
}
workers.clear();
if (overlay != null) {
imp.setOverlay(overlay);
}
MemoryUtils.runGarbageCollector();
Collections.sort(results, DoubletResult::compare);
summariseResults(results, density, runTime);
windowOrganiser.tile();
IJ.showStatus("");
}
use of uk.ac.sussex.gdsc.core.logging.Ticker in project GDSC-SMLM by aherbert.
the class SeriesImageSource method initialise.
/**
* Initialise the TIFF image sizes and data structures.
*/
private void initialise() {
if (imageData == null) {
trackProgress.status("Reading images sizes");
final Ticker ticker = Ticker.createStarted(trackProgress, images.size(), false);
// All images are TIFF. Get the size of each and count the total frames.
imageData = new ImageData[images.size()];
imageSize = new int[images.size()];
final String[] names = new String[images.size()];
frames = 0;
int ok = 0;
// We can guess for sequential read
final boolean estimate = getReadHint() == ReadHint.SEQUENTIAL;
boolean exact = true;
for (int i = 0; i < names.length; i++) {
final String path = images.get(i);
final File file = new File(path);
// Get the size of each file so we can determine if
// they can fit into memory. We only use pre-loading for
// sequential reading if all images fit into memory.
final long size = getSize(file);
try (SeekableStream ss = createSeekableStream(path)) {
final FastTiffDecoder td = FastTiffDecoder.create(ss, path);
NumberOfImages numberOfImages;
if (estimate) {
numberOfImages = td.getNumberOfImages(() -> size);
} else {
numberOfImages = td.getNumberOfImages();
}
if (numberOfImages.isExact()) {
trackProgress.log("%s : images=%d (%d bytes)", path, numberOfImages.getImageCount(), size);
} else {
trackProgress.log("%s : images=%d (approx) (%d bytes)", path, numberOfImages.getImageCount(), size);
}
if (estimate) {
// Track if this is exact
exact = exact && numberOfImages.isExact();
} else if (numberOfImages.getImageCount() <= 0) {
// using the cumulative size array so remove the image.
continue;
}
frames += numberOfImages.getImageCount();
imageSize[ok] = frames;
imageData[ok] = new ImageData(size);
names[ok] = path;
ok++;
} catch (final Throwable ex) {
if (estimate) {
// This is an untested method so log the error
ex.printStackTrace();
}
}
ticker.tick();
}
trackProgress.status("");
ticker.stop();
if (ok < images.size()) {
imageSize = Arrays.copyOf(imageSize, ok);
imageData = Arrays.copyOf(imageData, ok);
images.clear();
images.addAll(Arrays.asList(names));
}
// No support for non-sequential access
if (!exact) {
imageSize = null;
}
}
}
use of uk.ac.sussex.gdsc.core.logging.Ticker in project GDSC-SMLM by aherbert.
the class MedianFilter method run.
@Override
public void run(ImageProcessor ip) {
final long start = System.nanoTime();
// final ImageJTrackProgress trackProgress = SimpleImageJTrackProgress.getInstance();
final ImageStack stack = imp.getImageStack();
final int width = stack.getWidth();
final int height = stack.getHeight();
final float[][] imageStack = new float[stack.getSize()][];
final float[] mean = new float[imageStack.length];
// Get the mean for each frame and normalise the data using the mean
final int threadCount = Prefs.getThreads();
final ExecutorService threadPool = Executors.newFixedThreadPool(threadCount);
List<Future<?>> futures = new LinkedList<>();
Ticker ticker = ImageJUtils.createTicker(stack.getSize(), threadCount);
IJ.showStatus("Calculating means...");
for (int n = 1; n <= stack.getSize(); n++) {
futures.add(threadPool.submit(new ImageNormaliser(stack, imageStack, mean, n, ticker)));
}
// Finish processing data
ConcurrencyUtils.waitForCompletionUnchecked(futures);
futures = new LinkedList<>();
final int size = width * height;
ticker = ImageJUtils.createTicker(size, threadCount);
IJ.showStatus("Calculating medians...");
for (int i = 0; i < size; i += settings.blockSize) {
futures.add(threadPool.submit(new ImageGenerator(imageStack, mean, i, Math.min(i + settings.blockSize, size), ticker, settings)));
}
// Finish processing data
ConcurrencyUtils.waitForCompletionUnchecked(futures);
if (ImageJUtils.isInterrupted()) {
threadPool.shutdown();
return;
}
if (settings.subtract) {
IJ.showStatus("Subtracting medians...");
ticker = ImageJUtils.createTicker(stack.getSize(), threadCount);
for (int n = 1; n <= stack.getSize(); n++) {
futures.add(threadPool.submit(new ImageFilter(stack, imageStack, n, ticker, settings.bias)));
}
// Finish processing data
ConcurrencyUtils.waitForCompletionUnchecked(futures);
}
threadPool.shutdown();
// Update the image
final ImageStack outputStack = new ImageStack(stack.getWidth(), stack.getHeight(), stack.getSize());
for (int n = 1; n <= stack.getSize(); n++) {
outputStack.setPixels(imageStack[n - 1], n);
}
imp.setStack(outputStack);
imp.updateAndDraw();
IJ.showTime(imp, TimeUnit.NANOSECONDS.toMillis(start), "Completed");
final long nanoseconds = System.nanoTime() - start;
ImageJUtils.log(TITLE + " : Radius %d, Interval %d, Block size %d = %s, %s / frame", settings.radius, settings.interval, settings.blockSize, TextUtils.millisToString(nanoseconds), TextUtils.nanosToString(Math.round(nanoseconds / (double) imp.getStackSize())));
}
Aggregations