Beispiel #1
0
  /**
   * Calculate the Rand index between some 2D original labels and the corresponding proposed labels.
   * Both image are binarized. We follow the definition of Rand index as described by William M.
   * Rand \cite{Rand71}.
   *
   * <p>BibTeX:
   *
   * <pre>
   * &#64;article{Rand71,
   *   author    = {William M. Rand},
   *   title     = {Objective criteria for the evaluation of clustering methods},
   *   journal   = {Journal of the American Statistical Association},
   *   year      = {1971},
   *   volume    = {66},
   *   number    = {336},
   *   pages     = {846--850},
   *   doi       = {10.2307/2284239)
   * }
   * </pre>
   *
   * @param label 2D image with the original labels
   * @param proposal 2D image with the proposed labels
   * @param binaryThreshold threshold value to binarize the input images
   * @return rand index value and derived statistics
   */
  public ClassificationStatistics randIndexStats(
      ImageProcessor label, ImageProcessor proposal, double binaryThreshold) {
    // Binarize inputs
    ByteProcessor binaryLabel = new ByteProcessor(label.getWidth(), label.getHeight());
    ByteProcessor binaryProposal = new ByteProcessor(label.getWidth(), label.getHeight());

    for (int x = 0; x < label.getWidth(); x++)
      for (int y = 0; y < label.getHeight(); y++) {
        binaryLabel.set(x, y, label.getPixelValue(x, y) > binaryThreshold ? 255 : 0);
        binaryProposal.set(x, y, proposal.getPixelValue(x, y) > binaryThreshold ? 255 : 0);
      }

    // Find components
    ShortProcessor components1 =
        (ShortProcessor)
            Utils.connectedComponents(new ImagePlus("binary labels", binaryLabel), 4)
                .allRegions
                .getProcessor();

    ShortProcessor components2 =
        (ShortProcessor)
            Utils.connectedComponents(new ImagePlus("proposal labels", binaryProposal), 4)
                .allRegions
                .getProcessor();

    return getRandIndexStats(components1, components2);
  }
Beispiel #2
0
  public void run(String arg) {
    int[] wList = WindowManager.getIDList();
    if (wList == null) {
      IJ.error("No images are open.");
      return;
    }

    double thalf = 0.5;
    boolean keep;

    GenericDialog gd = new GenericDialog("Bleach correction");

    gd.addNumericField("t½:", thalf, 1);
    gd.addCheckbox("Keep source stack:", true);
    gd.showDialog();
    if (gd.wasCanceled()) return;

    long start = System.currentTimeMillis();
    thalf = gd.getNextNumber();
    keep = gd.getNextBoolean();
    if (keep) IJ.run("Duplicate...", "title='Bleach corrected' duplicate");
    ImagePlus imp1 = WindowManager.getCurrentImage();
    int d1 = imp1.getStackSize();
    double v1, v2;
    int width = imp1.getWidth();
    int height = imp1.getHeight();
    ImageProcessor ip1, ip2, ip3;

    int slices = imp1.getStackSize();
    ImageStack stack1 = imp1.getStack();
    ImageStack stack2 = imp1.getStack();
    int currentSlice = imp1.getCurrentSlice();

    for (int n = 1; n <= slices; n++) {
      ip1 = stack1.getProcessor(n);
      ip3 = stack1.getProcessor(1);
      ip2 = stack2.getProcessor(n);
      for (int x = 0; x < width; x++) {
        for (int y = 0; y < height; y++) {
          v1 = ip1.getPixelValue(x, y);
          v2 = ip3.getPixelValue(x, y);

          // =B8/(EXP(-C$7*A8))
          v1 = (v1 / Math.exp(-n * thalf));
          ip2.putPixelValue(x, y, v1);
        }
      }
      IJ.showProgress((double) n / slices);
      IJ.showStatus(n + "/" + slices);
    }

    // stack2.show();
    imp1.updateAndDraw();
  }
