public synchronized void adjustmentValueChanged(AdjustmentEvent e) {

      if (!checkImage()) {
        IJ.beep();
        IJ.showStatus("No Image");
        return;
      }

      if (e.getSource() == minSlider) {
        adjustMinHue((int) minSlider.getValue());
      } else if (e.getSource() == maxSlider) {
        adjustMaxHue((int) maxSlider.getValue());
      } else if (e.getSource() == minSlider2) {
        adjustMinSat((int) minSlider2.getValue());
      } else if (e.getSource() == maxSlider2) {
        adjustMaxSat((int) maxSlider2.getValue());
      } else if (e.getSource() == minSlider3) {
        adjustMinBri((int) minSlider3.getValue());
      } else if (e.getSource() == maxSlider3) {
        adjustMaxBri((int) maxSlider3.getValue());
      }
      originalB.setEnabled(true);
      updateLabels();
      updatePlot();
      notify();
    }
    // GL
    public synchronized void itemStateChanged(ItemEvent e) {
      if (e.getSource() == hsb) isRGB = false;
      if (e.getSource() == rgb) isRGB = true;

      if (e.getSource() == hsb || e.getSource() == rgb) {
        flag = true;
        originalB.setEnabled(false);
        filteredB.setEnabled(false);

        minHue = minSat = minBri = 0;
        maxHue = maxSat = maxBri = 255;

        bandPassH.setState(true);
        bandPassS.setState(true);
        bandPassB.setState(true);
      }
      reset(imp, ip);
      ip = setup(imp);
      apply(imp, ip);
      updateNames();
      notify();
    }
    public void actionPerformed(ActionEvent e) {
      Button b = (Button) e.getSource();
      if (b == null) return;

      boolean imageThere = checkImage();

      if (imageThere) {
        if (b == originalB) {
          reset(imp, ip);
          filteredB.setEnabled(true);
        } else if (b == filteredB) {
          apply(imp, ip);
        } else if (b == sampleB) {
          reset(imp, ip);
          sample();
          apply(imp, ip);
        } else if (b == stackB) {
          applyStack();
        } else if (b == helpB) {
          IJ.showMessage(
              "Help",
              "Threshold Colour  v1.0\n \n"
                  + "Modification of Bob Dougherty's BandPass2 plugin by G.Landini to\n"
                  + "threshold 24 bit RGB images based on Hue, Saturation and Brightness\n"
                  + "or Red, Green and Blue components.\n \n"
                  + "Pass: Band-pass filter (anything within range is displayed).\n \n"
                  + "Stop: Band-reject filter (anything within range is NOT displayed).\n \n"
                  + "Original: Shows the original image and updates the buffer when\n"
                  + " switching to another image.\n \n"
                  + "Filtered: Shows the filtered image.\n \n"
                  + "Stack: Processes the rest of the slices in the stack (if any)\n"
                  + " using the current settings.\n \n"
                  + "Threshold: Shows the object/background in the foreground and\n"
                  + " background colours selected in the ImageJ toolbar.\n \n"
                  + "Invert: Swaps the fore/background colours.\n \n"
                  + "Sample: (experimental) Sets the ranges of the filters based on the\n"
                  + " pixel value componentd in a rectangular, user-defined, ROI.\n \n"
                  + "HSB RGB: Selects HSB or RGB space and resets all the filters.\n \n"
                  + "Note that the \'thresholded\' image is RGB, not 8 bit grey.");
        }
        updatePlot();
        updateLabels();
        imp.updateAndDraw();
      } else {
        IJ.beep();
        IJ.showStatus("No Image");
      }
      notify();
    }
    public BandAdjuster() {

      super("Threshold Colour");
      if (instance != null) {
        instance.toFront();
        return;
      }
      imp = WindowManager.getCurrentImage();
      if (imp == null) {
        IJ.beep();
        IJ.showStatus("No image");
        return;
      }
      IJ.run("Select None");
      thread = new Thread(this, "BandAdjuster");
      WindowManager.addWindow(this);
      instance = this;
      IJ.register(PasteController.class);

      ij = IJ.getInstance();
      Font font = new Font("SansSerif", Font.PLAIN, 10);
      GridBagLayout gridbag = new GridBagLayout();
      GridBagConstraints c = new GridBagConstraints();
      setLayout(gridbag);

      int y = 0;
      c.gridx = 0;
      c.gridy = y;
      c.gridwidth = 1;
      c.weightx = 0;
      c.insets = new Insets(5, 0, 0, 0);
      labelh = new Label("Hue", Label.CENTER);
      add(labelh, c);

      c.gridx = 1;
      c.gridy = y++;
      c.gridwidth = 1;
      c.weightx = 0;
      c.insets = new Insets(7, 0, 0, 0);
      labelf = new Label("Filter type", Label.RIGHT);
      add(labelf, c);

      // plot
      c.gridx = 0;
      c.gridy = y;
      c.gridwidth = 1;
      c.fill = c.BOTH;
      c.anchor = c.CENTER;
      c.insets = new Insets(0, 5, 0, 0);
      add(plot, c);

      // checkboxes
      panelh = new Panel();
      filterTypeH = new CheckboxGroup();
      bandPassH = new Checkbox("Pass");
      bandPassH.setCheckboxGroup(filterTypeH);
      bandPassH.addItemListener(this);
      panelh.add(bandPassH);
      bandStopH = new Checkbox("Stop");
      bandStopH.setCheckboxGroup(filterTypeH);
      bandStopH.addItemListener(this);
      panelh.add(bandStopH);
      bandPassH.setState(true);
      c.gridx = 1;
      c.gridy = y++;
      c.gridwidth = 2;
      c.insets = new Insets(5, 0, 0, 0);
      add(panelh, c);

      // minHue slider
      minSlider = new Scrollbar(Scrollbar.HORIZONTAL, 0, 1, 0, sliderRange);
      c.gridx = 0;
      c.gridy = y++;
      c.gridwidth = 1;
      c.weightx = IJ.isMacintosh() ? 90 : 100;
      c.fill = c.HORIZONTAL;
      c.insets = new Insets(5, 5, 0, 0);

      add(minSlider, c);
      minSlider.addAdjustmentListener(this);
      minSlider.setUnitIncrement(1);

      // minHue slider label
      c.gridx = 1;
      c.gridwidth = 1;
      c.weightx = IJ.isMacintosh() ? 10 : 0;
      c.insets = new Insets(5, 0, 0, 0);
      label1 = new Label("       ", Label.LEFT);
      label1.setFont(font);
      add(label1, c);

      // maxHue sliderHue
      maxSlider = new Scrollbar(Scrollbar.HORIZONTAL, 0, 1, 0, sliderRange);
      c.gridx = 0;
      c.gridy = y;
      c.gridwidth = 1;
      c.weightx = 100;
      c.insets = new Insets(5, 5, 0, 0);
      add(maxSlider, c);
      maxSlider.addAdjustmentListener(this);
      maxSlider.setUnitIncrement(1);

      // maxHue slider label
      c.gridx = 1;
      c.gridwidth = 1;
      c.gridy = y++;
      c.weightx = 0;
      c.insets = new Insets(5, 0, 0, 0);
      label2 = new Label("       ", Label.LEFT);
      label2.setFont(font);
      add(label2, c);

      // =====
      c.gridx = 0;
      c.gridy = y++;
      c.gridwidth = 1;
      c.weightx = 0;
      c.insets = new Insets(10, 0, 0, 0);
      labels = new Label("Saturation", Label.CENTER);
      add(labels, c);

      // plot
      c.gridx = 0;
      c.gridy = y;
      c.gridwidth = 1;
      c.fill = c.BOTH;
      c.anchor = c.CENTER;
      c.insets = new Insets(0, 5, 0, 0);
      add(splot, c);

      // checkboxes
      panels = new Panel();
      filterTypeS = new CheckboxGroup();
      bandPassS = new Checkbox("Pass");
      bandPassS.setCheckboxGroup(filterTypeS);
      bandPassS.addItemListener(this);
      panels.add(bandPassS);
      bandStopS = new Checkbox("Stop");
      bandStopS.setCheckboxGroup(filterTypeS);
      bandStopS.addItemListener(this);
      panels.add(bandStopS);
      bandPassS.setState(true);
      c.gridx = 1;
      c.gridy = y++;
      c.gridwidth = 2;
      c.insets = new Insets(5, 0, 0, 0);
      add(panels, c);

      // minSat slider
      minSlider2 = new Scrollbar(Scrollbar.HORIZONTAL, 0, 1, 0, sliderRange);
      c.gridx = 0;
      c.gridy = y++;
      c.gridwidth = 1;
      c.weightx = IJ.isMacintosh() ? 90 : 100;
      c.fill = c.HORIZONTAL;
      c.insets = new Insets(5, 5, 0, 0);
      add(minSlider2, c);
      minSlider2.addAdjustmentListener(this);
      minSlider2.setUnitIncrement(1);

      // minSat slider label
      c.gridx = 1;
      c.gridwidth = 1;
      c.weightx = IJ.isMacintosh() ? 10 : 0;
      c.insets = new Insets(5, 0, 0, 0);
      label3 = new Label("       ", Label.LEFT);
      label3.setFont(font);
      add(label3, c);

      // maxSat slider
      maxSlider2 = new Scrollbar(Scrollbar.HORIZONTAL, 0, 1, 0, sliderRange);
      c.gridx = 0;
      c.gridy = y++;
      c.gridwidth = 1;
      c.weightx = 100;
      c.insets = new Insets(5, 5, 0, 0);
      add(maxSlider2, c);
      maxSlider2.addAdjustmentListener(this);
      maxSlider2.setUnitIncrement(1);

      // maxSat slider label
      c.gridx = 1;
      c.gridwidth = 1;
      c.weightx = 0;
      c.insets = new Insets(5, 0, 0, 0);
      label4 = new Label("       ", Label.LEFT);
      label4.setFont(font);
      add(label4, c);

      // =====
      c.gridx = 0;
      c.gridwidth = 1;
      c.gridy = y++;
      c.weightx = 0;
      c.insets = new Insets(10, 0, 0, 0);
      labelb = new Label("Brightness", Label.CENTER);
      add(labelb, c);

      c.gridx = 0;
      c.gridwidth = 1;
      c.gridy = y;
      c.fill = c.BOTH;
      c.anchor = c.CENTER;
      c.insets = new Insets(0, 5, 0, 0);
      add(bplot, c);

      // checkboxes
      panelb = new Panel();
      filterTypeB = new CheckboxGroup();
      bandPassB = new Checkbox("Pass");
      bandPassB.setCheckboxGroup(filterTypeB);
      bandPassB.addItemListener(this);
      panelb.add(bandPassB);
      bandStopB = new Checkbox("Stop");
      bandStopB.setCheckboxGroup(filterTypeB);
      bandStopB.addItemListener(this);
      panelb.add(bandStopB);
      bandPassB.setState(true);
      c.gridx = 1;
      c.gridy = y++;
      c.gridwidth = 2;
      c.insets = new Insets(5, 0, 0, 0);
      add(panelb, c);

      // minBri slider
      minSlider3 = new Scrollbar(Scrollbar.HORIZONTAL, 0, 1, 0, sliderRange);
      c.gridx = 0;
      c.gridy = y++;
      c.gridwidth = 1;
      c.weightx = IJ.isMacintosh() ? 90 : 100;
      c.fill = c.HORIZONTAL;
      c.insets = new Insets(5, 5, 0, 0);
      add(minSlider3, c);
      minSlider3.addAdjustmentListener(this);
      minSlider3.setUnitIncrement(1);

      // minBri slider label
      c.gridx = 1;
      c.gridwidth = 1;
      c.weightx = IJ.isMacintosh() ? 10 : 0;
      c.insets = new Insets(5, 0, 0, 0);
      label5 = new Label("       ", Label.LEFT);
      label5.setFont(font);
      add(label5, c);

      // maxBri slider
      maxSlider3 = new Scrollbar(Scrollbar.HORIZONTAL, 0, 1, 0, sliderRange);
      c.gridx = 0;
      c.gridy = y++;
      c.gridwidth = 1;
      c.weightx = 100;
      c.insets = new Insets(5, 5, 0, 0);
      add(maxSlider3, c);
      maxSlider3.addAdjustmentListener(this);
      maxSlider3.setUnitIncrement(1);

      // maxBri slider label
      c.gridx = 1;
      c.gridwidth = 1;
      c.weightx = 0;
      c.insets = new Insets(5, 0, 0, 0);
      label6 = new Label("       ", Label.LEFT);
      label6.setFont(font);
      add(label6, c);

      // =====
      panelt = new Panel();
      threshold = new Checkbox("Threshold");
      threshold.addItemListener(this);
      panelt.add(threshold);

      invert = new Checkbox("Invert");
      invert.addItemListener(this);
      panelt.add(invert);

      c.gridx = 0;
      c.gridy = y++;
      c.gridwidth = 2;
      c.insets = new Insets(0, 0, 0, 0);
      add(panelt, c);

      // buttons
      panel = new Panel();
      // panel.setLayout(new GridLayout(2, 2, 0, 0));
      originalB = new Button("Original");
      originalB.setEnabled(false);
      originalB.addActionListener(this);
      originalB.addKeyListener(ij);
      panel.add(originalB);

      filteredB = new Button("Filtered");
      filteredB.setEnabled(false);
      filteredB.addActionListener(this);
      filteredB.addKeyListener(ij);
      panel.add(filteredB);

      stackB = new Button("Stack");
      stackB.addActionListener(this);
      stackB.addKeyListener(ij);
      panel.add(stackB);

      helpB = new Button("Help");
      helpB.addActionListener(this);
      helpB.addKeyListener(ij);
      panel.add(helpB);

      c.gridx = 0;
      c.gridy = y++;
      c.gridwidth = 2;
      c.insets = new Insets(0, 0, 0, 0);
      add(panel, c);

      panelMode = new Panel();

      sampleB = new Button("Sample");
      sampleB.addActionListener(this);
      sampleB.addKeyListener(ij);
      panelMode.add(sampleB);

      colourMode = new CheckboxGroup();
      hsb = new Checkbox("HSB");
      hsb.setCheckboxGroup(colourMode);
      hsb.addItemListener(this);
      panelMode.add(hsb);
      hsb.setState(true);
      rgb = new Checkbox("RGB");
      rgb.setCheckboxGroup(colourMode);
      rgb.addItemListener(this);
      panelMode.add(rgb);

      c.gridx = 0;
      c.gridy = y++;
      c.gridwidth = 2;
      c.insets = new Insets(0, 0, 0, 0);
      add(panelMode, c);

      addKeyListener(ij); // ImageJ handles keyboard shortcuts
      pack();
      GUI.center(this);
      setVisible(true);

      ip = setup(imp);
      if (ip == null) {
        imp.unlock();
        IJ.beep();
        IJ.showStatus("RGB image cannot be thresholded");
        return;
      }
      thread.start();
    }
    void sample() {
      byte[] hsSource, ssSource, bsSource;
      // ImageProcessor ip2;
      // ip2 = imp.getProcessor();
      Rectangle myroi = ip.getRoi();
      int swidth = myroi.width;
      int sheight = myroi.height;
      int sy = myroi.y;
      int sx = myroi.x;
      if (swidth == width && sheight == height) {
        IJ.showMessage("Select a rectangular ROI");
        IJ.beep();
        return;
      }

      IJ.run("Select None");

      int snumPixels = swidth * sheight;

      hsSource = new byte[snumPixels];
      ssSource = new byte[snumPixels];
      bsSource = new byte[snumPixels];

      int[] pixs = new int[snumPixels];
      int[] bin = new int[256];

      int counter = 0, pi = 0, rangePassH = 0, rangeStopH = 0, rangePassL = 0, rangeStopL = 0, i, j;

      for (i = sy; i < sy + sheight; i++) {
        for (j = sx; j < sx + swidth; j++) {
          pixs[counter++] = ip.getPixel(j, i);
        }
      }

      // Get hsb or rgb from roi.
      ColorProcessor cp2 = new ColorProcessor(swidth, sheight, pixs);

      int iminhue = 256, imaxhue = -1, iminsat = 256, imaxsat = -1, iminbri = 256, imaxbri = -1;
      int iminred = 256, imaxred = -1, imingre = 256, imaxgre = -1, iminblu = 256, imaxblu = -1;

      if (isRGB) cp2.getRGB(hsSource, ssSource, bsSource);
      else cp2.getHSB(hsSource, ssSource, bsSource);

      for (i = 0; i < snumPixels; i++) {
        bin[hsSource[i] & 255] = 1;
        if ((hsSource[i] & 255) > imaxhue) imaxhue = (hsSource[i] & 255);
        if ((hsSource[i] & 255) < iminhue) iminhue = (hsSource[i] & 255);
        if ((ssSource[i] & 255) > imaxsat) imaxsat = (ssSource[i] & 255);
        if ((ssSource[i] & 255) < iminsat) iminsat = (ssSource[i] & 255);
        if ((bsSource[i] & 255) > imaxbri) imaxbri = (bsSource[i] & 255);
        if ((bsSource[i] & 255) < iminbri) iminbri = (bsSource[i] & 255);
        // IJ.showMessage("h:"+minhue+"H:"+maxhue+"s:"+minsat+"S:"+maxsat+"b:"+minbri+"B:"+maxbri);
      }

      if (!isRGB) { // get pass or stop filter whichever has a narrower range
        for (i = 0; i < 256; i++) {
          if (bin[i] > 0) {
            rangePassL = i;
            break;
          }
        }
        for (i = 255; i >= 0; i--) {
          if (bin[i] > 0) {
            rangePassH = i;
            break;
          }
        }
        for (i = 0; i < 256; i++) {
          if (bin[i] == 0) {
            rangeStopL = i;
            break;
          }
        }
        for (i = 255; i >= 0; i--) {
          if (bin[i] == 0) {
            rangeStopH = i;
            break;
          }
        }
        if ((rangePassH - rangePassL) < (rangeStopH - rangeStopL)) {
          bandPassH.setState(true);
          bandStopH.setState(false);
          iminhue = rangePassL;
          imaxhue = rangePassH;
        } else {
          bandPassH.setState(false);
          bandStopH.setState(true);
          iminhue = rangeStopL;
          imaxhue = rangeStopH;
        }
      } else {
        bandPassH.setState(true);
        bandStopH.setState(false);
      }

      adjustMinHue(iminhue);
      minSlider.setValue(iminhue);
      adjustMaxHue(imaxhue);
      maxSlider.setValue(imaxhue);
      adjustMinSat(iminsat);
      minSlider2.setValue(iminsat);
      adjustMaxSat(imaxsat);
      maxSlider2.setValue(imaxsat);
      adjustMinBri(iminbri);
      minSlider3.setValue(iminbri);
      adjustMaxBri(imaxbri);
      maxSlider3.setValue(imaxbri);
      originalB.setEnabled(true);
      // IJ.showStatus("done");
    }