Search in sources :

Example 6 with FloatPolygon

use of ij.process.FloatPolygon in project imagej1 by imagej.

the class RoiEncoder method write.

void write(Roi roi, OutputStream f) throws IOException {
    Rectangle r = roi.getBounds();
    if (r.width > 65535 || r.height > 65535 || r.x > 65535 || r.y > 65535)
        roi.enableSubPixelResolution();
    int roiType = roi.getType();
    int type = rect;
    int options = 0;
    roiName = roi.getName();
    if (roiName != null)
        roiNameSize = roiName.length() * 2;
    else
        roiNameSize = 0;
    roiProps = roi.getProperties();
    if (roiProps != null)
        roiPropsSize = roiProps.length() * 2;
    else
        roiPropsSize = 0;
    switch(roiType) {
        case Roi.POLYGON:
            type = polygon;
            break;
        case Roi.FREEROI:
            type = freehand;
            break;
        case Roi.TRACED_ROI:
            type = traced;
            break;
        case Roi.OVAL:
            type = oval;
            break;
        case Roi.LINE:
            type = line;
            break;
        case Roi.POLYLINE:
            type = polyline;
            break;
        case Roi.FREELINE:
            type = freeline;
            break;
        case Roi.ANGLE:
            type = angle;
            break;
        // shape array size (36-39) will be >0 to indicate composite type
        case Roi.COMPOSITE:
            type = rect;
            break;
        case Roi.POINT:
            type = point;
            break;
        default:
            type = rect;
            break;
    }
    if (roiType == Roi.COMPOSITE) {
        saveShapeRoi(roi, type, f, options);
        return;
    }
    int n = 0;
    int[] x = null, y = null;
    float[] xf = null, yf = null;
    int floatSize = 0;
    if (roi instanceof PolygonRoi) {
        PolygonRoi proi = (PolygonRoi) roi;
        Polygon p = proi.getNonSplineCoordinates();
        n = p.npoints;
        x = p.xpoints;
        y = p.ypoints;
        if (roi.subPixelResolution()) {
            FloatPolygon fp = null;
            if (proi.isSplineFit())
                fp = proi.getNonSplineFloatPolygon();
            else
                fp = roi.getFloatPolygon();
            if (n == fp.npoints) {
                options |= RoiDecoder.SUB_PIXEL_RESOLUTION;
                if (roi.getDrawOffset())
                    options |= RoiDecoder.DRAW_OFFSET;
                xf = fp.xpoints;
                yf = fp.ypoints;
                floatSize = n * 8;
            }
        }
    }
    if (roi instanceof PointRoi) {
        countersSize = 0;
        counters = ((PointRoi) roi).getCounters();
        if (counters != null && counters.length >= n)
            countersSize = n * 4;
    }
    data = new byte[HEADER_SIZE + HEADER2_SIZE + n * 4 + floatSize + roiNameSize + roiPropsSize + countersSize];
    // "Iout"
    data[0] = 73;
    // "Iout"
    data[1] = 111;
    // "Iout"
    data[2] = 117;
    // "Iout"
    data[3] = 116;
    putShort(RoiDecoder.VERSION_OFFSET, VERSION);
    data[RoiDecoder.TYPE] = (byte) type;
    putShort(RoiDecoder.TOP, r.y);
    putShort(RoiDecoder.LEFT, r.x);
    putShort(RoiDecoder.BOTTOM, r.y + r.height);
    putShort(RoiDecoder.RIGHT, r.x + r.width);
    if (roi.subPixelResolution() && (type == rect || type == oval)) {
        FloatPolygon p = roi.getFloatPolygon();
        if (p.npoints == 4) {
            putFloat(RoiDecoder.XD, p.xpoints[0]);
            putFloat(RoiDecoder.YD, p.ypoints[0]);
            putFloat(RoiDecoder.WIDTHD, p.xpoints[1] - p.xpoints[0]);
            putFloat(RoiDecoder.HEIGHTD, p.ypoints[2] - p.ypoints[1]);
            options |= RoiDecoder.SUB_PIXEL_RESOLUTION;
            putShort(RoiDecoder.OPTIONS, options);
        }
    }
    putShort(RoiDecoder.N_COORDINATES, n);
    putInt(RoiDecoder.POSITION, roi.getPosition());
    if (type == rect) {
        int arcSize = roi.getCornerDiameter();
        if (arcSize > 0)
            putShort(RoiDecoder.ROUNDED_RECT_ARC_SIZE, arcSize);
    }
    if (roi instanceof Line) {
        Line line = (Line) roi;
        putFloat(RoiDecoder.X1, (float) line.x1d);
        putFloat(RoiDecoder.Y1, (float) line.y1d);
        putFloat(RoiDecoder.X2, (float) line.x2d);
        putFloat(RoiDecoder.Y2, (float) line.y2d);
        if (roi instanceof Arrow) {
            putShort(RoiDecoder.SUBTYPE, RoiDecoder.ARROW);
            if (((Arrow) roi).getDoubleHeaded())
                options |= RoiDecoder.DOUBLE_HEADED;
            if (((Arrow) roi).getOutline())
                options |= RoiDecoder.OUTLINE;
            putShort(RoiDecoder.OPTIONS, options);
            putByte(RoiDecoder.ARROW_STYLE, ((Arrow) roi).getStyle());
            putByte(RoiDecoder.ARROW_HEAD_SIZE, (int) ((Arrow) roi).getHeadSize());
        } else {
            if (roi.getDrawOffset())
                options |= RoiDecoder.SUB_PIXEL_RESOLUTION + RoiDecoder.DRAW_OFFSET;
        }
    }
    if (roi instanceof PointRoi) {
        PointRoi point = (PointRoi) roi;
        putByte(RoiDecoder.POINT_TYPE, point.getPointType());
        putShort(RoiDecoder.STROKE_WIDTH, point.getSize());
    }
    if (roi instanceof RotatedRectRoi || roi instanceof EllipseRoi) {
        double[] p = null;
        if (roi instanceof RotatedRectRoi) {
            putShort(RoiDecoder.SUBTYPE, RoiDecoder.ROTATED_RECT);
            p = ((RotatedRectRoi) roi).getParams();
        } else {
            putShort(RoiDecoder.SUBTYPE, RoiDecoder.ELLIPSE);
            p = ((EllipseRoi) roi).getParams();
        }
        putFloat(RoiDecoder.X1, (float) p[0]);
        putFloat(RoiDecoder.Y1, (float) p[1]);
        putFloat(RoiDecoder.X2, (float) p[2]);
        putFloat(RoiDecoder.Y2, (float) p[3]);
        putFloat(RoiDecoder.FLOAT_PARAM, (float) p[4]);
    }
    // save stroke width, stroke color and fill color (1.43i or later)
    if (VERSION >= 218) {
        saveStrokeWidthAndColor(roi);
        if ((roi instanceof PolygonRoi) && ((PolygonRoi) roi).isSplineFit()) {
            options |= RoiDecoder.SPLINE_FIT;
            putShort(RoiDecoder.OPTIONS, options);
        }
    }
    if (n == 0 && roi instanceof TextRoi)
        saveTextRoi((TextRoi) roi);
    else if (n == 0 && roi instanceof ImageRoi)
        options = saveImageRoi((ImageRoi) roi, options);
    else
        putHeader2(roi, HEADER_SIZE + n * 4 + floatSize);
    if (n > 0) {
        int base1 = 64;
        int base2 = base1 + 2 * n;
        for (int i = 0; i < n; i++) {
            putShort(base1 + i * 2, x[i]);
            putShort(base2 + i * 2, y[i]);
        }
        if (xf != null) {
            base1 = 64 + 4 * n;
            base2 = base1 + 4 * n;
            for (int i = 0; i < n; i++) {
                putFloat(base1 + i * 4, xf[i]);
                putFloat(base2 + i * 4, yf[i]);
            }
        }
    }
    saveOverlayOptions(roi, options);
    f.write(data);
}
Also used : FloatPolygon(ij.process.FloatPolygon) FloatPolygon(ij.process.FloatPolygon)

