use of uk.ac.sussex.gdsc.smlm.data.config.UnitProtos.TimeUnit in project GDSC-SMLM by aherbert.
the class TimeUnitTest method check.
private static void check(double msPerFrame, ExpectedUnit<TimeUnit>... expectedUnits) {
final int n = expectedUnits.length;
TypeConverter<TimeUnit> conv;
for (int i = 0; i < n; i++) {
final TimeUnit u1 = expectedUnits[i].unit;
final double v1 = expectedUnits[i].value;
for (int j = 0; j < n; j++) {
final TimeUnit u2 = expectedUnits[j].unit;
conv = UnitConverterUtils.createConverter(u1, u2, msPerFrame);
final double o = conv.convert(v1);
Assertions.assertEquals(expectedUnits[j].value, o, 1e-5, () -> u1 + " to " + u2);
}
}
}
use of uk.ac.sussex.gdsc.smlm.data.config.UnitProtos.TimeUnit in project GDSC-SMLM by aherbert.
the class TraceExporter method exportSpotOn.
private void exportSpotOn(MemoryPeakResults results) {
try (BufferedWriter out = Files.newBufferedWriter(Paths.get(settings.directory, results.getName() + ".csv"))) {
out.write("frame,t,trajectory,x,y");
out.newLine();
final TypeConverter<TimeUnit> converter = UnitConverterUtils.createConverter(TimeUnit.FRAME, TimeUnit.SECOND, results.getCalibrationReader().getExposureTime());
@SuppressWarnings("resource") final BufferedWriter writer = out;
results.forEach(DistanceUnit.UM, (XyrResultProcedure) (x, y, result) -> {
try {
if (result.hasEndFrame()) {
final String sId = Integer.toString(result.getId());
final String sx = Float.toString(x);
final String sy = Float.toString(y);
for (int t = result.getFrame(); t <= result.getEndFrame(); t++) {
writer.write(Integer.toString(t));
writer.write(",");
writer.write(Float.toString(converter.convert(t)));
writer.write(",");
writer.write(sId);
writer.write(",");
writer.write(sx);
writer.write(",");
writer.write(sy);
writer.newLine();
}
} else {
writer.write(Integer.toString(result.getFrame()));
writer.write(",");
writer.write(Float.toString(converter.convert(result.getFrame())));
writer.write(",");
writer.write(Integer.toString(result.getId()));
writer.write(",");
writer.write(Float.toString(x));
writer.write(",");
writer.write(Float.toString(y));
writer.newLine();
}
} catch (final IOException ex) {
throw new RuntimeException(ex);
}
});
} catch (final IOException | RuntimeException ex) {
handleException(ex);
}
}
use of uk.ac.sussex.gdsc.smlm.data.config.UnitProtos.TimeUnit in project GDSC-SMLM by aherbert.
the class LoadLocalisations method getFields.
private static boolean getFields(LoadLocalisationsSettings.Builder settings) {
settings.getLocalisationsFilename();
final ExtendedGenericDialog gd = new ExtendedGenericDialog(TITLE);
gd.addMessage("Load delimited localisations");
// Show a preview of the file in a text area
final List<String> preview = loadLines(settings, 100);
if (!preview.isEmpty()) {
// Add a TextArea. This cannot add scroll bars after the constructor so we put up
// with this. But we can use a monospaced font and size the text area nicely.
gd.addTextAreas(preview.stream().collect(Collectors.joining("\n")), null, Math.min(10, preview.size()), Math.min(80, preview.stream().mapToInt(String::length).max().getAsInt()));
final TextArea ta = gd.getTextArea1();
final Font font = new Font(Font.MONOSPACED, Font.PLAIN, (int) (10 * Prefs.getGuiScale()));
ta.setFont(font);
ta.setEditable(false);
}
if (!settings.getHideFieldDatasetName()) {
gd.addStringField("Dataset_name", settings.getName(), 30);
}
gd.addMessage("Calibration:");
// Allow the full camera type top be captured
final Calibration.Builder calibrationBuilder = settings.getCalibrationBuilder();
final CalibrationWriter cw = new CalibrationWriter(calibrationBuilder);
PeakFit.addCameraOptions(gd, 0, cw);
// Only primitive support for other calibration
gd.addNumericField("Pixel_size", cw.getNmPerPixel(), 3, 8, "nm");
gd.addNumericField("Exposure_time", cw.getExposureTime(), 3, 8, "");
// This is the unit for the exposure time (used to convert the exposure time to milliseconds).
// Use the name as the list is a truncated list of the full enum.
final TimeUnit t = calibrationBuilder.getTimeCalibration().getTimeUnit();
gd.addChoice("Time_unit", TimeUnitLoader.getTimeUnits(), SettingsManager.getName(UnitHelper.getName(t), UnitHelper.getShortName(t)));
gd.addMessage("Records:");
gd.addNumericField("Header_lines", settings.getHeaderLines(), 0);
gd.addStringField("Comment", settings.getComment());
gd.addStringField("Delimiter", settings.getDelimiter());
gd.addChoice("Distance_unit", SettingsManager.getDistanceUnitNames(), cw.getDistanceUnitValue());
gd.addChoice("Intensity_unit", SettingsManager.getIntensityUnitNames(), cw.getIntensityUnitValue());
gd.addMessage("Define the fields:");
gd.addNumericField("Frame", settings.getFieldT(), 0);
gd.addNumericField("ID", settings.getFieldId(), 0);
gd.addNumericField("Category", settings.getFieldCategory(), 0);
gd.addNumericField("X", settings.getFieldX(), 0);
gd.addNumericField("Y", settings.getFieldY(), 0);
gd.addNumericField("Z", settings.getFieldZ(), 0);
gd.addNumericField("Intensity", settings.getFieldI(), 0);
gd.addNumericField("Sx", settings.getFieldSx(), 0);
gd.addNumericField("Sy", settings.getFieldSy(), 0);
gd.addNumericField("Precision", settings.getFieldPrecision(), 0);
gd.addChoice("Precision_method", SettingsManager.getPrecisionMethodNames(), cw.getPrecisionMethodValue());
gd.addHelp(HelpUrls.getUrl("load-localisations"));
gd.showDialog();
if (gd.wasCanceled()) {
return false;
}
if (!settings.getHideFieldDatasetName()) {
settings.setName(getNextString(gd, settings.getName()));
}
cw.setCameraType(SettingsManager.getCameraTypeValues()[gd.getNextChoiceIndex()]);
cw.setNmPerPixel(gd.getNextNumber());
cw.setExposureTime(gd.getNextNumber());
// The time units used a truncated list so look-up the value from the index
calibrationBuilder.getTimeCalibrationBuilder().setTimeUnit(TimeUnitLoader.getTimeUnitValues()[gd.getNextChoiceIndex()]);
settings.setHeaderLines((int) gd.getNextNumber());
settings.setComment(gd.getNextString());
settings.setDelimiter(getNextString(gd, settings.getDelimiter()));
cw.setDistanceUnit(DistanceUnit.forNumber(gd.getNextChoiceIndex()));
cw.setIntensityUnit(IntensityUnit.forNumber(gd.getNextChoiceIndex()));
final int[] columns = new int[10];
for (int i = 0; i < columns.length; i++) {
columns[i] = (int) gd.getNextNumber();
}
int index = 0;
settings.setFieldT(columns[index++]);
settings.setFieldId(columns[index++]);
settings.setFieldCategory(columns[index++]);
settings.setFieldX(columns[index++]);
settings.setFieldY(columns[index++]);
settings.setFieldZ(columns[index++]);
settings.setFieldI(columns[index++]);
settings.setFieldSx(columns[index++]);
settings.setFieldSy(columns[index++]);
settings.setFieldPrecision(columns[index]);
cw.setPrecisionMethod(PrecisionMethod.forNumber(gd.getNextChoiceIndex()));
// Collect the camera calibration
gd.collectOptions();
// Validate after reading the dialog (so we store the last entered values)
if (gd.invalidNumber()) {
IJ.error(TITLE, "Invalid number in input fields");
return false;
}
for (int i = 0; i < columns.length; i++) {
if (columns[i] < 0) {
continue;
}
for (int j = i + 1; j < columns.length; j++) {
if (columns[j] < 0) {
continue;
}
if (columns[i] == columns[j]) {
IJ.error(TITLE, "Duplicate indicies: " + columns[i]);
return false;
}
}
}
if (cw.getNmPerPixel() <= 0) {
IJ.error(TITLE, "Require positive pixel pitch");
return false;
}
if (cw.isCcdCamera()) {
if (!cw.hasCountPerPhoton()) {
IJ.error(TITLE, "Require positive count/photon for CCD camera type");
return false;
}
} else {
// Q.Validate other camera types?
}
if (settings.getFieldX() < 0 || settings.getFieldY() < 0) {
IJ.error(TITLE, "Require valid X and Y indices");
return false;
}
return true;
}
use of uk.ac.sussex.gdsc.smlm.data.config.UnitProtos.TimeUnit in project GDSC-SMLM by aherbert.
the class TraceMolecules method runOptimiser.
private void runOptimiser(TraceManager manager) {
// Get an estimate of the number of molecules without blinking
final Statistics stats = new Statistics();
final double nmPerPixel = this.results.getNmPerPixel();
final PrecisionResultProcedure pp = new PrecisionResultProcedure(results);
pp.getPrecision();
stats.add(pp.precisions);
// Use twice the precision to get the initial distance threshold
// Use 2.5x sigma as per the PC-PALM protocol in Sengupta, et al (2013) Nature Protocols 8, 345
final double dEstimate = stats.getMean() * 2.5 / nmPerPixel;
final int traceCount = manager.traceMolecules(dEstimate, 1);
if (!getParameters(traceCount, dEstimate)) {
return;
}
// TODO - Convert the distance threshold to use nm instead of pixels?
final List<double[]> results = runTracing(manager, settings.getMinDistanceThreshold(), settings.getMaxDistanceThreshold(), settings.getMinTimeThreshold(), settings.getMaxTimeThreshold(), settings.getOptimiserSteps());
// Compute fractional difference from the true value:
// Use blinking rate directly or the estimated number of molecules
double reference;
int statistic;
if (optimiseBlinkingRate) {
reference = settings.getBlinkingRate();
statistic = 3;
IJ.log(String.format("Estimating blinking rate: %.2f", reference));
} else {
reference = traceCount / settings.getBlinkingRate();
statistic = 2;
IJ.log(String.format("Estimating number of molecules: %d / %.2f = %.2f", traceCount, settings.getBlinkingRate(), reference));
}
for (final double[] result : results) {
if (optimiseBlinkingRate) {
result[2] = (reference - result[statistic]) / reference;
} else {
result[2] = (result[statistic] - reference) / reference;
}
}
// Locate the optimal parameters with a fit of the zero contour
final boolean found = findOptimalParameters(results);
createPlotResults(results);
if (!found) {
return;
}
// Make fractional difference absolute so that lowest is best
for (final double[] result : results) {
result[2] = Math.abs(result[2]);
}
// Set the optimal thresholds using the lowest value
double[] best = new double[] { 0, 0, Double.MAX_VALUE };
for (final double[] result : results) {
if (best[2] > result[2]) {
best = result;
}
}
settings.setDistanceThreshold(best[0]);
// The optimiser works using frames so convert back to the correct units
final TypeConverter<TimeUnit> convert = UnitConverterUtils.createConverter(TimeUnit.FRAME, settings.getTimeUnit(), getExposureTimeInMilliSeconds());
settings.setTimeThreshold(convert.convert(best[1]));
IJ.log(String.format("Optimal fractional difference @ D-threshold=%g nm, T-threshold=%f s (%d frames)", settings.getDistanceThreshold(), timeThresholdInSeconds(), timeThresholdInFrames()));
writeSettings();
}
use of uk.ac.sussex.gdsc.smlm.data.config.UnitProtos.TimeUnit in project GDSC-SMLM by aherbert.
the class TraceMolecules method findOptimalParameters.
/**
* Find the contour that intersects zero on the fractional difference plot. Find the point on the
* contour nearest the origin.
*
* @param results the results
* @return true, if successful
*/
private boolean findOptimalParameters(List<double[]> results) {
// This method only works if there are many results and if the results
// cover enough of the search space to go from above zero (i.e. not enough traces)
// to below zero (i.e. too many traces)
final int maxx = timeThresholds.length;
final int maxy = ddistanceThresholds.length;
// --------
// Find zero crossings using linear interpolation
zeroCrossingPoints = new ArrayList<>();
// --------
// Pass across all time points
boolean noZeroCrossingAtT0 = false;
boolean noZeroCrossingAtTn = false;
for (int x = 0; x < maxx; x++) {
// Find zero crossings on distance points
final double[] data = new double[maxy];
for (int y = 0; y < maxy; y++) {
final int i = y * maxx + x;
final double[] result = results.get(i);
data[y] = result[2];
}
final double zeroCrossing = findZeroCrossing(data, ddistanceThresholds);
if (zeroCrossing > 0) {
zeroCrossingPoints.add(new double[] { timeThresholds[x], zeroCrossing });
} else if (x == 0) {
noZeroCrossingAtT0 = true;
} else if (x == maxx - 1) {
noZeroCrossingAtTn = true;
}
}
// If there were not enough zero crossings then the ranges are wrong
if (zeroCrossingPoints.size() < 3) {
IJ.log(String.format("Very few zero crossings (%d). Increase the optimisation space", zeroCrossingPoints.size()));
return false;
}
// --------
// Use relative distances to find the zero crossing with the smallest distance from origin
// and set this as the optimal parameters
// --------
double minD = Double.MAX_VALUE;
final double maxTimeThresholdInFrames = settings.getMaxTimeThreshold();
// The optimiser works using frames so convert back to the correct units
final TypeConverter<TimeUnit> convert = UnitConverterUtils.createConverter(TimeUnit.FRAME, settings.getTimeUnit(), getExposureTimeInMilliSeconds());
for (final double[] point : zeroCrossingPoints) {
final double dx = point[0] / maxTimeThresholdInFrames;
final double dy = point[1] / settings.getMaxDistanceThreshold();
final double d = dx * dx + dy * dy;
if (d < minD) {
minD = d;
settings.setDistanceThreshold(point[1]);
settings.setTimeThreshold(convert.convert(point[0]));
}
}
// --------
// Add more points to make the plotted line look better when showing the plot.
// --------
// Pass across all distance points
boolean noZeroCrossingAtD0 = false;
boolean noZeroCrossingAtDn = false;
final double[] tThresholdsD = SimpleArrayUtils.toDouble(timeThresholds);
for (int y = 0; y < maxy; y++) {
// Find zero crossings on time points
final double[] data = new double[maxx];
for (int x = 0; x < maxx; x++) {
final int i = y * maxx + x;
final double[] result = results.get(i);
data[x] = result[2];
}
final double zeroCrossing = findZeroCrossing(data, tThresholdsD);
if (zeroCrossing > 0) {
zeroCrossingPoints.add(new double[] { zeroCrossing, ddistanceThresholds[y] });
} else if (y == 0) {
noZeroCrossingAtD0 = true;
} else if (y == maxy - 1) {
noZeroCrossingAtDn = true;
}
}
sortPoints();
// --------
// Output a message suggesting if the limits should be updated.
// --------
final StringBuilder sb = new StringBuilder();
boolean reduceTime = false;
boolean reduceDistance = false;
if (noZeroCrossingAtDn && settings.getMinTimeThreshold() > 1) {
sb.append(" * No zero crossing at max distance\n");
reduceTime = true;
}
if (noZeroCrossingAtTn && settings.getMinDistanceThreshold() > 0) {
sb.append(" * No zero crossing at max time\n");
reduceDistance = true;
}
if (!noZeroCrossingAtD0 && settings.getMinDistanceThreshold() > 0) {
sb.append(" * Zero crossing at min distance\n");
reduceDistance = true;
}
if (!noZeroCrossingAtT0 && settings.getMinTimeThreshold() > 1) {
sb.append(" * Zero crossing at min time\n");
reduceTime = true;
}
if (reduceTime) {
sb.append(" => Reduce the min time threshold\n");
}
if (reduceDistance) {
sb.append(" => Reduce the min distance threshold\n");
}
if (sb.length() > 0) {
sb.insert(0, "\nWarning:\n");
sb.append("\n");
IJ.log(sb.toString());
}
return true;
}
Aggregations