/** * Traces the boundary of the area with pixel values within 'tolerance' of the value of the pixel * at the starting location. 'tolerance' is in uncalibrated units. 'mode' can be FOUR_CONNECTED or * EIGHT_CONNECTED. Mode LEGACY_MODE is for compatibility with previous versions of ImageJ; * ignored if tolerance > 0. Mode bit THRESHOLDED_MODE for internal use only; it is set by * autoOutline with 'upper' and 'lower' arguments. When successful, npoints>0 and the boundary * points can be accessed in the public xpoints and ypoints fields. */ public void autoOutline(int startX, int startY, double tolerance, int mode) { if (startX < 0 || startX >= width || startY < 0 || startY >= height) return; if (fpixels != null && Float.isNaN(getPixel(startX, startY))) return; exactPixelValue = tolerance == 0; boolean thresholdMode = (mode & THRESHOLDED_MODE) != 0; boolean legacyMode = (mode & LEGACY_MODE) != 0 && tolerance == 0; if (!thresholdMode) { double startValue = getPixel(startX, startY); lowerThreshold = (float) (startValue - tolerance); upperThreshold = (float) (startValue + tolerance); } int x = startX; int y = startY; int seedX; // the first inside pixel if (inside(x, y)) { // find a border when coming from inside seedX = x; // (seedX, startY) is an inside pixel do { x++; } while (inside(x, y)); } else { // find a border when coming from outside (thresholded only) do { x++; if (x >= width) return; // no border found } while (!inside(x, y)); seedX = x; } boolean fourConnected; if (legacyMode) fourConnected = !thresholdMode && !(isLine(x, y)); else fourConnected = (mode & FOUR_CONNECTED) != 0; // now, we have a border between (x-1, y) and (x,y) boolean first = true; while (true) { // loop until we have not traced an inner hole boolean insideSelected = traceEdge(x, y, fourConnected); if (legacyMode) return; // in legacy mode, don't care what we have got if (insideSelected) { // not an inner hole if (first) return; // started at seed, so we got it (sucessful) if (xmin <= seedX) { // possibly the correct particle Polygon poly = new Polygon(xpoints, ypoints, npoints); if (poly.contains(seedX, startY)) return; // successful, particle contains seed } } first = false; // we have traced an inner hole or the wrong particle if (!inside(x, y)) do { x++; // traverse the hole if (x > width) throw new RuntimeException("Wand Malfunction"); // should never happen } while (!inside(x, y)); do { x++; } while (inside(x, y)); // retry here; maybe no inner hole any more } }
public boolean contains(int x, int y) { if (!super.contains(x, y)) return false; if (xSpline != null) { FloatPolygon poly = new FloatPolygon(xSpline, ySpline, splinePoints); return poly.contains(x - this.x, y - this.y); } else if (xpf != null) { FloatPolygon poly = new FloatPolygon(xpf, ypf, nPoints); return poly.contains(x - this.x, y - this.y); } else { Polygon poly = new Polygon(xp, yp, nPoints); return poly.contains(x - this.x, y - this.y); } }
void finishPolygon() { if (xpf != null) { FloatPolygon poly = new FloatPolygon(xpf, ypf, nPoints); Rectangle r = poly.getBounds(); x = r.x; y = r.y; width = r.width; height = r.height; bounds = poly.getFloatBounds(); float xbase = (float) bounds.getX(); float ybase = (float) bounds.getY(); for (int i = 0; i < nPoints; i++) { xpf[i] -= xbase; ypf[i] -= ybase; } } else { Polygon poly = new Polygon(xp, yp, nPoints); Rectangle r = poly.getBounds(); x = r.x; y = r.y; width = r.width; height = r.height; for (int i = 0; i < nPoints; i++) { xp[i] = xp[i] - x; yp[i] = yp[i] - y; } bounds = null; } if (nPoints < 2 || (!(type == FREELINE || type == POLYLINE || type == ANGLE) && (nPoints < 3 || width == 0 || height == 0))) { if (imp != null) imp.deleteRoi(); if (type != POINT) return; } state = NORMAL; if (imp != null && !(type == TRACED_ROI)) imp.draw(x - 5, y - 5, width + 10, height + 10); oldX = x; oldY = y; oldWidth = width; oldHeight = height; if (Recorder.record && userCreated && (type == POLYGON || type == POLYLINE || type == ANGLE || (type == POINT && Recorder.scriptMode() && nPoints == 3))) Recorder.recordRoi(getPolygon(), type); if (type != POINT) modifyRoi(); LineWidthAdjuster.update(); }
void analyzeParticle(int x, int y, ImagePlus imp, ImageProcessor ip) { // Wand wand = new Wand(ip); ImageProcessor ip2 = redirectIP != null ? redirectIP : ip; wand.autoOutline(x, y, level1, level2, wandMode); if (wand.npoints == 0) { IJ.log("wand error: " + x + " " + y); return; } Roi roi = new PolygonRoi(wand.xpoints, wand.ypoints, wand.npoints, roiType); Rectangle r = roi.getBounds(); if (r.width > 1 && r.height > 1) { PolygonRoi proi = (PolygonRoi) roi; pf.setPolygon(proi.getXCoordinates(), proi.getYCoordinates(), proi.getNCoordinates()); ip2.setMask(pf.getMask(r.width, r.height)); if (floodFill) ff.particleAnalyzerFill(x, y, level1, level2, ip2.getMask(), r); } ip2.setRoi(r); ip.setValue(fillColor); ImageStatistics stats = getStatistics(ip2, measurements, calibration); boolean include = true; if (excludeEdgeParticles) { if (r.x == minX || r.y == minY || r.x + r.width == maxX || r.y + r.height == maxY) include = false; if (polygon != null) { Rectangle bounds = roi.getBounds(); int x1 = bounds.x + wand.xpoints[wand.npoints - 1]; int y1 = bounds.y + wand.ypoints[wand.npoints - 1]; int x2, y2; for (int i = 0; i < wand.npoints; i++) { x2 = bounds.x + wand.xpoints[i]; y2 = bounds.y + wand.ypoints[i]; if (!polygon.contains(x2, y2)) { include = false; break; } if ((x1 == x2 && ip.getPixel(x1, y1 - 1) == fillColor) || (y1 == y2 && ip.getPixel(x1 - 1, y1) == fillColor)) { include = false; break; } x1 = x2; y1 = y2; } } } ImageProcessor mask = ip2.getMask(); if (minCircularity > 0.0 || maxCircularity < 1.0) { double perimeter = roi.getLength(); double circularity = perimeter == 0.0 ? 0.0 : 4.0 * Math.PI * (stats.pixelCount / (perimeter * perimeter)); if (circularity > 1.0) circularity = 1.0; // IJ.log(circularity+" "+perimeter+" "+stats.area); if (circularity < minCircularity || circularity > maxCircularity) include = false; } if (stats.pixelCount >= minSize && stats.pixelCount <= maxSize && include) { particleCount++; if (roiNeedsImage) roi.setImage(imp); stats.xstart = x; stats.ystart = y; saveResults(stats, roi); if (showChoice != NOTHING) drawParticle(drawIP, roi, stats, mask); } if (redirectIP != null) ip.setRoi(r); ip.fill(mask); }