Example 7 with FloatPolygon

use of ij.process.FloatPolygon in project imagej1 by imagej.

the class RotatedRectRoi method makePolygonRelative.

void makePolygonRelative() {
    FloatPolygon poly = new FloatPolygon(xpf, ypf, nPoints);
    Rectangle r = poly.getBounds();
    x = r.x;
    y = r.y;
    width = r.width;
    height = r.height;
    bounds = null;
    for (int i = 0; i < nPoints; i++) {
        xpf[i] = xpf[i] - x;
        ypf[i] = ypf[i] - y;
    }
}
Also used : FloatPolygon(ij.process.FloatPolygon)

Example 8 with FloatPolygon

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

the class AreaList method measure.

/**
 * Returns a double array with 0=volume, 1=lower_bound_surface, 2=upper_bound_surface_smoothed, 3=upper_bound_surface, 4=max_diameter, 5=all_tops_and_bottoms
 *  All measures are approximate.
 *  [0] Volume: sum(area * thickness) for all sections
 *  [1] Lower Bound Surface: measure area per section, compute radius of circumference of identical area, compute then area of the sides of the truncated cone of height thickness, for each section. Plus top and bottom areas when visiting sections without a painted area.
 *  [2] Upper Bound Surface Smoothed: measure smoothed perimeter lengths per section, multiply by thickness to get lateral area. Plus tops and bottoms.
 *  [3] Upper Bound Surface: measure raw pixelated perimeter lengths per section, multiply by thickness to get lateral area. Plus top and bottoms.
 *  [4] Maximum diameter: longest distance between any two points in the contours of all painted areas.
 *  [5] All tops and bottoms: Sum of all included surface areas that are not part of side area.
 *  [6] X coordinate of the center of mass.
 *  [7] Y coordinate of the center of mass.
 *  [8] Z coordinate of the center of mass.
 */
