public void fitSpline(int evaluationPoints) { if (xpf == null) { xpf = toFloat(xp); ypf = toFloat(yp); subPixel = true; } if (xSpline == null || splinePoints != evaluationPoints) { splinePoints = evaluationPoints; xSpline = new float[splinePoints]; ySpline = new float[splinePoints]; } int nNodes = nPoints; if (type == POLYGON) { nNodes++; if (nNodes >= xpf.length) enlargeArrays(); xpf[nNodes - 1] = xpf[0]; ypf[nNodes - 1] = ypf[0]; } float[] xindex = new float[nNodes]; for (int i = 0; i < nNodes; i++) xindex[i] = i; SplineFitter sfx = new SplineFitter(xindex, xpf, nNodes); SplineFitter sfy = new SplineFitter(xindex, ypf, nNodes); // Evaluate the splines at all points double scale = (double) (nNodes - 1) / (splinePoints - 1); float xs = 0f, ys = 0f; float xmin = Float.MAX_VALUE, xmax = -xmin, ymin = xmin, ymax = xmax; for (int i = 0; i < splinePoints; i++) { double xvalue = i * scale; xs = (float) sfx.evalSpline(xindex, xpf, nNodes, xvalue); if (xs < xmin) xmin = xs; if (xs > xmax) xmax = xs; xSpline[i] = xs; ys = (float) sfy.evalSpline(xindex, ypf, nNodes, xvalue); if (ys < ymin) ymin = ys; if (ys > ymax) ymax = ys; ySpline[i] = ys; } int ixmin = (int) Math.floor(xmin + 0.5f); int ixmax = (int) Math.floor(xmax + 0.5f); int iymin = (int) Math.floor(ymin + 0.5f); int iymax = (int) Math.floor(ymax + 0.5f); if (ixmin != 0) { for (int i = 0; i < nPoints; i++) xpf[i] -= ixmin; for (int i = 0; i < splinePoints; i++) xSpline[i] -= ixmin; } if (iymin != 0) { for (int i = 0; i < nPoints; i++) ypf[i] -= iymin; for (int i = 0; i < splinePoints; i++) ySpline[i] -= iymin; } x += ixmin; y += iymin; width = ixmax - ixmin; height = iymax - iymin; bounds = null; cachedMask = null; // update protected xp and yp arrays for backward compatibility xp = toInt(xpf, xp, nPoints); yp = toInt(ypf, yp, nPoints); }
void createEllipse(ImagePlus imp) { IJ.showStatus("Fitting ellipse"); Roi roi = imp.getRoi(); if (roi == null) { noRoi("Fit Ellipse"); return; } if (roi.isLine()) { IJ.error("Fit Ellipse", "\"Fit Ellipse\" does not work with line selections"); return; } ImageProcessor ip = imp.getProcessor(); ip.setRoi(roi); int options = Measurements.CENTROID + Measurements.ELLIPSE; ImageStatistics stats = ImageStatistics.getStatistics(ip, options, null); double dx = stats.major * Math.cos(stats.angle / 180.0 * Math.PI) / 2.0; double dy = -stats.major * Math.sin(stats.angle / 180.0 * Math.PI) / 2.0; double x1 = stats.xCentroid - dx; double x2 = stats.xCentroid + dx; double y1 = stats.yCentroid - dy; double y2 = stats.yCentroid + dy; double aspectRatio = stats.minor / stats.major; imp.killRoi(); imp.setRoi(new EllipseRoi(x1, y1, x2, y2, aspectRatio)); }
double rodbard(double x) { // y = c*((a-x/(x-d))^(1/b) // a=3.9, b=.88, c=712, d=44 double ex; if (x == 0.0) ex = 5.0; else ex = Math.exp(Math.log(x / 700.0) * 0.88); double y = 3.9 - 44.0; y = y / (1.0 + ex); return y + 44.0; }
/* Creates a spline fitted polygon with one pixel segment lengths that can be retrieved using the getFloatPolygon() method. */ public void fitSplineForStraightening() { fitSpline((int) getUncalibratedLength() * 2); if (splinePoints == 0) return; float[] xpoints = new float[splinePoints * 2]; float[] ypoints = new float[splinePoints * 2]; xpoints[0] = xSpline[0]; ypoints[0] = ySpline[0]; int n = 1, n2; double inc = 0.01; double distance = 0.0, distance2 = 0.0, dx = 0.0, dy = 0.0, xinc, yinc; double x, y, lastx, lasty, x1, y1, x2 = xSpline[0], y2 = ySpline[0]; for (int i = 1; i < splinePoints; i++) { x1 = x2; y1 = y2; x = x1; y = y1; x2 = xSpline[i]; y2 = ySpline[i]; dx = x2 - x1; dy = y2 - y1; distance = Math.sqrt(dx * dx + dy * dy); xinc = dx * inc / distance; yinc = dy * inc / distance; lastx = xpoints[n - 1]; lasty = ypoints[n - 1]; // n2 = (int)(dx/xinc); n2 = (int) (distance / inc); if (splinePoints == 2) n2++; do { dx = x - lastx; dy = y - lasty; distance2 = Math.sqrt(dx * dx + dy * dy); // IJ.log(i+" "+IJ.d2s(xinc,5)+" "+IJ.d2s(yinc,5)+" "+IJ.d2s(distance,2)+" // "+IJ.d2s(distance2,2)+" "+IJ.d2s(x,2)+" "+IJ.d2s(y,2)+" "+IJ.d2s(lastx,2)+" // "+IJ.d2s(lasty,2)+" "+n+" "+n2); if (distance2 >= 1.0 - inc / 2.0 && n < xpoints.length - 1) { xpoints[n] = (float) x; ypoints[n] = (float) y; // IJ.log("--- "+IJ.d2s(x,2)+" "+IJ.d2s(y,2)+" "+n); n++; lastx = x; lasty = y; } x += xinc; y += yinc; } while (--n2 > 0); } xSpline = xpoints; ySpline = ypoints; splinePoints = n; }
String getAngleAsString() { double angle1 = 0.0; double angle2 = 0.0; if (xpf != null) { angle1 = getFloatAngle(xpf[0], ypf[0], xpf[1], ypf[1]); angle2 = getFloatAngle(xpf[1], ypf[1], xpf[2], ypf[2]); } else { angle1 = getFloatAngle(xp[0], yp[0], xp[1], yp[1]); angle2 = getFloatAngle(xp[1], yp[1], xp[2], yp[2]); } degrees = Math.abs(180 - Math.abs(angle1 - angle2)); if (degrees > 180.0) degrees = 360.0 - degrees; double degrees2 = Prefs.reflexAngle && type == ANGLE ? 360.0 - degrees : degrees; return ", angle=" + IJ.d2s(degrees2); }
int[] smooth(int[] a, int n) { FloatProcessor fp = new FloatProcessor(n, 1); for (int i = 0; i < n; i++) fp.putPixelValue(i, 0, a[i]); GaussianBlur gb = new GaussianBlur(); gb.blur1Direction(fp, 2.0, 0.01, true, 0); for (int i = 0; i < n; i++) a[i] = (int) Math.round(fp.getPixelValue(i, 0)); return a; }
/** * Returns the perimeter length of ROIs created using the wand tool and the particle analyzer. The * algorithm counts edge pixels as 1 and corner pixels as sqrt(2). It does this by calculating the * total length of the ROI boundary and subtracting 2-sqrt(2) for each non-adjacent corner. For * example, a 1x1 pixel ROI has a boundary length of 4 and 2 non-adjacent edges so the perimeter * is 4-2*(2-sqrt(2)). A 2x2 pixel ROI has a boundary length of 8 and 4 non-adjacent edges so the * perimeter is 8-4*(2-sqrt(2)). */ double getTracedPerimeter() { int sumdx = 0; int sumdy = 0; int nCorners = 0; int dx1 = xp[0] - xp[nPoints - 1]; int dy1 = yp[0] - yp[nPoints - 1]; int side1 = Math.abs(dx1) + Math.abs(dy1); // one of these is 0 boolean corner = false; int nexti, dx2, dy2, side2; for (int i = 0; i < nPoints; i++) { nexti = i + 1; if (nexti == nPoints) nexti = 0; dx2 = xp[nexti] - xp[i]; dy2 = yp[nexti] - yp[i]; sumdx += Math.abs(dx1); sumdy += Math.abs(dy1); side2 = Math.abs(dx2) + Math.abs(dy2); if (side1 > 1 || !corner) { corner = true; nCorners++; } else corner = false; dx1 = dx2; dy1 = dy2; side1 = side2; } double w = 1.0, h = 1.0; if (imp != null) { Calibration cal = imp.getCalibration(); w = cal.pixelWidth; h = cal.pixelHeight; } return sumdx * w + sumdy * h - (nCorners * ((w + h) - Math.sqrt(w * w + h * h))); }
PolygonRoi trimPolygon(PolygonRoi roi, double length) { int[] x = roi.getXCoordinates(); int[] y = roi.getYCoordinates(); int n = roi.getNCoordinates(); x = smooth(x, n); y = smooth(y, n); float[] curvature = getCurvature(x, y, n); Rectangle r = roi.getBounds(); double threshold = rodbard(length); // IJ.log("trim: "+length+" "+threshold); double distance = Math.sqrt((x[1] - x[0]) * (x[1] - x[0]) + (y[1] - y[0]) * (y[1] - y[0])); x[0] += r.x; y[0] += r.y; int i2 = 1; int x1, y1, x2 = 0, y2 = 0; for (int i = 1; i < n - 1; i++) { x1 = x[i]; y1 = y[i]; x2 = x[i + 1]; y2 = y[i + 1]; distance += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) + 1; distance += curvature[i] * 2; if (distance >= threshold) { x[i2] = x2 + r.x; y[i2] = y2 + r.y; i2++; distance = 0.0; } } int type = roi.getType() == Roi.FREELINE ? Roi.POLYLINE : Roi.POLYGON; if (type == Roi.POLYLINE && distance > 0.0) { x[i2] = x2 + r.x; y[i2] = y2 + r.y; i2++; } PolygonRoi p = new PolygonRoi(x, y, i2, type); if (roi.getStroke() != null) p.setStrokeWidth(roi.getStrokeWidth()); p.setStrokeColor(roi.getStrokeColor()); p.setName(roi.getName()); imp.setRoi(p); return p; }
PolygonRoi trimFloatPolygon(PolygonRoi roi, double length) { FloatPolygon poly = roi.getFloatPolygon(); float[] x = poly.xpoints; float[] y = poly.ypoints; int n = poly.npoints; x = smooth(x, n); y = smooth(y, n); float[] curvature = getCurvature(x, y, n); double threshold = rodbard(length); // IJ.log("trim: "+length+" "+threshold); double distance = Math.sqrt((x[1] - x[0]) * (x[1] - x[0]) + (y[1] - y[0]) * (y[1] - y[0])); int i2 = 1; double x1, y1, x2 = 0, y2 = 0; for (int i = 1; i < n - 1; i++) { x1 = x[i]; y1 = y[i]; x2 = x[i + 1]; y2 = y[i + 1]; distance += Math.sqrt((x2 - x1) * (x2 - x1) + (y2 - y1) * (y2 - y1)) + 1; distance += curvature[i] * 2; if (distance >= threshold) { x[i2] = (float) x2; y[i2] = (float) y2; i2++; distance = 0.0; } } int type = roi.getType() == Roi.FREELINE ? Roi.POLYLINE : Roi.POLYGON; if (type == Roi.POLYLINE && distance > 0.0) { x[i2] = (float) x2; y[i2] = (float) y2; i2++; } PolygonRoi p = new PolygonRoi(x, y, i2, type); if (roi.getStroke() != null) p.setStrokeWidth(roi.getStrokeWidth()); p.setStrokeColor(roi.getStrokeColor()); p.setDrawOffset(roi.getDrawOffset()); p.setName(roi.getName()); imp.setRoi(p); return p; }
void handleMouseMove(int sx, int sy) { // Do rubber banding int tool = Toolbar.getToolId(); if (!(tool == Toolbar.POLYGON || tool == Toolbar.POLYLINE || tool == Toolbar.ANGLE)) { imp.deleteRoi(); imp.draw(); return; } drawRubberBand(sx, sy); degrees = Double.NaN; double len = -1; if (nPoints > 1) { double x1, y1, x2, y2; if (xpf != null) { x1 = xpf[nPoints - 2]; y1 = ypf[nPoints - 2]; x2 = xpf[nPoints - 1]; y2 = ypf[nPoints - 1]; } else { x1 = xp[nPoints - 2]; y1 = yp[nPoints - 2]; x2 = xp[nPoints - 1]; y2 = yp[nPoints - 1]; } degrees = getAngle( (int) Math.round(x1), (int) Math.round(y1), (int) Math.round(x2), (int) Math.round(y2)); if (tool != Toolbar.ANGLE) { Calibration cal = imp.getCalibration(); double pw = cal.pixelWidth, ph = cal.pixelHeight; if (IJ.altKeyDown()) { pw = 1.0; ph = 1.0; } len = Math.sqrt((x2 - x1) * pw * (x2 - x1) * pw + (y2 - y1) * ph * (y2 - y1) * ph); } } if (tool == Toolbar.ANGLE) { if (nPoints == 2) angle1 = degrees; else if (nPoints == 3) { double angle2 = getAngle(xp[1], yp[1], xp[2], yp[2]); degrees = Math.abs(180 - Math.abs(angle1 - angle2)); if (degrees > 180.0) degrees = 360.0 - degrees; } } String length = len != -1 ? ", length=" + IJ.d2s(len) : ""; double degrees2 = tool == Toolbar.ANGLE && nPoints == 3 && Prefs.reflexAngle ? 360.0 - degrees : degrees; String angle = !Double.isNaN(degrees) ? ", angle=" + IJ.d2s(degrees2) : ""; int ox = ic != null ? ic.offScreenX(sx) : sx; int oy = ic != null ? ic.offScreenY(sy) : sy; IJ.showStatus(imp.getLocationAsString(ox, oy) + length + angle); }
double getFloatSmoothedPerimeter() { double length = getSmoothedLineLength(); double w2 = 1.0, h2 = 1.0; if (imp != null) { Calibration cal = imp.getCalibration(); w2 = cal.pixelWidth * cal.pixelWidth; h2 = cal.pixelHeight * cal.pixelHeight; } double dx = xpf[nPoints - 1] - xpf[0]; double dy = ypf[nPoints - 1] - ypf[0]; length += Math.sqrt(dx * dx * w2 + dy * dy * h2); return length; }
double getFloatSmoothedLineLength() { double length = 0.0; double w2 = 1.0; double h2 = 1.0; double dx, dy; if (imp != null) { Calibration cal = imp.getCalibration(); w2 = cal.pixelWidth * cal.pixelWidth; h2 = cal.pixelHeight * cal.pixelHeight; } dx = (xpf[0] + xpf[1] + xpf[2]) / 3.0 - xpf[0]; dy = (ypf[0] + ypf[1] + ypf[2]) / 3.0 - ypf[0]; length += Math.sqrt(dx * dx * w2 + dy * dy * h2); for (int i = 1; i < nPoints - 2; i++) { dx = (xpf[i + 2] - xpf[i - 1]) / 3.0; dy = (ypf[i + 2] - ypf[i - 1]) / 3.0; length += Math.sqrt(dx * dx * w2 + dy * dy * h2); } dx = xpf[nPoints - 1] - (xpf[nPoints - 3] + xpf[nPoints - 2] + xpf[nPoints - 1]) / 3.0; dy = ypf[nPoints - 1] - (ypf[nPoints - 3] + ypf[nPoints - 2] + ypf[nPoints - 1]) / 3.0; length += Math.sqrt(dx * dx * w2 + dy * dy * h2); return length; }
/** Returns the perimeter (for ROIs) or length (for lines). */ public double getLength() { if (type == TRACED_ROI) return getTracedPerimeter(); if (nPoints > 2) { if (type == FREEROI) return getSmoothedPerimeter(); else if (type == FREELINE && !(width == 0 || height == 0)) return getSmoothedLineLength(); } double length = 0.0; int dx, dy; double w2 = 1.0, h2 = 1.0; if (imp != null) { Calibration cal = imp.getCalibration(); w2 = cal.pixelWidth * cal.pixelWidth; h2 = cal.pixelHeight * cal.pixelHeight; } if (xSpline != null) { double fdx, fdy; for (int i = 0; i < (splinePoints - 1); i++) { fdx = xSpline[i + 1] - xSpline[i]; fdy = ySpline[i + 1] - ySpline[i]; length += Math.sqrt(fdx * fdx * w2 + fdy * fdy * h2); } if (type == POLYGON) { fdx = xSpline[0] - xSpline[splinePoints - 1]; fdy = ySpline[0] - ySpline[splinePoints - 1]; length += Math.sqrt(fdx * fdx * w2 + fdy * fdy * h2); } } else if (xpf != null) { double fdx, fdy; for (int i = 0; i < (nPoints - 1); i++) { fdx = xpf[i + 1] - xpf[i]; fdy = ypf[i + 1] - ypf[i]; length += Math.sqrt(fdx * fdx * w2 + fdy * fdy * h2); } if (type == POLYGON) { fdx = xpf[0] - xpf[nPoints - 1]; fdy = ypf[0] - ypf[nPoints - 1]; length += Math.sqrt(fdx * fdx * w2 + fdy * fdy * h2); } } else { for (int i = 0; i < (nPoints - 1); i++) { dx = xp[i + 1] - xp[i]; dy = yp[i + 1] - yp[i]; length += Math.sqrt(dx * dx * w2 + dy * dy * h2); } if (type == POLYGON) { dx = xp[0] - xp[nPoints - 1]; dy = yp[0] - yp[nPoints - 1]; length += Math.sqrt(dx * dx * w2 + dy * dy * h2); } } return length; }
float[] getCurvature(float[] x, float[] y, int n) { float[] x2 = new float[n]; float[] y2 = new float[n]; for (int i = 0; i < n; i++) { x2[i] = x[i]; y2[i] = y[i]; } ImageProcessor ipx = new FloatProcessor(n, 1, x, null); ImageProcessor ipy = new FloatProcessor(n, 1, y, null); ipx.convolve(kernel, kernel.length, 1); ipy.convolve(kernel, kernel.length, 1); float[] indexes = new float[n]; float[] curvature = new float[n]; for (int i = 0; i < n; i++) { indexes[i] = i; curvature[i] = (float) Math.sqrt((x2[i] - x[i]) * (x2[i] - x[i]) + (y2[i] - y[i]) * (y2[i] - y[i])); } return curvature; }
/* if selection is closed shape, create a circle with the same area and centroid, otherwise use<br> the Pratt method to fit a circle to the points that define the line or multi-point selection.<br> Reference: Pratt V., Direct least-squares fitting of algebraic surfaces", Computer Graphics, Vol. 21, pages 145-152 (1987).<br> Original code: Nikolai Chernov's MATLAB script for Newton-based Pratt fit.<br> (http://www.math.uab.edu/~chernov/cl/MATLABcircle.html)<br> Java version: https://github.com/mdoube/BoneJ/blob/master/src/org/doube/geometry/FitCircle.java<br> @authors Nikolai Chernov, Michael Doube, Ved Sharma */ void fitCircle(ImagePlus imp) { Roi roi = imp.getRoi(); if (roi == null) { noRoi("Fit Circle"); return; } if (roi.isArea()) { // create circle with the same area and centroid ImageProcessor ip = imp.getProcessor(); ip.setRoi(roi); ImageStatistics stats = ImageStatistics.getStatistics(ip, Measurements.AREA + Measurements.CENTROID, null); double r = Math.sqrt(stats.pixelCount / Math.PI); imp.killRoi(); int d = (int) Math.round(2.0 * r); IJ.makeOval( (int) Math.round(stats.xCentroid - r), (int) Math.round(stats.yCentroid - r), d, d); return; } Polygon poly = roi.getPolygon(); int n = poly.npoints; int[] x = poly.xpoints; int[] y = poly.ypoints; if (n < 3) { IJ.error("Fit Circle", "At least 3 points are required to fit a circle."); return; } // calculate point centroid double sumx = 0, sumy = 0; for (int i = 0; i < n; i++) { sumx = sumx + poly.xpoints[i]; sumy = sumy + poly.ypoints[i]; } double meanx = sumx / n; double meany = sumy / n; // calculate moments double[] X = new double[n], Y = new double[n]; double Mxx = 0, Myy = 0, Mxy = 0, Mxz = 0, Myz = 0, Mzz = 0; for (int i = 0; i < n; i++) { X[i] = x[i] - meanx; Y[i] = y[i] - meany; double Zi = X[i] * X[i] + Y[i] * Y[i]; Mxy = Mxy + X[i] * Y[i]; Mxx = Mxx + X[i] * X[i]; Myy = Myy + Y[i] * Y[i]; Mxz = Mxz + X[i] * Zi; Myz = Myz + Y[i] * Zi; Mzz = Mzz + Zi * Zi; } Mxx = Mxx / n; Myy = Myy / n; Mxy = Mxy / n; Mxz = Mxz / n; Myz = Myz / n; Mzz = Mzz / n; // calculate the coefficients of the characteristic polynomial double Mz = Mxx + Myy; double Cov_xy = Mxx * Myy - Mxy * Mxy; double Mxz2 = Mxz * Mxz; double Myz2 = Myz * Myz; double A2 = 4 * Cov_xy - 3 * Mz * Mz - Mzz; double A1 = Mzz * Mz + 4 * Cov_xy * Mz - Mxz2 - Myz2 - Mz * Mz * Mz; double A0 = Mxz2 * Myy + Myz2 * Mxx - Mzz * Cov_xy - 2 * Mxz * Myz * Mxy + Mz * Mz * Cov_xy; double A22 = A2 + A2; double epsilon = 1e-12; double ynew = 1e+20; int IterMax = 20; double xnew = 0; int iterations = 0; // Newton's method starting at x=0 for (int iter = 1; iter <= IterMax; iter++) { iterations = iter; double yold = ynew; ynew = A0 + xnew * (A1 + xnew * (A2 + 4. * xnew * xnew)); if (Math.abs(ynew) > Math.abs(yold)) { if (IJ.debugMode) IJ.log("Fit Circle: wrong direction: |ynew| > |yold|"); xnew = 0; break; } double Dy = A1 + xnew * (A22 + 16 * xnew * xnew); double xold = xnew; xnew = xold - ynew / Dy; if (Math.abs((xnew - xold) / xnew) < epsilon) break; if (iter >= IterMax) { if (IJ.debugMode) IJ.log("Fit Circle: will not converge"); xnew = 0; } if (xnew < 0) { if (IJ.debugMode) IJ.log("Fit Circle: negative root: x = " + xnew); xnew = 0; } } if (IJ.debugMode) IJ.log("Fit Circle: n=" + n + ", xnew=" + IJ.d2s(xnew, 2) + ", iterations=" + iterations); // calculate the circle parameters double DET = xnew * xnew - xnew * Mz + Cov_xy; double CenterX = (Mxz * (Myy - xnew) - Myz * Mxy) / (2 * DET); double CenterY = (Myz * (Mxx - xnew) - Mxz * Mxy) / (2 * DET); double radius = Math.sqrt(CenterX * CenterX + CenterY * CenterY + Mz + 2 * xnew); if (Double.isNaN(radius)) { IJ.error("Fit Circle", "Points are collinear."); return; } CenterX = CenterX + meanx; CenterY = CenterY + meany; imp.killRoi(); IJ.makeOval( (int) Math.round(CenterX - radius), (int) Math.round(CenterY - radius), (int) Math.round(2 * radius), (int) Math.round(2 * radius)); }
private void makeBand(ImagePlus imp) { Roi roi = imp.getRoi(); if (roi == null) { noRoi("Make Band"); return; } if (!roi.isArea()) { IJ.error("Make Band", "Area selection required"); return; } Calibration cal = imp.getCalibration(); double pixels = bandSize; double size = pixels * cal.pixelWidth; int decimalPlaces = 0; if ((int) size != size) decimalPlaces = 2; GenericDialog gd = new GenericDialog("Make Band"); gd.addNumericField("Band Size:", size, decimalPlaces, 4, cal.getUnits()); gd.showDialog(); if (gd.wasCanceled()) return; size = gd.getNextNumber(); if (Double.isNaN(size)) { IJ.error("Make Band", "invalid number"); return; } int n = (int) Math.round(size / cal.pixelWidth); if (n > 255) { IJ.error("Make Band", "Cannot make bands wider that 255 pixels"); return; } int width = imp.getWidth(); int height = imp.getHeight(); Rectangle r = roi.getBounds(); ImageProcessor ip = roi.getMask(); if (ip == null) { ip = new ByteProcessor(r.width, r.height); ip.invert(); } ImageProcessor mask = new ByteProcessor(width, height); mask.insert(ip, r.x, r.y); ImagePlus edm = new ImagePlus("mask", mask); boolean saveBlackBackground = Prefs.blackBackground; Prefs.blackBackground = false; IJ.run(edm, "Distance Map", ""); Prefs.blackBackground = saveBlackBackground; ip = edm.getProcessor(); ip.setThreshold(0, n, ImageProcessor.NO_LUT_UPDATE); int xx = -1, yy = -1; for (int x = r.x; x < r.x + r.width; x++) { for (int y = r.y; y < r.y + r.height; y++) { if (ip.getPixel(x, y) < n) { xx = x; yy = y; break; } } if (xx >= 0 || yy >= 0) break; } int count = IJ.doWand(edm, xx, yy, 0, null); if (count <= 0) { IJ.error("Make Band", "Unable to make band"); return; } ShapeRoi roi2 = new ShapeRoi(edm.getRoi()); if (!(roi instanceof ShapeRoi)) roi = new ShapeRoi(roi); ShapeRoi roi1 = (ShapeRoi) roi; roi2 = roi2.not(roi1); imp.setRoi(roi2); bandSize = n; }
public void drawPixels(ImageProcessor ip) { int saveWidth = ip.getLineWidth(); if (getStrokeWidth() > 1f) ip.setLineWidth((int) Math.round(getStrokeWidth())); double offset = getOffset(0.5); if (xSpline != null) { ip.moveTo( x + (int) (Math.round(xSpline[0]) + offset), y + (int) Math.round(ySpline[0] + offset)); for (int i = 1; i < splinePoints; i++) ip.lineTo( x + (int) (Math.round(xSpline[i]) + offset), y + (int) Math.round(ySpline[i] + offset)); if (type == POLYGON || type == FREEROI || type == TRACED_ROI) ip.lineTo( x + (int) (Math.round(xSpline[0]) + offset), y + (int) Math.round(ySpline[0] + offset)); } else if (xpf != null) { ip.moveTo(x + (int) (Math.round(xpf[0]) + offset), y + (int) Math.round(ypf[0] + offset)); for (int i = 1; i < nPoints; i++) ip.lineTo(x + (int) (Math.round(xpf[i]) + offset), y + (int) Math.round(ypf[i] + offset)); if (type == POLYGON || type == FREEROI || type == TRACED_ROI) ip.lineTo(x + (int) (Math.round(xpf[0]) + offset), y + (int) Math.round(ypf[0] + offset)); } else { ip.moveTo(x + xp[0], y + yp[0]); for (int i = 1; i < nPoints; i++) ip.lineTo(x + xp[i], y + yp[i]); if (type == POLYGON || type == FREEROI || type == TRACED_ROI) ip.lineTo(x + xp[0], y + yp[0]); } ip.setLineWidth(saveWidth); updateFullWindow = true; }
public void build_bricks() { ImagePlus imp; ImagePlus orgimp; ImageStack stack; FileInfo finfo; if (lvImgTitle.isEmpty()) return; orgimp = WindowManager.getImage(lvImgTitle.get(0)); imp = orgimp; finfo = imp.getFileInfo(); if (finfo == null) return; int[] dims = imp.getDimensions(); int imageW = dims[0]; int imageH = dims[1]; int nCh = dims[2]; int imageD = dims[3]; int nFrame = dims[4]; int bdepth = imp.getBitDepth(); double xspc = finfo.pixelWidth; double yspc = finfo.pixelHeight; double zspc = finfo.pixelDepth; double z_aspect = Math.max(xspc, yspc) / zspc; int orgW = imageW; int orgH = imageH; int orgD = imageD; double orgxspc = xspc; double orgyspc = yspc; double orgzspc = zspc; lv = lvImgTitle.size(); if (filetype == "JPEG") { for (int l = 0; l < lv; l++) { if (WindowManager.getImage(lvImgTitle.get(l)).getBitDepth() != 8) { IJ.error("A SOURCE IMAGE MUST BE 8BIT GLAYSCALE"); return; } } } // calculate levels /* int baseXY = 256; int baseZ = 256; if (z_aspect < 0.5) baseZ = 128; if (z_aspect > 2.0) baseXY = 128; if (z_aspect >= 0.5 && z_aspect < 1.0) baseZ = (int)(baseZ*z_aspect); if (z_aspect > 1.0 && z_aspect <= 2.0) baseXY = (int)(baseXY/z_aspect); IJ.log("Z_aspect: " + z_aspect); IJ.log("BaseXY: " + baseXY); IJ.log("BaseZ: " + baseZ); */ int baseXY = 256; int baseZ = 128; int dbXY = Math.max(orgW, orgH) / baseXY; if (Math.max(orgW, orgH) % baseXY > 0) dbXY *= 2; int dbZ = orgD / baseZ; if (orgD % baseZ > 0) dbZ *= 2; lv = Math.max(log2(dbXY), log2(dbZ)) + 1; int ww = orgW; int hh = orgH; int dd = orgD; for (int l = 0; l < lv; l++) { int bwnum = ww / baseXY; if (ww % baseXY > 0) bwnum++; int bhnum = hh / baseXY; if (hh % baseXY > 0) bhnum++; int bdnum = dd / baseZ; if (dd % baseZ > 0) bdnum++; if (bwnum % 2 == 0) bwnum++; if (bhnum % 2 == 0) bhnum++; if (bdnum % 2 == 0) bdnum++; int bw = (bwnum <= 1) ? ww : ww / bwnum + 1 + (ww % bwnum > 0 ? 1 : 0); int bh = (bhnum <= 1) ? hh : hh / bhnum + 1 + (hh % bhnum > 0 ? 1 : 0); int bd = (bdnum <= 1) ? dd : dd / bdnum + 1 + (dd % bdnum > 0 ? 1 : 0); bwlist.add(bw); bhlist.add(bh); bdlist.add(bd); IJ.log("LEVEL: " + l); IJ.log(" width: " + ww); IJ.log(" hight: " + hh); IJ.log(" depth: " + dd); IJ.log(" bw: " + bw); IJ.log(" bh: " + bh); IJ.log(" bd: " + bd); int xyl2 = Math.max(ww, hh) / baseXY; if (Math.max(ww, hh) % baseXY > 0) xyl2 *= 2; if (lv - 1 - log2(xyl2) <= l) { ww /= 2; hh /= 2; } IJ.log(" xyl2: " + (lv - 1 - log2(xyl2))); int zl2 = dd / baseZ; if (dd % baseZ > 0) zl2 *= 2; if (lv - 1 - log2(zl2) <= l) dd /= 2; IJ.log(" zl2: " + (lv - 1 - log2(zl2))); if (l < lv - 1) { lvImgTitle.add(lvImgTitle.get(0) + "_level" + (l + 1)); IJ.selectWindow(lvImgTitle.get(0)); IJ.run( "Scale...", "x=- y=- z=- width=" + ww + " height=" + hh + " depth=" + dd + " interpolation=Bicubic average process create title=" + lvImgTitle.get(l + 1)); } } for (int l = 0; l < lv; l++) { IJ.log(lvImgTitle.get(l)); } Document doc = newXMLDocument(); Element root = doc.createElement("BRK"); root.setAttribute("version", "1.0"); root.setAttribute("nLevel", String.valueOf(lv)); root.setAttribute("nChannel", String.valueOf(nCh)); root.setAttribute("nFrame", String.valueOf(nFrame)); doc.appendChild(root); for (int l = 0; l < lv; l++) { IJ.showProgress(0.0); int[] dims2 = imp.getDimensions(); IJ.log( "W: " + String.valueOf(dims2[0]) + " H: " + String.valueOf(dims2[1]) + " C: " + String.valueOf(dims2[2]) + " D: " + String.valueOf(dims2[3]) + " T: " + String.valueOf(dims2[4]) + " b: " + String.valueOf(bdepth)); bw = bwlist.get(l).intValue(); bh = bhlist.get(l).intValue(); bd = bdlist.get(l).intValue(); boolean force_pow2 = false; /* if(IsPowerOf2(bw) && IsPowerOf2(bh) && IsPowerOf2(bd)) force_pow2 = true; if(force_pow2){ //force pow2 if(Pow2(bw) > bw) bw = Pow2(bw)/2; if(Pow2(bh) > bh) bh = Pow2(bh)/2; if(Pow2(bd) > bd) bd = Pow2(bd)/2; } if(bw > imageW) bw = (Pow2(imageW) == imageW) ? imageW : Pow2(imageW)/2; if(bh > imageH) bh = (Pow2(imageH) == imageH) ? imageH : Pow2(imageH)/2; if(bd > imageD) bd = (Pow2(imageD) == imageD) ? imageD : Pow2(imageD)/2; */ if (bw > imageW) bw = imageW; if (bh > imageH) bh = imageH; if (bd > imageD) bd = imageD; if (bw <= 1 || bh <= 1 || bd <= 1) break; if (filetype == "JPEG" && (bw < 8 || bh < 8)) break; Element lvnode = doc.createElement("Level"); lvnode.setAttribute("lv", String.valueOf(l)); lvnode.setAttribute("imageW", String.valueOf(imageW)); lvnode.setAttribute("imageH", String.valueOf(imageH)); lvnode.setAttribute("imageD", String.valueOf(imageD)); lvnode.setAttribute("xspc", String.valueOf(xspc)); lvnode.setAttribute("yspc", String.valueOf(yspc)); lvnode.setAttribute("zspc", String.valueOf(zspc)); lvnode.setAttribute("bitDepth", String.valueOf(bdepth)); root.appendChild(lvnode); Element brksnode = doc.createElement("Bricks"); brksnode.setAttribute("brick_baseW", String.valueOf(bw)); brksnode.setAttribute("brick_baseH", String.valueOf(bh)); brksnode.setAttribute("brick_baseD", String.valueOf(bd)); lvnode.appendChild(brksnode); ArrayList<Brick> bricks = new ArrayList<Brick>(); int mw, mh, md, mw2, mh2, md2; double tx0, ty0, tz0, tx1, ty1, tz1; double bx0, by0, bz0, bx1, by1, bz1; for (int k = 0; k < imageD; k += bd) { if (k > 0) k--; for (int j = 0; j < imageH; j += bh) { if (j > 0) j--; for (int i = 0; i < imageW; i += bw) { if (i > 0) i--; mw = Math.min(bw, imageW - i); mh = Math.min(bh, imageH - j); md = Math.min(bd, imageD - k); if (force_pow2) { mw2 = Pow2(mw); mh2 = Pow2(mh); md2 = Pow2(md); } else { mw2 = mw; mh2 = mh; md2 = md; } if (filetype == "JPEG") { if (mw2 < 8) mw2 = 8; if (mh2 < 8) mh2 = 8; } tx0 = i == 0 ? 0.0d : ((mw2 - mw + 0.5d) / mw2); ty0 = j == 0 ? 0.0d : ((mh2 - mh + 0.5d) / mh2); tz0 = k == 0 ? 0.0d : ((md2 - md + 0.5d) / md2); tx1 = 1.0d - 0.5d / mw2; if (mw < bw) tx1 = 1.0d; if (imageW - i == bw) tx1 = 1.0d; ty1 = 1.0d - 0.5d / mh2; if (mh < bh) ty1 = 1.0d; if (imageH - j == bh) ty1 = 1.0d; tz1 = 1.0d - 0.5d / md2; if (md < bd) tz1 = 1.0d; if (imageD - k == bd) tz1 = 1.0d; bx0 = i == 0 ? 0.0d : (i + 0.5d) / (double) imageW; by0 = j == 0 ? 0.0d : (j + 0.5d) / (double) imageH; bz0 = k == 0 ? 0.0d : (k + 0.5d) / (double) imageD; bx1 = Math.min((i + bw - 0.5d) / (double) imageW, 1.0d); if (imageW - i == bw) bx1 = 1.0d; by1 = Math.min((j + bh - 0.5d) / (double) imageH, 1.0d); if (imageH - j == bh) by1 = 1.0d; bz1 = Math.min((k + bd - 0.5d) / (double) imageD, 1.0d); if (imageD - k == bd) bz1 = 1.0d; int x, y, z; x = i - (mw2 - mw); y = j - (mh2 - mh); z = k - (md2 - md); bricks.add( new Brick( x, y, z, mw2, mh2, md2, 0, 0, tx0, ty0, tz0, tx1, ty1, tz1, bx0, by0, bz0, bx1, by1, bz1)); } } } Element fsnode = doc.createElement("Files"); lvnode.appendChild(fsnode); stack = imp.getStack(); int totalbricknum = nFrame * nCh * bricks.size(); int curbricknum = 0; for (int f = 0; f < nFrame; f++) { for (int ch = 0; ch < nCh; ch++) { int sizelimit = bdsizelimit * 1024 * 1024; int bytecount = 0; int filecount = 0; int pd_bufsize = Math.max(sizelimit, bw * bh * bd * bdepth / 8); byte[] packed_data = new byte[pd_bufsize]; String base_dataname = basename + "_Lv" + String.valueOf(l) + "_Ch" + String.valueOf(ch) + "_Fr" + String.valueOf(f); String current_dataname = base_dataname + "_data" + filecount; Brick b_first = bricks.get(0); if (b_first.z_ != 0) IJ.log("warning"); int st_z = b_first.z_; int ed_z = b_first.z_ + b_first.d_; LinkedList<ImageProcessor> iplist = new LinkedList<ImageProcessor>(); for (int s = st_z; s < ed_z; s++) iplist.add(stack.getProcessor(imp.getStackIndex(ch + 1, s + 1, f + 1))); // ImagePlus test; // ImageStack tsst; // test = NewImage.createByteImage("test", imageW, imageH, imageD, // NewImage.FILL_BLACK); // tsst = test.getStack(); for (int i = 0; i < bricks.size(); i++) { Brick b = bricks.get(i); if (ed_z > b.z_ || st_z < b.z_ + b.d_) { if (b.z_ > st_z) { for (int s = 0; s < b.z_ - st_z; s++) iplist.pollFirst(); st_z = b.z_; } else if (b.z_ < st_z) { IJ.log("warning"); for (int s = st_z - 1; s > b.z_; s--) iplist.addFirst(stack.getProcessor(imp.getStackIndex(ch + 1, s + 1, f + 1))); st_z = b.z_; } if (b.z_ + b.d_ > ed_z) { for (int s = ed_z; s < b.z_ + b.d_; s++) iplist.add(stack.getProcessor(imp.getStackIndex(ch + 1, s + 1, f + 1))); ed_z = b.z_ + b.d_; } else if (b.z_ + b.d_ < ed_z) { IJ.log("warning"); for (int s = 0; s < ed_z - (b.z_ + b.d_); s++) iplist.pollLast(); ed_z = b.z_ + b.d_; } } else { IJ.log("warning"); iplist.clear(); st_z = b.z_; ed_z = b.z_ + b.d_; for (int s = st_z; s < ed_z; s++) iplist.add(stack.getProcessor(imp.getStackIndex(ch + 1, s + 1, f + 1))); } if (iplist.size() != b.d_) { IJ.log("Stack Error"); return; } // int zz = st_z; int bsize = 0; byte[] bdata = new byte[b.w_ * b.h_ * b.d_ * bdepth / 8]; Iterator<ImageProcessor> ipite = iplist.iterator(); while (ipite.hasNext()) { // ImageProcessor tsip = tsst.getProcessor(zz+1); ImageProcessor ip = ipite.next(); ip.setRoi(b.x_, b.y_, b.w_, b.h_); if (bdepth == 8) { byte[] data = (byte[]) ip.crop().getPixels(); System.arraycopy(data, 0, bdata, bsize, data.length); bsize += data.length; } else if (bdepth == 16) { ByteBuffer buffer = ByteBuffer.allocate(b.w_ * b.h_ * bdepth / 8); buffer.order(ByteOrder.LITTLE_ENDIAN); short[] data = (short[]) ip.crop().getPixels(); for (short e : data) buffer.putShort(e); System.arraycopy(buffer.array(), 0, bdata, bsize, buffer.array().length); bsize += buffer.array().length; } else if (bdepth == 32) { ByteBuffer buffer = ByteBuffer.allocate(b.w_ * b.h_ * bdepth / 8); buffer.order(ByteOrder.LITTLE_ENDIAN); float[] data = (float[]) ip.crop().getPixels(); for (float e : data) buffer.putFloat(e); System.arraycopy(buffer.array(), 0, bdata, bsize, buffer.array().length); bsize += buffer.array().length; } } String filename = basename + "_Lv" + String.valueOf(l) + "_Ch" + String.valueOf(ch) + "_Fr" + String.valueOf(f) + "_ID" + String.valueOf(i); int offset = bytecount; int datasize = bdata.length; if (filetype == "RAW") { int dummy = -1; // do nothing } if (filetype == "JPEG" && bdepth == 8) { try { DataBufferByte db = new DataBufferByte(bdata, datasize); Raster raster = Raster.createPackedRaster(db, b.w_, b.h_ * b.d_, 8, null); BufferedImage img = new BufferedImage(b.w_, b.h_ * b.d_, BufferedImage.TYPE_BYTE_GRAY); img.setData(raster); ByteArrayOutputStream baos = new ByteArrayOutputStream(); ImageOutputStream ios = ImageIO.createImageOutputStream(baos); String format = "jpg"; Iterator<javax.imageio.ImageWriter> iter = ImageIO.getImageWritersByFormatName("jpeg"); javax.imageio.ImageWriter writer = iter.next(); ImageWriteParam iwp = writer.getDefaultWriteParam(); iwp.setCompressionMode(ImageWriteParam.MODE_EXPLICIT); iwp.setCompressionQuality((float) jpeg_quality * 0.01f); writer.setOutput(ios); writer.write(null, new IIOImage(img, null, null), iwp); // ImageIO.write(img, format, baos); bdata = baos.toByteArray(); datasize = bdata.length; } catch (IOException e) { e.printStackTrace(); return; } } if (filetype == "ZLIB") { byte[] tmpdata = new byte[b.w_ * b.h_ * b.d_ * bdepth / 8]; Deflater compresser = new Deflater(); compresser.setInput(bdata); compresser.setLevel(Deflater.DEFAULT_COMPRESSION); compresser.setStrategy(Deflater.DEFAULT_STRATEGY); compresser.finish(); datasize = compresser.deflate(tmpdata); bdata = tmpdata; compresser.end(); } if (bytecount + datasize > sizelimit && bytecount > 0) { BufferedOutputStream fis = null; try { File file = new File(directory + current_dataname); fis = new BufferedOutputStream(new FileOutputStream(file)); fis.write(packed_data, 0, bytecount); } catch (IOException e) { e.printStackTrace(); return; } finally { try { if (fis != null) fis.close(); } catch (IOException e) { e.printStackTrace(); return; } } filecount++; current_dataname = base_dataname + "_data" + filecount; bytecount = 0; offset = 0; System.arraycopy(bdata, 0, packed_data, bytecount, datasize); bytecount += datasize; } else { System.arraycopy(bdata, 0, packed_data, bytecount, datasize); bytecount += datasize; } Element filenode = doc.createElement("File"); filenode.setAttribute("filename", current_dataname); filenode.setAttribute("channel", String.valueOf(ch)); filenode.setAttribute("frame", String.valueOf(f)); filenode.setAttribute("brickID", String.valueOf(i)); filenode.setAttribute("offset", String.valueOf(offset)); filenode.setAttribute("datasize", String.valueOf(datasize)); filenode.setAttribute("filetype", String.valueOf(filetype)); fsnode.appendChild(filenode); curbricknum++; IJ.showProgress((double) (curbricknum) / (double) (totalbricknum)); } if (bytecount > 0) { BufferedOutputStream fis = null; try { File file = new File(directory + current_dataname); fis = new BufferedOutputStream(new FileOutputStream(file)); fis.write(packed_data, 0, bytecount); } catch (IOException e) { e.printStackTrace(); return; } finally { try { if (fis != null) fis.close(); } catch (IOException e) { e.printStackTrace(); return; } } } } } for (int i = 0; i < bricks.size(); i++) { Brick b = bricks.get(i); Element bricknode = doc.createElement("Brick"); bricknode.setAttribute("id", String.valueOf(i)); bricknode.setAttribute("st_x", String.valueOf(b.x_)); bricknode.setAttribute("st_y", String.valueOf(b.y_)); bricknode.setAttribute("st_z", String.valueOf(b.z_)); bricknode.setAttribute("width", String.valueOf(b.w_)); bricknode.setAttribute("height", String.valueOf(b.h_)); bricknode.setAttribute("depth", String.valueOf(b.d_)); brksnode.appendChild(bricknode); Element tboxnode = doc.createElement("tbox"); tboxnode.setAttribute("x0", String.valueOf(b.tx0_)); tboxnode.setAttribute("y0", String.valueOf(b.ty0_)); tboxnode.setAttribute("z0", String.valueOf(b.tz0_)); tboxnode.setAttribute("x1", String.valueOf(b.tx1_)); tboxnode.setAttribute("y1", String.valueOf(b.ty1_)); tboxnode.setAttribute("z1", String.valueOf(b.tz1_)); bricknode.appendChild(tboxnode); Element bboxnode = doc.createElement("bbox"); bboxnode.setAttribute("x0", String.valueOf(b.bx0_)); bboxnode.setAttribute("y0", String.valueOf(b.by0_)); bboxnode.setAttribute("z0", String.valueOf(b.bz0_)); bboxnode.setAttribute("x1", String.valueOf(b.bx1_)); bboxnode.setAttribute("y1", String.valueOf(b.by1_)); bboxnode.setAttribute("z1", String.valueOf(b.bz1_)); bricknode.appendChild(bboxnode); } if (l < lv - 1) { imp = WindowManager.getImage(lvImgTitle.get(l + 1)); int[] newdims = imp.getDimensions(); imageW = newdims[0]; imageH = newdims[1]; imageD = newdims[3]; xspc = orgxspc * ((double) orgW / (double) imageW); yspc = orgyspc * ((double) orgH / (double) imageH); zspc = orgzspc * ((double) orgD / (double) imageD); bdepth = imp.getBitDepth(); } } File newXMLfile = new File(directory + basename + ".vvd"); writeXML(newXMLfile, doc); for (int l = 1; l < lv; l++) { imp = WindowManager.getImage(lvImgTitle.get(l)); imp.changes = false; imp.close(); } }