Beispiel #3
0
 // get a pixel value; returns Float.NaN if outside the field.
 private float getPixel(int x, int y) {
   if (x < 0 || x >= width || y < 0 || y >= height) return Float.NaN;
   if (bpixels != null) return bpixels[y * width + x] & 0xff;
   else if (spixels != null) return spixels[y * width + x] & 0xffff;
   else if (fpixels != null) return fpixels[y * width + x];
   else if (exactPixelValue) // RGB for exact match
   return cpixels[y * width + x] & 0xffffff; // don't care for upper byte
   else // gray value of RGB
   return ip.getPixelValue(x, y);
 }
Beispiel #4
0
  void avg_col(ImageProcessor ip) {

    float sum; // sum of pixel values column
    float avg; // average pixel value of a column
    float[] sliceavgs = new float[width]; // means across columns of one slice
    int sliceNumber = ip.getSliceNumber() - 1; // slice number

    for (int x = 0; x < width; x += 1) {
      sum = 0; // reset with each column
      avg = 0; // reset with each column

      for (int y = 0; y < height; y += 1) {
        sum = sum + ip.getPixelValue(x, y);
      }
      avg = sum / height;
      sliceavgs[x] = avg; // building array of means
    }

    this.slicecols[sliceNumber] = sliceavgs; // add this slice's means to array
  }
  public OpenCLVolumeRenderer(ImagePlus image) {
    super(
        new byte[image.getWidth() * image.getHeight() * image.getStackSize() / image.getNFrames()],
        image.getWidth(),
        image.getHeight(),
        image.getStackSize() / image.getNFrames(),
        false);

    transferFunc =
        new float[] {
          0.0f, 0.0f, 0.0f, 0.0f,
          1.0f, 1.0f, 1.0f, 1.0f,
          0.0f, 0.0f, 0.0f, 0.0f,
        };

    minmax = ImageUtil.minAndMaxOfImageProcessor(image);
    minmax[1] *= 1.05;

    if (image.getNFrames() == 1) multiFrameMode = false;
    else multiFrameMode = true;

    nFrames = image.getNFrames();
    // Create the image array
    clImages = new ArrayList<CLImage3d<IntBuffer>>(image.getNFrames());
    // rewrite imagePlus container into nFrames single byte volumes
    volumes = new byte[image.getNFrames()][volumeSize[2] * volumeSize[1] * volumeSize[0]];
    for (int n = 0; n < image.getNFrames(); n++) {
      for (int k = 0; k < volumeSize[2]; k++) {
        ImageProcessor img = image.getStack().getProcessor((n * volumeSize[2]) + k + 1);
        for (int i = 0; i < image.getWidth(); i++) {
          for (int j = 0; j < image.getHeight(); j++) {
            setVoxel(volumes[n], i, j, k, img.getPixelValue(i, j));
          }
        }
      }
    }

    initialized = false;
    // System.out.println("init");
    frame.setTitle("Volume: " + image.getTitle());
  }
