Search in sources :

Example 86 with ByteProcessor

use of ij.process.ByteProcessor in project TrakEM2 by trakem2.

the class ImageArrayConverter method ImageToFloatArray2D.

public static FloatArray2D ImageToFloatArray2D(ImageProcessor ip) {
    FloatArray2D image;
    Object pixelArray = ip.getPixels();
    int count = 0;
    if (ip instanceof ByteProcessor) {
        image = new FloatArray2D(ip.getWidth(), ip.getHeight());
        byte[] pixels = (byte[]) pixelArray;
        for (int y = 0; y < ip.getHeight(); y++) for (int x = 0; x < ip.getWidth(); x++) image.data[count] = pixels[count++] & 0xff;
    } else if (ip instanceof ShortProcessor) {
        image = new FloatArray2D(ip.getWidth(), ip.getHeight());
        short[] pixels = (short[]) pixelArray;
        for (int y = 0; y < ip.getHeight(); y++) for (int x = 0; x < ip.getWidth(); x++) image.data[count] = pixels[count++] & 0xffff;
    } else if (ip instanceof FloatProcessor) {
        image = new FloatArray2D(ip.getWidth(), ip.getHeight());
        float[] pixels = (float[]) pixelArray;
        for (int y = 0; y < ip.getHeight(); y++) for (int x = 0; x < ip.getWidth(); x++) image.data[count] = pixels[count++];
    } else // RGB
    {
        image = new FloatArray2D(ip.getWidth(), ip.getHeight());
        int[] pixels = (int[]) pixelArray;
    // still unknown how to do...
    /*
            for (int y = 0; y < ip.getHeight(); y++)
                for (int x = 0; x < ip.getWidth(); x++)
                        image[x][y] = pixels[count++];// & 0xffffff;
            */
    }
    return image;
}
Also used : ByteProcessor(ij.process.ByteProcessor) FloatArray2D(mpi.fruitfly.math.datastructures.FloatArray2D) FloatProcessor(ij.process.FloatProcessor) Point(java.awt.Point) ShortProcessor(ij.process.ShortProcessor)

Example 87 with ByteProcessor

use of ij.process.ByteProcessor in project GDSC-SMLM by aherbert.

the class SplitResults method splitResults.

private void splitResults(MemoryPeakResults results, ImageProcessor ip) {
    IJ.showStatus("Splitting " + TextUtils.pleural(results.size(), "result"));
    // Create an object mask
    final ObjectAnalyzer objectAnalyzer = new ObjectAnalyzer(ip, false);
    final int maxx = ip.getWidth();
    final int maxy = ip.getHeight();
    final Rectangle bounds = results.getBounds();
    final double ox = bounds.getX();
    final double oy = bounds.getY();
    final double scaleX = bounds.getWidth() / maxx;
    final double scaleY = bounds.getHeight() / maxy;
    // Create a results set for each object
    final int maxObject = objectAnalyzer.getMaxObject();
    final MemoryPeakResults[] resultsSet = new MemoryPeakResults[maxObject + 1];
    for (int object = 0; object <= maxObject; object++) {
        final MemoryPeakResults newResults = new MemoryPeakResults();
        newResults.copySettings(results);
        newResults.setName(results.getName() + " " + object);
        resultsSet[object] = newResults;
    }
    final int[] mask = objectAnalyzer.getObjectMask();
    if (settings.showObjectMask) {
        final ImageProcessor objectIp = (maxObject <= 255) ? new ByteProcessor(maxx, maxy) : new ShortProcessor(maxx, maxy);
        for (int i = 0; i < mask.length; i++) {
            objectIp.set(i, mask[i]);
        }
        final ImagePlus imp = ImageJUtils.display(settings.objectMask + " Objects", objectIp);
        imp.setDisplayRange(0, maxObject);
        imp.updateAndDraw();
    }
    // Process the results mapping them to their objects
    final Counter i = new Counter();
    final int size = results.size();
    final int step = ImageJUtils.getProgressInterval(size);
    results.forEach(DistanceUnit.PIXEL, (XyrResultProcedure) (xx, yy, result) -> {
        if (i.incrementAndGet() % step == 0) {
            IJ.showProgress(i.getCount(), size);
        }
        // Map to the mask objects
        final int object;
        final int x = (int) ((xx - ox) / scaleX);
        final int y = (int) ((yy - oy) / scaleY);
        if (x < 0 || x >= maxx || y < 0 || y >= maxy) {
            object = 0;
        } else {
            final int index = y * maxx + x;
            // is within the bounds of the image processor?
            if (index < 0 || index >= mask.length) {
                object = 0;
            } else {
                object = mask[index];
            }
        }
        resultsSet[object].add(result);
    });
    IJ.showProgress(1);
    // Add the new results sets to memory
    i.reset();
    for (int object = (settings.nonMaskDataset) ? 0 : 1; object <= maxObject; object++) {
        if (resultsSet[object].isNotEmpty()) {
            MemoryPeakResults.addResults(resultsSet[object]);
            i.increment();
        }
    }
    IJ.showStatus("Split " + TextUtils.pleural(results.size(), "result") + " into " + TextUtils.pleural(i.getCount(), "set"));
}
Also used : ByteProcessor(ij.process.ByteProcessor) Rectangle(java.awt.Rectangle) XyrResultProcedure(uk.ac.sussex.gdsc.smlm.results.procedures.XyrResultProcedure) ByteProcessor(ij.process.ByteProcessor) ObjectAnalyzer(uk.ac.sussex.gdsc.smlm.ij.utils.ObjectAnalyzer) ImageProcessor(ij.process.ImageProcessor) ExtendedGenericDialog(uk.ac.sussex.gdsc.core.ij.gui.ExtendedGenericDialog) InputSource(uk.ac.sussex.gdsc.smlm.ij.plugins.ResultsManager.InputSource) WindowManager(ij.WindowManager) DistanceUnit(uk.ac.sussex.gdsc.smlm.data.config.UnitProtos.DistanceUnit) AtomicReference(java.util.concurrent.atomic.AtomicReference) TextUtils(uk.ac.sussex.gdsc.core.utils.TextUtils) ImagePlus(ij.ImagePlus) Counter(uk.ac.sussex.gdsc.smlm.results.count.Counter) ShortProcessor(ij.process.ShortProcessor) ImageJUtils(uk.ac.sussex.gdsc.core.ij.ImageJUtils) MemoryPeakResults(uk.ac.sussex.gdsc.smlm.results.MemoryPeakResults) IJ(ij.IJ) PlugIn(ij.plugin.PlugIn) Rectangle(java.awt.Rectangle) ImagePlus(ij.ImagePlus) ShortProcessor(ij.process.ShortProcessor) ImageProcessor(ij.process.ImageProcessor) ObjectAnalyzer(uk.ac.sussex.gdsc.smlm.ij.utils.ObjectAnalyzer) Counter(uk.ac.sussex.gdsc.smlm.results.count.Counter) MemoryPeakResults(uk.ac.sussex.gdsc.smlm.results.MemoryPeakResults)

