void updateSliceSummary() {
   int slices = imp.getStackSize();
   float[] areas = rt.getColumn(ResultsTable.AREA);
   if (areas == null) areas = new float[0];
   String label = imp.getTitle();
   if (slices > 1) {
     label = imp.getStack().getShortSliceLabel(slice);
     label = label != null && !label.equals("") ? label : "" + slice;
   }
   String aLine = null;
   double sum = 0.0;
   int start = areas.length - particleCount;
   if (start < 0) return;
   for (int i = start; i < areas.length; i++) sum += areas[i];
   int places = Analyzer.getPrecision();
   Calibration cal = imp.getCalibration();
   String total = "\t" + ResultsTable.d2s(sum, places);
   String average = "\t" + ResultsTable.d2s(sum / particleCount, places);
   String fraction = "\t" + ResultsTable.d2s(sum * 100.0 / totalArea, 1);
   aLine = label + "\t" + particleCount + total + average + fraction;
   aLine = addMeans(aLine, areas.length > 0 ? start : -1);
   if (slices == 1) {
     Frame frame = WindowManager.getFrame("Summary");
     if (frame != null && (frame instanceof TextWindow) && summaryHdr.equals(prevHdr))
       tw = (TextWindow) frame;
   }
   if (tw == null) {
     String title = slices == 1 ? "Summary" : "Summary of " + imp.getTitle();
     tw = new TextWindow(title, summaryHdr, aLine, 450, 300);
     prevHdr = summaryHdr;
   } else tw.append(aLine);
 }
Exemple #2
0
 void showDialog() {
   int width = imp.getWidth();
   int height = imp.getHeight();
   Calibration cal = imp.getCalibration();
   int places;
   if (cal.scaled()) {
     pixelWidth = cal.pixelWidth;
     pixelHeight = cal.pixelHeight;
     units = cal.getUnits();
     places = 2;
   } else {
     pixelWidth = 1.0;
     pixelHeight = 1.0;
     units = "pixels";
     places = 0;
   }
   if (areaPerPoint == 0.0)
     areaPerPoint =
         (width * cal.pixelWidth * height * cal.pixelHeight) / 81.0; // default to 9x9 grid
   ImageWindow win = imp.getWindow();
   GenericDialog gd = new GenericDialog("Grid...");
   gd.addChoice("Grid Type:", types, type);
   gd.addNumericField("Area per Point:", areaPerPoint, places, 6, units + "^2");
   gd.addChoice("Color:", colors, color);
   gd.addCheckbox("Random Offset", randomOffset);
   gd.addDialogListener(this);
   gd.showDialog();
   if (gd.wasCanceled()) showGrid(null);
 }
Exemple #3
0
 void scale(ImageProcessor ip) {
   if (newWindow) {
     Rectangle r = ip.getRoi();
     ImagePlus imp2 = imp.createImagePlus();
     imp2.setProcessor(title, ip.resize(newWidth, newHeight));
     Calibration cal = imp2.getCalibration();
     if (cal.scaled()) {
       cal.pixelWidth *= 1.0 / xscale;
       cal.pixelHeight *= 1.0 / yscale;
     }
     imp2.show();
     imp.trimProcessor();
     imp2.trimProcessor();
     imp2.changes = true;
   } else {
     if (processStack && imp.getStackSize() > 1) {
       Undo.reset();
       StackProcessor sp = new StackProcessor(imp.getStack(), ip);
       sp.scale(xscale, yscale, bgValue);
     } else {
       ip.snapshot();
       Undo.setup(Undo.FILTER, imp);
       ip.setSnapshotCopyMode(true);
       ip.scale(xscale, yscale);
       ip.setSnapshotCopyMode(false);
     }
     imp.killRoi();
     imp.updateAndDraw();
     imp.changes = true;
   }
 }
Exemple #4
0
 void createMask(ImagePlus imp) {
   Roi roi = imp.getRoi();
   boolean useInvertingLut = Prefs.useInvertingLut;
   Prefs.useInvertingLut = false;
   boolean selectAll =
       roi != null
           && roi.getType() == Roi.RECTANGLE
           && roi.getBounds().width == imp.getWidth()
           && roi.getBounds().height == imp.getHeight()
           && imp.isThreshold();
   if (roi == null || !(roi.isArea() || roi.getType() == Roi.POINT) || selectAll) {
     createMaskFromThreshold(imp);
     Prefs.useInvertingLut = useInvertingLut;
     return;
   }
   ImagePlus maskImp = null;
   Frame frame = WindowManager.getFrame("Mask");
   if (frame != null && (frame instanceof ImageWindow))
     maskImp = ((ImageWindow) frame).getImagePlus();
   if (maskImp == null) {
     ImageProcessor ip = new ByteProcessor(imp.getWidth(), imp.getHeight());
     if (!Prefs.blackBackground) ip.invertLut();
     maskImp = new ImagePlus("Mask", ip);
     maskImp.show();
   }
   ImageProcessor ip = maskImp.getProcessor();
   ip.setRoi(roi);
   ip.setValue(255);
   ip.fill(ip.getMask());
   Calibration cal = imp.getCalibration();
   if (cal.scaled()) {
     Calibration cal2 = maskImp.getCalibration();
     cal2.pixelWidth = cal.pixelWidth;
     cal2.pixelHeight = cal.pixelHeight;
     cal2.setUnit(cal.getUnit());
   }
   maskImp.updateAndRepaintWindow();
   Prefs.useInvertingLut = useInvertingLut;
 }
Exemple #5
0
 void createNewStack(ImagePlus imp, ImageProcessor ip) {
   int nSlices = imp.getStackSize();
   int w = imp.getWidth(), h = imp.getHeight();
   ImagePlus imp2 = imp.createImagePlus();
   Rectangle r = ip.getRoi();
   boolean crop = r.width != imp.getWidth() || r.height != imp.getHeight();
   ImageStack stack1 = imp.getStack();
   ImageStack stack2 = new ImageStack(newWidth, newHeight);
   ImageProcessor ip1, ip2;
   int method = interpolationMethod;
   if (w == 1 || h == 1) method = ImageProcessor.NONE;
   for (int i = 1; i <= nSlices; i++) {
     IJ.showStatus("Scale: " + i + "/" + nSlices);
     ip1 = stack1.getProcessor(i);
     String label = stack1.getSliceLabel(i);
     if (crop) {
       ip1.setRoi(r);
       ip1 = ip1.crop();
     }
     ip1.setInterpolationMethod(method);
     ip2 = ip1.resize(newWidth, newHeight, averageWhenDownsizing);
     if (ip2 != null) stack2.addSlice(label, ip2);
     IJ.showProgress(i, nSlices);
   }
   imp2.setStack(title, stack2);
   Calibration cal = imp2.getCalibration();
   if (cal.scaled()) {
     cal.pixelWidth *= 1.0 / xscale;
     cal.pixelHeight *= 1.0 / yscale;
   }
   IJ.showProgress(1.0);
   int[] dim = imp.getDimensions();
   imp2.setDimensions(dim[2], dim[3], dim[4]);
   if (imp.isComposite()) {
     imp2 = new CompositeImage(imp2, ((CompositeImage) imp).getMode());
     ((CompositeImage) imp2).copyLuts(imp);
   }
   if (imp.isHyperStack()) imp2.setOpenAsHyperStack(true);
   if (newDepth > 0 && newDepth != oldDepth)
     imp2 = (new Resizer()).zScale(imp2, newDepth, interpolationMethod);
   if (imp2 != null) {
     imp2.show();
     imp2.changes = true;
   }
 }
Exemple #6
0
 void createNewStack(ImagePlus imp, ImageProcessor ip) {
   Rectangle r = ip.getRoi();
   boolean crop = r.width != imp.getWidth() || r.height != imp.getHeight();
   int nSlices = imp.getStackSize();
   ImageStack stack1 = imp.getStack();
   ImageStack stack2 = new ImageStack(newWidth, newHeight);
   ImageProcessor ip1, ip2;
   boolean interp = interpolate;
   if (imp.getWidth() == 1 || imp.getHeight() == 1) interp = false;
   for (int i = 1; i <= nSlices; i++) {
     IJ.showStatus("Scale: " + i + "/" + nSlices);
     ip1 = stack1.getProcessor(i);
     String label = stack1.getSliceLabel(i);
     if (crop) {
       ip1.setRoi(r);
       ip1 = ip1.crop();
     }
     ip1.setInterpolate(interp);
     ip2 = ip1.resize(newWidth, newHeight);
     if (ip2 != null) stack2.addSlice(label, ip2);
     IJ.showProgress(i, nSlices);
   }
   ImagePlus imp2 = imp.createImagePlus();
   imp2.setStack(title, stack2);
   Calibration cal = imp2.getCalibration();
   if (cal.scaled()) {
     cal.pixelWidth *= 1.0 / xscale;
     cal.pixelHeight *= 1.0 / yscale;
   }
   int[] dim = imp.getDimensions();
   imp2.setDimensions(dim[2], dim[3], dim[4]);
   IJ.showProgress(1.0);
   if (imp.isComposite()) {
     imp2 = new CompositeImage(imp2, 0);
     ((CompositeImage) imp2).copyLuts(imp);
   }
   if (imp.isHyperStack()) imp2.setOpenAsHyperStack(true);
   imp2.show();
   imp2.changes = true;
 }
Exemple #7
0
  void setCalibration(ImagePlus imp) {
    if (fi.fileType == FileInfo.GRAY16_SIGNED) {
      if (IJ.debugMode) IJ.log("16-bit signed");
      double[] coeff = new double[2];
      coeff[0] = -32768.0;
      coeff[1] = 1.0;
      imp.getLocalCalibration().setFunction(Calibration.STRAIGHT_LINE, coeff, "gray value");
    }

    Properties props = decodeDescriptionString(fi);
    Calibration cal = imp.getCalibration();
    boolean calibrated = false;
    if (fi.pixelWidth > 0.0 && fi.unit != null) {
      cal.pixelWidth = fi.pixelWidth;
      cal.pixelHeight = fi.pixelHeight;
      cal.pixelDepth = fi.pixelDepth;
      cal.setUnit(fi.unit);
      calibrated = true;
    }

    if (fi.valueUnit != null) {
      int f = fi.calibrationFunction;
      if ((f >= Calibration.STRAIGHT_LINE && f <= Calibration.RODBARD2 && fi.coefficients != null)
          || f == Calibration.UNCALIBRATED_OD) {
        boolean zeroClip = props != null && props.getProperty("zeroclip", "false").equals("true");
        cal.setFunction(f, fi.coefficients, fi.valueUnit, zeroClip);
        calibrated = true;
      }
    }

    if (calibrated) checkForCalibrationConflict(imp, cal);

    if (fi.frameInterval != 0.0) cal.frameInterval = fi.frameInterval;

    if (props == null) return;

    cal.xOrigin = getDouble(props, "xorigin");
    cal.yOrigin = getDouble(props, "yorigin");
    cal.zOrigin = getDouble(props, "zorigin");
    cal.info = props.getProperty("info");

    cal.fps = getDouble(props, "fps");
    cal.loop = getBoolean(props, "loop");
    cal.frameInterval = getDouble(props, "finterval");
    cal.setTimeUnit(props.getProperty("tunit", "sec"));

    double displayMin = getDouble(props, "min");
    double displayMax = getDouble(props, "max");
    if (!(displayMin == 0.0 && displayMax == 0.0)) {
      int type = imp.getType();
      ImageProcessor ip = imp.getProcessor();
      if (type == ImagePlus.GRAY8 || type == ImagePlus.COLOR_256)
        ip.setMinAndMax(displayMin, displayMax);
      else if (type == ImagePlus.GRAY16 || type == ImagePlus.GRAY32) {
        if (ip.getMin() != displayMin || ip.getMax() != displayMax)
          ip.setMinAndMax(displayMin, displayMax);
      }
    }

    int stackSize = imp.getStackSize();
    if (stackSize > 1) {
      int channels = (int) getDouble(props, "channels");
      int slices = (int) getDouble(props, "slices");
      int frames = (int) getDouble(props, "frames");
      if (channels == 0) channels = 1;
      if (slices == 0) slices = 1;
      if (frames == 0) frames = 1;
      // IJ.log("setCalibration: "+channels+"  "+slices+"  "+frames);
      if (channels * slices * frames == stackSize) {
        imp.setDimensions(channels, slices, frames);
        if (getBoolean(props, "hyperstack")) imp.setOpenAsHyperStack(true);
      }
    }
  }
Exemple #8
0
 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;
 }