public double[] measure() {
    // zeros
    if (0 == ht_areas.size())
        return new double[6];
    // prepare suitable transform
    final AffineTransform aff = new AffineTransform(this.at);
    AffineTransform aff2 = new AffineTransform();
    // remove translation (for no reason other than historical, and that it may
    // help avoid numerical overflows)
    final Rectangle box = getBoundingBox(null);
    aff2.translate(-box.x, -box.y);
    aff.preConcatenate(aff2);
    aff2 = null;
    double volume = 0;
    double lower_bound_surface_h = 0;
    double upper_bound_surface = 0;
    double upper_bound_surface_smoothed = 0;
    double prev_surface = 0;
    double prev_perimeter = 0;
    double prev_smooth_perimeter = 0;
    double prev_thickness = 0;
    // i.e. surface area that is not part of the side area
    double all_tops_and_bottoms = 0;
    final Calibration cal = layer_set.getCalibration();
    final double pixelWidth = cal.pixelWidth;
    final double pixelHeight = cal.pixelHeight;
    // Put areas in order of their layer index:
    final TreeMap<Integer, Area> ias = new TreeMap<Integer, Area>();
    for (final Map.Entry<Long, Area> e : ht_areas.entrySet()) {
        final int ilayer = layer_set.indexOf(layer_set.getLayer(e.getKey()));
        if (-1 == ilayer) {
            Utils.log("Could not find a layer with id " + e.getKey());
            continue;
        }
        ias.put(ilayer, e.getValue());
    }
    final ArrayList<Layer> layers = layer_set.getLayers();
    int last_layer_index = -1;
    final ArrayList<Point3f> points = new ArrayList<Point3f>();
    final float[] coords = new float[6];
    final float fpixelWidth = (float) pixelWidth;
    final float fpixelHeight = (float) pixelHeight;
    final float resampling_delta = project.getProperty("measurement_resampling_delta", 1.0f);
    // for each area, measure its area and its perimeter, to compute volume and surface
    for (final Map.Entry<Integer, Area> e : ias.entrySet()) {
        // fetch Layer
        final int layer_index = e.getKey();
        if (layer_index > layers.size()) {
            Utils.log("Could not find a layer at index " + layer_index);
            continue;
        }
        final Layer la = layers.get(layer_index);
        // fetch Area
        Area area = e.getValue();
        if (UNLOADED == area)
            area = loadLayer(la.getId());
        // Transform area to world coordinates
        area = area.createTransformedArea(aff);
        // measure surface
        final double pixel_area = Math.abs(AreaCalculations.area(area.getPathIterator(null)));
        final double surface = pixel_area * pixelWidth * pixelHeight;
        // Utils.log2(layer_index + " pixel_area: " + pixel_area + "  surface " + surface);
        // measure volume
        // the last one is NOT pixelDepth because layer thickness and Z are in pixels
        final double thickness = la.getThickness() * pixelWidth;
        volume += surface * thickness;
        final double pix_perimeter = AreaCalculations.circumference(area.getPathIterator(null));
        final double perimeter = pix_perimeter * pixelWidth;
        double smooth_perimeter = 0;
        // smoothed perimeter:
        {
            double smooth_pix_perimeter = 0;
            for (final Polygon pol : M.getPolygons(area)) {
                try {
                    if (pol.npoints < 5) {
                        // No point in smoothing out such a short polygon:
                        // (Plus can't convolve it with a gaussian that needs 5 points adjacent)
                        smooth_perimeter += new PolygonRoi(pol, PolygonRoi.POLYGON).getLength();
                        continue;
                    }
                    /*
						// Works but it is not the best smoothing of the Area's countour
						double[] xp = new double[pol.npoints];
						double[] yp = new double[pol.npoints];
						for (int p=0; p<pol.npoints; p++) {
							xp[p] = pol.xpoints[p];
							yp[p] = pol.ypoints[p];
						}
						VectorString2D v = new VectorString2D(xp, yp, 0, true);
						v.resample(resampling_delta);
						smooth_pix_perimeter += v.length() * resampling_delta;
						*/
                    // The best solution I've found:
                    // 1. Run getInterpolatedPolygon with an interval of 1 to get a point at every pixel
                    // 2. convolve with a gaussian
                    // Resample to 1 so that at every one pixel of the contour there is a point
                    FloatPolygon fpol = new FloatPolygon(new float[pol.npoints], new float[pol.npoints], pol.npoints);
                    for (int i = 0; i < pol.npoints; ++i) {
                        fpol.xpoints[i] = pol.xpoints[i];
                        fpol.ypoints[i] = pol.ypoints[i];
                    }
                    fpol = M.createInterpolatedPolygon(fpol, 1, false);
                    final FloatPolygon fp;
                    if (fpol.npoints < 5) {
                        smooth_pix_perimeter += fpol.getLength(false);
                        fp = fpol;
                    } else {
                        // Convolve with a sigma of 1 to smooth it out
                        final FloatPolygon gpol = new FloatPolygon(new float[fpol.npoints], new float[fpol.npoints], fpol.npoints);
                        final CircularSequence seq = new CircularSequence(fpol.npoints);
                        M.convolveGaussianSigma1(fpol.xpoints, gpol.xpoints, seq);
                        M.convolveGaussianSigma1(fpol.ypoints, gpol.ypoints, seq);
                        // Resample it to the desired resolution (also facilitates measurement: npoints * resampling_delta)
                        if (gpol.npoints > resampling_delta) {
                            fp = M.createInterpolatedPolygon(gpol, resampling_delta, false);
                        } else {
                            fp = gpol;
                        }
                        // Measure perimeter: last line segment is potentially shorter or longer than resampling_delta
                        smooth_pix_perimeter += (fp.npoints - 1) * resampling_delta + Math.sqrt(Math.pow(fp.xpoints[0] - fp.xpoints[fp.npoints - 1], 2) + Math.pow(fp.ypoints[0] - fp.ypoints[fp.npoints - 1], 2));
                    }
                // TEST:
                // ij.plugin.frame.RoiManager.getInstance().addRoi(new PolygonRoi(fp, PolygonRoi.POLYGON));
                // TESTING: make a polygon roi and show it
                // ... just in case to see that resampling works as expected, without weird endings
                /*
						int[] x = new int[v.length()];
						int[] y = new int[x.length];
						double[] xd = v.getPoints(0);
						double[] yd = v.getPoints(1);
						for (int p=0; p<x.length; p++) {
							x[p] = (int)xd[p];
							y[p] = (int)yd[p];
						}
						PolygonRoi proi = new PolygonRoi(x, y, x.length, PolygonRoi.POLYGON);
						Rectangle b = proi.getBounds();
						for (int p=0; p<x.length; p++) {
							x[p] -= b.x;
							y[p] -= b.y;
						}
						ImagePlus imp = new ImagePlus("test", new ByteProcessor(b.width, b.height));
						imp.setRoi(new PolygonRoi(x, y, x.length, PolygonRoi.POLYGON));
						imp.show();
						*/
                } catch (final Exception le) {
                    le.printStackTrace();
                }
            }
            smooth_perimeter = smooth_pix_perimeter * pixelWidth;
        }
        if (-1 == last_layer_index) {
            // Start of the very first continuous set:
            lower_bound_surface_h += surface;
            upper_bound_surface += surface;
            upper_bound_surface_smoothed += surface;
            all_tops_and_bottoms += surface;
        } else if (layer_index - last_layer_index > 1) {
            // End of a continuous set ...
            // Sum the last surface and its side:
            // (2x + 2x) / 2   ==   2x
            lower_bound_surface_h += prev_surface + prev_thickness * 2 * Math.sqrt(prev_surface * Math.PI);
            upper_bound_surface += prev_surface + prev_perimeter * prev_thickness;
            upper_bound_surface_smoothed += prev_surface + prev_smooth_perimeter * prev_thickness;
            all_tops_and_bottoms += prev_surface;
            // ... and start of a new set
            lower_bound_surface_h += surface;
            upper_bound_surface += surface;
            upper_bound_surface_smoothed += surface;
            all_tops_and_bottoms += surface;
        } else {
            // Continuation of a set: use this Area and the previous as continuous
            final double diff_surface = Math.abs(prev_surface - surface);
            upper_bound_surface += prev_perimeter * (prev_thickness / 2) + perimeter * (prev_thickness / 2) + diff_surface;
            upper_bound_surface_smoothed += prev_smooth_perimeter * (prev_thickness / 2) + smooth_perimeter * (prev_thickness / 2) + diff_surface;
            // Compute area of the mantle of the truncated cone defined by the radiuses of the circles of same area as the two areas
            // PI * s * (r1 + r2) where s is the hypothenusa
            final double r1 = Math.sqrt(prev_surface / Math.PI);
            final double r2 = Math.sqrt(surface / Math.PI);
            final double hypothenusa = Math.sqrt(Math.pow(Math.abs(r1 - r2), 2) + Math.pow(thickness, 2));
            lower_bound_surface_h += Math.PI * hypothenusa * (r1 + r2);
            // Adjust volume too:
            volume += diff_surface * prev_thickness / 2;
        }
        // store for next iteration:
        prev_surface = surface;
        prev_perimeter = perimeter;
        prev_smooth_perimeter = smooth_perimeter;
        last_layer_index = layer_index;
        prev_thickness = thickness;
        // Iterate points:
        final float z = (float) la.getZ();
        for (final PathIterator pit = area.getPathIterator(null); !pit.isDone(); pit.next()) {
            switch(pit.currentSegment(coords)) {
                case PathIterator.SEG_MOVETO:
                case PathIterator.SEG_LINETO:
                case PathIterator.SEG_CLOSE:
                    points.add(new Point3f(coords[0] * fpixelWidth, coords[1] * fpixelHeight, z * fpixelWidth));
                    break;
                default:
                    Utils.log2("WARNING: unhandled seg type.");
                    break;
            }
        }
    }
    // finish last:
    lower_bound_surface_h += prev_surface + prev_perimeter * prev_thickness;
    upper_bound_surface += prev_surface + prev_perimeter * prev_thickness;
    upper_bound_surface_smoothed += prev_surface + prev_smooth_perimeter * prev_thickness;
    all_tops_and_bottoms += prev_surface;
    // Compute maximum diameter
    final boolean measure_largest_diameter = project.getBooleanProperty("measure_largest_diameter");
    double max_diameter_sq = measure_largest_diameter ? 0 : Double.NaN;
    final int lp = points.size();
    final Point3f c;
    if (lp > 0) {
        // center of mass
        c = new Point3f(points.get(0));
        for (int i = 0; i < lp; i++) {
            final Point3f p = points.get(i);
            if (measure_largest_diameter) {
                for (int j = i; j < lp; j++) {
                    final double len = p.distanceSquared(points.get(j));
                    if (len > max_diameter_sq)
                        max_diameter_sq = len;
                }
            }
            if (0 == i)
                continue;
            c.x += p.x;
            c.y += p.y;
            c.z += p.z;
        }
    } else {
        c = new Point3f(Float.NaN, Float.NaN, Float.NaN);
    }
    // Translate the center of mass
    c.x = box.x + c.x / lp;
    c.y = box.y + c.y / lp;
    c.z /= lp;
    return new double[] { volume, lower_bound_surface_h, upper_bound_surface_smoothed, upper_bound_surface, Math.sqrt(max_diameter_sq), all_tops_and_bottoms, c.x, c.y, c.z };
}
Also used : PathIterator(java.awt.geom.PathIterator) Rectangle(java.awt.Rectangle) ArrayList(java.util.ArrayList) PolygonRoi(ij.gui.PolygonRoi) Point3f(org.scijava.vecmath.Point3f) FloatPolygon(ij.process.FloatPolygon) Polygon(java.awt.Polygon) Calibration(ij.measure.Calibration) TreeMap(java.util.TreeMap) Point(java.awt.Point) USHORTPaint(ini.trakem2.display.paint.USHORTPaint) NoninvertibleTransformException(java.awt.geom.NoninvertibleTransformException) Area(java.awt.geom.Area) AffineTransform(java.awt.geom.AffineTransform) Map(java.util.Map) HashMap(java.util.HashMap) TreeMap(java.util.TreeMap) FloatPolygon(ij.process.FloatPolygon) CircularSequence(ini.trakem2.utils.CircularSequence)

