All Downloads are FREE. Search and download functionalities are using the official Maven repository.

uk.ac.sussex.gdsc.smlm.model.GridDistribution Maven / Gradle / Ivy

Go to download

Genome Damage and Stability Centre SMLM Package Software for single molecule localisation microscopy (SMLM)

The newest version!
/*-
 * #%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.model;

import java.util.Arrays;
import org.apache.commons.rng.UniformRandomProvider;
import org.apache.commons.rng.sampling.distribution.NormalizedGaussianSampler;
import uk.ac.sussex.gdsc.core.utils.rng.SamplerUtils;
import uk.ac.sussex.gdsc.core.utils.rng.UniformRandomProviders;

/**
 * Populates an image with well spaced unary or binary localisations.
 *
 * 

Creates a grid layout using cells of the specified size within the image area. Each cell can * have one or two localisations. The first localisation is placed within the central 50% of the * cell. The second localisation (if present) is placed randomly up to a maximum distance away. When * all cells have been sampled then no more localisations are generated. */ public class GridDistribution implements SpatialDistribution { private final UniformRandomProvider rng; private final NormalizedGaussianSampler gauss; private final int size; private final int cellSize; private final double probBinary; private final double minBinaryDistance; private final double maxBinaryDistance; private final double min; private final double depth; private int cell = -1; private final int cellsPerRow; private final int totalCells; private double[] previous; /** * Create a distribution with the binary spots placed from 0 - distance. * * @param size the size * @param depth the depth * @param cellSize the cell size * @param probBinary the probability of a binary spot * @param binaryDistance the probability of a binary spot distance */ public GridDistribution(int size, double depth, int cellSize, double probBinary, double binaryDistance) { this(size, depth, cellSize, probBinary, 0, binaryDistance, null); } /** * Create a distribution with the binary spots placed from min - max distance. * * @param size the size * @param depth the depth * @param cellSize the cell size * @param probBinary the probability of a binary spot * @param minBinaryDistance the min binary distance * @param maxBinaryDistance the max binary distance */ public GridDistribution(int size, double depth, int cellSize, double probBinary, double minBinaryDistance, double maxBinaryDistance) { this(size, depth, cellSize, probBinary, minBinaryDistance, maxBinaryDistance, null); } /** * Create a distribution with the binary spots placed from min - max distance. * * @param size the size * @param depth the depth * @param cellSize the cell size * @param probBinary the probability of a binary spot * @param minBinaryDistance the min binary distance * @param maxBinaryDistance the max binary distance * @param randomGenerator the random generator */ public GridDistribution(int size, double depth, int cellSize, double probBinary, double minBinaryDistance, double maxBinaryDistance, UniformRandomProvider randomGenerator) { if (size < 1) { throw new IllegalArgumentException("Size must be above zero"); } if (size < cellSize) { throw new IllegalArgumentException("Size must be >= cell size"); } if (probBinary < 0 || probBinary > 1) { throw new IllegalArgumentException("Probability must be between 0 and 1"); } if (maxBinaryDistance < 0) { throw new IllegalArgumentException("Max distance must be positive"); } if (minBinaryDistance > maxBinaryDistance) { throw new IllegalArgumentException("Min distance must be below max distance"); } if (randomGenerator == null) { this.rng = UniformRandomProviders.create(); } else { this.rng = randomGenerator; } gauss = SamplerUtils.createNormalizedGaussianSampler(rng); this.size = size; this.min = -depth / 2; this.depth = depth; this.cellSize = cellSize; this.probBinary = probBinary; this.minBinaryDistance = minBinaryDistance; this.maxBinaryDistance = maxBinaryDistance; cellsPerRow = size / cellSize; totalCells = cellsPerRow * cellsPerRow; } @Override public double[] next() { // See if a binary localisation should be created near the previous spot if (previous != null && rng.nextDouble() < probBinary) { final double[] xyz = Arrays.copyOf(previous, 3); // Create a random unit vector double x = gauss.sample(); double y = gauss.sample(); double z = gauss.sample(); final double length = Math.sqrt(x * x + y * y + z * z); if (length != 0) { // Shift by a random distance final double distance = (maxBinaryDistance == minBinaryDistance) ? maxBinaryDistance : nextUniform(minBinaryDistance, maxBinaryDistance); final double d = distance / length; x *= d; y *= d; z *= d; } xyz[0] += x; xyz[1] += y; xyz[2] += z; previous = null; return xyz; } previous = null; // See if any more localisations will fit in the grid if (++cell < totalCells) { final int cellx = cell % cellsPerRow; final int celly = cell / cellsPerRow; previous = new double[3]; // Ensure the centre of the distribution is [0,0,0] previous[0] = cellx * cellSize - size / 2 + cellSize * nextUniform(0.25, 0.75); previous[1] = celly * cellSize - size / 2 + cellSize * nextUniform(0.25, 0.75); previous[2] = min + rng.nextDouble() * depth; } return previous; } /** * Create a uniform deviate between low and high inclusive. * * @param lo the low * @param hi the high * @return the double */ private double nextUniform(double lo, double hi) { final double u = rng.nextDouble(); return u * hi + (1 - u) * lo; } @Override public boolean isWithin(double[] xyz) { for (final double d : xyz) { if (d < 0 || d > size) { return false; } } return true; } @Override public boolean isWithinXy(double[] xyz) { for (int i = 0; i < 2; i++) { if (xyz[i] < 0 || xyz[i] > size) { return false; } } return true; } @Override public void initialise(double[] xyz) { // Ignore } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy