void Contrast(ImagePlus imp, int radius, double par1, double par2, boolean doIwhite) {
    // G. Landini, 2013
    // Based on a simple contrast toggle. This procedure does not have user-provided paramters other
    // than the kernel radius
    // Sets the pixel value to either white or black depending on whether its current value is
    // closest to the local Max or Min respectively
    // The procedure is similar to Toggle Contrast Enhancement (see Soille, Morphological Image
    // Analysis (2004), p. 259

    ImagePlus Maximp, Minimp;
    ImageProcessor ip = imp.getProcessor(), ipMax, ipMin;
    int c_value = 0;
    int mid_gray;
    byte object;
    byte backg;

    if (doIwhite) {
      object = (byte) 0xff;
      backg = (byte) 0;
    } else {
      object = (byte) 0;
      backg = (byte) 0xff;
    }

    Maximp = duplicateImage(ip);
    ipMax = Maximp.getProcessor();
    RankFilters rf = new RankFilters();
    rf.rank(ipMax, radius, rf.MAX); // Maximum
    // Maximp.show();
    Minimp = duplicateImage(ip);
    ipMin = Minimp.getProcessor();
    rf.rank(ipMin, radius, rf.MIN); // Minimum
    // Minimp.show();
    byte[] pixels = (byte[]) ip.getPixels();
    byte[] max = (byte[]) ipMax.getPixels();
    byte[] min = (byte[]) ipMin.getPixels();
    for (int i = 0; i < pixels.length; i++) {
      pixels[i] =
          ((Math.abs((int) (max[i] & 0xff - pixels[i] & 0xff))
                  <= Math.abs((int) (pixels[i] & 0xff - min[i] & 0xff))))
              ? object
              : backg;
    }
    // imp.updateAndDraw();
    return;
  }
  /*------------------------------------------------------------------*/
  double getInitialCausalCoefficientMirrorOnBounds(double[] c, double z, double tolerance) {
    double z1 = z, zn = Math.pow(z, c.length - 1);
    double sum = c[0] + zn * c[c.length - 1];
    int horizon = c.length;

    if (0.0 < tolerance) {
      horizon = 2 + (int) (Math.log(tolerance) / Math.log(Math.abs(z)));
      horizon = (horizon < c.length) ? (horizon) : (c.length);
    }
    zn = zn * zn;
    for (int n = 1; (n < (horizon - 1)); n++) {
      zn = zn / z;
      sum = sum + (z1 + zn) * c[n];
      z1 = z1 * z;
    }
    return (sum / (1.0 - Math.pow(z, 2 * c.length - 2)));
  } /* end getInitialCausalCoefficientMirrorOnBounds */
