Search in sources :

Example 1 with ImagePSF

use of uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.ImagePSF in project GDSC-SMLM by aherbert.

the class CreateData method getImageHwhm.

/**
 * Get the PSF half-width at half-maxima from the Image PSF.
 *
 * @return the PSF half-width at half-maxima
 */
private double getImageHwhm() {
    final ImagePlus imp = WindowManager.getImage(settings.getPsfImageName());
    if (imp == null) {
        IJ.error(TITLE, "Unable to create the PSF model from image: " + settings.getPsfImageName());
        return -1;
    }
    final ImagePSF psfSettings = ImagePsfHelper.fromString(imp.getProperty("Info").toString());
    if (psfSettings == null) {
        IJ.error(TITLE, "Unknown PSF settings for image: " + imp.getTitle());
        return -1;
    }
    if (psfSettings.getFwhm() <= 0) {
        IJ.error(TITLE, "Unknown PSF FWHM setting for image: " + imp.getTitle());
        return -1;
    }
    if (psfSettings.getPixelSize() <= 0) {
        IJ.error(TITLE, "Unknown PSF pixel size setting for image: " + imp.getTitle());
        return -1;
    }
    // output image
    return 0.5 * psfSettings.getFwhm() * psfSettings.getPixelSize() / settings.getPixelPitch();
}
Also used : ImagePSF(uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.ImagePSF) ImagePlus(ij.ImagePlus)

Example 2 with ImagePSF

use of uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.ImagePSF in project GDSC-SMLM by aherbert.

the class CubicSplineManager method loadFromFile.

private static CubicSplinePsf loadFromFile(String name, String filename) {
    // Try to load from file
    try (InputStream is = new BufferedInputStream(new FileInputStream(filename))) {
        IJ.showStatus("Loading cubic spline: " + name);
        final ImagePSF imagePsf = ImagePSF.parseDelimitedFrom(is);
        final CubicSplineData function = CubicSplineData.read(is, SimpleImageJTrackProgress.getInstance());
        return new CubicSplinePsf(imagePsf, function);
    } catch (final Exception ex) {
        ImageJUtils.log("Failed to load spline model %s from file: %s. %s", name, filename, ex.getMessage());
    } finally {
        IJ.showStatus("");
    }
    return null;
}
Also used : BufferedInputStream(java.io.BufferedInputStream) ImagePSF(uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.ImagePSF) BufferedInputStream(java.io.BufferedInputStream) FileInputStream(java.io.FileInputStream) InputStream(java.io.InputStream) CubicSplineData(uk.ac.sussex.gdsc.smlm.function.cspline.CubicSplineData) FileInputStream(java.io.FileInputStream)

Example 3 with ImagePSF

use of uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.ImagePSF in project GDSC-SMLM by aherbert.

the class CubicSplineManager method createCubicSpline.

/**
 * Creates the cubic spline.
 *
 * @param imagePsf the image PSF details
 * @param image the image
 * @param singlePrecision Set to true to use single precision (float values) to store the cubic
 *        spline coefficients
 * @return the cubic spline PSF
 */