Exemple #9
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;
  }
  /**
   * 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;
  }
  /** 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;
  }
  public void run(String arg) {
    ImagePlus imp = WindowManager.getCurrentImage();
    Calibration cal = imp.getCalibration();
    GenericDialog gd = new GenericDialog("Options");
    int subsize = 32;
    gd.addNumericField("Subregion Size (pixels)?", subsize, 0);
    int stepsize = 16;
    gd.addNumericField("Step Size?", stepsize, 0);
    int shift = 3;
    gd.addNumericField("STICS temporal Shift?", shift, 0);
    float xoffset = 0.0f;
    gd.addNumericField("X_Offset", xoffset, 5, 15, null);
    float yoffset = 0.0f;
    gd.addNumericField("Y_Offset", yoffset, 5, 15, null);
    float multiplier = 8.0f;
    gd.addNumericField("Velocity Multiplier", multiplier, 5, 15, null);
    float ftime = 1.0f;
    gd.addNumericField("Frame_Time(min)", ftime, 5, 15, null);
    float scaling = (float) cal.pixelWidth;
    gd.addNumericField("Pixel_Size(um)", scaling, 5, 15, null);
    boolean norm = true;
    gd.addCheckbox("Normalize_Vector_lengths?", norm);
    boolean centered = true;
    gd.addCheckbox("Center_Vectors?", centered);
    float magthresh = 0.0f;
    gd.addNumericField("Magnitude_Threshhold?", magthresh, 5, 15, null);
    int rlength = 10;
    gd.addNumericField("Running_avg_length", rlength, 0);
    int inc = 5;
    gd.addNumericField("Start_frame_increment", inc, 0);
    gd.showDialog();
    if (gd.wasCanceled()) {
      return;
    }
    subsize = (int) gd.getNextNumber();
    stepsize = (int) gd.getNextNumber();
    shift = (int) gd.getNextNumber();
    xoffset = (float) gd.getNextNumber();
    yoffset = (float) gd.getNextNumber();
    multiplier = (float) gd.getNextNumber();
    ftime = (float) gd.getNextNumber();
    scaling = (float) gd.getNextNumber();
    norm = gd.getNextBoolean();
    centered = gd.getNextBoolean();
    magthresh = (float) gd.getNextNumber();
    rlength = (int) gd.getNextNumber();
    inc = (int) gd.getNextNumber();

    int width = imp.getWidth();
    int xregions = 1 + (int) (((float) width - (float) subsize) / (float) stepsize);
    int newwidth = xregions * subsize;
    int height = imp.getHeight();
    int yregions = 1 + (int) (((float) height - (float) subsize) / (float) stepsize);
    int newheight = yregions * subsize;
    ImageStack stack = imp.getStack();
    int slices = imp.getNSlices();
    int channels = imp.getNChannels();
    int frames = imp.getNFrames();
    if (frames == 1) {
      frames = slices;
      slices = 1;
    }

    Roi roi = imp.getRoi();
    if (roi == null) {
      roi = new Roi(0, 0, width, height);
    }

    STICS_map map = new STICS_map(subsize, stepsize);
    Object[] tseries = jutils.get3DTSeries(stack, 0, 0, frames, slices, channels);
    map.update_STICS_map(tseries, width, height, 0, rlength, roi.getPolygon(), shift);
    FloatProcessor fp =
        map.get_map(scaling, ftime, stepsize, centered, norm, multiplier, stepsize, magthresh);
    ImageStack vector_stack = new ImageStack(fp.getWidth(), fp.getHeight());
    vector_stack.addSlice("", fp);
    float[][] vel = map.get_scaled_velocities(scaling, ftime, stepsize);
    ImageStack velstack = new ImageStack(map.xregions, map.yregions);
    velstack.addSlice("", vel[0]);
    velstack.addSlice("", vel[1]);
    int velframes = 2;
    IJ.showStatus("frame " + 0 + " calculated");
    for (int i = inc; i < (frames - rlength); i += inc) {
      map.update_STICS_map(tseries, width, height, i, rlength, roi.getPolygon(), shift);
      FloatProcessor fp2 =
          map.get_map(scaling, ftime, stepsize, centered, norm, multiplier, stepsize, magthresh);
      vector_stack.addSlice("", fp2);
      vel = map.get_scaled_velocities(scaling, ftime, stepsize);
      velstack.addSlice("", vel[0]);
      velstack.addSlice("", vel[1]);
      velframes += 2;
      IJ.showStatus("frame " + i + " calculated");
    }
    (new ImagePlus("STICS Vectors", vector_stack)).show();
    ImagePlus imp3 = new ImagePlus("Velocities", velstack);
    imp3.setOpenAsHyperStack(true);
    imp3.setDimensions(2, 1, velframes / 2);
    new CompositeImage(imp3, CompositeImage.COLOR).show();
  }