Example 88 with ByteProcessor

use of ij.process.ByteProcessor in project GDSC-SMLM by aherbert.

the class DrawClusters method run.

@Override
public void run(String arg) {
    SmlmUsageTracker.recordPlugin(this.getClass(), arg);
    if (MemoryPeakResults.isMemoryEmpty()) {
        IJ.error(TITLE, "No localisations in memory");
        return;
    }
    if (!showDialog()) {
        return;
    }
    // Load the results
    final MemoryPeakResults results = ResultsManager.loadInputResults(settings.inputOption, false, DistanceUnit.PIXEL);
    if (MemoryPeakResults.isEmpty(results)) {
        IJ.error(TITLE, "No results could be loaded");
        return;
    }
    // Get the traces
    final Trace[] traces = TraceManager.convert(results);
    if (traces == null || traces.length == 0) {
        IJ.error(TITLE, "No traces could be loaded");
        return;
    }
    // Filter traces to a min size
    int maxFrame = 0;
    int count = 0;
    final int myMaxSize = (settings.maxSize < settings.minSize) ? Integer.MAX_VALUE : settings.maxSize;
    final boolean myDrawLines = myMaxSize > 1 && settings.drawLines;
    for (int i = 0; i < traces.length; i++) {
        if (settings.expandToSingles) {
            traces[i].expandToSingles();
        }
        if (traces[i].size() >= settings.minSize && traces[i].size() <= myMaxSize) {
            traces[count++] = traces[i];
            traces[i].sort();
            if (maxFrame < traces[i].getTail().getFrame()) {
                maxFrame = traces[i].getTail().getFrame();
            }
        }
    }
    if (count == 0) {
        IJ.error(TITLE, "No traces achieved the size limits");
        return;
    }
    final String msg = String.format(TITLE + ": %d / %s (%s)", count, TextUtils.pleural(traces.length, "trace"), TextUtils.pleural(results.size(), "localisation"));
    IJ.showStatus(msg);
    final Rectangle bounds = results.getBounds(true);
    ImagePlus imp = WindowManager.getImage(settings.title);
    boolean isUseStackPosition = settings.useStackPosition;
    if (imp == null) {
        // Create a default image using 100 pixels as the longest edge
        final double maxD = (bounds.width > bounds.height) ? bounds.width : bounds.height;
        int width;
        int height;
        if (maxD == 0) {
            // Note that imageSize can be zero (for auto sizing)
            width = height = (settings.imageSize == 0) ? 20 : settings.imageSize;
        } else if (settings.imageSize == 0) {
            // Note that imageSize can be zero (for auto sizing)
            width = bounds.width;
            height = bounds.height;
        } else {
            width = (int) (settings.imageSize * bounds.width / maxD);
            height = (int) (settings.imageSize * bounds.height / maxD);
        }
        final ByteProcessor bp = new ByteProcessor(width, height);
        if (isUseStackPosition) {
            final ImageStack stack = new ImageStack(width, height, maxFrame);
            for (int i = 1; i <= maxFrame; i++) {
                // Do not clone as the image is empty
                stack.setPixels(bp.getPixels(), i);
            }
            imp = ImageJUtils.display(TITLE, stack);
        } else {
            imp = ImageJUtils.display(TITLE, bp);
        }
        // Enlarge
        final ImageWindow iw = imp.getWindow();
        for (int i = 9; i-- > 0 && iw.getWidth() < 500 && iw.getHeight() < 500; ) {
            iw.getCanvas().zoomIn(imp.getWidth() / 2, imp.getHeight() / 2);
        }
    // Check if the image has enough frames for all the traces
    } else if (maxFrame > imp.getNFrames()) {
        isUseStackPosition = false;
    }
    final float xScale = (float) (imp.getWidth() / bounds.getWidth());
    final float yScale = (float) (imp.getHeight() / bounds.getHeight());
    // Create ROIs and store data to sort them
    final Roi[] rois = new Roi[count];
    final int[][] frames = (isUseStackPosition) ? new int[count][] : null;
    final int[] indices = SimpleArrayUtils.natural(count);
    final double[] values = new double[count];
    for (int i = 0; i < count; i++) {
        final Trace trace = traces[i];
        final int npoints = trace.size();
        final float[] xpoints = new float[npoints];
        final float[] ypoints = new float[npoints];
        int ii = 0;
        if (frames != null) {
            frames[i] = new int[npoints];
        }
        for (int k = 0; k < trace.size(); k++) {
            final PeakResult result = trace.get(k);
            xpoints[ii] = (result.getXPosition() - bounds.x) * xScale;
            ypoints[ii] = (result.getYPosition() - bounds.y) * yScale;
            if (frames != null) {
                frames[i][ii] = result.getFrame();
            }
            ii++;
        }
        Roi roi;
        if (myDrawLines) {
            roi = new PolygonRoi(xpoints, ypoints, npoints, Roi.POLYLINE);
            if (settings.splineFit) {
                ((PolygonRoi) roi).fitSpline();
            }
        } else {
            roi = new OffsetPointRoi(xpoints, ypoints, npoints);
            ((PointRoi) roi).setShowLabels(false);
        }
        rois[i] = roi;
        switch(settings.sort) {
            case // Sort by ID
            1:
                values[i] = traces[i].getId();
                break;
            case // Sort by time
            2:
                values[i] = traces[i].getHead().getFrame();
                break;
            case // Sort by size descending
            3:
                values[i] = -traces[i].size();
                break;
            case // Sort by length descending
            4:
                values[i] = -roi.getLength();
                break;
            case // Mean Square Displacement
            5:
                values[i] = -traces[i].getMsd();
                break;
            case // Mean / Frame
            6:
                values[i] = -traces[i].getMeanDistance();
                break;
            // No sort
            case 0:
            default:
                break;
        }
    }
    if (settings.sort > 0) {
        SortUtils.sortIndices(indices, values, true);
    }
    // Draw the traces as ROIs on an overlay
    final Overlay o = new Overlay();
    final LUT lut = LutHelper.createLut(settings.lut);
    final double scale = 256.0 / count;
    if (frames != null) {
        // Add the tracks on the frames containing the results
        final boolean isHyperStack = imp.isDisplayedHyperStack();
        for (int i = 0; i < count; i++) {
            final int index = indices[i];
            final Color c = LutHelper.getColour(lut, (int) (i * scale));
            final PolygonRoi roi = (PolygonRoi) rois[index];
            roi.setFillColor(c);
            roi.setStrokeColor(c);
            // roi.setStrokeWidth(settings.lineWidth);
            roi.updateWideLine(settings.lineWidth);
            final FloatPolygon fp = roi.getNonSplineFloatPolygon();
            // For each frame in the track, add the ROI track and a point ROI for the current position
            for (int j = 0; j < frames[index].length; j++) {
                addToOverlay(o, (Roi) roi.clone(), isHyperStack, frames[index][j]);
                final PointRoi pointRoi = new OffsetPointRoi(fp.xpoints[j], fp.ypoints[j]);
                pointRoi.setPointType(3);
                pointRoi.setFillColor(c);
                pointRoi.setStrokeColor(Color.black);
                addToOverlay(o, pointRoi, isHyperStack, frames[index][j]);
            }
        }
    } else {
        // Add the tracks as a single overlay
        for (int i = 0; i < count; i++) {
            final Roi roi = rois[indices[i]];
            roi.setStrokeColor(new Color(lut.getRGB((int) (i * scale))));
            // roi.setStrokeWidth(settings.lineWidth);
            roi.updateWideLine(settings.lineWidth);
            o.add(roi);
        }
    }
    imp.setOverlay(o);
    IJ.showStatus(msg);
}
Also used : ByteProcessor(ij.process.ByteProcessor) ImageWindow(ij.gui.ImageWindow) Rectangle(java.awt.Rectangle) PeakResult(uk.ac.sussex.gdsc.smlm.results.PeakResult) PolygonRoi(ij.gui.PolygonRoi) MemoryPeakResults(uk.ac.sussex.gdsc.smlm.results.MemoryPeakResults) Overlay(ij.gui.Overlay) PointRoi(ij.gui.PointRoi) OffsetPointRoi(uk.ac.sussex.gdsc.core.ij.gui.OffsetPointRoi) ImageStack(ij.ImageStack) OffsetPointRoi(uk.ac.sussex.gdsc.core.ij.gui.OffsetPointRoi) Color(java.awt.Color) LUT(ij.process.LUT) ImagePlus(ij.ImagePlus) PolygonRoi(ij.gui.PolygonRoi) PointRoi(ij.gui.PointRoi) OffsetPointRoi(uk.ac.sussex.gdsc.core.ij.gui.OffsetPointRoi) Roi(ij.gui.Roi) Trace(uk.ac.sussex.gdsc.smlm.results.Trace) FloatPolygon(ij.process.FloatPolygon)

