Example #1
0
  void Otsu(ImagePlus imp, int radius, double par1, double par2, boolean doIwhite) {
    // Otsu's threshold algorithm
    // C++ code by Jordan Bevik <*****@*****.**>
    // ported to ImageJ plugin by G.Landini. Same algorithm as in Auto_Threshold, this time on local
    // circular regions
    int[] data;
    int w = imp.getWidth();
    int h = imp.getHeight();
    int position;
    int radiusx2 = radius * 2;
    ImageProcessor ip = imp.getProcessor();
    byte[] pixels = (byte[]) ip.getPixels();
    byte[] pixelsOut =
        new byte
            [pixels.length]; // need this to avoid changing the image data (and further histograms)
    byte object;
    byte backg;

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

    int k, kStar; // k = the current threshold; kStar = optimal threshold
    int N1, N; // N1 = # points with intensity <=k; N = total number of points
    double BCV, BCVmax; // The current Between Class Variance and maximum BCV
    double num, denom; // temporary bookeeping
    int Sk; // The total intensity for all histogram points <=k
    int S,
        L =
            256; // The total intensity of the image. Need to hange here if modifying for >8 bits
                 // images
    int roiy;

    Roi roi = new OvalRoi(0, 0, radiusx2, radiusx2);
    // ip.setRoi(roi);
    for (int y = 0; y < h; y++) {
      IJ.showProgress(
          (double) (y) / (h - 1)); // this method is slow, so let's show the progress bar
      roiy = y - radius;
      for (int x = 0; x < w; x++) {
        roi.setLocation(x - radius, roiy);
        ip.setRoi(roi);
        // ip.setRoi(new OvalRoi(x-radius, roiy, radiusx2, radiusx2));
        position = x + y * w;
        data = ip.getHistogram();

        // Initialize values:
        S = N = 0;
        for (k = 0; k < L; k++) {
          S += k * data[k]; // Total histogram intensity
          N += data[k]; // Total number of data points
        }

        Sk = 0;
        N1 = data[0]; // The entry for zero intensity
        BCV = 0;
        BCVmax = 0;
        kStar = 0;

        // Look at each possible threshold value,
        // calculate the between-class variance, and decide if it's a max
        for (k = 1; k < L - 1; k++) { // No need to check endpoints k = 0 or k = L-1
          Sk += k * data[k];
          N1 += data[k];

          // The float casting here is to avoid compiler warning about loss of precision and
          // will prevent overflow in the case of large saturated images
          denom = (double) (N1) * (N - N1); // Maximum value of denom is (N^2)/4 =  approx. 3E10

          if (denom != 0) {
            // Float here is to avoid loss of precision when dividing
            num = ((double) N1 / N) * S - Sk; // Maximum value of num =  255*N = approx 8E7
            BCV = (num * num) / denom;
          } else BCV = 0;

          if (BCV >= BCVmax) { // Assign the best threshold found so far
            BCVmax = BCV;
            kStar = k;
          }
        }
        // kStar += 1;	// Use QTI convention that intensity -> 1 if intensity >= k
        // (the algorithm was developed for I-> 1 if I <= k.)
        // return kStar;
        pixelsOut[position] = ((int) (pixels[position] & 0xff) > kStar) ? object : backg;
      }
    }
    for (position = 0; position < w * h; position++)
      pixels[position] = pixelsOut[position]; // update with thresholded pixels
  }