Beispiel #6
0
  /**
   * Returns image in units of adjusted count-rate (Klimpki et al., 2016), i.e. compensated for
   * laser power and dwell time. If requested, non-linearities in laser-power compensation are
   * considered.
   *
   * @param img Input image
   * @param dwell_time Pixel dwell time, unit will match rate (i.e. us --> MHz)
   * @param laser_power Percentage laser power,
   * @param laser_exponent Exponent of laser-power compensation non-linearity, referred to 10%
   *     percentage laser power. Equals 0.0 for perfect linearity
   * @return
   */
  public static ImagePlus getAdjustedCountrateImage(
      ImagePlus img, double dwell_time, double laser_power, double laser_exponent) {

    boolean silent = (IJ.getInstance() == null);

    int nX = img.getWidth();
    int nY = img.getHeight();
    int nSlices = img.getNSlices();
    int nFrames = img.getNFrames();
    int nChannels = img.getNChannels();

    ImageStack resIms = new ImageStack(nX, nY);
    FloatProcessor fp;
    ImageProcessor ip1;

    int total = nSlices * nFrames * nChannels;
    double prog = 0;

    if (silent) {
      System.out.println("DWELL-TIME/LASER-POWER COMPENSATION");
    } else {
      IJ.showStatus("DWELL-TIME/LASER-POWER COMPENSATION");
    }

    for (int i = 0; i < nChannels; i++) {
      for (int j = 0; j < nFrames; j++) {

        for (int k = 0; k < nSlices; k++) {
          if (silent) {
            FNTDprogress.updateProgress(prog / total);
          } else {
            IJ.showProgress(prog / total);
          }

          prog++;

          img.setPosition(i + 1, k + 1, j + 1);
          ip1 = img.getProcessor();
          fp = new FloatProcessor(nX, nY);

          double laser_factor = Math.pow(laser_power / 0.10, laser_exponent);

          for (int m = 0; m < nX; m++) {
            for (int n = 0; n < nY; n++) {
              fp.putPixelValue(
                  m, n, ip1.getPixelValue(m, n) * laser_factor / (laser_power * dwell_time));
            }
          }
          resIms.addSlice(fp);
        }
      }
    }
    FNTDprogress.updateProgress(1);
    System.out.println("");

    ImagePlus resImp = new ImagePlus(img.getTitle() + " (adj. count-rate)", resIms);
    if (resIms.getSize() > 1) {
      resImp =
          HyperStackConverter.toHyperStack(
              resImp, nChannels, nSlices, nFrames, "xyztc", "grayscale");
    }
    return (resImp);
  }
Beispiel #7
0
  /**
   * Returns saturation corrected version of the input image. A simple, one-parametric
   * exponential-saturation function with characteristic saturation rate is used (see Greilich et
   * al., 2013; Klimpki et al., 2016)
   *
   * @param img Input image
   * @param dwell_time Pixel dwell time, unit has to match saturation_rate
   * @param saturation_rate Characteristic saturation rate, unit has to match dwell_time
   * @return
   */
  public static ImagePlus saturationCorrection(
      ImagePlus img, double dwell_time, double saturation_rate) {

    boolean silent = (IJ.getInstance() == null);

    int nX = img.getWidth();
    int nY = img.getHeight();
    int nSlices = img.getNSlices();
    int nFrames = img.getNFrames();
    int nChannels = img.getNChannels();

    ImageStack resIms = new ImageStack(nX, nY);
    FloatProcessor fp;
    ImageProcessor ip1;

    int total = nSlices * nFrames * nChannels;
    double prog = 0;

    if (silent) {
      System.out.println("SATURATION CORRECTION");
    } else {
      IJ.showStatus("SATURATION CORRECTION");
    }

    for (int i = 0; i < nChannels; i++) {
      for (int j = 0; j < nFrames; j++) {
        for (int k = 0; k < nSlices; k++) {
          if (silent) {
            FNTDprogress.updateProgress(prog / total);
          } else {
            IJ.showProgress(prog / total);
          }

          prog++;

          img.setPosition(i + 1, k + 1, j + 1);
          ip1 = img.getProcessor();
          fp = new FloatProcessor(nX, nY);

          double count_rate;

          for (int m = 0; m < nX; m++) {
            for (int n = 0; n < nY; n++) {
              count_rate = ip1.getPixelValue(m, n);
              count_rate = 1.0 - count_rate / (dwell_time * saturation_rate);
              count_rate = -1.0 * saturation_rate * dwell_time * log(count_rate);
              fp.putPixelValue(m, n, count_rate);
            }
          }
          resIms.addSlice(fp);
        }
      }
    }
    FNTDprogress.updateProgress(1);
    System.out.println("");

    ImagePlus resImp = new ImagePlus(img.getTitle() + " (sat. corrected)", resIms);
    if (resIms.getSize() > 1) {
      resImp =
          HyperStackConverter.toHyperStack(
              resImp, nChannels, nSlices, nFrames, "xyztc", "grayscale");
    }
    return (resImp);
  }
