Exemple #1
0
 void createMask(ImagePlus imp) {
   Roi roi = imp.getRoi();
   boolean useInvertingLut = Prefs.useInvertingLut;
   Prefs.useInvertingLut = false;
   if (roi == null || !(roi.isArea() || roi.getType() == Roi.POINT)) {
     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());
   maskImp.updateAndDraw();
   Prefs.useInvertingLut = useInvertingLut;
 }
 public ImageProcessor expandImage(ImageProcessor ipOld, int wNew, int hNew, int xOff, int yOff) {
   ImageProcessor ipNew = ipOld.createProcessor(wNew, hNew);
   if (zeroFill) ipNew.setValue(0.0);
   else ipNew.setColor(Toolbar.getBackgroundColor());
   ipNew.fill();
   ipNew.insert(ipOld, xOff, yOff);
   return ipNew;
 }
 boolean eraseOutsideRoi(ImageProcessor ip, Rectangle r, ImageProcessor mask) {
   int width = ip.getWidth();
   int height = ip.getHeight();
   ip.setRoi(r);
   if (excludeEdgeParticles && polygon != null) {
     ImageStatistics stats = ImageStatistics.getStatistics(ip, MIN_MAX, null);
     if (fillColor >= stats.min && fillColor <= stats.max) {
       double replaceColor = level1 - 1.0;
       if (replaceColor < 0.0 || replaceColor == fillColor) {
         replaceColor = level2 + 1.0;
         int maxColor = imageType == BYTE ? 255 : 65535;
         if (replaceColor > maxColor || replaceColor == fillColor) {
           IJ.error("Particle Analyzer", "Unable to remove edge particles");
           return false;
         }
       }
       for (int y = minY; y < maxY; y++) {
         for (int x = minX; x < maxX; x++) {
           int v = ip.getPixel(x, y);
           if (v == fillColor) ip.putPixel(x, y, (int) replaceColor);
         }
       }
     }
   }
   ip.setValue(fillColor);
   if (mask != null) {
     mask = mask.duplicate();
     mask.invert();
     ip.fill(mask);
   }
   ip.setRoi(0, 0, r.x, height);
   ip.fill();
   ip.setRoi(r.x, 0, r.width, r.y);
   ip.fill();
   ip.setRoi(r.x, r.y + r.height, r.width, height - (r.y + r.height));
   ip.fill();
   ip.setRoi(r.x + r.width, 0, width - (r.x + r.width), height);
   ip.fill();
   ip.resetRoi();
   // IJ.log("erase: "+fillColor+"	"+level1+"	"+level2+"	"+excludeEdgeParticles);
   // (new ImagePlus("ip2", ip.duplicate())).show();
   return true;
 }
Exemple #4
0
 ImageProcessor expand(ImageProcessor ip, boolean hasEdgePixels) {
   if (hasEdgePixels) {
     ImageProcessor ip2 = ip.createProcessor(ip.getWidth() + 2, ip.getHeight() + 2);
     if (foreground == 0) {
       ip2.setColor(255);
       ip2.fill();
     }
     ip2.insert(ip, 1, 1);
     // new ImagePlus("ip2", ip2).show();
     return ip2;
   } else return ip;
 }
  public ImageStack expandStack(ImageStack stackOld, int wNew, int hNew, int xOff, int yOff) {
    int nFrames = stackOld.getSize();
    ImageProcessor ipOld = stackOld.getProcessor(1);
    java.awt.Color colorBack = Toolbar.getBackgroundColor();

    ImageStack stackNew = new ImageStack(wNew, hNew, stackOld.getColorModel());
    ImageProcessor ipNew;

    for (int i = 1; i <= nFrames; i++) {
      IJ.showProgress((double) i / nFrames);
      ipNew = ipOld.createProcessor(wNew, hNew);
      if (zeroFill) ipNew.setValue(0.0);
      else ipNew.setColor(colorBack);
      ipNew.fill();
      ipNew.insert(stackOld.getProcessor(i), xOff, yOff);
      stackNew.addSlice(stackOld.getSliceLabel(i), ipNew);
    }
    return stackNew;
  }
 private static Image5D createImage5D(CMMCore core, String wndTitle) throws Exception {
   core_ = core;
   ImageProcessor ip;
   int type = 0;
   int width_ = (int) core_.getImageWidth();
   int height_ = (int) core_.getImageHeight();
   long byteDepth = core_.getBytesPerPixel();
   long channels = core_.getNumberOfChannels();
   if (byteDepth == 1 && channels == 1) {
     type = ImagePlus.GRAY8;
     ip = new ByteProcessor(width_, height_);
     if (contrastSettings8_.getRange() == 0.0) ip.setMinAndMax(0, 255);
     else ip.setMinAndMax(contrastSettings8_.min, contrastSettings8_.max);
   } else if (byteDepth == 2 && channels == 1) {
     type = ImagePlus.GRAY16;
     ip = new ShortProcessor(width_, height_);
     if (contrastSettings16_.getRange() == 0.0) ip.setMinAndMax(0, 65535);
     else ip.setMinAndMax(contrastSettings16_.min, contrastSettings16_.max);
   } else if (byteDepth == 0) {
     throw (new Exception(logError("Imaging device not initialized")));
   } else if (byteDepth == 1 && channels == 4) {
     // assuming RGB32 format
     ip = new ColorProcessor(width_, height_);
     if (contrastSettings8_.getRange() == 0.0) ip.setMinAndMax(0, 255);
     else ip.setMinAndMax(contrastSettings8_.min, contrastSettings8_.max);
   } else {
     String message =
         "Unsupported pixel depth: "
             + core_.getBytesPerPixel()
             + " byte(s) and "
             + channels
             + " channel(s).";
     throw (new Exception(logError(message)));
   }
   ip.setColor(Color.black);
   if (currentColorModel_ != null) ip.setColorModel(currentColorModel_);
   ip.fill();
   Image5D img5d = new Image5D(wndTitle, type, width_, height_, 1, 1, 1, false);
   @SuppressWarnings("unused")
   Image5DWindow i5dw = new Image5DWindow(img5d);
   return img5d;
 }
