/** * Creates the Euclidian Distance Map of a (binary) byte image. * * @param ip The input image, not modified; must be a ByteProcessor. * @param backgroundValue Pixels in the input with this value are interpreted as background. Note: * for pixel value 255, write either -1 or (byte)255. * @param edgesAreBackground Whether out-of-image pixels are considered background * @return The EDM, containing the distances to the nearest background pixel. Returns null if the * thread is interrupted. */ public FloatProcessor makeFloatEDM( ImageProcessor ip, int backgroundValue, boolean edgesAreBackground) { int width = ip.getWidth(); int height = ip.getHeight(); FloatProcessor fp = new FloatProcessor(width, height); byte[] bPixels = (byte[]) ip.getPixels(); float[] fPixels = (float[]) fp.getPixels(); final int progressInterval = 100; int nProgressUpdates = height / progressInterval; // how often the progress bar is updated when passing once through y // range double progressAddendum = (nProgressUpdates > 0) ? 0.5 / nProgressUpdates : 0; for (int i = 0; i < width * height; i++) if (bPixels[i] != backgroundValue) fPixels[i] = Float.MAX_VALUE; int[][] pointBufs = new int[2][width]; // two buffers for two passes; low short contains x, high short y int yDist = Integer.MAX_VALUE; // this value is used only if edges are not background // pass 1 & 2: increasing y for (int x = 0; x < width; x++) { pointBufs[0][x] = NO_POINT; pointBufs[1][x] = NO_POINT; } for (int y = 0; y < height; y++) { if (edgesAreBackground) yDist = y + 1; // distance to nearest background point (along y) edmLine(bPixels, fPixels, pointBufs, width, y * width, y, backgroundValue, yDist); if (y % progressInterval == 0) { if (Thread.currentThread().isInterrupted()) return null; addProgress(progressAddendum); } } // pass 3 & 4: decreasing y for (int x = 0; x < width; x++) { pointBufs[0][x] = NO_POINT; pointBufs[1][x] = NO_POINT; } for (int y = height - 1; y >= 0; y--) { if (edgesAreBackground) yDist = height - y; edmLine(bPixels, fPixels, pointBufs, width, y * width, y, backgroundValue, yDist); if (y % progressInterval == 0) { if (Thread.currentThread().isInterrupted()) return null; addProgress(progressAddendum); } } fp.sqrt(); return fp; } // public FloatProcessor makeFloatEDM
void doIterations(ImageProcessor ip, String mode) { if (escapePressed) return; if (!previewing && iterations > 1) IJ.showStatus(arg + "... press ESC to cancel"); for (int i = 0; i < iterations; i++) { if (Thread.currentThread().isInterrupted()) return; if (IJ.escapePressed()) { escapePressed = true; ip.reset(); return; } if (mode.equals("erode")) ((ByteProcessor) ip).erode(count, background); else ((ByteProcessor) ip).dilate(count, background); } }