Beispiel #3
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 #4
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;
  }
  private void geterrors() {
    GenericDialog gd = new GenericDialog("Options");
    float conf = 0.67f;
    gd.addNumericField("Confidence Limit", (int) (conf * 100.0f), 5, 10, null);
    gd.addChoice("Error Parameter", paramsnames, paramsnames[0]);
    double spacing = 0.01;
    gd.addNumericField("Chi^2 plot spacing (% of value)?", spacing * 100.0, 2, 10, null);
    boolean globalerror = false;
    gd.addCheckbox("Global Fit Error?", globalerror);
    int dataset = 0;
    gd.addNumericField("Data Set (for Global Error)", dataset, 0);
    gd.showDialog();
    if (gd.wasCanceled()) {
      return;
    }
    conf = 0.01f * (float) gd.getNextNumber();
    int paramindex = (int) gd.getNextChoiceIndex();
    spacing = 0.01 * gd.getNextNumber();
    globalerror = gd.getNextBoolean();
    dataset = (int) gd.getNextNumber();

    if (globalerror) {
      support_plane_errors erclass = new support_plane_errors(this, 0.0001, 50, true, 0.1);
      int[] erindeces = {paramindex, dataset};
      // need to set up all the matrices
      int nsel = 0;
      int nparams = 11;
      for (int i = 0; i < ncurves; i++) {
        if (include[i]) {
          nsel++;
        }
      }
      double[][] params = new double[nsel][nparams];
      String[][] tempformulas = new String[nsel][nparams];
      double[][][] constraints = new double[2][nsel][nparams];
      int[][] vflmatrix = new int[nsel][nparams];

      float[][] tempdata = new float[nsel][xpts * ypts];
      float[][] tempweights = new float[nsel][xpts * ypts];

      int nfit = 0;
      int counter = 0;
      for (int i = 0; i < ncurves; i++) {
        if (include[i]) {
          for (int j = 0; j < nparams; j++) {
            params[counter][j] = globalparams[i][j];
            tempformulas[counter][j] = globalformulas[i][j];
            constraints[0][counter][j] = globalconstraints[0][i][j];
            constraints[1][counter][j] = globalconstraints[1][i][j];
            vflmatrix[counter][j] = globalvflmatrix[i][j];
            if (vflmatrix[counter][j] == 0 || (j == 0 && vflmatrix[counter][j] == 2)) {
              nfit++;
            }
          }
          for (int j = 0; j < xpts; j++) {
            for (int k = 0; k < ypts; k++) {
              tempdata[counter][j + k * xpts] = (float) ((double) pch[i][j][k] / (double) nmeas[i]);
              tempweights[counter][j + k * xpts] = weights[i][j][k];
            }
          }
          counter++;
        }
      }
      int dofnum = xpts * ypts * nsel - (nfit - 1) - 1;
      int dofden = xpts * ypts * nsel - nfit - 1;
      // double flim=FLimit(dofnum,dofden,(double)conf);
      double flim = (new jdist()).FLimit(dofnum, dofden, (double) conf);
      IJ.log("FLimit = " + (float) flim);
      if (flim == Double.NaN && flim < 1.0) {
        IJ.showMessage("Invalid Limiting F Value");
        return;
      }
      double truespacing = Math.abs(params[erindeces[1]][erindeces[0]] * spacing);
      double[][] c2plot =
          erclass.geterrorsglobal(
              params,
              vflmatrix,
              tempformulas,
              paramsnames,
              constraints,
              tempdata,
              tempweights,
              flim,
              truespacing,
              erindeces);
      IJ.log("upper limit = " + c2plot[1][0] + " lower limit = " + c2plot[0][0]);
      int templength = c2plot[0].length;
      float[][] c2plotf = new float[2][templength - 1];
      for (int i = 0; i < (templength - 1); i++) {
        c2plotf[0][i] = (float) c2plot[0][i + 1];
        c2plotf[1][i] = (float) c2plot[1][i + 1];
      }
      new PlotWindow4(
              "c2 plot",
              paramsnames[paramindex] + "[" + dataset + "]",
              "Chi^2",
              c2plotf[0],
              c2plotf[1])
          .draw();
    } else {
      support_plane_errors erclass = new support_plane_errors(this, 0.0001, 50, false, 0.1);
      int errindex = paramindex;

      float[] tempdata = new float[xpts * ypts];
      float[] tempweights = new float[xpts * ypts];
      for (int i = 0; i < xpts; i++) {
        for (int j = 0; j < ypts; j++) {
          tempdata[i + j * xpts] = (float) ((double) avg[i][j] / (double) nmeas[ncurves]);
          tempweights[i + j * xpts] = avgweights[i][j];
        }
      }

      int nfit = 0;
      for (int i = 0; i < 7; i++) {
        if (avgfixes[i] == 0) {
          nfit++;
        }
      }
      int dofnum = xpts * ypts - (nfit - 1) - 1;
      int dofden = xpts * ypts - nfit - 1;
      double flim = (new jdist()).FLimit(dofnum, dofden, (double) conf);
      IJ.log("FLimit = " + (float) flim);
      if (flim == Double.NaN && flim < 1.0) {
        IJ.showMessage("Invalid Limiting F Value");
        return;
      }
      double truespacing = Math.abs(avgparams[errindex] * spacing);
      double[][] c2plot =
          erclass.geterrors(
              avgparams,
              avgfixes,
              avgconstraints,
              tempdata,
              tempweights,
              flim,
              truespacing,
              errindex);
      IJ.log("upper limit = " + c2plot[1][0] + " lower limit = " + c2plot[0][0]);
      int templength = c2plot[0].length;
      float[][] c2plotf = new float[2][templength - 1];
      for (int i = 0; i < (templength - 1); i++) {
        c2plotf[0][i] = (float) c2plot[0][i + 1];
        c2plotf[1][i] = (float) c2plot[1][i + 1];
      }
      new PlotWindow4("c2 plot", paramsnames[errindex], "Chi^2", c2plotf[0], c2plotf[1]).draw();
    }
  }
  private boolean track(
      ImagePlus siPlus, ArrayList<Point2D.Double> xyPoints, ArrayList<Double> timePoints) {

    GaussianFit gs = new GaussianFit(shape_, fitMode_);

    double cPCF = photonConversionFactor_ / gain_;

    // for now, take the active ImageJ image
    // (this should be an image of a difraction limited spot)

    Roi originalRoi = siPlus.getRoi();
    if (null == originalRoi) {
      if (!silent_) IJ.error("Please draw a Roi around the spot you want to track");
      return false;
    }

    Polygon pol = FindLocalMaxima.FindMax(siPlus, halfSize_, noiseTolerance_, preFilterType_);
    if (pol.npoints == 0) {
      if (!silent_) ReportingUtils.showError("No local maxima found in ROI");
      else ReportingUtils.logError("No local maxima found in ROI");
      return false;
    }

    int xc = pol.xpoints[0];
    int yc = pol.ypoints[0];
    // not sure if needed, but look for the maximum local maximum
    int max = siPlus.getProcessor().getPixel(pol.xpoints[0], pol.ypoints[0]);
    if (pol.npoints > 1) {
      for (int i = 1; i < pol.npoints; i++) {
        if (siPlus.getProcessor().getPixel(pol.xpoints[i], pol.ypoints[i]) > max) {
          max = siPlus.getProcessor().getPixel(pol.xpoints[i], pol.ypoints[i]);
          xc = pol.xpoints[i];
          yc = pol.ypoints[i];
        }
      }
    }

    long startTime = System.nanoTime();

    // This is confusing.   We like to accomodate stacks with multiple slices
    // and stacks with multiple frames (which is actually the correct way

    int ch = siPlus.getChannel();
    Boolean useSlices = siPlus.getNSlices() > siPlus.getNFrames();

    int n = siPlus.getSlice();
    int nMax = siPlus.getNSlices();
    if (!useSlices) {
      n = siPlus.getFrame();
      nMax = siPlus.getNFrames();
    }
    boolean stop = false;
    int missedFrames = 0;
    int size = 2 * halfSize_;

    for (int i = n; i <= nMax && !stop; i++) {
      SpotData spot;

      // Give user feedback
      ij.IJ.showStatus("Tracking...");
      ij.IJ.showProgress(i, nMax);

      // Search in next slice in same Roi for local maximum
      Roi searchRoi = new Roi(xc - size, yc - size, 2 * size + 1, 2 * size + 1);
      if (useSlices) {
        siPlus.setSliceWithoutUpdate(siPlus.getStackIndex(ch, i, 1));
      } else {
        siPlus.setSliceWithoutUpdate(siPlus.getStackIndex(ch, 1, i));
      }
      siPlus.setRoi(searchRoi, false);

      // Find maximum in Roi, might not be needed....
      pol = FindLocalMaxima.FindMax(siPlus, 2 * halfSize_, noiseTolerance_, preFilterType_);

      // do not stray more than 2 pixels in x or y.
      // This velocity maximum parameter should be tunable by the user
      if (pol.npoints >= 1) {
        if (Math.abs(xc - pol.xpoints[0]) < 2 && Math.abs(yc - pol.ypoints[0]) < 2) {
          xc = pol.xpoints[0];
          yc = pol.ypoints[0];
        }
      }

      // Reset ROI to the original
      if (i == n) {
        firstX_ = xc;
        firstY_ = yc;
      }

      // Set Roi for fitting centered around maximum
      Roi spotRoi = new Roi(xc - halfSize_, yc - halfSize_, 2 * halfSize_, 2 * halfSize_);
      siPlus.setRoi(spotRoi, false);
      ImageProcessor ip;
      try {
        if (siPlus.getRoi() != spotRoi) {
          ReportingUtils.logError(
              "There seems to be a thread synchronization issue going on that causes this weirdness");
        }
        ip = siPlus.getProcessor().crop();
      } catch (ArrayIndexOutOfBoundsException aex) {
        ReportingUtils.logError(aex, "ImageJ failed to crop the image, not sure why");
        siPlus.setRoi(spotRoi, true);
        ip = siPlus.getProcessor().crop();
      }

      spot = new SpotData(ip, ch, 1, i, 1, i, xc, yc);
      double[] paramsOut = gs.dogaussianfit(ip, maxIterations_);
      double sx;
      double sy;
      double a = 1.0;
      double theta = 0.0;
      if (paramsOut.length >= 4) {
        // anormalize the intensity from the Gaussian fit
        double N =
            cPCF
                * paramsOut[GaussianFit.INT]
                * (2 * Math.PI * paramsOut[GaussianFit.S] * paramsOut[GaussianFit.S]);
        double xpc = paramsOut[GaussianFit.XC];
        double ypc = paramsOut[GaussianFit.YC];
        double x = (xpc - halfSize_ + xc) * pixelSize_;
        double y = (ypc - halfSize_ + yc) * pixelSize_;

        double s = paramsOut[GaussianFit.S] * pixelSize_;
        // express background in photons after base level correction
        double bgr = cPCF * (paramsOut[GaussianFit.BGR] - baseLevel_);
        // calculate error using formular from Thompson et al (2002)
        // (dx)2 = (s*s + (a*a/12)) / N + (8*pi*s*s*s*s * b*b) / (a*a*N*N)
        double sigma =
            (s * s + (pixelSize_ * pixelSize_) / 12) / N
                + (8 * Math.PI * s * s * s * s * bgr * bgr) / (pixelSize_ * pixelSize_ * N * N);
        sigma = Math.sqrt(sigma);

        double width = 2 * s;
        if (paramsOut.length >= 6) {
          sx = paramsOut[GaussianFit.S1] * pixelSize_;
          sy = paramsOut[GaussianFit.S2] * pixelSize_;
          a = sx / sy;
        }

        if (paramsOut.length >= 7) {
          theta = paramsOut[GaussianFit.S3];
        }
        if ((!useWidthFilter_ || (width > widthMin_ && width < widthMax_))
            && (!useNrPhotonsFilter_ || (N > nrPhotonsMin_ && N < nrPhotonsMax_))) {
          // If we have a good fit, update position of the box
          if (xpc > 0 && xpc < (2 * halfSize_) && ypc > 0 && ypc < (2 * halfSize_)) {
            xc += (int) xpc - halfSize_;
            yc += (int) ypc - halfSize_;
          }
          spot.setData(N, bgr, x, y, 0.0, 2 * s, a, theta, sigma);
          xyPoints.add(new Point2D.Double(x, y));
          timePoints.add(i * timeIntervalMs_);
          resultList_.add(spot);
          missedFrames = 0;
        } else {
          missedFrames += 1;
        }
      } else {
        missedFrames += 1;
      }
      if (endTrackAfterBadFrames_) {
        if (missedFrames >= this.endTrackAfterNBadFrames_) {
          stop = true;
        }
      }
    }

    long endTime = System.nanoTime();
    double took = (endTime - startTime) / 1E6;

    print("Calculation took: " + took + " milli seconds");

    ij.IJ.showStatus("");

    siPlus.setSlice(n);
    siPlus.setRoi(originalRoi);

    return true;
  }
 public boolean get_errors(double[] params, int[] fixes) {
   GenericDialog gd = new GenericDialog("Error Options");
   String[] methods = {"Support Plane", "Monte Carlo"};
   gd.addChoice("Method", methods, methods[0]);
   float conf = 0.67f;
   gd.addNumericField("SP_Confidence Limit (%)", (int) (conf * 100.0f), 5, 10, null);
   String[] labels = {"P1", "P2", "P3", "P4", "P5", "P6", "P7", "P8", "P9", "P10"};
   gd.addChoice("SP_Parameter", labels, labels[0]);
   double spacing = 0.01;
   gd.addNumericField("SP_Chi^2_plot_spacing (% of value)?", spacing * 100.0, 2, 10, null);
   int ntrials = 100;
   gd.addNumericField("MC_#_Trials", ntrials, 0);
   gd.showDialog();
   if (gd.wasCanceled()) {
     return false;
   }
   int methodindex = gd.getNextChoiceIndex();
   conf = 0.01f * (float) gd.getNextNumber();
   int paramindex = gd.getNextChoiceIndex();
   spacing = 0.01 * gd.getNextNumber();
   ntrials = (int) gd.getNextNumber();
   if (methodindex == 0) {
     support_plane_errors_v2 erclass = new support_plane_errors_v2(this, 0.0001, 50, false, 0.1);
     int errindex = paramindex;
     int nfit = 0;
     for (int i = 0; i < labels.length; i++) {
       if (fixes[i] == 0) {
         nfit++;
       }
     }
     int npts = tempdata.length;
     int dofnum = npts - (nfit - 1) - 1;
     int dofden = npts - nfit - 1;
     double flim = (new jdist()).FLimit(dofnum, dofden, (double) conf);
     IJ.log("FLimit = " + (float) flim);
     if (flim == Double.NaN && flim < 1.0) {
       IJ.showMessage("Invalid Limiting F Value");
       return false;
     }
     double truespacing = Math.abs(params[errindex] * spacing);
     double[][] c2plot =
         erclass.geterrors(
             params, fixes, constraints, tempdata, weights, flim, truespacing, errindex);
     IJ.log("upper limit = " + c2plot[1][0] + " lower limit = " + c2plot[0][0]);
     IJ.log(
         "upper error = "
             + (c2plot[1][0] - params[errindex])
             + " lower error = "
             + (params[errindex] - c2plot[0][0]));
     int templength = c2plot[0].length;
     float[][] c2plotf = new float[2][templength - 1];
     for (int i = 0; i < (templength - 1); i++) {
       c2plotf[0][i] = (float) c2plot[0][i + 1];
       c2plotf[1][i] = (float) c2plot[1][i + 1];
     }
     new PlotWindow4("c2 plot", labels[errindex], "Chi^2", c2plotf[0], c2plotf[1]).draw();
   } else {
     StringBuffer sb = new StringBuffer();
     sb.append("Trial\t");
     for (int i = 0; i < labels.length; i++) {
       if (fixes[i] == 0) sb.append(labels[i] + "\t");
     }
     sb.append("chi^2");
     tw = new TextWindow("Monte Carlo Results", sb.toString(), "", 400, 400);
     redirect = true;
     monte_carlo_errors_v2 erclass = new monte_carlo_errors_v2(this, 0.0001, 50, false, 0.1);
     double[][] errors = erclass.geterrors(params, fixes, constraints, tempdata, weights, ntrials);
     sb = new StringBuffer();
     sb.append("StDev\t");
     for (int i = 0; i < errors.length; i++) {
       float[] ferr = new float[errors[0].length];
       for (int j = 0; j < ferr.length; j++) ferr[j] = (float) errors[i][j];
       float stdev = jstatistics.getstatistic("StDev", ferr, null);
       sb.append("" + stdev);
       if (i < (errors.length - 1)) sb.append("\t");
     }
     tw.append(sb.toString());
     redirect = false;
   }
   return true;
 }
  public void Calc_5Fr(ImagePlus imp1, ImagePlus imp2) {
    if (imp1.getType() != imp2.getType()) {
      error();
      return;
    }
    if (imp1.getType() == 0) { // getType returns 0 for 8-bit, 1 for 16-bit
      bitDepth = "8-bit";
      Prefs.set("ps.bitDepth", bitDepth);
    } else {
      bitDepth = "16-bit";
      Prefs.set("ps.bitDepth", bitDepth);
    }
    int width = imp1.getWidth();
    int height = imp1.getHeight();
    if (width != imp2.getWidth() || height != imp2.getHeight()) {
      error();
      return;
    }

    ImageStack stack1 = imp1.getStack();
    //		if (bgStackTitle != "NoBg") ImageStack stack2 = imp2.getStack();
    ImageStack stack2 = imp2.getStack();

    ImageProcessor ip = imp1.getProcessor();
    int dimension = width * height;
    byte[] pixB;
    short[] pixS;
    float[][] pixF = new float[5][dimension];
    float[][] pixFBg = new float[5][dimension];

    float a;
    float b;
    float den;
    float aSmp;
    float bSmp;
    float denSmp;
    float aBg;
    float bBg;
    float denBg;
    float retF;
    float azimF;

    byte[] retB = new byte[dimension];
    short[] retS = new short[dimension];
    byte[] azimB = new byte[dimension];
    short[] azimS = new short[dimension];
    // Derived Variables:
    float swingAngle = 2f * (float) Math.PI * swing;
    float tanSwingAngleDiv2 = (float) Math.tan(swingAngle / 2.f);
    float tanSwingAngleDiv2DivSqrt2 = (float) (Math.tan(swingAngle / 2.f) / Math.sqrt(2));
    float wavelengthDiv2Pi = wavelength / (2f * (float) Math.PI);

    // get the pixels of each slice in the stack and convert to float
    for (int i = 0; i < 5; i++) {
      if (bitDepth == "8-bit") {
        pixB = (byte[]) stack1.getPixels(i + 3);
        for (int j = 0; j < dimension; j++) pixF[i][j] = 0xff & pixB[j];
        if (bgStackTitle != "NoBg") {
          pixB = (byte[]) stack2.getPixels(i + 3);
          for (int j = 0; j < dimension; j++) pixFBg[i][j] = 0xff & pixB[j];
        }
      } else {
        pixS = (short[]) stack1.getPixels(i + 3);
        for (int j = 0; j < dimension; j++) pixF[i][j] = (float) pixS[j];
        if (bgStackTitle != "NoBg") {
          pixS = (short[]) stack2.getPixels(i + 3);
          for (int j = 0; j < dimension; j++) pixFBg[i][j] = (float) pixS[j];
        }
      }
    }

    // Algorithm
    // terms a and b
    for (int j = 0; j < dimension; j++) {
      denSmp = (pixF[1][j] + pixF[2][j] + pixF[3][j] + pixF[4][j] - 4 * pixF[0][j]) / 2;
      denBg = denSmp;
      a = (pixF[4][j] - pixF[1][j]);
      aSmp = a;
      aBg = a;
      b = (pixF[2][j] - pixF[3][j]);
      bSmp = b;
      bBg = b;
      if (bgStackTitle != "NoBg") {
        denBg = (pixFBg[1][j] + pixFBg[2][j] + pixFBg[3][j] + pixFBg[4][j] - 4 * pixFBg[0][j]) / 2;
        aBg = pixFBg[4][j] - pixFBg[1][j];
        bBg = pixFBg[2][j] - pixFBg[3][j];
      }
      // Special case of sample retardance half wave, denSmp = 0
      if (denSmp == 0) {
        retF = (float) wavelength / 4;
        azimF =
            (float) (a == 0 & b == 0 ? 0 : (azimRef + 90 + 90 * Math.atan2(a, b) / Math.PI) % 180);
      } else {
        // Retardance, the background correction can be improved by separately considering sample
        // retardance values larger than a quarter wave
        if (bgStackTitle != "NoBg") {
          a = aSmp / denSmp - aBg / denBg;
          b = bSmp / denSmp - bBg / denBg;
        } else {
          a = aSmp / denSmp;
          b = bSmp / denSmp;
        }
        retF = (float) Math.atan(tanSwingAngleDiv2 * Math.sqrt(a * a + b * b));
        if (denSmp < 0) retF = (float) Math.PI - retF;
        retF = retF * wavelengthDiv2Pi; // convert to nm
        if (retF > retCeiling) retF = retCeiling;

        // Orientation
        if ((bgStackTitle == "NoBg") || ((bgStackTitle != "NoBg") && (Math.abs(denSmp) < 1))) {
          a = aSmp;
          b = bSmp;
        }
        azimF =
            (float) (a == 0 & b == 0 ? 0 : (azimRef + 90 + 90 * Math.atan2(a, b) / Math.PI) % 180);
      }
      if (bitDepth == "8-bit") retB[j] = (byte) (((int) (255 * retF / retCeiling)) & 0xff);
      else retS[j] = (short) (4095 * retF / retCeiling);
      if (mirror == "Yes") azimF = 180 - azimF;
      if (bitDepth == "8-bit") azimB[j] = (byte) (((int) azimF) & 0xff);
      else azimS[j] = (short) (azimF * 10f);
    }
    // show the resulting images in slice 1 and 2
    imp1.setSlice(3);
    if (bitDepth == "8-bit") {
      stack1.setPixels(retB, 1);
      stack1.setPixels(azimB, 2);
    } else {
      stack1.setPixels(retS, 1);
      stack1.setPixels(azimS, 2);
    }
    imp1.setSlice(1);
    IJ.selectWindow(imp1.getTitle());

    Prefs.set("ps.sampleStackTitle", sampleStackTitle);
    Prefs.set("ps.bgStackTitle", bgStackTitle);
    Prefs.set("ps.mirror", mirror);
    Prefs.set("ps.wavelength", wavelength);
    Prefs.set("ps.swing", swing);
    Prefs.set("ps.retCeiling", retCeiling);
    Prefs.set("ps.azimRef", azimRef);
    Prefs.savePreferences();
  }