package AngioTool; import Utils.Utils; import ij.gui.Roi; import ij.gui.ShapeRoi; import ij.process.ImageProcessor; import java.awt.Polygon; import java.awt.geom.GeneralPath; import java.util.ArrayList; public class ThresholdToSelection { ImageProcessor ip; public float min; public float max; int w; int h; public Roi convert(ImageProcessor ip) { this.ip = ip; this.min = (float)ip.getMinThreshold(); this.max = (float)ip.getMaxThreshold(); this.w = ip.getWidth(); this.h = ip.getHeight(); return this.getRoi(); } final boolean selected(int x, int y) { float v = this.ip.getf(x, y); return v >= this.min && v <= this.max; } Roi getRoi() { ArrayList polygons = new ArrayList(); int progressInc = Math.max(this.h / 50, 1); boolean[] prevRow = new boolean[this.w + 2]; boolean[] thisRow = new boolean[this.w + 2]; ThresholdToSelection.Outline[] outline = new ThresholdToSelection.Outline[this.w + 1]; for(int y = 0; y <= this.h; ++y) { boolean[] b = prevRow; prevRow = thisRow; thisRow = b; for(int x = 0; x <= this.w; ++x) { if (y < this.h && x < this.w) { thisRow[x + 1] = this.selected(x, y); } else { thisRow[x + 1] = false; } if (thisRow[x + 1]) { if (!prevRow[x + 1]) { if (outline[x] == null) { if (outline[x + 1] == null) { outline[x + 1] = outline[x] = new ThresholdToSelection.Outline(); outline[x].push(x + 1, y); outline[x].push(x, y); } else { outline[x] = outline[x + 1]; outline[x + 1] = null; outline[x].push(x, y); } } else if (outline[x + 1] == null) { outline[x + 1] = outline[x]; outline[x] = null; outline[x + 1].shift(x + 1, y); } else if (outline[x + 1] == outline[x]) { polygons.add(outline[x].getPolygon()); outline[x] = outline[x + 1] = null; } else { outline[x].shift(outline[x + 1]); for(int x1 = 0; x1 <= this.w; ++x1) { if (x1 != x + 1 && outline[x1] == outline[x + 1]) { outline[x1] = outline[x]; outline[x] = outline[x + 1] = null; break; } } if (outline[x] != null) { throw new RuntimeException("assertion failed"); } } } if (!thisRow[x]) { if (outline[x] == null) { throw new RuntimeException("assertion failed!"); } outline[x].push(x, y + 1); } } else { if (prevRow[x + 1]) { if (outline[x] == null) { if (outline[x + 1] == null) { outline[x] = outline[x + 1] = new ThresholdToSelection.Outline(); outline[x].push(x, y); outline[x].push(x + 1, y); } else { outline[x] = outline[x + 1]; outline[x + 1] = null; outline[x].shift(x, y); } } else if (outline[x + 1] == null) { outline[x + 1] = outline[x]; outline[x] = null; outline[x + 1].push(x + 1, y); } else if (outline[x + 1] == outline[x]) { polygons.add(outline[x].getPolygon()); outline[x] = outline[x + 1] = null; } else { outline[x].push(outline[x + 1]); for(int x1 = 0; x1 <= this.w; ++x1) { if (x1 != x + 1 && outline[x1] == outline[x + 1]) { outline[x1] = outline[x]; outline[x] = outline[x + 1] = null; break; } } if (outline[x] != null) { throw new RuntimeException("assertion failed"); } } } if (thisRow[x]) { if (outline[x] == null) { throw new RuntimeException("assertion failed"); } outline[x].shift(x, y + 1); } } } } GeneralPath path = new GeneralPath(0); for(int i = 0; i < polygons.size(); ++i) { path.append((Polygon)polygons.get(i), false); } ShapeRoi shape = new ShapeRoi(path); Roi roi = shape != null ? shape.shapeToRoi() : null; return (Roi)(roi != null ? roi : shape); } static class Outline { int[] x; int[] y; int first; int last; int reserved; final int GROW = 10; public Outline() { this.reserved = 10; this.x = new int[this.reserved]; this.y = new int[this.reserved]; this.first = this.last = 5; } private void needs(int newCount, int offset) { if (newCount > this.reserved || offset > this.first) { if (newCount < this.reserved + 10 + 1) { newCount = this.reserved + 10 + 1; } int[] newX = new int[newCount]; int[] newY = new int[newCount]; System.arraycopy(this.x, 0, newX, offset, this.last); System.arraycopy(this.y, 0, newY, offset, this.last); this.x = newX; this.y = newY; this.first += offset; this.last += offset; this.reserved = newCount; } } public void push(int x, int y) { this.needs(this.last + 1, 0); this.x[this.last] = x; this.y[this.last] = y; ++this.last; } public void shift(int x, int y) { this.needs(this.last + 1, 10); --this.first; this.x[this.first] = x; this.y[this.first] = y; } public void push(ThresholdToSelection.Outline o) { int count = o.last - o.first; this.needs(this.last + count, 0); System.arraycopy(o.x, o.first, this.x, this.last, count); System.arraycopy(o.y, o.first, this.y, this.last, count); this.last += count; } public void shift(ThresholdToSelection.Outline o) { int count = o.last - o.first; this.needs(this.last + count + 10, count + 10); this.first -= count; System.arraycopy(o.x, o.first, this.x, this.first, count); System.arraycopy(o.y, o.first, this.y, this.first, count); } public Polygon getPolygon() { int j = this.first + 1; int i; for(i = this.first + 1; i + 1 < this.last; ++j) { int x1 = this.x[j] - this.x[j - 1]; int y1 = this.y[j] - this.y[j - 1]; int x2 = this.x[j + 1] - this.x[j]; int y2 = this.y[j + 1] - this.y[j]; if (x1 * y2 == x2 * y1) { --this.last; } else { if (i != j) { this.x[i] = this.x[j]; this.y[i] = this.y[j]; } ++i; } } int x1 = this.x[j] - this.x[j - 1]; int y1 = this.y[j] - this.y[j - 1]; int x2 = this.x[this.first] - this.x[j]; int y2 = this.y[this.first] - this.y[j]; if (x1 * y2 == x2 * y1) { --this.last; } else { this.x[i] = this.x[j]; this.y[i] = this.y[j]; } int count = this.last - this.first; int[] xNew = new int[count]; int[] yNew = new int[count]; System.arraycopy(this.x, this.first, xNew, 0, count); System.arraycopy(this.y, this.first, yNew, 0, count); return new Polygon(xNew, yNew, count); } @Override public String toString() { String res = "(first:" + this.first + ",last:" + this.last + ",reserved:" + this.reserved + ":"; if (this.last > this.x.length && !Utils.isReleaseVersion) { System.err.println("ERROR!"); } for(int i = this.first; i < this.last && i < this.x.length; ++i) { res = res + "(" + this.x[i] + "," + this.y[i] + ")"; } return res + ")"; } } }