Beispiel #8
0
  public static ImagePlus subtract(ImagePlus a, ImagePlus b) {

    boolean silent = (IJ.getInstance() == null);

    int nX = a.getWidth();
    int nY = a.getHeight();
    int nSlices = a.getNSlices();
    int nFrames = a.getNFrames();
    int nChannels = a.getNChannels();

    if ((nX != b.getWidth())
        || (nY != b.getHeight())
        || (nSlices != b.getNSlices())
        || (nFrames != b.getNFrames())
        || (nChannels != b.getNChannels())) {
      if (silent) {
        System.out.println("Subtract: image dimensions do not match, return nothing.");
      } else {
        IJ.showMessage("Subtract: image dimensions do not match, return nothing.");
      }
    }

    ImageStack resIms = new ImageStack(nX, nY);
    FloatProcessor fp;
    ImageProcessor ip1, ip2;

    int total = nSlices * nFrames * nChannels;
    double prog = 0;

    if (silent) {
      System.out.println("SUBSTRACTING BACKGROUND");
    } else {
      IJ.showStatus("SUBSTRACTING BACKGROUND");
    }

    for (int i = 0; i < nChannels; i++) {
      for (int j = 0; j < nFrames; j++) {

        for (int k = 0; k < nSlices; k++) {
          if (silent) {
            FNTDprogress.updateProgress(prog / total);
          } else {
            IJ.showProgress(prog / total);
          }

          prog++;

          a.setPosition(i + 1, k + 1, j + 1);
          b.setPosition(i + 1, k + 1, j + 1);
          ip1 = a.getProcessor();
          ip2 = b.getProcessor();
          fp = new FloatProcessor(nX, nY);

          for (int m = 0; m < nX; m++) {
            for (int n = 0; n < nY; n++) {
              fp.putPixelValue(m, n, ip1.getPixelValue(m, n) - ip2.getPixelValue(m, n));
            }
          }
          resIms.addSlice(fp);
        }
      }
    }
    FNTDprogress.updateProgress(1);
    System.out.println("");

    ImagePlus resImp = new ImagePlus("Result of" + a.getTitle() + "-" + b.getTitle(), resIms);
    if (resIms.getSize() > 1) {
      resImp =
          HyperStackConverter.toHyperStack(
              resImp, nChannels, nSlices, nFrames, "xyztc", "grayscale");
    }
    return (resImp);
  }