public static CubicSplinePsf createCubicSpline(ImagePSFOrBuilder imagePsf, ImageStack image, final boolean singlePrecision) {
    final int maxx = image.getWidth();
    final int maxy = image.getHeight();
    final int maxz = image.getSize();
    final float[][] psf = new float[maxz][];
    for (int z = 0; z < maxz; z++) {
        psf[z] = ImageJImageConverter.getData(image.getPixels(z + 1), null);
    }
    // We reduce by a factor of 3
    final int maxi = (maxx - 1) / 3;
    final int maxj = (maxy - 1) / 3;
    final int maxk = (maxz - 1) / 3;
    final int size = maxi * maxj;
    final CustomTricubicFunction[][] splines = new CustomTricubicFunction[maxk][size];
    final int threadCount = Prefs.getThreads();
    final Ticker ticker = ImageJUtils.createTicker((long) maxi * maxj * maxk, threadCount);
    final ExecutorService threadPool = Executors.newFixedThreadPool(threadCount);
    final LocalList<Future<?>> futures = new LocalList<>(maxk);
    // spline node along each dimension, i.e. dimension length = n*3 + 1 with n the number of nodes.
    for (int k = 0; k < maxk; k++) {
        final int kk = k;
        futures.add(threadPool.submit(() -> {
            final CubicSplineCalculator calc = new CubicSplineCalculator();
            final double[] value = new double[64];
            final int zz = 3 * kk;
            for (int j = 0, index = 0; j < maxj; j++) {
                // 4x4 block origin in the XY data
                int index0 = 3 * j * maxx;
                for (int i = 0; i < maxi; i++, index++) {
                    ticker.tick();
                    int count = 0;
                    for (int z = 0; z < 4; z++) {
                        final float[] data = psf[zz + z];
                        for (int y = 0; y < 4; y++) {
                            for (int x = 0, ii = index0 + y * maxx; x < 4; x++) {
                                value[count++] = data[ii++];
                            }
                        }
                    }
                    splines[kk][index] = CustomTricubicFunctionUtils.create(calc.compute(value));
                    if (singlePrecision) {
                        splines[kk][index] = splines[kk][index].toSinglePrecision();
                    }
                    index0 += 3;
                }
            }
        }));
    }
    ticker.stop();
    threadPool.shutdown();
    ConcurrencyUtils.waitForCompletionUnchecked(futures);
    // Normalise
    double maxSum = 0;
    for (int k = 0; k < maxk; k++) {
        double sum = 0;
        for (int i = 0; i < size; i++) {
            sum += splines[k][i].value000();
        }
        if (maxSum < sum) {
            maxSum = sum;
        }
    }
    if (maxSum == 0) {
        throw new IllegalStateException("The cubic spline has no maximum signal");
    }
    final double scale = 1.0 / maxSum;
    for (int k = 0; k < maxk; k++) {
        for (int i = 0; i < size; i++) {
            splines[k][i] = splines[k][i].scale(scale);
        }
    }
    // Create on an integer scale
    final CubicSplineData f = new CubicSplineData(maxi, maxj, splines);
    // Create a new info with the PSF details
    final ImagePSF.Builder b = ImagePSF.newBuilder();
    b.setImageCount(imagePsf.getImageCount());
    // Reducing the image has the effect of enlarging the pixel size
    b.setPixelSize(imagePsf.getPixelSize() * 3.0);
    b.setPixelDepth(imagePsf.getPixelDepth() * 3.0);
    // The centre has to be moved as we reduced the image size by 3.
    // In the ImagePSF the XY centre puts 0.5 at the centre of the pixel.
    // The spline puts 0,0 at the centre of each pixel for convenience.
    double cx = maxi / 2.0;
    if (imagePsf.getXCentre() != 0) {
        cx = (imagePsf.getXCentre() - 0.5) / 3;
    }
    double cy = maxj / 2.0;
    if (imagePsf.getYCentre() != 0) {
        cy = (imagePsf.getYCentre() - 0.5) / 3;
    }
    double cz = maxk / 2.0;
    if (imagePsf.getZCentre() != 0) {
        cz = imagePsf.getZCentre() / 3;
    } else if (imagePsf.getCentreImage() != 0) {
        cz = (imagePsf.getCentreImage() - 1) / 3.0;
    }
    b.setXCentre(cx);
    b.setYCentre(cy);
    b.setZCentre(cz);
    return new CubicSplinePsf(b.build(), f);
}
Also used : CubicSplineCalculator(uk.ac.sussex.gdsc.smlm.function.cspline.CubicSplineCalculator) Ticker(uk.ac.sussex.gdsc.core.logging.Ticker) LocalList(uk.ac.sussex.gdsc.core.utils.LocalList) ImagePSF(uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.ImagePSF) CubicSplineData(uk.ac.sussex.gdsc.smlm.function.cspline.CubicSplineData) ExecutorService(java.util.concurrent.ExecutorService) Future(java.util.concurrent.Future) CustomTricubicFunction(uk.ac.sussex.gdsc.core.math.interpolation.CustomTricubicFunction)

Example 4 with ImagePSF

use of uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.ImagePSF in project GDSC-SMLM by aherbert.

the class CreateData method createImagePsf.

/**
 * Create a PSF model from the image that contains all the z-slices needed to draw the given
 * localisations.
 *
 * @param localisationSets the localisation sets
 * @return the image PSF model
 */
