/** Returns this OvalRoi as a polygon. */ public Polygon getPolygon() { ImageProcessor mask = getMask(); Wand wand = new Wand(mask); wand.autoOutline(width / 2, height / 2, 255, 255); for (int i = 0; i < wand.npoints; i++) { wand.xpoints[i] += x; wand.ypoints[i] += y; } return new Polygon(wand.xpoints, wand.ypoints, wand.npoints); }
@Test public void imageOneTest() { BufferedImage img = null; try { img = ImageIO.read(new File("NeuronTest-03.gif")); } catch (IOException e) { System.out.println(e); } catch (IllegalArgumentException p) { System.out.println(p); } // Constructs the color processor for the image ColorProcessor cp = new ColorProcessor(img); // Execute the line of code that clicking the "Wand" tool in the GUI // would call testWand = new Wand(cp); // Simulate clicking on a point in the straight white line of // NeuronTest-01 testWand.autoOutline(324, 239); // Now test the points that should be in/out of the set int xPixel, yPixel; Roi region = new PolygonRoi(testWand.xpoints, testWand.ypoints, testWand.npoints, Roi.TRACED_ROI); for (int percent = 0; percent <= 100; percent++) { xPixel = 50 + (percent * 425 / 100); yPixel = 425 - (percent * 285 / 100); assertTrue(wandContains(region, xPixel, yPixel)); System.out.println("Asserted true"); yPixel -= 300; assertFalse(wandContains(region, xPixel, yPixel)); System.out.println("Asserted false"); } }
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); }
/** * Performs particle analysis on the specified ImagePlus and ImageProcessor. Returns false if * there is an error. */ public boolean analyze(ImagePlus imp, ImageProcessor ip) { if (this.imp == null) this.imp = imp; showResults = (options & SHOW_RESULTS) != 0; excludeEdgeParticles = (options & EXCLUDE_EDGE_PARTICLES) != 0; resetCounter = (options & CLEAR_WORKSHEET) != 0; showProgress = (options & SHOW_PROGRESS) != 0; floodFill = (options & INCLUDE_HOLES) == 0; recordStarts = (options & RECORD_STARTS) != 0; addToManager = (options & ADD_TO_MANAGER) != 0; displaySummary = (options & DISPLAY_SUMMARY) != 0; inSituShow = (options & IN_SITU_SHOW) != 0; outputImage = null; ip.snapshot(); ip.setProgressBar(null); if (Analyzer.isRedirectImage()) { redirectImp = Analyzer.getRedirectImage(imp); if (redirectImp == null) return false; int depth = redirectImp.getStackSize(); if (depth > 1 && depth == imp.getStackSize()) { ImageStack redirectStack = redirectImp.getStack(); redirectIP = redirectStack.getProcessor(imp.getCurrentSlice()); } else redirectIP = redirectImp.getProcessor(); } else if (imp.getType() == ImagePlus.COLOR_RGB) { ImagePlus original = (ImagePlus) imp.getProperty("OriginalImage"); if (original != null && original.getWidth() == imp.getWidth() && original.getHeight() == imp.getHeight()) { redirectImp = original; redirectIP = original.getProcessor(); } } if (!setThresholdLevels(imp, ip)) return false; width = ip.getWidth(); height = ip.getHeight(); if (!(showChoice == NOTHING || showChoice == OVERLAY_OUTLINES || showChoice == OVERLAY_MASKS)) { blackBackground = Prefs.blackBackground && inSituShow; if (slice == 1) outlines = new ImageStack(width, height); if (showChoice == ROI_MASKS) drawIP = new ShortProcessor(width, height); else drawIP = new ByteProcessor(width, height); drawIP.setLineWidth(lineWidth); if (showChoice == ROI_MASKS) { } // Place holder for now... else if (showChoice == MASKS && !blackBackground) drawIP.invertLut(); else if (showChoice == OUTLINES) { if (!inSituShow) { if (customLut == null) makeCustomLut(); drawIP.setColorModel(customLut); } drawIP.setFont(new Font("SansSerif", Font.PLAIN, fontSize)); if (fontSize > 12 && inSituShow) drawIP.setAntialiasedText(true); } outlines.addSlice(null, drawIP); if (showChoice == ROI_MASKS || blackBackground) { drawIP.setColor(Color.black); drawIP.fill(); drawIP.setColor(Color.white); } else { drawIP.setColor(Color.white); drawIP.fill(); drawIP.setColor(Color.black); } } calibration = redirectImp != null ? redirectImp.getCalibration() : imp.getCalibration(); if (rt == null) { rt = Analyzer.getResultsTable(); analyzer = new Analyzer(imp); } else analyzer = new Analyzer(imp, measurements, rt); if (resetCounter && slice == 1) { if (!Analyzer.resetCounter()) return false; } beginningCount = Analyzer.getCounter(); byte[] pixels = null; if (ip instanceof ByteProcessor) pixels = (byte[]) ip.getPixels(); if (r == null) { r = ip.getRoi(); mask = ip.getMask(); if (displaySummary) { if (mask != null) totalArea = ImageStatistics.getStatistics(ip, AREA, calibration).area; else totalArea = r.width * calibration.pixelWidth * r.height * calibration.pixelHeight; } } minX = r.x; maxX = r.x + r.width; minY = r.y; maxY = r.y + r.height; if (r.width < width || r.height < height || mask != null) { if (!eraseOutsideRoi(ip, r, mask)) return false; } int offset; double value; int inc = Math.max(r.height / 25, 1); int mi = 0; ImageWindow win = imp.getWindow(); if (win != null) win.running = true; if (measurements == 0) measurements = Analyzer.getMeasurements(); if (showChoice == ELLIPSES) measurements |= ELLIPSE; measurements &= ~LIMIT; // ignore "Limit to Threshold" roiNeedsImage = (measurements & PERIMETER) != 0 || (measurements & SHAPE_DESCRIPTORS) != 0 || (measurements & FERET) != 0; particleCount = 0; wand = new Wand(ip); pf = new PolygonFiller(); if (floodFill) { ImageProcessor ipf = ip.duplicate(); ipf.setValue(fillColor); ff = new FloodFiller(ipf); } roiType = Wand.allPoints() ? Roi.FREEROI : Roi.TRACED_ROI; for (int y = r.y; y < (r.y + r.height); y++) { offset = y * width; for (int x = r.x; x < (r.x + r.width); x++) { if (pixels != null) value = pixels[offset + x] & 255; else if (imageType == SHORT) value = ip.getPixel(x, y); else value = ip.getPixelValue(x, y); if (value >= level1 && value <= level2) analyzeParticle(x, y, imp, ip); } if (showProgress && ((y % inc) == 0)) IJ.showProgress((double) (y - r.y) / r.height); if (win != null) canceled = !win.running; if (canceled) { Macro.abort(); break; } } if (showProgress) IJ.showProgress(1.0); if (showResults) rt.updateResults(); imp.killRoi(); ip.resetRoi(); ip.reset(); if (displaySummary && IJ.getInstance() != null) updateSliceSummary(); if (addToManager && roiManager != null) roiManager.setEditMode(imp, true); maxParticleCount = (particleCount > maxParticleCount) ? particleCount : maxParticleCount; totalCount += particleCount; if (!canceled) showResults(); return true; }
public void runStuff( DimensionMap map, TreeMap<DimensionMap, ROIPlus> maximaMap, TreeMap<DimensionMap, String> segMap, TreeMap<DimensionMap, String> maskMap, TreeMap<DimensionMap, String> imageMap, TreeMap<DimensionMap, Double> results, Canceler canceler) { // Get the Maxima ROIPlus maxima = maximaMap.get(map); // Make the mask image impMask // ByteProcessor impMask = (ByteProcessor) (new // ImagePlus(maskMap.get(map)).getProcessor().convertToByte(false)); // ByteProcessor impSeg = (ByteProcessor) (new // ImagePlus(segMap.get(map)).getProcessor().convertToByte(false)); ByteProcessor impSeg = (ByteProcessor) (new ImagePlus(segMap.get(map))).getProcessor(); ByteProcessor impMask = (ByteProcessor) (new ImagePlus(maskMap.get(map))).getProcessor(); ByteBlitter blit = new ByteBlitter(impSeg); blit.copyBits(impMask, 0, 0, Blitter.AND); FloatProcessor impImage = (FloatProcessor) (new ImagePlus(imageMap.get(map))).getProcessor().convertToFloat(); Wand wand = new Wand(impSeg); Wand wand2 = new Wand(impMask); Vector<Double> measurements; for (IdPoint p : maxima.getPointList()) { if (canceler.isCanceled()) { return; } if (impSeg.getPixel(p.x, p.y) == 255) // if we land on a cell that made it through thresholding { wand.autoOutline(p.x, p.y); // outline it wand2.autoOutline(p.x, p.y); boolean partOfCellClump = !this.selectionsAreEqual( wand, wand2); // If the segmented and unsegmented masks do not agree on the roi, then this // cell is part of a clump. if (wand.npoints > 0) { Roi roi = new PolygonRoi( wand.xpoints, wand.ypoints, wand.npoints, Roi.POLYGON); // The roi helps for using getLength() (DON'T USE Roi.TRACED_ROI., // IT SCREWS UP THE Polygon OBJECTS!!!! Bug emailed to ImageJ // folks) Polygon poly = new Polygon( wand.xpoints, wand.ypoints, wand.npoints); // The polygon helps for using contains() Rectangle r = roi.getBounds(); measurements = new Vector<Double>(); for (int i = r.x; i < r.x + r.width; i++) { for (int j = r.y; j < r.y + r.height; j++) { // innerBoundary if (poly.contains(i, j) && impSeg.getPixelValue(i, j) == 255) { measurements.add((double) impImage.getPixelValue(i, j)); // Logs.log("In - " + innerT, this); } } } impMask.setRoi(roi); ImageStatistics stats = ImageStatistics.getStatistics( impMask, ImageStatistics.AREA & ImageStatistics.PERIMETER & ImageStatistics.CIRCULARITY & ImageStatistics.ELLIPSE, null); if (measurements.size() > 0) { DimensionMap resultsMap = map.copy(); resultsMap.put("Id", "" + p.id); resultsMap.put("Measurement", "X"); results.put(resultsMap.copy(), (double) p.x); resultsMap.put("Measurement", "Y"); results.put(resultsMap.copy(), (double) p.y); resultsMap.put("Measurement", "AREA"); results.put(resultsMap.copy(), stats.area); resultsMap.put("Measurement", "PERIMETER"); results.put(resultsMap.copy(), roi.getLength()); resultsMap.put("Measurement", "CIRCULARITY"); results.put( resultsMap.copy(), 4.0 * Math.PI * (stats.area / (Math.pow(roi.getLength(), 2)))); resultsMap.put("Measurement", "ELLIPSE MAJOR"); results.put(resultsMap.copy(), stats.major); resultsMap.put("Measurement", "ELLIPSE MINOR"); results.put(resultsMap.copy(), stats.minor); resultsMap.put("Measurement", "MEAN"); results.put(resultsMap.copy(), StatisticsUtility.mean(measurements)); resultsMap.put("Measurement", "MEDIAN"); results.put(resultsMap.copy(), StatisticsUtility.median(measurements)); resultsMap.put("Measurement", "SUM"); results.put(resultsMap.copy(), StatisticsUtility.sum(measurements)); resultsMap.put("Measurement", "MIN"); results.put(resultsMap.copy(), StatisticsUtility.min(measurements)); resultsMap.put("Measurement", "MAX"); results.put(resultsMap.copy(), StatisticsUtility.max(measurements)); resultsMap.put("Measurement", "STDDEV"); results.put(resultsMap.copy(), StatisticsUtility.stdDev(measurements)); resultsMap.put("Measurement", "VARIANCE"); results.put(resultsMap.copy(), StatisticsUtility.variance(measurements)); resultsMap.put("Measurement", "CLUMP"); results.put(resultsMap.copy(), (double) (partOfCellClump ? 1 : 0)); } } } } }