Exemple #7
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;
 }
  public void run(ImageProcessor ip) {
    int w = ip.getWidth(); // Get width of image
    int h = ip.getHeight(); // Get height of image

    /**
     * ------------------------------------------------------------------ BEGIN PRELIMINARY STEPS
     * ------------------------------------------------------------------*
     */

    /**
     * ----------------------------------- BEGIN: CREATE IMAGES THAT WILL BE USED IN COMPUTATIONS
     * -----------------------------------*
     */
    // Create the smoothed image to be used for the different edge images
    ImageProcessor Smoothed_Ip_xf = new FloatProcessor(w, h);
    ImageProcessor Smoothed_Ip_yf = new FloatProcessor(w, h);
    ImageProcessor Smoothed_Ip_45f = new FloatProcessor(w, h);
    ImageProcessor Smoothed_Ip_135f = new FloatProcessor(w, h);

    // Create the edge image detecting vertical edges
    ImageProcessor G_xf_Ip = new FloatProcessor(w, h);

    // Create the edge image detecting horizontal edges
    ImageProcessor G_yf_Ip = new FloatProcessor(w, h);

    // Create the edge image detecting 135 degree edges
    ImageProcessor G_45f_Ip = new FloatProcessor(w, h);

    // Create the edge image detecting 45 degree edges
    ImageProcessor G_135f_Ip = new FloatProcessor(w, h);

    // Create the gradient magnitude image
    ImageProcessor GMag_Ip = new ByteProcessor(w, h); // Byte version
    ImageProcessor GMagf_Ip = new FloatProcessor(w, h); // Floating point version

    // Create the gradient direction image
    ImageProcessor GDir_Ip = new ByteProcessor(w, h); // Byte version
    ImageProcessor GDirf_Ip = new FloatProcessor(w, h); // Floating point version

    // Create the edge image (output from non-maximal suppression)
    ImageProcessor Edge_Ip = new ByteProcessor(w, h); // Byte Version
    Edge_Ip.setValue(0); // 0 = Black
    Edge_Ip.fill(); // Fill Edge_Ip all black

    ImageProcessor Copy_Edge_Ip = new ByteProcessor(w, h); // Byte Version
    Copy_Edge_Ip.setValue(0); // 0 = Black
    Copy_Edge_Ip.fill(); // Fill Edge_Ip all black

    ImageProcessor Edgef_Ip = new FloatProcessor(w, h); // Floating Point version
    Edgef_Ip.setValue(0); // 0 = Black
    Edgef_Ip.fill(); // Fill Edge_Ip all black

    ImageProcessor Copy_Edgef_Ip = new FloatProcessor(w, h); // Floating Point version
    Copy_Edgef_Ip.setValue(0); // 0 = Black
    Copy_Edgef_Ip.fill(); // Fill Edge_Ip all black

    // Create the Threshold with Hysteresis image
    ImageProcessor Threshold_Ip = new ByteProcessor(w, h);
    Threshold_Ip.setValue(0); // 0 = Black
    Threshold_Ip.fill(); // Fill Edge_Ip all black
    /**
     * ----------------------------------- END: CREATE IMAGES THAT WILL BE USED IN COMPUTATIONS
     * -----------------------------------*
     */

    /**
     * ----------------------------------------------------- BEGIN: USER INPUT
     * -----------------------------------------------------*
     */
    double STDDev = 0,
        TLow = 0,
        THigh =
            0; // Declare and initialize variables for the standard deviation, low threshold, and
               // high threshold
    int Size = 0; // Initialize size of Gaussian Filter
    boolean EdgeStrengthImage; // specifies whether edge strength image should be shown
    GenericDialog gd = new GenericDialog("User Inputs");
    gd.addNumericField(
        "Size of Gaussian Filter (Odd Integer)", Size, 0); // Field for Size of Gaussian Filter
    gd.addNumericField("Standard Deviation", STDDev, 0); // Field for Standard Deviation
    gd.addNumericField("Low Threshold (1 - 255)", TLow, 0); // Field for Low Threshold
    gd.addNumericField("High Threshold (1 - 255)", THigh, 0); // Field for High Threshold
    gd.showDialog();
    if (gd.wasCanceled()) {
      return;
    } else {
      Size =
          (int)
              gd
                  .getNextNumber(); // Set Size variable from user input. This allows the user to
                                    // set the size of the Gaussian Filter
      STDDev = gd.getNextNumber(); // Set STDDev variable from user input
      TLow = gd.getNextNumber(); // Set TLow variable from user input
      THigh = gd.getNextNumber(); // Set THigh variable from user input
    }

    /**
     * ----------------------------------------------------- END: USER INPUT
     * -----------------------------------------------------*
     */

    /**
     * ------------------------------------------------------------------ END PRELIMINARY STEPS
     * ------------------------------------------------------------------*
     */

    /**
     * ------------------------------------------------------------------ BEGIN CANNY EDGE DETECTION
     * ------------------------------------------------------------------*
     */

    /**
     * ----------------------------------------------------- BEGIN STEP 1: NOISE REDUCTION VIA
     * GAUSSIAN ----------------------------------------------------- *
     */
    ImageProcessor ipf = ip.convertToFloat(); // Convert original image to floating point
    int SizeSquared = (int) Math.pow(Size, 2); // Square the size of Gaussian Kernel
    int HalfSize = (Size - 1) / 2; // Cut the size of the Gaussian Kernel almost in half
    float pix; // Temporary storage to be used throughout code to store pixel values
    float[] GaussianFilter =
        new float[SizeSquared]; // Initialize Gaussian Filter to be used in the convolution
    double[] GaussianFilterD =
        new double
            [SizeSquared]; // Initialize Gaussian Filter to be used...this filter will be composed
                           // of numbers of type double
    double Constant = 1 / (2 * Math.PI * Math.pow(STDDev, 2)); // Compute 1/(2*pi*sigma^2)
    double ExponentDenom = 2 * Math.pow(STDDev, 2); // Compute 2*sigma^2
    double Value; // Temporary storage to store the computations that will form the Gaussian Filter

    // FOR LOOP TO FORM GaussianFilterD
    for (int i = 0; i < Size; i++) {
      for (int j = 0; j < Size; j++) {
        Value =
            Math.exp(
                -1
                    * (Math.pow(j - HalfSize, 2) + Math.pow(i - HalfSize, 2))
                    / (ExponentDenom)); // Set Value = e^(-(i^2 + j^2)/(2*sigma^2))
        GaussianFilterD[Size * i + j] = Constant * Value; // Place Value in GaussianFilterD
      }
    }

    // FOR LOOP TO FORM GaussianFilter using GaussianFilterD
    for (int i = 0; i < Math.pow(Size, 2); i++) {
      GaussianFilter[i] = (float) GaussianFilterD[i]; // Convert double values to float one by one
    }

    // CONVOLVE IMAGE WITH GAUSSIAN
    Convolver cv = new Convolver(); // Create the convolver
    cv.setNormalize(true); // Normalize the filter
    cv.convolve(
        ipf,
        GaussianFilter,
        Size,
        Size); // Apply the GaussianFilter using convolution on the image ipf

    // For loop to create 4 smoothed images to be used in detecting the 4 edges: 0 deg, 45 deg, 90
    // deg, 135 deg
    for (int i = 0; i < w; i++) {
      for (int j = 0; j < h; j++) {
        pix = ipf.getf(i, j);
        Smoothed_Ip_xf.setf(
            i, j,
            pix); // Smoothed image to convolve with Sobel filter in x-direction (detects vertical
                  // edges)
        Smoothed_Ip_yf.setf(
            i, j,
            pix); // Smoothed image to convolve with Sobel filter in y-direction (detects horizontal
                  // edges)
        Smoothed_Ip_45f.setf(
            i, j,
            pix); // Smoothed image to convolve with Sobel filter in 45 degree direction (detects
                  // 135 degree edges)
        Smoothed_Ip_135f.setf(
            i, j,
            pix); // Smoothed image to convolve with Sobel filter in 135 degree direction (detects
                  // 45 degree edges)
      }
    }

    /**
     * ----------------------------------------------------- END STEP 1: NOISE REDUCTION VIA
     * GAUSSIAN ----------------------------------------------------- *
     */

    /**
     * ----------------------------------------------------- BEGIN STEP 2: COMPUTE GRADIENT
     * MAGNITUDE AND DIRECTION IMAGES ----------------------------------------------------- *
     */

    // Sobel Filters to detect edges
    float[] G_x = {-1, 0, 1, -2, 0, 2, -1, 0, 1}; // Sobel operator in x direction
    float[] G_y = {-1, -2, -1, 0, 0, 0, 1, 2, 1}; // Sobel operator in y direction
    float[] G_135 = {2, 1, 0, 1, 0, -1, 0, -1, -2}; // Sobel operator in 135 degree direction
    float[] G_45 = {0, 1, 2, -1, 0, 1, -2, -1, 0}; // Sobel operator in 45 degree direction

    // CONVOLVE IMAGE USING SOBEL FILTERS
    cv.convolve(
        Smoothed_Ip_xf,
        G_x,
        3,
        3); // Apply the Sobel filter in x-direction using convolution on the smoothed image
    cv.convolve(
        Smoothed_Ip_yf,
        G_y,
        3,
        3); // Apply the Sobel filter in y-direction using convolution on the smoothed image
    cv.convolve(
        Smoothed_Ip_45f,
        G_45,
        3,
        3); // Apply the Sobel filter in 45 degree direction using convolution on the smoothed image
    cv.convolve(
        Smoothed_Ip_135f,
        G_135,
        3,
        3); // Apply the Sobel filter in 135 degree direction using convolution on the smoothed
            // image

    // For loop to define the 4 floating point images G_xf_Ip, G_yf_Ip, G_45f_Ip, G_135f_Ip
    for (int i = 0; i < w; i++) {
      for (int j = 0; j < h; j++) {
        pix = Smoothed_Ip_xf.getf(i, j);
        G_xf_Ip.setf(i, j, pix);
        pix = Smoothed_Ip_yf.getf(i, j);
        G_yf_Ip.setf(i, j, pix);
        pix = Smoothed_Ip_45f.getf(i, j);
        G_45f_Ip.setf(i, j, pix);
        pix = Smoothed_Ip_135f.getf(i, j);
        G_135f_Ip.setf(i, j, pix);
      }
    }

    // COMPUTE THE GRADIENT MAGNITUDE IMAGE GMagf_Ip
    float pix1, pix2; // Variables to store pixel values of G_xf_Ip and G_yf_Ip
    for (int i = 0; i < w; i++) {
      for (int j = 0; j < h; j++) {
        pix1 = G_xf_Ip.getf(i, j); // Get pixel value
        pix2 = G_yf_Ip.getf(i, j); // Get Pixel Value
        pix =
            (float)
                Math.sqrt(
                    pix1 * pix1
                        + pix2
                            * pix2); // Take the square root of the sum of the squares of both pixel
                                     // values
        GMagf_Ip.setf(
            i, j, 255 * pix); // Place in (i,j) position of GMagf_Ip and scale by 255 to view
      }
    }

    // COMPUTE THE GRADIENT DIRECTION IMAGE
    double v1, v2, v3, v4; // Temporary storage for the abs. value of pixel vlaues
    int pixi; // Temporary storage for pixel values
    double[][] GDir =
        new double[h]
            [w]; // Define 2D Array to store gradient direction values. Will use this during Step 3
                 // Non-Maximal Suppression instead of the gradient direction image

    // For loop to compute gradient direction image
    for (int i = 0; i < w; i++) {
      for (int j = 0; j < h; j++) {
        // Obtain the absolute value of each pixel in the following four floating point images
        v1 = Math.abs(G_xf_Ip.getf(i, j));
        v2 = Math.abs(G_yf_Ip.getf(i, j));
        v3 = Math.abs(G_45f_Ip.getf(i, j));
        v4 = Math.abs(G_135f_Ip.getf(i, j));

        // If statements to find the maximal response (strongest edge direction)

        if (v1 > v2 && v1 > v3 && v1 > v4) // Vertical edge orientation
        {
          GDir_Ip.putPixel(i, j, 0);
          GDir[j][i] = 0; // 0 stands for vertical edge orientation
        } else if (v3 > v1 && v3 > v2 && v3 > v4) // 45 degree edge orientation
        {
          GDir_Ip.putPixel(i, j, 1);
          GDir[j][i] = 1; // 1 stands for 45 degree edge orientation
        } else if (v2 > v1 && v2 > v3 && v2 > v4) // Horizontal edge orientation
        {
          GDir_Ip.putPixel(i, j, 2);
          GDir[j][i] = 2; // 2 stands for horizontal edge orientation
        } else if (v4 > v1 && v4 > v2 && v4 > v3) // 135 degree edge orientation
        {
          GDir_Ip.putPixel(i, j, 3);
          GDir[j][i] = 3; // 3 stands for 135 degree edge orientation
        }

        pixi =
            (int) (255.0 / 3.0)
                * GDir_Ip.getPixel(
                    i, j); // Scale the gradient direction image so we can actually see it
        GDir_Ip.putPixel(
            i, j,
            pixi); // Place pixi in the (i,j) location of GDir_Ip...we can now view the gradient
                   // direction image
      }
    }

    // OUTPUT GRADIENT DIRECTION IMAGE
    String DirTitle = "Gradient Direction";
    ImagePlus GDir_Im = new ImagePlus(DirTitle, GDir_Ip);
    GDir_Im.show();

    // OUTPUT GRADIENT MAGNITUDE IMAGE (need to convert to ByteProcessor to view first)
    GMagf_Ip.resetMinAndMax();
    GMag_Ip.insert(GMagf_Ip.convertToByte(true), 0, 0);

    String MagTitle = "Gradient Magnitude";
    ImagePlus GMag_Im = new ImagePlus(MagTitle, GMag_Ip);
    GMag_Im.show();

    /**
     * ----------------------------------------------------- BEGIN STEP 2: COMPUTE GRADIENT
     * MAGNITUDE AND DIRECTION IMAGES ----------------------------------------------------- *
     */

    /**
     * ----------------------------------------------------- BEGIN STEP 3: NON-MAXIMAL SUPPRESSION
     * -----------------------------------------------------*
     */
    // Ignoring boundaries for convenience
    float Magnitude; // Storage for magnitude
    double Direction; // Storage for direction

    // FOR LOOP TO COMPUTE NON-MAXIMAL SUPPRESSION IMAGE
    for (int i = 1; i < w - 1; i++) {
      for (int j = 1; j < h - 1; j++) {
        Magnitude =
            GMagf_Ip.getf(
                i, j); // Get the magnitude in the (i,j) position of the gradient magnitude image

        if (Magnitude != 0) // If the magnitude is non-zero then we find the direction of the edge
        {
          Direction = GDir[j][i]; // Obtain the direction
          float n1GradMag = 0,
              n2GradMag = 0; // Initialize storage for the magnitude of the 2 neighboring pixels

          if (Direction
              == 0) // If Direction is 0 get the magnitude in the columns to the left and right
          {
            n1GradMag = GMagf_Ip.getf(i - 1, j);
            n2GradMag = GMagf_Ip.getf(i + 1, j);
          } else if (Direction
              == 1) // If Direction is 45 degree get the magnitude in adjacent pixels
          {
            n1GradMag = GMagf_Ip.getf(i + 1, j - 1);
            n2GradMag = GMagf_Ip.getf(i - 1, j + 1);
          } else if (Direction
              == 2) // If Direction is 2 get the magnitude in the rows above and below
          {
            n1GradMag = GMagf_Ip.getf(i, j - 1);
            n2GradMag = GMagf_Ip.getf(i, j + 1);
          } else if (Direction
              == 3) // If Direction is 135 degrees get the magnitude in adjacent pixels
          {
            n1GradMag = GMagf_Ip.getf(i - 1, j - 1);
            n2GradMag = GMagf_Ip.getf(i + 1, j + 1);
          }

          if (Magnitude > n1GradMag
              && Magnitude
                  > n2GradMag) // Check to see if the magnitude of pixel under inspection is the
                               // largest relative to its adjacent pixels
          {
            pix = GMagf_Ip.getf(i, j); // Store magnitude in (i,j) position in pix variable
            Edgef_Ip.setf(
                i, j,
                pix); // Place this pixel value in the (i,j) position of Edge Image (Edge Image is
                      // output from non-maximal suppression)
            Copy_Edgef_Ip.setf(
                i, j,
                pix); // Place this pixel value in the (i,j) position of Copy Edge Image (this will
                      // be used for thresholding with hysteresis)

          } else {
          } // Else do nothing since edge image was already filled with 0's at beginning of code
        } else {
        } // Do nothing if magnitude is 0
      }
    }

    Copy_Edgef_Ip.resetMinAndMax();
    Copy_Edge_Ip.insert(Copy_Edgef_Ip.convertToByte(true), 0, 0);

    // Display edge magnitude image but we need to convert to ByteProcessor first
    Edgef_Ip.resetMinAndMax();
    Edge_Ip.insert(Edgef_Ip.convertToByte(true), 0, 0);

    String cTitle = "Non-Maximal Suppression";
    ImagePlus Edge_Im = new ImagePlus(cTitle, Edge_Ip);
    Edge_Im.show();
    /**
     * ----------------------------------------------------- END STEP 3: NON-MAXIMAL SUPPRESSION
     * -----------------------------------------------------*
     */

    /**
     * ----------------------------------------------------- BEGIN STEP 4: THRESHOLDING WITH
     * HYSTERESIS -----------------------------------------------------*
     */
    int count = 0; // Initialize counter to be used in while loop
    int IterationCount = 500; // Number of iterations to perform

    // Scan through all pixels in the edge image and mark all edges with magnitude above the high
    // threshold as a true edge otherwise if the magnitude is below the low threshold
    // then we delete that pixel (set it to zero)
    for (int i = 0; i < w; i++) {
      for (int j = 0; j < h; j++) {
        Magnitude = Copy_Edge_Ip.getPixel(i, j); // Obtain magnitude in edge image

        if (Magnitude
            > THigh) // If Magnitude is larger than the high threshold then make pixel white
        {
          Threshold_Ip.putPixel(i, j, 255); // True edge (Updates Threshold image to be output)
          Copy_Edge_Ip.putPixel(
              i, j,
              255); // True edge (Updates edge image which will be used in the iterative
                    // thresholding)
        } else if (Magnitude
            < TLow) // Else if magnitude is below the low threshold then make pixel black
        {
          Threshold_Ip.putPixel(i, j, 0); // Not an edge (Updates Threshold image to be output)
          Copy_Edge_Ip.putPixel(
              i, j,
              0); // Not an edge (Updates edge image which will be used in the iterative
                  // thresholding)
        }
      }
    }

    while (count < IterationCount) // Iterate again and again
    {
      // Ignore boundary pixels for convenience
      for (int i = 1; i < w - 1; i++) {
        for (int j = 1; j < h - 1; j++) {
          Magnitude = Copy_Edge_Ip.getPixel(i, j); // Obtain magnitude in edge image
          if (Magnitude == 255) // If we reach a true edge then we look at its 8 neighbors
          {
            // Obtain the magnitude in the 8 neighbors
            int n1, n2, n3, n4, n5, n6, n7, n8;
            n1 = Copy_Edge_Ip.getPixel(i - 1, j);
            n2 = Copy_Edge_Ip.getPixel(i - 1, j - 1);
            n3 = Copy_Edge_Ip.getPixel(i, j - 1);
            n4 = Copy_Edge_Ip.getPixel(i + 1, j - 1);
            n5 = Copy_Edge_Ip.getPixel(i + 1, j);
            n6 = Copy_Edge_Ip.getPixel(i + 1, j + 1);
            n7 = Copy_Edge_Ip.getPixel(i, j + 1);
            n8 = Copy_Edge_Ip.getPixel(i - 1, j + 1);
            if (n1
                >= TLow) // If n1 is greater than or equal to the low threshold then we mark it as
                         // an edge
            {
              Copy_Edge_Ip.putPixel(i - 1, j, 255); // Update edge image
              Threshold_Ip.putPixel(
                  i - 1, j,
                  255); // Update threshold image (This is the output image from thresholding with
                        // hysteresis)
            }
            if (n2
                >= TLow) // If n2 is greater than or equal to the low threshold then we mark it as
                         // an edge
            {
              Copy_Edge_Ip.putPixel(i - 1, j - 1, 255); // Update edge image
              Threshold_Ip.putPixel(
                  i - 1, j - 1,
                  255); // Update threshold image (This is the output image from thresholding with
                        // hysteresis)
            }
            if (n3
                >= TLow) // If n3 is greater than or equal to the low threshold then we mark it as
                         // an edge
            {
              Copy_Edge_Ip.putPixel(i, j - 1, 255); // Update edge image
              Threshold_Ip.putPixel(
                  i, j - 1,
                  255); // Update threshold image (This is the output image from thresholding with
                        // hysteresis)
            }
            if (n4
                >= TLow) // If n4 is greater than or equal to the low threshold then we mark it as
                         // an edge
            {
              Copy_Edge_Ip.putPixel(i + 1, j - 1, 255); // Update edge image
              Threshold_Ip.putPixel(
                  i + 1, j - 1,
                  255); // Update threshold image (This is the output image from thresholding with
                        // hysteresis)
            }
            if (n5
                >= TLow) // If n5 is greater than or equal to the low threshold then we mark it as
                         // an edge
            {
              Copy_Edge_Ip.putPixel(i + 1, j, 255); // Update edge image
              Threshold_Ip.putPixel(
                  i + 1, j,
                  255); // Update threshold image (This is the output image from thresholding with
                        // hysteresis)
            }
            if (n6
                >= TLow) // If n6 is greater than or equal to the low threshold then we mark it as
                         // an edge
            {
              Copy_Edge_Ip.putPixel(i + 1, j + 1, 255); // Update edge image
              Threshold_Ip.putPixel(
                  i + 1, j + 1,
                  255); // Update threshold image (This is the output image from thresholding with
                        // hysteresis)
            }
            if (n7
                >= TLow) // If n7 is greater than or equal to the low threshold then we mark it as
                         // an edge
            {
              Copy_Edge_Ip.putPixel(i, j + 1, 255); // Update edge image
              Threshold_Ip.putPixel(
                  i, j + 1,
                  255); // Update threshold image (This is the output image from thresholding with
                        // hysteresis)
            }
            if (n8
                >= TLow) // If n8 is greater than or equal to the low threshold then we mark it as
                         // an edge
            {
              Copy_Edge_Ip.putPixel(i - 1, j + 1, 255); // Update edge image
              Threshold_Ip.putPixel(
                  i - 1, j + 1,
                  255); // Update threshold image (This is the output image from thresholding with
                        // hysteresis)
            }
          }
        }
      }
      count++; // Update counter and continue iterations
    }

    // Display the threshold with hysteresis image.
    String ThreshTitle = "Threshold with Hysteresis";
    ImagePlus Threshold_Im = new ImagePlus(ThreshTitle, Threshold_Ip);
    Threshold_Im.show();
    /**
     * ----------------------------------------------------- END STEP 4: THRESHOLDING WITH
     * HYSTERESIS -----------------------------------------------------*
     */

    /**
     * ------------------------------------------------------------------ END CANNY EDGE DETECTION
     * ------------------------------------------------------------------*
     */
  }
  public void run(ImageProcessor ip) {
    String[] imageNames = getOpenImageNames();
    if (imageNames[0] == "None") {
      IJ.error("need at least 2 binary open images");
      return;
    }
    double previousMinOverlap = Prefs.get("BVTB.BinaryFeatureExtractor.minOverlap", 0);
    boolean previousCombine = Prefs.get("BVTB.BinaryFeatureExtractor.combine", false);

    GenericDialog gd = new GenericDialog("Binary Feature Extractor");
    gd.addChoice("Objects image", imageNames, imageNames[0]);
    gd.addChoice("Selector image", imageNames, imageNames[1]);
    gd.addNumericField("Object_overlap in % (0=off)", previousMinOverlap, 0, 9, "");
    gd.addCheckbox("Combine objects and selectors", previousCombine);
    gd.addCheckbox("Count output", true);
    gd.addCheckbox("Analysis tables", false);
    gd.showDialog();
    if (gd.wasCanceled()) {
      return;
    }
    String objectsImgTitle = gd.getNextChoice();
    String selectorsImgTitle = gd.getNextChoice();
    double minOverlap = gd.getNextNumber();
    boolean combineImages = gd.getNextBoolean();
    boolean showCountOutput = gd.getNextBoolean();
    boolean showAnalysis = gd.getNextBoolean();
    if (gd.invalidNumber() || minOverlap < 0 || minOverlap > 100) {
      IJ.error("invalid number");
      return;
    }
    Prefs.set("BVTB.BinaryFeatureExtractor.minOverlap", minOverlap);
    Prefs.set("BVTB.BinaryFeatureExtractor.combine", combineImages);

    if (objectsImgTitle.equals(selectorsImgTitle)) {
      IJ.error("images need to be different");
      return;
    }

    ImagePlus objectsImp = WindowManager.getImage(objectsImgTitle);
    ImageProcessor objectsIP = objectsImp.getProcessor();
    ImagePlus selectorsImp = WindowManager.getImage(selectorsImgTitle);
    ImageProcessor selectorsIP = selectorsImp.getProcessor();

    if (!objectsIP.isBinary() || !selectorsIP.isBinary()) {
      IJ.error("works with 8-bit binary images only");
      return;
    }

    if ((objectsImp.getWidth() != selectorsImp.getWidth())
        || objectsImp.getHeight() != selectorsImp.getHeight()) {
      IJ.error("images need to be of the same size");
      return;
    }

    // close any existing RoiManager before instantiating a new one for this analysis
    RoiManager oldRM = RoiManager.getInstance2();
    if (oldRM != null) {
      oldRM.close();
    }

    RoiManager objectsRM = new RoiManager(true);
    ResultsTable objectsRT = new ResultsTable();
    ParticleAnalyzer analyzeObjects =
        new ParticleAnalyzer(analyzerOptions, measurementFlags, objectsRT, 0.0, 999999999.9);
    analyzeObjects.setRoiManager(objectsRM);

    analyzeObjects.analyze(objectsImp);
    objectsRM.runCommand("Show None");
    int objectNumber = objectsRT.getCounter();

    Roi[] objectRoi = objectsRM.getRoisAsArray();

    ResultsTable measureSelectorsRT = new ResultsTable();
    Analyzer overlapAnalyzer = new Analyzer(selectorsImp, measurementFlags, measureSelectorsRT);

    ImagePlus outputImp =
        IJ.createImage("output", "8-bit black", objectsImp.getWidth(), objectsImp.getHeight(), 1);
    ImageProcessor outputIP = outputImp.getProcessor();

    double[] measuredOverlap = new double[objectNumber];

    outputIP.setValue(255.0);
    for (int o = 0; o < objectNumber; o++) {
      selectorsImp.killRoi();
      selectorsImp.setRoi(objectRoi[o]);
      overlapAnalyzer.measure();
      measuredOverlap[o] = measureSelectorsRT.getValue("%Area", o);
      if (minOverlap != 0.0 && measuredOverlap[o] >= minOverlap) {
        outputIP.fill(objectRoi[o]);
        finalCount++;
      } else if (minOverlap == 0.0 && measuredOverlap[o] > 0.0) {
        outputIP.fill(objectRoi[o]);
        finalCount++;
      }
    }
    // measureSelectorsRT.show("Objects");

    selectorsImp.killRoi();
    RoiManager selectorRM = new RoiManager(true);
    ResultsTable selectorRT = new ResultsTable();
    ParticleAnalyzer.setRoiManager(selectorRM);
    ParticleAnalyzer analyzeSelectors =
        new ParticleAnalyzer(analyzerOptions, measurementFlags, selectorRT, 0.0, 999999999.9);
    analyzeSelectors.analyze(selectorsImp);
    selectorRM.runCommand("Show None");
    int selectorNumber = selectorRT.getCounter();

    if (combineImages) {
      outputImp.updateAndDraw();
      Roi[] selectorRoi = selectorRM.getRoisAsArray();

      ResultsTable measureObjectsRT = new ResultsTable();
      Analyzer selectorAnalyzer = new Analyzer(outputImp, measurementFlags, measureObjectsRT);

      double[] selectorOverlap = new double[selectorNumber];
      outputIP.setValue(255.0);
      for (int s = 0; s < selectorNumber; s++) {
        outputImp.killRoi();
        outputImp.setRoi(selectorRoi[s]);
        selectorAnalyzer.measure();
        selectorOverlap[s] = measureObjectsRT.getValue("%Area", s);
        if (selectorOverlap[s] > 0.0d) {
          outputIP.fill(selectorRoi[s]);
        }
      }
      selectorRoi = null;
      selectorAnalyzer = null;
      measureObjectsRT = null;
    }
    // selectorRT.show("Selectors");
    outputImp.killRoi();
    String outputImageTitle = WindowManager.getUniqueName("Extracted_" + objectsImgTitle);
    outputImp.setTitle(outputImageTitle);
    outputImp.show();
    outputImp.changes = true;

    if (showCountOutput) {
      String[] openTextWindows = WindowManager.getNonImageTitles();
      boolean makeNewTable = true;
      for (int w = 0; w < openTextWindows.length; w++) {
        if (openTextWindows[w].equals("BFE_Results")) {
          makeNewTable = false;
        }
      }

      TextWindow existingCountTable = ResultsTable.getResultsWindow();
      if (makeNewTable) {
        countTable = new ResultsTable();
        countTable.setPrecision(0);
        countTable.setValue("Image", 0, outputImageTitle);
        countTable.setValue("Objects", 0, objectNumber);
        countTable.setValue("Selectors", 0, selectorNumber);
        countTable.setValue("Extracted", 0, finalCount);
        countTable.show("BFE_Results");
      } else {
        IJ.renameResults("BFE_Results", "Results");
        countTable = ResultsTable.getResultsTable();
        countTable.setPrecision(0);
        countTable.incrementCounter();
        countTable.addValue("Image", outputImageTitle);
        countTable.addValue("Objects", objectNumber);
        countTable.addValue("Selectors", selectorNumber);
        countTable.addValue("Extracted", finalCount);
        IJ.renameResults("Results", "BFE_Results");
        countTable.show("BFE_Results");
      }
    }

    if (showAnalysis) {
      ResultsTable extractedRT = new ResultsTable();
      ParticleAnalyzer analyzeExtracted =
          new ParticleAnalyzer(
              ParticleAnalyzer.CLEAR_WORKSHEET | ParticleAnalyzer.RECORD_STARTS,
              measurementFlags,
              extractedRT,
              0.0,
              999999999.9);
      analyzeExtracted.analyze(outputImp);
      objectsRT.show("Objects");
      selectorRT.show("Selectors");
      extractedRT.show("Extracted");
    } else {
      objectsRT = null;
      selectorRT = null;
    }

    objectsRM = null;
    measureSelectorsRT = null;
    analyzeObjects = null;
    overlapAnalyzer = null;
    objectRoi = null;
    selectorRM = null;

    objectsImp.killRoi();
    objectsImp.changes = false;
    selectorsImp.changes = false;
  }
 void drawRoiFilledParticle(ImageProcessor ip, Roi roi, ImageProcessor mask, int count) {
   int grayLevel = (count < 65535) ? count : 65535;
   ip.setValue((double) grayLevel);
   ip.setRoi(roi.getBounds());
   ip.fill(mask);
 }
 void drawFilledParticle(ImageProcessor ip, Roi roi, ImageProcessor mask) {
   // IJ.write(roi.getBounds()+" "+mask.length);
   ip.setRoi(roi.getBounds());
   ip.fill(mask);
 }
 void analyzeParticle(int x, int y, ImagePlus imp, ImageProcessor ip) {
   // Wand wand = new Wand(ip);
   ImageProcessor ip2 = redirectIP != null ? redirectIP : ip;
   wand.autoOutline(x, y, level1, level2, wandMode);
   if (wand.npoints == 0) {
     IJ.log("wand error: " + x + " " + y);
     return;
   }
   Roi roi = new PolygonRoi(wand.xpoints, wand.ypoints, wand.npoints, roiType);
   Rectangle r = roi.getBounds();
   if (r.width > 1 && r.height > 1) {
     PolygonRoi proi = (PolygonRoi) roi;
     pf.setPolygon(proi.getXCoordinates(), proi.getYCoordinates(), proi.getNCoordinates());
     ip2.setMask(pf.getMask(r.width, r.height));
     if (floodFill) ff.particleAnalyzerFill(x, y, level1, level2, ip2.getMask(), r);
   }
   ip2.setRoi(r);
   ip.setValue(fillColor);
   ImageStatistics stats = getStatistics(ip2, measurements, calibration);
   boolean include = true;
   if (excludeEdgeParticles) {
     if (r.x == minX || r.y == minY || r.x + r.width == maxX || r.y + r.height == maxY)
       include = false;
     if (polygon != null) {
       Rectangle bounds = roi.getBounds();
       int x1 = bounds.x + wand.xpoints[wand.npoints - 1];
       int y1 = bounds.y + wand.ypoints[wand.npoints - 1];
       int x2, y2;
       for (int i = 0; i < wand.npoints; i++) {
         x2 = bounds.x + wand.xpoints[i];
         y2 = bounds.y + wand.ypoints[i];
         if (!polygon.contains(x2, y2)) {
           include = false;
           break;
         }
         if ((x1 == x2 && ip.getPixel(x1, y1 - 1) == fillColor)
             || (y1 == y2 && ip.getPixel(x1 - 1, y1) == fillColor)) {
           include = false;
           break;
         }
         x1 = x2;
         y1 = y2;
       }
     }
   }
   ImageProcessor mask = ip2.getMask();
   if (minCircularity > 0.0 || maxCircularity < 1.0) {
     double perimeter = roi.getLength();
     double circularity =
         perimeter == 0.0 ? 0.0 : 4.0 * Math.PI * (stats.pixelCount / (perimeter * perimeter));
     if (circularity > 1.0) circularity = 1.0;
     // IJ.log(circularity+"	"+perimeter+"  "+stats.area);
     if (circularity < minCircularity || circularity > maxCircularity) include = false;
   }
   if (stats.pixelCount >= minSize && stats.pixelCount <= maxSize && include) {
     particleCount++;
     if (roiNeedsImage) roi.setImage(imp);
     stats.xstart = x;
     stats.ystart = y;
     saveResults(stats, roi);
     if (showChoice != NOTHING) drawParticle(drawIP, roi, stats, mask);
   }
   if (redirectIP != null) ip.setRoi(r);
   ip.fill(mask);
 }
  /**
   * 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;
  }
    void apply(ImagePlus imp, ImageProcessor ip) {
      // this.setCursor(wait);
      // IJ.showStatus("Bandpassing slice "+previousSlice);
      java.awt.Color col;

      if (invert.getState()) col = Toolbar.getForegroundColor();
      else col = Toolbar.getBackgroundColor();

      ip.setColor(col);

      int fill = ip.BLACK;
      int keep = 0;

      if (bandPassH.getState() && bandPassS.getState() && bandPassB.getState()) { // PPP All pass
        for (int j = 0; j < numPixels; j++) {
          int hue = hSource[j] & 0xff;
          int sat = sSource[j] & 0xff;
          int bri = bSource[j] & 0xff;
          if (((hue < minHue) || (hue > maxHue))
              || ((sat < minSat) || (sat > maxSat))
              || ((bri < minBri) || (bri > maxBri))) fillMask[j] = fill;
          else fillMask[j] = keep;
        }
      } else if (!bandPassH.getState()
          && !bandPassS.getState()
          && !bandPassB.getState()) { // SSS All stop
        for (int j = 0; j < numPixels; j++) {
          int hue = hSource[j] & 0xff;
          int sat = sSource[j] & 0xff;
          int bri = bSource[j] & 0xff;
          if (((hue >= minHue) && (hue <= maxHue))
              || ((sat >= minSat) && (sat <= maxSat))
              || ((bri >= minBri) && (bri <= maxBri))) fillMask[j] = fill;
          else fillMask[j] = keep;
        }
      } else if (bandPassH.getState() && bandPassS.getState() && !bandPassB.getState()) { // PPS
        for (int j = 0; j < numPixels; j++) {
          int hue = hSource[j] & 0xff;
          int sat = sSource[j] & 0xff;
          int bri = bSource[j] & 0xff;
          if (((hue < minHue) || (hue > maxHue))
              || ((sat < minSat) || (sat > maxSat))
              || ((bri >= minBri) && (bri <= maxBri))) fillMask[j] = fill;
          else fillMask[j] = keep;
        }
      } else if (!bandPassH.getState() && !bandPassS.getState() && bandPassB.getState()) { // SSP
        for (int j = 0; j < numPixels; j++) {
          int hue = hSource[j] & 0xff;
          int sat = sSource[j] & 0xff;
          int bri = bSource[j] & 0xff;
          if (((hue >= minHue) && (hue <= maxHue))
              || ((sat >= minSat) && (sat <= maxSat))
              || ((bri < minBri) || (bri > maxBri))) fillMask[j] = fill;
          else fillMask[j] = keep;
        }
      } else if (bandPassH.getState() && !bandPassS.getState() && !bandPassB.getState()) { // PSS
        for (int j = 0; j < numPixels; j++) {
          int hue = hSource[j] & 0xff;
          int sat = sSource[j] & 0xff;
          int bri = bSource[j] & 0xff;
          if (((hue < minHue) || (hue > maxHue))
              || ((sat >= minSat) && (sat <= maxSat))
              || ((bri >= minBri) && (bri <= maxBri))) fillMask[j] = fill;
          else fillMask[j] = keep;
        }
      } else if (!bandPassH.getState() && bandPassS.getState() && bandPassB.getState()) { // SPP
        for (int j = 0; j < numPixels; j++) {
          int hue = hSource[j] & 0xff;
          int sat = sSource[j] & 0xff;
          int bri = bSource[j] & 0xff;
          if (((hue >= minHue) && (hue <= maxHue))
              || ((sat < minSat) || (sat > maxSat))
              || ((bri < minBri) || (bri > maxBri))) fillMask[j] = fill;
          else fillMask[j] = keep;
        }
      } else if (!bandPassH.getState() && bandPassS.getState() && !bandPassB.getState()) { // SPS
        for (int j = 0; j < numPixels; j++) {
          int hue = hSource[j] & 0xff;
          int sat = sSource[j] & 0xff;
          int bri = bSource[j] & 0xff;
          if (((hue >= minHue) && (hue <= maxHue))
              || ((sat < minSat) || (sat > maxSat))
              || ((bri >= minBri) && (bri <= maxBri))) fillMask[j] = fill;
          else fillMask[j] = keep;
        }
      } else if (bandPassH.getState() && !bandPassS.getState() && bandPassB.getState()) { // PSP
        for (int j = 0; j < numPixels; j++) {
          int hue = hSource[j] & 0xff;
          int sat = sSource[j] & 0xff;
          int bri = bSource[j] & 0xff;
          if (((hue < minHue) || (hue > maxHue))
              || ((sat >= minSat) && (sat <= maxSat))
              || ((bri < minBri) || (bri > maxBri))) fillMask[j] = fill;
          else fillMask[j] = keep;
        }
      }

      ip.fill(fillMask);

      if (threshold.getState()) {
        ip.invert();
        for (int j = 0; j < numPixels; j++) {
          if (fillMask[j] == fill) fillMask[j] = keep;
          else fillMask[j] = fill;
        }
        ip.fill(fillMask);
        ip.invert();
      }
    }