uk.ac.sussex.gdsc.smlm.data.config.CalibrationReader Maven / Gradle / Ivy
Show all versions of gdsc-smlm Show documentation
/*-
* #%L
* Genome Damage and Stability Centre SMLM Package
*
* Software for single molecule localisation microscopy (SMLM)
* %%
* Copyright (C) 2011 - 2023 Alex Herbert
* %%
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as
* published by the Free Software Foundation, either version 3 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public
* License along with this program. If not, see
* .
* #L%
*/
/*
*
*/
package uk.ac.sussex.gdsc.smlm.data.config;
import java.util.Objects;
import uk.ac.sussex.gdsc.core.data.utils.ConversionException;
import uk.ac.sussex.gdsc.core.data.utils.TypeConverter;
import uk.ac.sussex.gdsc.core.utils.MathUtils;
import uk.ac.sussex.gdsc.core.utils.TextUtils;
import uk.ac.sussex.gdsc.smlm.data.config.CalibrationProtos.CalibrationOrBuilder;
import uk.ac.sussex.gdsc.smlm.data.config.CalibrationProtos.CameraType;
import uk.ac.sussex.gdsc.smlm.data.config.FitProtos.PrecisionMethod;
import uk.ac.sussex.gdsc.smlm.data.config.UnitProtos.AngleUnit;
import uk.ac.sussex.gdsc.smlm.data.config.UnitProtos.DistanceUnit;
import uk.ac.sussex.gdsc.smlm.data.config.UnitProtos.IntensityUnit;
import uk.ac.sussex.gdsc.smlm.data.config.UnitProtos.TimeUnit;
/**
* Contains helper functions for reading the Calibration class.
*/
public class CalibrationReader {
/** The calibration or builder. */
private CalibrationOrBuilder calibrationOrBuilder;
/**
* Instantiates a new calibration reader with no calibration.
*/
protected CalibrationReader() {
// This constructor is intentionally empty. Nothing special is needed here.
}
/**
* Instantiates a new calibration reader.
*
* @param calibration the calibration (must not be null)
*/
public CalibrationReader(CalibrationOrBuilder calibration) {
this.calibrationOrBuilder = Objects.requireNonNull(calibration, "calibration");
}
/**
* Gets the calibration or builder with the latest changes.
*
* @return the calibration or builder
*/
public CalibrationOrBuilder getCalibrationOrBuilder() {
return calibrationOrBuilder;
}
/**
* Gets a distance converter to update values.
*
* If the conversion is not possible then an exception is thrown.
*
* @param toDistanceUnit the distance unit
* @return the distance converter
* @throws ConversionException the conversion exception
*/
public TypeConverter getDistanceConverter(DistanceUnit toDistanceUnit) {
return CalibrationHelper.getDistanceConverter(getCalibrationOrBuilder(), toDistanceUnit);
}
/**
* Gets an intensity converter to update values.
*
* If the conversion is not possible then an exception is thrown.
*
* @param toIntensityUnit the intensity unit
* @return the intensity converter
* @throws ConversionException the conversion exception
*/
public TypeConverter getIntensityConverter(IntensityUnit toIntensityUnit) {
return CalibrationHelper.getIntensityConverter(getCalibrationOrBuilder(), toIntensityUnit);
}
/**
* Gets a time converter to update values.
*
* If the conversion is not possible then an exception is thrown.
*
* @param toTimeUnit the time unit
* @return the time converter
* @throws ConversionException the conversion exception
*/
public TypeConverter getTimeConverter(TimeUnit toTimeUnit) {
return CalibrationHelper.getTimeConverter(getCalibrationOrBuilder(), toTimeUnit);
}
/**
* Gets an angle converter to update values.
*
* If the conversion is not possible then an exception is thrown.
*
* @param toAngleUnit the angle unit
* @return the angle converter
* @throws ConversionException the conversion exception
*/
public TypeConverter getAngleConverter(AngleUnit toAngleUnit) {
return CalibrationHelper.getAngleConverter(getCalibrationOrBuilder(), toAngleUnit);
}
/**
* Gets a distance converter to update values.
*
* If the calibration is already in the given units or conversion is not possible then an
* identity converter will be returned.
*
* @param toDistanceUnit the distance unit
* @return CalibrationHelper.the distance converter
*/
public TypeConverter getDistanceConverterSafe(DistanceUnit toDistanceUnit) {
return CalibrationHelper.getDistanceConverterSafe(getCalibrationOrBuilder(), toDistanceUnit);
}
/**
* Gets an intensity converter to update values.
*
* If the calibration is already in the given units or conversion is not possible then an
* identity converter will be returned.
*
* @param toIntensityUnit the intensity unit
* @return CalibrationHelper.the intensity converter
*/
public TypeConverter getIntensityConverterSafe(IntensityUnit toIntensityUnit) {
return CalibrationHelper.getIntensityConverterSafe(getCalibrationOrBuilder(), toIntensityUnit);
}
/**
* Gets a time converter to update values.
*
* If the calibration is already in the given units or conversion is not possible then an
* identity converter will be returned.
*
* @param toTimeUnit the time unit
* @return CalibrationHelper.the time converter
*/
public TypeConverter getTimeConverterSafe(TimeUnit toTimeUnit) {
return CalibrationHelper.getTimeConverterSafe(getCalibrationOrBuilder(), toTimeUnit);
}
/**
* Gets an angle converter to update values.
*
* If the calibration is already in the given units or conversion is not possible then an
* identity converter will be returned.
*
* @param toAngleUnit the angle unit
* @return CalibrationHelper.the angle converter
*/
public TypeConverter getAngleConverterSafe(AngleUnit toAngleUnit) {
return CalibrationHelper.getAngleConverterSafe(getCalibrationOrBuilder(), toAngleUnit);
}
/**
* Gets image pixel size in nanometers.
*
* @return image pixel size in nanometers
*/
public double getNmPerPixel() {
final CalibrationOrBuilder c = getCalibrationOrBuilder();
return (c.hasDistanceCalibration()) ? c.getDistanceCalibration().getNmPerPixel() : 0;
}
/**
* Checks for nm per pixel.
*
* @return true, if successful
*/
public boolean hasNmPerPixel() {
return getNmPerPixel() > 0;
}
/**
* Gets the gain (Count/photon). Can be used to convert the signal in count units to photons.
*
* @return the gain
*/
public double getCountPerPhoton() {
final CalibrationOrBuilder c = getCalibrationOrBuilder();
return (c.hasIntensityCalibration()) ? c.getIntensityCalibration().getCountPerPhoton() : 0;
}
/**
* Checks for gain (Count/photon).
*
* @return true, if successful
*/
public boolean hasCountPerPhoton() {
return getCountPerPhoton() > 0;
}
/**
* Gets the exposure time in milliseconds per frame.
*
* @return the exposure time
*/
public double getExposureTime() {
final CalibrationOrBuilder c = getCalibrationOrBuilder();
return (c.hasTimeCalibration()) ? c.getTimeCalibration().getExposureTime() : 0;
}
/**
* Checks for exposure time.
*
* @return true, if successful
*/
public boolean hasExposureTime() {
return getExposureTime() > 0;
}
/**
* Gets the camera Gaussian read noise (in Count units).
*
* @return the camera Gaussian read noise (in Count units)
*/
public double getReadNoise() {
final CalibrationOrBuilder c = getCalibrationOrBuilder();
return (c.hasCameraCalibration()) ? c.getCameraCalibration().getReadNoise() : 0;
}
/**
* Checks for read noise.
*
* @return true, if successful
*/
public boolean hasReadNoise() {
return getReadNoise() > 0;
}
/**
* Gets camera bias (in Count units).
*
* @return camera bias (in Count units)
*/
public double getBias() {
final CalibrationOrBuilder c = getCalibrationOrBuilder();
return (c.hasCameraCalibration()) ? c.getCameraCalibration().getBias() : 0;
}
/**
* Checks for bias.
*
* @return true, if successful
*/
public boolean hasBias() {
// Bias can be zero (the default) so check for a camera calibration first
final CalibrationOrBuilder c = getCalibrationOrBuilder();
return c.hasCameraCalibration() && c.getCameraCalibration().getBias() >= 0;
}
/**
* Get the camera type.
*
* @return the camera type
*/
public CameraType getCameraType() {
final CalibrationOrBuilder c = getCalibrationOrBuilder();
return (c.hasCameraCalibration()) ? c.getCameraCalibration().getCameraType()
: CameraType.CAMERA_TYPE_NA;
}
/**
* Get the camera type.
*
* @return the camera type
*/
public int getCameraTypeValue() {
final CalibrationOrBuilder c = getCalibrationOrBuilder();
return (c.hasCameraCalibration()) ? c.getCameraCalibration().getCameraTypeValue()
: CameraType.CAMERA_TYPE_NA_VALUE;
}
/**
* Checks for camera type.
*
* @return true, if successful
*/
public boolean hasCameraType() {
return getCameraType().getNumber() > 0;
}
/**
* Checks for camera calibration.
*
* @return true, if successful
*/
public boolean hasCameraCalibration() {
return getCalibrationOrBuilder().hasCameraCalibration();
}
/**
* Checks for a CCD camera.
*
* @return true, if successful
*/
public boolean isCcdCamera() {
final CalibrationOrBuilder c = getCalibrationOrBuilder();
if (c.hasCameraCalibration()) {
return CalibrationProtosHelper.isCcdCameraType(c.getCameraCalibration().getCameraType());
}
return false;
}
/**
* Checks if the camera type was an Electron Multiplying (EM) CCD.
*
* @return true, if the camera type was an Electron Multiplying (EM) CCD
*/
public boolean isEmCcd() {
return getCameraType() == CameraType.EMCCD;
}
/**
* Checks if the camera type was a standard CCD.
*
* @return true, if the camera type was a standard CCD.
*/
public boolean isCcd() {
return getCameraType() == CameraType.CCD;
}
/**
* Checks if the camera type was a sCMOS.
*
* @return true, if the camera type was a sCMOS.
*/
public boolean isScmos() {
return getCameraType() == CameraType.SCMOS;
}
/**
* Get the camera quantum efficiency (e-/photon) used when modelling a microscope camera.
*
* Note that the camera noise model assumes that photons are converted to counts by a process
* that is not perfect (i.e. it has noise). The underlying process is photons converted to
* electrons in the camera chip and then amplification (count/electron) occurring in the camera
* hardware. Ideally this should be recorded by storing the QE and the amplification. However the
* total gain (Count/photon) is already stored with the results. Thus the amplification can be
* inferred by dividing the total gain by the quantum efficiency which should be in the range 0-1.
*
* @return the quantum efficiency
*/
public double getQuantumEfficiency() {
final CalibrationOrBuilder c = getCalibrationOrBuilder();
return (c.hasCameraCalibration())
? MathUtils.clip(0, 1, c.getCameraCalibration().getQuantumEfficiency())
: 0;
}
/**
* Checks for quantum efficiency (e-/photon).
*
* @return true, if successful (QE is in the range 0 (exclusive) to 1 (inclusive)).
*/
public boolean hasQuantumEfficiency() {
final double qe = getQuantumEfficiency();
return qe > 0 && qe <= 1;
}
/**
* Get the camera amplification (Count/e-) used when modelling a microscope camera.
*
*
Note that the camera noise model assumes that electrons are converted to Count units by
* amplification that is not perfect (i.e. it has noise). The amplification is equal to the gain
* (Count/photon) divided by the quantum efficiency [QE] (e-/photon).
*
*
If the QE is not set then it is assumed to be 1.
*
* @return the amplification
*/
public double getCountPerElectron() {
final double countPerPhoton = getCountPerPhoton();
if (countPerPhoton > 0) {
double qe = getQuantumEfficiency();
if (qe == 0) {
qe = 1;
}
return countPerPhoton / qe;
}
return 0;
}
/**
* Checks for amplification (Count/e-). This is true if there is a count/photon since the quantum
* efficiency is assumed to be 1 if absent.
*
* @return true, if successful
*/
public boolean hasCountPerElectron() {
return hasCountPerPhoton(); // && hasQuantumEfficiency();
}
/**
* Gets the camera model name. This should contain all the information required to load the camera
* model, e.g. in the case of a per-pixel camera model for sCMOS cameras.
*
* @return the camera model name
*/
public String getCameraModelName() {
final CalibrationOrBuilder c = getCalibrationOrBuilder();
return (c.hasCameraCalibration()) ? c.getCameraCalibration().getCameraModelName() : null;
}
/**
* Checks for camera model name.
*
* @return true, if successful
*/
public boolean hasCameraModelName() {
return !TextUtils.isNullOrEmpty(getCameraModelName());
}
/**
* Get the distance unit used for the results.
*
* @return the distance unit
*/
public DistanceUnit getDistanceUnit() {
final CalibrationOrBuilder c = getCalibrationOrBuilder();
return (c.hasDistanceCalibration()) ? c.getDistanceCalibration().getDistanceUnit()
: DistanceUnit.DISTANCE_UNIT_NA;
}
/**
* Get the distance unit used for the results.
*
* @return the distance unit
*/
public int getDistanceUnitValue() {
final CalibrationOrBuilder c = getCalibrationOrBuilder();
return (c.hasDistanceCalibration()) ? c.getDistanceCalibration().getDistanceUnitValue()
: DistanceUnit.DISTANCE_UNIT_NA_VALUE;
}
/**
* Checks for distance unit.
*
* @return true, if successful
*/
public boolean hasDistanceUnit() {
return getDistanceUnit().getNumber() > 0;
}
/**
* Get the intensity unit used for the results.
*
* @return the intensity unit
*/
public IntensityUnit getIntensityUnit() {
final CalibrationOrBuilder c = getCalibrationOrBuilder();
return (c.hasIntensityCalibration()) ? c.getIntensityCalibration().getIntensityUnit()
: IntensityUnit.INTENSITY_UNIT_NA;
}
/**
* Get the intensity unit used for the results.
*
* @return the intensity unit
*/
public int getIntensityUnitValue() {
final CalibrationOrBuilder c = getCalibrationOrBuilder();
return (c.hasIntensityCalibration()) ? c.getIntensityCalibration().getIntensityUnitValue()
: IntensityUnit.INTENSITY_UNIT_NA_VALUE;
}
/**
* Checks for intensity unit.
*
* @return true, if successful
*/
public boolean hasIntensityUnit() {
return getIntensityUnit().getNumber() > 0;
}
/**
* Get the angle unit used for the results.
*
* @return the angle unit
*/
public AngleUnit getAngleUnit() {
final CalibrationOrBuilder c = getCalibrationOrBuilder();
return (c.hasAngleCalibration()) ? c.getAngleCalibration().getAngleUnit()
: AngleUnit.ANGLE_UNIT_NA;
}
/**
* Get the angle unit used for the results.
*
* @return the angle unit
*/
public int getAngleUnitValue() {
final CalibrationOrBuilder c = getCalibrationOrBuilder();
return (c.hasAngleCalibration()) ? c.getAngleCalibration().getAngleUnitValue()
: AngleUnit.ANGLE_UNIT_NA_VALUE;
}
/**
* Checks for angle unit.
*
* @return true, if successful
*/
public boolean hasAngleUnit() {
return getAngleUnit().getNumber() > 0;
}
/**
* Get the time unit used for the results.
*
* @return the time unit
*/
public TimeUnit getTimeUnit() {
final CalibrationOrBuilder c = getCalibrationOrBuilder();
return (c.hasTimeCalibration()) ? c.getTimeCalibration().getTimeUnit() : TimeUnit.TIME_UNIT_NA;
}
/**
* Get the time unit used for the results.
*
* @return the time unit
*/
public int getTimeUnitValue() {
final CalibrationOrBuilder c = getCalibrationOrBuilder();
return (c.hasTimeCalibration()) ? c.getTimeCalibration().getTimeUnitValue()
: TimeUnit.TIME_UNIT_NA_VALUE;
}
/**
* Checks for time unit.
*
* @return true, if successful
*/
public boolean hasTimeUnit() {
return getTimeUnit().getNumber() > 0;
}
/**
* Get the precision method used for the results.
*
* @return the precision method
*/
public PrecisionMethod getPrecisionMethod() {
final CalibrationOrBuilder c = getCalibrationOrBuilder();
return (c.hasResultDataCalibration()) ? c.getResultDataCalibration().getPrecisionMethod()
: PrecisionMethod.PRECISION_METHOD_NA;
}
/**
* Get the precision method used for the results.
*
* @return the precision method
*/
public int getPrecisionMethodValue() {
final CalibrationOrBuilder c = getCalibrationOrBuilder();
return (c.hasResultDataCalibration()) ? c.getResultDataCalibration().getPrecisionMethodValue()
: PrecisionMethod.PRECISION_METHOD_NA_VALUE;
}
/**
* Checks for precision method.
*
* @return true, if successful
*/
public boolean hasPrecisionMethod() {
return getPrecisionMethod().getNumber() > 0;
}
}