Beispiel #1
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);
 }
Beispiel #2
0
 private String displayRanges(ImagePlus imp) {
   LUT[] luts = imp.getLuts();
   if (luts == null) return "";
   String s = "Display ranges\n";
   int n = luts.length;
   if (n > 7) n = 7;
   for (int i = 0; i < n; i++) {
     double min = luts[i].min;
     double max = luts[i].max;
     int digits = (int) min == min && (int) max == max ? 0 : 2;
     s += "  " + (i + 1) + ": " + IJ.d2s(min, digits) + "-" + IJ.d2s(max, digits) + "\n";
   }
   return s;
 }
Beispiel #3
0
 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);
 }
Beispiel #4
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));
  }
Beispiel #5
0
  String getInfo(ImagePlus imp, ImageProcessor ip) {
    String s = new String("\n");
    s += "Title: " + imp.getTitle() + "\n";
    Calibration cal = imp.getCalibration();
    int stackSize = imp.getStackSize();
    int channels = imp.getNChannels();
    int slices = imp.getNSlices();
    int frames = imp.getNFrames();
    int digits = imp.getBitDepth() == 32 ? 4 : 0;
    if (cal.scaled()) {
      String unit = cal.getUnit();
      String units = cal.getUnits();
      s +=
          "Width:  "
              + IJ.d2s(imp.getWidth() * cal.pixelWidth, 2)
              + " "
              + units
              + " ("
              + imp.getWidth()
              + ")\n";
      s +=
          "Height:  "
              + IJ.d2s(imp.getHeight() * cal.pixelHeight, 2)
              + " "
              + units
              + " ("
              + imp.getHeight()
              + ")\n";
      if (slices > 1)
        s += "Depth:  " + IJ.d2s(slices * cal.pixelDepth, 2) + " " + units + " (" + slices + ")\n";
      double xResolution = 1.0 / cal.pixelWidth;
      double yResolution = 1.0 / cal.pixelHeight;
      int places = Tools.getDecimalPlaces(xResolution, yResolution);
      if (xResolution == yResolution)
        s += "Resolution:  " + IJ.d2s(xResolution, places) + " pixels per " + unit + "\n";
      else {
        s += "X Resolution:  " + IJ.d2s(xResolution, places) + " pixels per " + unit + "\n";
        s += "Y Resolution:  " + IJ.d2s(yResolution, places) + " pixels per " + unit + "\n";
      }
    } else {
      s += "Width:  " + imp.getWidth() + " pixels\n";
      s += "Height:  " + imp.getHeight() + " pixels\n";
      if (stackSize > 1) s += "Depth:  " + slices + " pixels\n";
    }
    if (stackSize > 1)
      s +=
          "Voxel size: "
              + d2s(cal.pixelWidth)
              + "x"
              + d2s(cal.pixelHeight)
              + "x"
              + d2s(cal.pixelDepth)
              + " "
              + cal.getUnit()
              + "\n";
    else
      s +=
          "Pixel size: "
              + d2s(cal.pixelWidth)
              + "x"
              + d2s(cal.pixelHeight)
              + " "
              + cal.getUnit()
              + "\n";

    s += "ID: " + imp.getID() + "\n";
    String zOrigin = stackSize > 1 || cal.zOrigin != 0.0 ? "," + d2s(cal.zOrigin) : "";
    s += "Coordinate origin:  " + d2s(cal.xOrigin) + "," + d2s(cal.yOrigin) + zOrigin + "\n";
    int type = imp.getType();
    switch (type) {
      case ImagePlus.GRAY8:
        s += "Bits per pixel: 8 ";
        String lut = "LUT";
        if (imp.getProcessor().isColorLut()) lut = "color " + lut;
        else lut = "grayscale " + lut;
        if (imp.isInvertedLut()) lut = "inverting " + lut;
        s += "(" + lut + ")\n";
        if (imp.getNChannels() > 1) s += displayRanges(imp);
        else s += "Display range: " + (int) ip.getMin() + "-" + (int) ip.getMax() + "\n";
        break;
      case ImagePlus.GRAY16:
      case ImagePlus.GRAY32:
        if (type == ImagePlus.GRAY16) {
          String sign = cal.isSigned16Bit() ? "signed" : "unsigned";
          s += "Bits per pixel: 16 (" + sign + ")\n";
        } else s += "Bits per pixel: 32 (float)\n";
        if (imp.getNChannels() > 1) s += displayRanges(imp);
        else {
          s += "Display range: ";
          double min = ip.getMin();
          double max = ip.getMax();
          if (cal.calibrated()) {
            min = cal.getCValue((int) min);
            max = cal.getCValue((int) max);
          }
          s += IJ.d2s(min, digits) + " - " + IJ.d2s(max, digits) + "\n";
        }
        break;
      case ImagePlus.COLOR_256:
        s += "Bits per pixel: 8 (color LUT)\n";
        break;
      case ImagePlus.COLOR_RGB:
        s += "Bits per pixel: 32 (RGB)\n";
        break;
    }
    double interval = cal.frameInterval;
    double fps = cal.fps;
    if (stackSize > 1) {
      ImageStack stack = imp.getStack();
      int slice = imp.getCurrentSlice();
      String number = slice + "/" + stackSize;
      String label = stack.getShortSliceLabel(slice);
      if (label != null && label.length() > 0) label = " (" + label + ")";
      else label = "";
      if (interval > 0.0 || fps != 0.0) {
        s += "Frame: " + number + label + "\n";
        if (fps != 0.0) {
          String sRate =
              Math.abs(fps - Math.round(fps)) < 0.00001 ? IJ.d2s(fps, 0) : IJ.d2s(fps, 5);
          s += "Frame rate: " + sRate + " fps\n";
        }
        if (interval != 0.0)
          s +=
              "Frame interval: "
                  + ((int) interval == interval ? IJ.d2s(interval, 0) : IJ.d2s(interval, 5))
                  + " "
                  + cal.getTimeUnit()
                  + "\n";
      } else s += "Image: " + number + label + "\n";
      if (imp.isHyperStack()) {
        if (channels > 1) s += "  Channel: " + imp.getChannel() + "/" + channels + "\n";
        if (slices > 1) s += "  Slice: " + imp.getSlice() + "/" + slices + "\n";
        if (frames > 1) s += "  Frame: " + imp.getFrame() + "/" + frames + "\n";
      }
      if (imp.isComposite()) {
        if (!imp.isHyperStack() && channels > 1) s += "  Channels: " + channels + "\n";
        String mode = ((CompositeImage) imp).getModeAsString();
        s += "  Composite mode: \"" + mode + "\"\n";
      }
    }

    if (ip.getMinThreshold() == ImageProcessor.NO_THRESHOLD) s += "No Threshold\n";
    else {
      double lower = ip.getMinThreshold();
      double upper = ip.getMaxThreshold();
      int dp = digits;
      if (cal.calibrated()) {
        lower = cal.getCValue((int) lower);
        upper = cal.getCValue((int) upper);
        dp = cal.isSigned16Bit() ? 0 : 4;
      }
      s += "Threshold: " + IJ.d2s(lower, dp) + "-" + IJ.d2s(upper, dp) + "\n";
    }
    ImageCanvas ic = imp.getCanvas();
    double mag = ic != null ? ic.getMagnification() : 1.0;
    if (mag != 1.0) s += "Magnification: " + IJ.d2s(mag, 2) + "\n";

    if (cal.calibrated()) {
      s += " \n";
      int curveFit = cal.getFunction();
      s += "Calibration Function: ";
      if (curveFit == Calibration.UNCALIBRATED_OD) s += "Uncalibrated OD\n";
      else if (curveFit == Calibration.CUSTOM) s += "Custom lookup table\n";
      else s += CurveFitter.fList[curveFit] + "\n";
      double[] c = cal.getCoefficients();
      if (c != null) {
        s += "  a: " + IJ.d2s(c[0], 6) + "\n";
        s += "  b: " + IJ.d2s(c[1], 6) + "\n";
        if (c.length >= 3) s += "  c: " + IJ.d2s(c[2], 6) + "\n";
        if (c.length >= 4) s += "  c: " + IJ.d2s(c[3], 6) + "\n";
        if (c.length >= 5) s += "  c: " + IJ.d2s(c[4], 6) + "\n";
      }
      s += "  Unit: \"" + cal.getValueUnit() + "\"\n";
    } else s += "Uncalibrated\n";

    FileInfo fi = imp.getOriginalFileInfo();
    if (fi != null) {
      if (fi.url != null && !fi.url.equals("")) s += "URL: " + fi.url + "\n";
      else if (fi.directory != null && fi.fileName != null)
        s += "Path: " + fi.directory + fi.fileName + "\n";
    }

    ImageWindow win = imp.getWindow();
    if (win != null) {
      Point loc = win.getLocation();
      Dimension screen = IJ.getScreenSize();
      s +=
          "Screen location: "
              + loc.x
              + ","
              + loc.y
              + " ("
              + screen.width
              + "x"
              + screen.height
              + ")\n";
    }

    Overlay overlay = imp.getOverlay();
    if (overlay != null) {
      String hidden = imp.getHideOverlay() ? " (hidden)" : " ";
      int n = overlay.size();
      String elements = n == 1 ? " element" : " elements";
      s += "Overlay: " + n + elements + (imp.getHideOverlay() ? " (hidden)" : "") + "\n";
    } else s += "No Overlay\n";

    Roi roi = imp.getRoi();
    if (roi == null) {
      if (cal.calibrated()) s += " \n";
      s += "No Selection\n";
    } else if (roi instanceof EllipseRoi) {
      s += "\nElliptical Selection\n";
      double[] p = ((EllipseRoi) roi).getParams();
      double dx = p[2] - p[0];
      double dy = p[3] - p[1];
      double major = Math.sqrt(dx * dx + dy * dy);
      s += "  Major: " + IJ.d2s(major, 2) + "\n";
      s += "  Minor: " + IJ.d2s(major * p[4], 2) + "\n";
      s += "  X1: " + IJ.d2s(p[0], 2) + "\n";
      s += "  Y1: " + IJ.d2s(p[1], 2) + "\n";
      s += "  X2: " + IJ.d2s(p[2], 2) + "\n";
      s += "  Y2: " + IJ.d2s(p[3], 2) + "\n";
      s += "  Aspect ratio: " + IJ.d2s(p[4], 2) + "\n";
    } else {
      s += " \n";
      s += roi.getTypeAsString() + " Selection";
      String points = null;
      if (roi instanceof PointRoi) {
        int npoints = ((PolygonRoi) roi).getNCoordinates();
        String suffix = npoints > 1 ? "s)" : ")";
        points = " (" + npoints + " point" + suffix;
      }
      String name = roi.getName();
      if (name != null) {
        s += " (\"" + name + "\")";
        if (points != null) s += "\n " + points;
      } else if (points != null) s += points;
      s += "\n";
      Rectangle r = roi.getBounds();
      if (roi instanceof Line) {
        Line line = (Line) roi;
        s += "  X1: " + IJ.d2s(line.x1d * cal.pixelWidth) + "\n";
        s += "  Y1: " + IJ.d2s(yy(line.y1d, imp) * cal.pixelHeight) + "\n";
        s += "  X2: " + IJ.d2s(line.x2d * cal.pixelWidth) + "\n";
        s += "  Y2: " + IJ.d2s(yy(line.y2d, imp) * cal.pixelHeight) + "\n";
      } else if (cal.scaled()) {
        s += "  X: " + IJ.d2s(cal.getX(r.x)) + " (" + r.x + ")\n";
        s += "  Y: " + IJ.d2s(cal.getY(r.y, imp.getHeight())) + " (" + r.y + ")\n";
        s += "  Width: " + IJ.d2s(r.width * cal.pixelWidth) + " (" + r.width + ")\n";
        s += "  Height: " + IJ.d2s(r.height * cal.pixelHeight) + " (" + r.height + ")\n";
      } else {
        s += "  X: " + r.x + "\n";
        s += "  Y: " + yy(r.y, imp) + "\n";
        s += "  Width: " + r.width + "\n";
        s += "  Height: " + r.height + "\n";
      }
    }

    return s;
  }