private ImagePsfModel createImagePsf(List<LocalisationModelSet> localisationSets) {
    final ImagePlus imp = WindowManager.getImage(settings.getPsfImageName());
    if (imp == null) {
        IJ.error(TITLE, "Unable to create the PSF model from image: " + settings.getPsfImageName());
        return null;
    }
    try {
        final ImagePSF psfSettings = ImagePsfHelper.fromString(imp.getProperty("Info").toString());
        if (psfSettings == null) {
            throw new IllegalStateException("Unknown PSF settings for image: " + imp.getTitle());
        }
        // Check all the settings have values
        if (psfSettings.getPixelSize() <= 0) {
            throw new IllegalStateException("Missing nmPerPixel calibration settings for image: " + imp.getTitle());
        }
        if (psfSettings.getPixelDepth() <= 0) {
            throw new IllegalStateException("Missing nmPerSlice calibration settings for image: " + imp.getTitle());
        }
        if (psfSettings.getCentreImage() <= 0) {
            throw new IllegalStateException("Missing zCentre calibration settings for image: " + imp.getTitle());
        }
        if (psfSettings.getFwhm() <= 0) {
            throw new IllegalStateException("Missing FWHM calibration settings for image: " + imp.getTitle());
        }
        // To save memory construct the Image PSF using only the slices that are within
        // the depth of field of the simulation
        double minZ = Double.POSITIVE_INFINITY;
        double maxZ = Double.NEGATIVE_INFINITY;
        for (final LocalisationModelSet l : localisationSets) {
            for (final LocalisationModel m : l.getLocalisations()) {
                final double z = m.getZ();
                if (minZ > z) {
                    minZ = z;
                }
                if (maxZ < z) {
                    maxZ = z;
                }
            }
        }
        final int nSlices = imp.getStackSize();
        // z-centre should be an index and not the ImageJ slice number so subtract 1
        final int zCentre = psfSettings.getCentreImage() - 1;
        // Calculate the start/end slices to cover the depth of field
        // This logic must match the ImagePSFModel.
        final double unitsPerSlice = psfSettings.getPixelDepth() / settings.getPixelPitch();
        // We assume the PSF was imaged axially with increasing z-stage position (moving the stage
        // closer to the objective). Thus higher z-coordinate are for higher slice numbers.
        int lower = (int) Math.round(minZ / unitsPerSlice) + zCentre;
        int upper = (int) Math.round(maxZ / unitsPerSlice) + zCentre;
        // Add extra to the range so that gradients can be computed.
        lower--;
        upper++;
        upper = (upper < 0) ? 0 : (upper >= nSlices) ? nSlices - 1 : upper;
        lower = (lower < 0) ? 0 : (lower >= nSlices) ? nSlices - 1 : lower;
        // Image PSF requires the z-centre for normalisation
        if (!(lower <= zCentre && upper >= zCentre)) {
            // Ensure we include the zCentre
            lower = Math.min(lower, zCentre);
            upper = Math.max(upper, zCentre);
        }
        final double noiseFraction = 1e-3;
        final float[][] image = extractImageStack(imp, lower, upper);
        final ImagePsfModel model = new ImagePsfModel(image, zCentre - lower, psfSettings.getPixelSize() / settings.getPixelPitch(), unitsPerSlice, noiseFraction);
        // Add the calibrated centres. The map will not be null
        final Map<Integer, Offset> map = psfSettings.getOffsetsMap();
        if (!map.isEmpty()) {
            final int sliceOffset = lower + 1;
            for (final Entry<Integer, Offset> entry : map.entrySet()) {
                model.setRelativeCentre(entry.getKey() - sliceOffset, entry.getValue().getCx(), entry.getValue().getCy());
            }
        } else {
            // Use the CoM if present
            final double cx = psfSettings.getXCentre();
            final double cy = psfSettings.getYCentre();
            if (cx != 0 || cy != 0) {
                for (int slice = 0; slice < image.length; slice++) {
                    model.setCentre(slice, cx, cy);
                }
            }
        }
        // Initialise the HWHM table so that it can be cloned
        model.initialiseHwhm();
        return model;
    } catch (final Exception ex) {
        IJ.error(TITLE, "Unable to create the image PSF model:\n" + ex.getMessage());
        return null;
    }
}
Also used : ImagePlus(ij.ImagePlus) ReadHint(uk.ac.sussex.gdsc.smlm.results.ImageSource.ReadHint) ConfigurationException(uk.ac.sussex.gdsc.smlm.data.config.ConfigurationException) IOException(java.io.IOException) DataException(uk.ac.sussex.gdsc.core.data.DataException) ConversionException(uk.ac.sussex.gdsc.core.data.utils.ConversionException) NullArgumentException(org.apache.commons.math3.exception.NullArgumentException) Offset(uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.Offset) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) LocalisationModel(uk.ac.sussex.gdsc.smlm.model.LocalisationModel) ImagePSF(uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.ImagePSF) LocalisationModelSet(uk.ac.sussex.gdsc.smlm.model.LocalisationModelSet) ImagePsfModel(uk.ac.sussex.gdsc.smlm.model.ImagePsfModel)