Example 89 with ByteProcessor

use of ij.process.ByteProcessor in project GDSC-SMLM by aherbert.

the class PcPalmMolecules method runSimulation.

private void runSimulation(boolean resultsAvailable) {
    if (resultsAvailable && !showSimulationDialog()) {
        return;
    }
    startLog();
    log("Simulation parameters");
    if (settings.blinkingDistribution == 3) {
        log("  - Clusters = %d", settings.numberOfMolecules);
        log("  - Simulation size = %s um", MathUtils.rounded(settings.simulationSize, 4));
        log("  - Molecules/cluster = %s", MathUtils.rounded(settings.blinkingRate, 4));
        log("  - Blinking distribution = %s", Settings.BLINKING_DISTRIBUTION[settings.blinkingDistribution]);
        log("  - p-Value = %s", MathUtils.rounded(settings.pvalue, 4));
    } else {
        log("  - Molecules = %d", settings.numberOfMolecules);
        log("  - Simulation size = %s um", MathUtils.rounded(settings.simulationSize, 4));
        log("  - Blinking rate = %s", MathUtils.rounded(settings.blinkingRate, 4));
        log("  - Blinking distribution = %s", Settings.BLINKING_DISTRIBUTION[settings.blinkingDistribution]);
    }
    log("  - Average precision = %s nm", MathUtils.rounded(settings.sigmaS, 4));
    log("  - Clusters simulation = " + Settings.CLUSTER_SIMULATION[settings.clusterSimulation]);
    if (settings.clusterSimulation > 0) {
        log("  - Cluster number = %s +/- %s", MathUtils.rounded(settings.clusterNumber, 4), MathUtils.rounded(settings.clusterNumberStdDev, 4));
        log("  - Cluster radius = %s nm", MathUtils.rounded(settings.clusterRadius, 4));
    }
    final double nmPerPixel = 100;
    final double width = settings.simulationSize * 1000.0;
    final UniformRandomProvider rng = UniformRandomProviders.create();
    final UniformDistribution dist = new UniformDistribution(null, new double[] { width, width, 0 }, rng.nextInt());
    final NormalizedGaussianSampler gauss = SamplerUtils.createNormalizedGaussianSampler(rng);
    settings.molecules = new ArrayList<>(settings.numberOfMolecules);
    // Create some dummy results since the calibration is required for later analysis
    settings.results = new MemoryPeakResults(PsfHelper.create(PSFType.CUSTOM));
    settings.results.setCalibration(CalibrationHelper.create(nmPerPixel, 1, 100));
    settings.results.setSource(new NullSource("Molecule Simulation"));
    settings.results.begin();
    int count = 0;
    // Generate a sequence of coordinates
    final ArrayList<double[]> xyz = new ArrayList<>((int) (settings.numberOfMolecules * 1.1));
    final Statistics statsRadius = new Statistics();
    final Statistics statsSize = new Statistics();
    final String maskTitle = TITLE + " Cluster Mask";
    ByteProcessor bp = null;
    double maskScale = 0;
    if (settings.clusterSimulation > 0) {
        // Simulate clusters.
        // Note: In the Veatch et al. paper (Plos 1, e31457) correlation functions are built using
        // circles with small radii of 4-8 Arbitrary Units (AU) or large radii of 10-30 AU. A
        // fluctuations model is created at T = 1.075 Tc. It is not clear exactly how the particles
        // are distributed.
        // It may be that a mask is created first using the model. The particles are placed on the
        // mask using a specified density. This simulation produces a figure to show either a damped
        // cosine function (circles) or an exponential (fluctuations). The number of particles in
        // each circle may be randomly determined just by density. The figure does not discuss the
        // derivation of the cluster size statistic.
        // 
        // If this plugin simulation is run with a uniform distribution and blinking rate of 1 then
        // the damped cosine function is reproduced. The curve crosses g(r)=1 at a value equivalent
        // to the average distance to the centre-of-mass of each drawn cluster, not the input cluster
        // radius parameter (which is a hard upper limit on the distance to centre).
        final int maskSize = settings.lowResolutionImageSize;
        int[] mask = null;
        // scale is in nm/pixel
        maskScale = width / maskSize;
        final ArrayList<double[]> clusterCentres = new ArrayList<>();
        int totalSteps = 1 + (int) Math.ceil(settings.numberOfMolecules / settings.clusterNumber);
        if (settings.clusterSimulation == 2 || settings.clusterSimulation == 3) {
            // Clusters are non-overlapping circles
            // Ensure the circles do not overlap by using an exclusion mask that accumulates
            // out-of-bounds pixels by drawing the last cluster (plus some border) on an image. When no
            // more pixels are available then stop generating molecules.
            // This is done by cumulatively filling a mask and using the MaskDistribution to select
            // a new point. This may be slow but it works.
            // TODO - Allow clusters of different sizes...
            mask = new int[maskSize * maskSize];
            Arrays.fill(mask, 255);
            MaskDistribution maskDistribution = new MaskDistribution(mask, maskSize, maskSize, 0, maskScale, maskScale, rng);
            double[] centre;
            IJ.showStatus("Computing clusters mask");
            final int roiRadius = (int) Math.round((settings.clusterRadius * 2) / maskScale);
            if (settings.clusterSimulation == 3) {
                // Generate a mask of circles then sample from that.
                // If we want to fill the mask completely then adjust the total steps to be the number of
                // circles that can fit inside the mask.
                totalSteps = (int) (maskSize * maskSize / (Math.PI * MathUtils.pow2(settings.clusterRadius / maskScale)));
            }
            while ((centre = maskDistribution.next()) != null && clusterCentres.size() < totalSteps) {
                IJ.showProgress(clusterCentres.size(), totalSteps);
                // The mask returns the coordinates with the centre of the image at 0,0
                centre[0] += width / 2;
                centre[1] += width / 2;
                clusterCentres.add(centre);
                // Fill in the mask around the centre to exclude any more circles that could overlap
                final double cx = centre[0] / maskScale;
                final double cy = centre[1] / maskScale;
                fillMask(mask, maskSize, (int) cx, (int) cy, roiRadius, 0);
                try {
                    maskDistribution = new MaskDistribution(mask, maskSize, maskSize, 0, maskScale, maskScale, rng);
                } catch (final IllegalArgumentException ex) {
                    // This can happen when there are no more non-zero pixels
                    log("WARNING: No more room for clusters on the mask area (created %d of estimated %d)", clusterCentres.size(), totalSteps);
                    break;
                }
            }
            ImageJUtils.finished();
        } else {
            // Pick centres randomly from the distribution
            while (clusterCentres.size() < totalSteps) {
                clusterCentres.add(dist.next());
            }
        }
        final double scaledRadius = settings.clusterRadius / maskScale;
        if (settings.showClusterMask || settings.clusterSimulation == 3) {
            // Show the mask for the clusters
            if (mask == null) {
                mask = new int[maskSize * maskSize];
            } else {
                Arrays.fill(mask, 0);
            }
            final int roiRadius = (int) Math.round(scaledRadius);
            for (final double[] c : clusterCentres) {
                final double cx = c[0] / maskScale;
                final double cy = c[1] / maskScale;
                fillMask(mask, maskSize, (int) cx, (int) cy, roiRadius, 1);
            }
            if (settings.clusterSimulation == 3) {
                // We have the mask. Now pick points at random from the mask.
                final MaskDistribution maskDistribution = new MaskDistribution(mask, maskSize, maskSize, 0, maskScale, maskScale, rng);
                // Allocate each molecule position to a parent circle so defining clusters.
                final int[][] clusters = new int[clusterCentres.size()][];
                final int[] clusterSize = new int[clusters.length];
                for (int i = 0; i < settings.numberOfMolecules; i++) {
                    final double[] centre = maskDistribution.next();
                    // The mask returns the coordinates with the centre of the image at 0,0
                    centre[0] += width / 2;
                    centre[1] += width / 2;
                    xyz.add(centre);
                    // Output statistics on cluster size and number.
                    // TODO - Finding the closest cluster could be done better than an all-vs-all comparison
                    double max = distance2(centre, clusterCentres.get(0));
                    int cluster = 0;
                    for (int j = 1; j < clusterCentres.size(); j++) {
                        final double d2 = distance2(centre, clusterCentres.get(j));
                        if (d2 < max) {
                            max = d2;
                            cluster = j;
                        }
                    }
                    // Assign point i to cluster
                    centre[2] = cluster;
                    if (clusterSize[cluster] == 0) {
                        clusters[cluster] = new int[10];
                    }
                    if (clusters[cluster].length <= clusterSize[cluster]) {
                        clusters[cluster] = Arrays.copyOf(clusters[cluster], (int) (clusters[cluster].length * 1.5));
                    }
                    clusters[cluster][clusterSize[cluster]++] = i;
                }
                // Generate real cluster size statistics
                for (int j = 0; j < clusterSize.length; j++) {
                    final int size = clusterSize[j];
                    if (size == 0) {
                        continue;
                    }
                    statsSize.add(size);
                    if (size == 1) {
                        statsRadius.add(0);
                        continue;
                    }
                    // Find centre of cluster and add the distance to each point
                    final double[] com = new double[2];
                    for (int n = 0; n < size; n++) {
                        final double[] xy = xyz.get(clusters[j][n]);
                        for (int k = 0; k < 2; k++) {
                            com[k] += xy[k];
                        }
                    }
                    for (int k = 0; k < 2; k++) {
                        com[k] /= size;
                    }
                    for (int n = 0; n < size; n++) {
                        final double dx = xyz.get(clusters[j][n])[0] - com[0];
                        final double dy = xyz.get(clusters[j][n])[1] - com[1];
                        statsRadius.add(Math.sqrt(dx * dx + dy * dy));
                    }
                }
            }
            if (settings.showClusterMask) {
                bp = new ByteProcessor(maskSize, maskSize);
                for (int i = 0; i < mask.length; i++) {
                    if (mask[i] != 0) {
                        bp.set(i, 128);
                    }
                }
                ImageJUtils.display(maskTitle, bp);
            }
        }
        // Use the simulated cluster centres to create clusters of the desired size
        if (settings.clusterSimulation == 1 || settings.clusterSimulation == 2) {
            for (final double[] clusterCentre : clusterCentres) {
                final int clusterN = (int) Math.round((settings.clusterNumberStdDev > 0) ? settings.clusterNumber + gauss.sample() * settings.clusterNumberStdDev : settings.clusterNumber);
                if (clusterN < 1) {
                    continue;
                }
                if (clusterN == 1) {
                    // No need for a cluster around a point
                    xyz.add(clusterCentre);
                    statsRadius.add(0);
                    statsSize.add(1);
                } else {
                    // Generate N random points within a circle of the chosen cluster radius.
                    // Locate the centre-of-mass and the average distance to the centre.
                    final double[] com = new double[3];
                    int size = 0;
                    while (size < clusterN) {
                        // Generate a random point within a circle uniformly
                        // http://stackoverflow.com/questions/5837572/generate-a-random-point-within-a-circle-uniformly
                        final double t = 2.0 * Math.PI * rng.nextDouble();
                        final double u = rng.nextDouble() + rng.nextDouble();
                        final double r = settings.clusterRadius * ((u > 1) ? 2 - u : u);
                        final double x = r * Math.cos(t);
                        final double y = r * Math.sin(t);
                        final double[] xy = new double[] { clusterCentre[0] + x, clusterCentre[1] + y };
                        xyz.add(xy);
                        for (int k = 0; k < 2; k++) {
                            com[k] += xy[k];
                        }
                        size++;
                    }
                    // Add the distance of the points from the centre of the cluster.
                    // Note this does not account for the movement due to precision.
                    statsSize.add(size);
                    if (size == 1) {
                        statsRadius.add(0);
                    } else {
                        for (int k = 0; k < 2; k++) {
                            com[k] /= size;
                        }
                        while (size > 0) {
                            final double dx = xyz.get(xyz.size() - size)[0] - com[0];
                            final double dy = xyz.get(xyz.size() - size)[1] - com[1];
                            statsRadius.add(Math.sqrt(dx * dx + dy * dy));
                            size--;
                        }
                    }
                }
            }
        }
    } else {
        // Random distribution
        for (int i = 0; i < settings.numberOfMolecules; i++) {
            xyz.add(dist.next());
        }
    }
    // The Gaussian sigma should be applied so the overall distance from the centre
    // ( sqrt(x^2+y^2) ) has a standard deviation of sigmaS?
    final double sigma1D = settings.sigmaS / Math.sqrt(2);
    // Show optional histograms
    StoredDataStatistics intraDistances = null;
    StoredData blinks = null;
    if (settings.showHistograms) {
        final int capacity = (int) (xyz.size() * settings.blinkingRate);
        intraDistances = new StoredDataStatistics(capacity);
        blinks = new StoredData(capacity);
    }
    final Statistics statsSigma = new Statistics();
    for (int i = 0; i < xyz.size(); i++) {
        int occurrences = getBlinks(rng, settings.blinkingRate);
        if (blinks != null) {
            blinks.add(occurrences);
        }
        final int size = settings.molecules.size();
        // Get coordinates in nm
        final double[] moleculeXyz = xyz.get(i);
        if (bp != null && occurrences > 0) {
            bp.putPixel((int) Math.round(moleculeXyz[0] / maskScale), (int) Math.round(moleculeXyz[1] / maskScale), 255);
        }
        while (occurrences-- > 0) {
            final double[] localisationXy = Arrays.copyOf(moleculeXyz, 2);
            // Add random precision
            if (sigma1D > 0) {
                final double dx = gauss.sample() * sigma1D;
                final double dy = gauss.sample() * sigma1D;
                localisationXy[0] += dx;
                localisationXy[1] += dy;
                if (!dist.isWithinXy(localisationXy)) {
                    continue;
                }
                // Calculate mean-squared displacement
                statsSigma.add(dx * dx + dy * dy);
            }
            final double x = localisationXy[0];
            final double y = localisationXy[1];
            settings.molecules.add(new Molecule(x, y, i, 1));
            // Store in pixels
            final float xx = (float) (x / nmPerPixel);
            final float yy = (float) (y / nmPerPixel);
            final float[] params = PeakResult.createParams(0, 0, xx, yy, 0);
            settings.results.add(i + 1, (int) xx, (int) yy, 0, 0, 0, 0, params, null);
        }
        if (settings.molecules.size() > size) {
            count++;
            if (intraDistances != null) {
                final int newCount = settings.molecules.size() - size;
                if (newCount == 1) {
                    // No intra-molecule distances
                    continue;
                }
                // Get the distance matrix between these molecules
                final double[][] matrix = new double[newCount][newCount];
                for (int ii = size, x = 0; ii < settings.molecules.size(); ii++, x++) {
                    for (int jj = size + 1, y = 1; jj < settings.molecules.size(); jj++, y++) {
                        final double d2 = settings.molecules.get(ii).distance2(settings.molecules.get(jj));
                        matrix[x][y] = matrix[y][x] = d2;
                    }
                }
                // Get the maximum distance for particle linkage clustering of this molecule
                double max = 0;
                for (int x = 0; x < newCount; x++) {
                    // Compare to all-other molecules and get the minimum distance
                    // needed to join at least one
                    double linkDistance = Double.POSITIVE_INFINITY;
                    for (int y = 0; y < newCount; y++) {
                        if (x == y) {
                            continue;
                        }
                        if (matrix[x][y] < linkDistance) {
                            linkDistance = matrix[x][y];
                        }
                    }
                    // Check if this is larger
                    if (max < linkDistance) {
                        max = linkDistance;
                    }
                }
                intraDistances.add(Math.sqrt(max));
            }
        }
    }
    settings.results.end();
    if (bp != null) {
        final ImagePlus imp = ImageJUtils.display(maskTitle, bp);
        final Calibration cal = imp.getCalibration();
        cal.setUnit("nm");
        cal.pixelWidth = cal.pixelHeight = maskScale;
    }
    log("Simulation results");
    log("  * Molecules = %d (%d activated)", xyz.size(), count);
    log("  * Blinking rate = %s", MathUtils.rounded((double) settings.molecules.size() / xyz.size(), 4));
    log("  * Precision (Mean-displacement) = %s nm", (statsSigma.getN() > 0) ? MathUtils.rounded(Math.sqrt(statsSigma.getMean()), 4) : "0");
    if (intraDistances != null) {
        if (intraDistances.getN() == 0) {
            log("  * Mean Intra-Molecule particle linkage distance = 0 nm");
            log("  * Fraction of inter-molecule particle linkage @ 0 nm = 0 %%");
        } else {
            plot(blinks, "Blinks/Molecule", true);
            final double[][] intraHist = plot(intraDistances, "Intra-molecule particle linkage distance", false);
            // Determine 95th and 99th percentile
            // Will not be null as we requested a non-integer histogram.
            int p99 = intraHist[0].length - 1;
            final double limit1 = 0.99 * intraHist[1][p99];
            final double limit2 = 0.95 * intraHist[1][p99];
            while (intraHist[1][p99] > limit1 && p99 > 0) {
                p99--;
            }
            int p95 = p99;
            while (intraHist[1][p95] > limit2 && p95 > 0) {
                p95--;
            }
            log("  * Mean Intra-Molecule particle linkage distance = %s nm" + " (95%% = %s, 99%% = %s, 100%% = %s)", MathUtils.rounded(intraDistances.getMean(), 4), MathUtils.rounded(intraHist[0][p95], 4), MathUtils.rounded(intraHist[0][p99], 4), MathUtils.rounded(intraHist[0][intraHist[0].length - 1], 4));
            if (settings.distanceAnalysis) {
                performDistanceAnalysis(intraHist, p99);
            }
        }
    }
    if (settings.clusterSimulation > 0) {
        log("  * Cluster number = %s +/- %s", MathUtils.rounded(statsSize.getMean(), 4), MathUtils.rounded(statsSize.getStandardDeviation(), 4));
        log("  * Cluster radius = %s +/- %s nm (mean distance to centre-of-mass)", MathUtils.rounded(statsRadius.getMean(), 4), MathUtils.rounded(statsRadius.getStandardDeviation(), 4));
    }
}
Also used : ByteProcessor(ij.process.ByteProcessor) TDoubleArrayList(gnu.trove.list.array.TDoubleArrayList) ArrayList(java.util.ArrayList) MaskDistribution(uk.ac.sussex.gdsc.smlm.model.MaskDistribution) MemoryPeakResults(uk.ac.sussex.gdsc.smlm.results.MemoryPeakResults) NullSource(uk.ac.sussex.gdsc.smlm.results.NullSource) UniformDistribution(uk.ac.sussex.gdsc.smlm.model.UniformDistribution) StoredDataStatistics(uk.ac.sussex.gdsc.core.utils.StoredDataStatistics) Calibration(ij.measure.Calibration) StoredDataStatistics(uk.ac.sussex.gdsc.core.utils.StoredDataStatistics) Statistics(uk.ac.sussex.gdsc.core.utils.Statistics) DescriptiveStatistics(org.apache.commons.math3.stat.descriptive.DescriptiveStatistics) ImagePlus(ij.ImagePlus) WeightedObservedPoint(org.apache.commons.math3.fitting.WeightedObservedPoint) ClusterPoint(uk.ac.sussex.gdsc.core.clustering.ClusterPoint) StoredData(uk.ac.sussex.gdsc.core.utils.StoredData) UniformRandomProvider(org.apache.commons.rng.UniformRandomProvider) NormalizedGaussianSampler(org.apache.commons.rng.sampling.distribution.NormalizedGaussianSampler)