Beispiel #6
0
 String d2s(double n) {
   return n == (int) n ? Integer.toString((int) n) : IJ.d2s(n);
 }
  /** Displays a modal options dialog. */
  public boolean showDialog() {
    Calibration cal = imp != null ? imp.getCalibration() : (new Calibration());
    double unitSquared = cal.pixelWidth * cal.pixelHeight;
    if (pixelUnits) unitSquared = 1.0;
    if (Macro.getOptions() != null) {
      boolean oldMacro = updateMacroOptions();
      if (oldMacro) unitSquared = 1.0;
      staticMinSize = 0.0;
      staticMaxSize = DEFAULT_MAX_SIZE;
      staticMinCircularity = 0.0;
      staticMaxCircularity = 1.0;
      staticShowChoice = NOTHING;
    }
    GenericDialog gd = new GenericDialog("Analyze Particles");
    minSize = staticMinSize;
    maxSize = staticMaxSize;
    minCircularity = staticMinCircularity;
    maxCircularity = staticMaxCircularity;
    showChoice = staticShowChoice;
    if (maxSize == 999999) maxSize = DEFAULT_MAX_SIZE;
    options = staticOptions;
    String unit = cal.getUnit();
    boolean scaled = cal.scaled();
    if (unit.equals("inch")) {
      unit = "pixel";
      unitSquared = 1.0;
      scaled = false;
      pixelUnits = true;
    }
    String units = unit + "^2";
    int places = 0;
    double cmin = minSize * unitSquared;
    if ((int) cmin != cmin) places = 2;
    double cmax = maxSize * unitSquared;
    if ((int) cmax != cmax && cmax != DEFAULT_MAX_SIZE) places = 2;
    String minStr = ResultsTable.d2s(cmin, places);
    if (minStr.indexOf("-") != -1) {
      for (int i = places; i <= 6; i++) {
        minStr = ResultsTable.d2s(cmin, i);
        if (minStr.indexOf("-") == -1) break;
      }
    }
    String maxStr = ResultsTable.d2s(cmax, places);
    if (maxStr.indexOf("-") != -1) {
      for (int i = places; i <= 6; i++) {
        maxStr = ResultsTable.d2s(cmax, i);
        if (maxStr.indexOf("-") == -1) break;
      }
    }
    if (scaled) gd.setInsets(5, 0, 0);
    gd.addStringField("Size (" + units + "):", minStr + "-" + maxStr, 12);
    if (scaled) {
      gd.setInsets(0, 40, 5);
      gd.addCheckbox("Pixel units", pixelUnits);
    }
    gd.addStringField("Circularity:", IJ.d2s(minCircularity) + "-" + IJ.d2s(maxCircularity), 12);
    gd.addChoice("Show:", showStrings, showStrings[showChoice]);
    String[] labels = new String[8];
    boolean[] states = new boolean[8];
    labels[0] = "Display results";
    states[0] = (options & SHOW_RESULTS) != 0;
    labels[1] = "Exclude on edges";
    states[1] = (options & EXCLUDE_EDGE_PARTICLES) != 0;
    labels[2] = "Clear results";
    states[2] = (options & CLEAR_WORKSHEET) != 0;
    labels[3] = "Include holes";
    states[3] = (options & INCLUDE_HOLES) != 0;
    labels[4] = "Summarize";
    states[4] = (options & DISPLAY_SUMMARY) != 0;
    labels[5] = "Record starts";
    states[5] = (options & RECORD_STARTS) != 0;
    labels[6] = "Add to Manager";
    states[6] = (options & ADD_TO_MANAGER) != 0;
    labels[7] = "In_situ Show";
    states[7] = (options & IN_SITU_SHOW) != 0;
    gd.addCheckboxGroup(4, 2, labels, states);
    gd.addHelp(IJ.URL + "/docs/menus/analyze.html#ap");
    gd.showDialog();
    if (gd.wasCanceled()) return false;

    String size = gd.getNextString(); // min-max size
    if (scaled) pixelUnits = gd.getNextBoolean();
    if (pixelUnits) unitSquared = 1.0;
    else unitSquared = cal.pixelWidth * cal.pixelHeight;
    String[] minAndMax = Tools.split(size, " -");
    double mins = gd.parseDouble(minAndMax[0]);
    double maxs = minAndMax.length == 2 ? gd.parseDouble(minAndMax[1]) : Double.NaN;
    minSize = Double.isNaN(mins) ? DEFAULT_MIN_SIZE : mins / unitSquared;
    maxSize = Double.isNaN(maxs) ? DEFAULT_MAX_SIZE : maxs / unitSquared;
    if (minSize < DEFAULT_MIN_SIZE) minSize = DEFAULT_MIN_SIZE;
    if (maxSize < minSize) maxSize = DEFAULT_MAX_SIZE;
    staticMinSize = minSize;
    staticMaxSize = maxSize;

    minAndMax = Tools.split(gd.getNextString(), " -"); // min-max circularity
    double minc = gd.parseDouble(minAndMax[0]);
    double maxc = minAndMax.length == 2 ? gd.parseDouble(minAndMax[1]) : Double.NaN;
    minCircularity = Double.isNaN(minc) ? 0.0 : minc;
    maxCircularity = Double.isNaN(maxc) ? 1.0 : maxc;
    if (minCircularity < 0.0 || minCircularity > 1.0) minCircularity = 0.0;
    if (maxCircularity < minCircularity || maxCircularity > 1.0) maxCircularity = 1.0;
    if (minCircularity == 1.0 && maxCircularity == 1.0) minCircularity = 0.0;
    staticMinCircularity = minCircularity;
    staticMaxCircularity = maxCircularity;

    if (gd.invalidNumber()) {
      IJ.error("Bins invalid.");
      canceled = true;
      return false;
    }
    showChoice = gd.getNextChoiceIndex();
    staticShowChoice = showChoice;
    if (gd.getNextBoolean()) options |= SHOW_RESULTS;
    else options &= ~SHOW_RESULTS;
    if (gd.getNextBoolean()) options |= EXCLUDE_EDGE_PARTICLES;
    else options &= ~EXCLUDE_EDGE_PARTICLES;
    if (gd.getNextBoolean()) options |= CLEAR_WORKSHEET;
    else options &= ~CLEAR_WORKSHEET;
    if (gd.getNextBoolean()) options |= INCLUDE_HOLES;
    else options &= ~INCLUDE_HOLES;
    if (gd.getNextBoolean()) options |= DISPLAY_SUMMARY;
    else options &= ~DISPLAY_SUMMARY;
    if (gd.getNextBoolean()) options |= RECORD_STARTS;
    else options &= ~RECORD_STARTS;
    if (gd.getNextBoolean()) options |= ADD_TO_MANAGER;
    else options &= ~ADD_TO_MANAGER;
    if (gd.getNextBoolean()) options |= IN_SITU_SHOW;
    else options &= ~IN_SITU_SHOW;
    staticOptions = options;
    options |= SHOW_PROGRESS;
    if ((options & DISPLAY_SUMMARY) != 0)
      Analyzer.setMeasurements(Analyzer.getMeasurements() | AREA);
    return true;
  }
 private String d2s(double n) {
   return IJ.d2s(n, Tools.getDecimalPlaces(n));
 }