/** * Calculates a 16-bit grayscale Euclidean Distance Map for a binary 8-bit image. Each foreground * (nonzero) pixel in the binary image is assigned a value equal to its distance from the nearest * background (zero) pixel, multiplied by EDM.ONE. For compatibility with previous versions of * ImageJ only. */ public ShortProcessor make16bitEDM(ImageProcessor ip) { FloatProcessor floatEdm = makeFloatEDM(ip, 0, false); floatEdm.setMinAndMax(0, 65535. / ONE); return (ShortProcessor) floatEdm.convertToShort(true); }
/** * Computes the geodesic distance function for each pixel in mask, using the given mask. Mask and * marker should be ImageProcessor the same size and containing float values. The function returns * a new Float processor the same size as the input, with values greater or equal to zero. */ @Override public FloatProcessor geodesicDistanceMap(ImageProcessor marker, ImageProcessor mask) { // size of image width = mask.getWidth(); height = mask.getHeight(); // update mask this.maskProc = mask; // create new empty image, and fill it with black FloatProcessor result = new FloatProcessor(width, height); result.setValue(0); result.fill(); // initialize empty image with either 0 (foreground) or Inf (background) array = result.getFloatArray(); for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { int val = marker.get(i, j) & 0x00ff; array[i][j] = val == 0 ? backgroundValue : 0; } } int iter = 0; do { modif = false; // forward iteration IJ.showStatus("Forward iteration " + iter); forwardIteration(); // backward iteration IJ.showStatus("Backward iteration " + iter); backwardIteration(); // Iterate while pixels have been modified iter++; } while (modif); // Normalize values by the first weight if (this.normalizeMap) { for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { array[i][j] /= this.weights[0]; } } } // Compute max value within the mask float maxVal = 0; for (int i = 0; i < width; i++) { for (int j = 0; j < height; j++) { if (maskProc.getPixel(i, j) != 0) maxVal = Math.max(maxVal, array[i][j]); } } // update and return resulting Image processor result.setFloatArray(array); result.setMinAndMax(0, maxVal); // Forces the display to non-inverted LUT if (result.isInvertedLut()) result.invertLut(); return result; }
/** Called by the PlugInFilterRunner to process the image or one frame of a stack */ public void run(ImageProcessor ip) { if (interrupted) return; int width = ip.getWidth(); int height = ip.getHeight(); int backgroundValue = (processType == VORONOI) ? (background255 ? 0 : (byte) 255) : // Voronoi needs EDM of the background (background255 ? (byte) 255 : 0); // all others do EDM of the foreground if (USES_WATERSHED[processType]) nPasses = 0; // watershed has its own progress bar FloatProcessor floatEdm = makeFloatEDM(ip, backgroundValue, false); ByteProcessor maxIp = null; if (USES_MAX_FINDER[processType]) { if (processType == VORONOI) floatEdm.multiply(-1); // Voronoi starts from minima of EDM int maxOutputType = USES_WATERSHED[processType] ? MaximumFinder.SEGMENTED : MaximumFinder.SINGLE_POINTS; boolean isEDM = processType != VORONOI; maxIp = maxFinder.findMaxima( floatEdm, MAXFINDER_TOLERANCE, ImageProcessor.NO_THRESHOLD, maxOutputType, false, isEDM); if (maxIp == null) { // segmentation cancelled by user? interrupted = true; return; } else if (processType != WATERSHED) { if (processType == VORONOI) floatEdm.multiply(-1); resetMasked(floatEdm, maxIp, processType == VORONOI ? -1 : 0); } } ImageProcessor outIp = null; if (processType == WATERSHED) { if (background255) maxIp.invert(); ip.copyBits(maxIp, 0, 0, Blitter.COPY); ip.setBinaryThreshold(); } else switch (outImageType) { // for all these, output contains the values of the EDM case FLOAT: outIp = floatEdm; break; case SHORT: floatEdm.setMinAndMax(0., 65535.); outIp = floatEdm.convertToShort(true); break; case BYTE: floatEdm.setMinAndMax(0., 255.); outIp = floatEdm.convertToByte(true); break; case BYTE_OVERWRITE: ip.setPixels(0, floatEdm); if (floatEdm.getMax() > 255.) ip.resetMinAndMax(); // otherwise we have max of floatEdm } if (outImageType != BYTE_OVERWRITE) { // new output image if (outStack == null) { outImp = new ImagePlus(TITLE_PREFIX[processType] + imp.getShortTitle(), outIp); } else outStack.setPixels(outIp.getPixels(), pfr.getSliceNumber()); } } // public void run