Example 90 with ByteProcessor

use of ij.process.ByteProcessor in project GDSC-SMLM by aherbert.

the class PsfCreator method plotSignalAtSpecifiedSd.

/**
 * Show a plot of the amount of signal within N x SD for each z position. This indicates how much
 * the PSF has spread from the original Gaussian shape.
 *
 * @param psf The PSF
 * @param fittedSd The width of the PSF (in pixels)
 * @param factor The factor to use
 * @param slice The slice used to create the label
 */
private void plotSignalAtSpecifiedSd(ImageStack psf, double fittedSd, double factor, int slice) {
    if (signalZ == null) {
        // Get the bounds
        final int radius = (int) Math.round(fittedSd * factor);
        final int min = Math.max(0, psf.getWidth() / 2 - radius);
        final int max = Math.min(psf.getWidth() - 1, psf.getWidth() / 2 + radius);
        // Create a circle mask of the PSF projection
        final ByteProcessor circle = new ByteProcessor(max - min + 1, max - min + 1);
        circle.setColor(255);
        circle.fillOval(0, 0, circle.getWidth(), circle.getHeight());
        final byte[] mask = (byte[]) circle.getPixels();
        // Sum the pixels within the mask for each slice
        signalZ = new double[psf.getSize()];
        signal = new double[psf.getSize()];
        for (int i = 0; i < psf.getSize(); i++) {
            double sum = 0;
            final float[] data = (float[]) psf.getProcessor(i + 1).getPixels();
            for (int y = min, ii = 0; y <= max; y++) {
                int index = y * psf.getWidth() + min;
                for (int x = min; x <= max; x++, ii++, index++) {
                    if (mask[ii] != 0 && data[index] > 0) {
                        sum += data[index];
                    }
                }
            }
            double total = 0;
            for (final float f : data) {
                if (f > 0) {
                    total += f;
                }
            }
            signalZ[i] = i + 1;
            signal[i] = 100 * sum / total;
        }
        signalTitle = String.format("%% PSF signal at %s x SD", MathUtils.rounded(factor, 3));
        signalLimits = MathUtils.limits(signal);
    }
    // Plot the sum
    final boolean alignWindows = (WindowManager.getFrame(signalTitle) == null);
    final double total = signal[slice - 1];
    final Plot plot = new Plot(signalTitle, "z", "Signal");
    plot.addPoints(signalZ, signal, Plot.LINE);
    plot.addLabel(0, 0, String.format("Total = %s. z = %s nm", MathUtils.rounded(total), MathUtils.rounded((slice - zCentre) * settings.getNmPerSlice())));
    plot.setColor(Color.green);
    plot.drawLine(slice, signalLimits[0], slice, signalLimits[1]);
    plot.setColor(Color.blue);
    final PlotWindow plotWindow = ImageJUtils.display(signalTitle, plot);
    if (alignWindows && plotWindow != null) {
        final PlotWindow otherWindow = getPlot(TITLE_AMPLITUDE);
        if (otherWindow != null) {
            // Put the two plots tiled together so both are visible
            final Point l = plotWindow.getLocation();
            l.x = otherWindow.getLocation().x + otherWindow.getWidth();
            l.y = otherWindow.getLocation().y;
            plotWindow.setLocation(l);
        }
    }
}
Also used : ByteProcessor(ij.process.ByteProcessor) Plot(ij.gui.Plot) PlotWindow(ij.gui.PlotWindow) Point(java.awt.Point) BasePoint(uk.ac.sussex.gdsc.core.match.BasePoint) Point(java.awt.Point) BasePoint(uk.ac.sussex.gdsc.core.match.BasePoint)

Aggregations

ByteProcessor (ij.process.ByteProcessor)103 ImagePlus (ij.ImagePlus)36 ImageProcessor (ij.process.ImageProcessor)31 FloatProcessor (ij.process.FloatProcessor)23 ShortProcessor (ij.process.ShortProcessor)21 ColorProcessor (ij.process.ColorProcessor)20 ArrayList (java.util.ArrayList)13 Point (java.awt.Point)12 Rectangle (java.awt.Rectangle)11 Roi (ij.gui.Roi)10 AffineTransform (java.awt.geom.AffineTransform)10 ImageStack (ij.ImageStack)9 Patch (ini.trakem2.display.Patch)9 Calibration (ij.measure.Calibration)8 Pair (mpicbg.trakem2.util.Pair)7 Color (java.awt.Color)6 LUT (ij.process.LUT)5 BufferedImage (java.awt.image.BufferedImage)5 IOException (java.io.IOException)5 CoordinateTransformMesh (mpicbg.models.CoordinateTransformMesh)5