Beispiel #9
0
	public void run(String arg) {

  int[] wList = WindowManager.getIDList();
        if (wList==null) {
            IJ.error("No images are open.");
            return;
        }
	double kernel=3;
	double kernelsum = 0;
	double kernelvarsum =0;
	double kernalvar = 0;
	double sigmawidth = 2;
	int kernelindex, minpixnumber;
	String[] kernelsize =  { "3�,"5�, "7�, "9�};

	GenericDialog gd = new GenericDialog("Sigma Filter");
	gd.addChoice("Kernel size", kernelsize, kernelsize[0]);
	gd.addNumericField("Sigma width",sigmawidth , 2);
	gd.addNumericField("Minimum number of pixels", 1, 0);

	gd.addCheckbox("Keep source:",true);
	gd.addCheckbox("Do all stack:",true);
	gd.addCheckbox("Modified Lee's FIlter:",true);
	       	
	gd.showDialog();
       	if (gd.wasCanceled()) return ;
	kernelindex =  gd.getNextChoiceIndex();
          	sigmawidth = gd.getNextNumber();
          	minpixnumber = ((int)gd.getNextNumber());
          	boolean keep = gd.getNextBoolean();
	boolean doallstack = gd.getNextBoolean();
	boolean modified = gd.getNextBoolean();
	if (kernelindex==0) kernel = 3;
	if (kernelindex==1) kernel = 5;
	if (kernelindex==2) kernel = 7;
	if (kernelindex==3) kernel = 9;
    	long start = System.currentTimeMillis();
	
if (minpixnumber> (kernel*kernel)){
	      IJ.showMessage("Sigma filter", "There must be more pixels in the kernel than+\n" + "the minimum number to be included");
            return;
        }
	double v, midintensity;
	int   x, y, ix, iy;
	double sum = 0;
	double backupsum =0;
	int count = 0;
	int n = 0;
	if (keep) {IJ.run("Select All"); IJ.run("Duplicate...", "title='Sigma filtered' duplicate");}

	int radius = (int)(kernel-1)/2;
	ImagePlus imp = WindowManager.getCurrentImage();
	ImageStack stack1 = imp.getStack();
	int width = imp.getWidth();
	int height = imp.getHeight();
	int nslices = stack1.getSize();
	int cslice = imp.getCurrentSlice();
	double status = width*height*nslices;
	
	ImageProcessor  ip = imp.getProcessor();
	int sstart = 1;
	if (!doallstack) {sstart = cslice; nslices=sstart;status = status/nslices;};

 for (int i=sstart; i<=nslices; i++) {
                imp.setSlice(i);
                    
for (x=radius;x<width+radius;x++)	{
		for (y=radius;y<height+radius;y++)	{
			
			midintensity = ip.getPixelValue(x,y);
			count = 0;
			sum = 0;
			kernelsum =0;
			kernalvar =0;
			kernelvarsum =0;
			backupsum = 0;

		//calculate mean of kernel value
			for (ix=0;ix<kernel;ix++)	{
					for (iy=0;iy<kernel;iy++)	{
							v = ip.getPixelValue(x+ix-radius,y+iy-radius);
							kernelsum = kernelsum+v;
								}
						}
			double sigmacalcmean = (kernelsum/(kernel*kernel));

		//calculate variance of kernel
			for (ix=0;ix<kernel;ix++)	{
					for (iy=0;iy<kernel;iy++)	{
							v = ip.getPixelValue(x+ix-radius,y+iy-radius);
							kernalvar = (v-sigmacalcmean)*(v-sigmacalcmean);
							kernelvarsum = kernelvarsum + kernalvar;
								}
						}
			//double variance = kernelvarsum/kernel;
			double sigmacalcvar = kernelvarsum/((kernel*kernel)-1);

			//calcuate sigma range = sqrt(variance/(mean^2)) � sigmawidth
			double sigmarange  = sigmawidth*(Math.sqrt((sigmacalcvar) /(sigmacalcmean*sigmacalcmean)));
			//calulate sigma top value and bottom value
			double sigmatop = midintensity*(1+sigmarange);
			double sigmabottom = midintensity*(1-sigmarange);
			//calculate mean of values that differ are in sigma range.
			for (ix=0;ix<kernel;ix++)	{
					for (iy=0;iy<kernel;iy++)	{
							v = ip.getPixelValue(x+ix-radius,y+iy-radius);
							if ((v>=sigmabottom)&&(v<=sigmatop)){
								sum = sum+v;
								count = count+1;   }
								backupsum = v+ backupsum;
										}		
						}
//if there are too few pixels in the kernal that are within sigma range, the 
//mean of the entire kernal is taken. My modification of Lee's filter is to exclude the central value 
//from the calculation of the mean as I assume it to be spuriously high or low 
			if (!(count>(minpixnumber)))
				{sum = (backupsum-midintensity);
				count = (int)((kernel*kernel)-1);
				if (!modified)
					{sum = (backupsum);
					count  = (int)(kernel*kernel);}
				}
			
			double val =  (sum/count);
			ip.putPixelValue(x,y, val);
			n = n+1;
	double percentage = (((double)n/status)*100);
			 IJ.showStatus(IJ.d2s(percentage,0) +"% done");		
			
}

	//		IJ.showProgress(i, status);
					}}
			imp.updateAndDraw();
 			IJ.showStatus(IJ.d2s((System.currentTimeMillis()-start)/1000.0, 2)+" seconds");        }      
  /**
   * 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;
  }