Example 9 with FloatPolygon

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

the class AstigmatismModelManager method getImageList.

private static String[] getImageList() {
    final LocalList<String> newImageList = new LocalList<>();
    for (final int id : ImageJUtils.getIdList()) {
        final ImagePlus imp = WindowManager.getImage(id);
        if (imp == null) {
            continue;
        }
        if (imp.getNDimensions() != 3) {
            continue;
        }
        if (imp.getBitDepth() == 24) {
            continue;
        }
        final Roi roi = imp.getRoi();
        if (roi == null || roi.getType() != Roi.POINT) {
            continue;
        }
        final FloatPolygon p = roi.getFloatPolygon();
        if (p.npoints != 1) {
            continue;
        }
        newImageList.add(imp.getTitle());
    }
    return newImageList.toArray(new String[0]);
}
Also used : LocalList(uk.ac.sussex.gdsc.core.utils.LocalList) ImagePlus(ij.ImagePlus) Roi(ij.gui.Roi) FloatPolygon(ij.process.FloatPolygon)

Example 10 with FloatPolygon

use of ij.process.FloatPolygon 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)

Aggregations

FloatPolygon (ij.process.FloatPolygon)11 Roi (ij.gui.Roi)6 ImagePlus (ij.ImagePlus)3 PolygonRoi (ij.gui.PolygonRoi)3 Point (java.awt.Point)3 Rectangle (java.awt.Rectangle)3 OffsetPointRoi (uk.ac.sussex.gdsc.core.ij.gui.OffsetPointRoi)3 ImageStack (ij.ImageStack)2 ImageWindow (ij.gui.ImageWindow)2 Overlay (ij.gui.Overlay)2 PointRoi (ij.gui.PointRoi)2 ByteProcessor (ij.process.ByteProcessor)2 LUT (ij.process.LUT)2 Color (java.awt.Color)2 BasePoint (uk.ac.sussex.gdsc.core.match.BasePoint)2 MemoryPeakResults (gdsc.smlm.results.MemoryPeakResults)1 PeakResult (gdsc.smlm.results.PeakResult)1 Trace (gdsc.smlm.results.Trace)1 Calibration (ij.measure.Calibration)1 USHORTPaint (ini.trakem2.display.paint.USHORTPaint)1