Example #1
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;
 }
Example #2
0
 /**
  * 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)));
 }
Example #3
0
 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);
 }
Example #4
0
 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;
 }
Example #5
0
 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;
 }
Example #6
0
 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;
 }
Example #7
0
 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;
 }
Example #8
0
  /** 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;
  }
Example #9
0
 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;
 }
Example #10
0
  /*
  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));
  }