Example 5 with ImagePSF

use of uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.ImagePSF in project GDSC-SMLM by aherbert.

the class PsfDrift method createImageList.

private static List<String> createImageList(boolean requireFwhm) {
    final List<String> titles = new LinkedList<>();
    final int[] ids = WindowManager.getIDList();
    if (ids != null) {
        for (final int id : ids) {
            final ImagePlus imp = WindowManager.getImage(id);
            if (imp != null && // Image must be greyscale
            (imp.getType() == ImagePlus.GRAY8 || imp.getType() == ImagePlus.GRAY16 || imp.getType() == ImagePlus.GRAY32) && // Image must be square and a stack of a single channel
            (imp.getWidth() == imp.getHeight() && imp.getNChannels() == 1)) {
                // Check if these are PSF images created by the SMLM plugins
                final ImagePSF psfSettings = getPsfSettings(imp);
                if (psfSettings != null) {
                    if (psfSettings.getCentreImage() <= 0) {
                        ImageJUtils.log(TITLE + ": Unknown PSF z-centre setting for image: " + imp.getTitle());
                        continue;
                    }
                    if (psfSettings.getPixelSize() <= 0) {
                        ImageJUtils.log(TITLE + ": Unknown PSF nm/pixel setting for image: " + imp.getTitle());
                        continue;
                    }
                    if (psfSettings.getPixelDepth() <= 0) {
                        ImageJUtils.log(TITLE + ": Unknown PSF nm/slice setting for image: " + imp.getTitle());
                        continue;
                    }
                    if (requireFwhm && psfSettings.getFwhm() <= 0) {
                        ImageJUtils.log(TITLE + ": Unknown PSF FWHM setting for image: " + imp.getTitle());
                        continue;
                    }
                    titles.add(imp.getTitle());
                }
            }
        }
    }
    return titles;
}
Also used : ImagePSF(uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.ImagePSF) ImagePlus(ij.ImagePlus) LinkedList(java.util.LinkedList)

Aggregations

ImagePSF (uk.ac.sussex.gdsc.smlm.data.config.PSFProtos.ImagePSF)6 ImagePlus (ij.ImagePlus)3 CubicSplineData (uk.ac.sussex.gdsc.smlm.function.cspline.CubicSplineData)2 GenericDialog (ij.gui.GenericDialog)1 ImageCanvas (ij.gui.ImageCanvas)1 Overlay (ij.gui.Overlay)1 Plot (ij.gui.Plot)1 Roi (ij.gui.Roi)1 Point (java.awt.Point)1 Rectangle (java.awt.Rectangle)1 BufferedInputStream (java.io.BufferedInputStream)1 FileInputStream (java.io.FileInputStream)1 IOException (java.io.IOException)1 InputStream (java.io.InputStream)1 LinkedList (java.util.LinkedList)1 ExecutorService (java.util.concurrent.ExecutorService)1 Future (java.util.concurrent.Future)1 AtomicInteger (java.util.concurrent.atomic.AtomicInteger)1 NullArgumentException (org.apache.commons.math3.exception.NullArgumentException)1 DataException (uk.ac.sussex.gdsc.core.data.DataException)1