@Override public ImageProcessor process(ImageProcessor ip) { BackgroundSubtracter bs = new BackgroundSubtracter(); if (ip instanceof ColorProcessor) { bs.subtractRGBBackround((ColorProcessor)ip, radius); } else { bs.subtractBackround(ip, radius); } return ip; }
BackgroundSubtracter bs = new BackgroundSubtracter(); bs.rollingBallBackground(img.getProcessor(), (double)rollballsize, false, true, false, true, true); img.getProcessor().resetMinAndMax();
float coeff2diag = 1.f/radius; //same for diagonal directions where step is sqrt2 showProgress(0.000001); //start the progress bar (only filter1D will increment it) if (invert) for (int i=0; i<pixels.length; i++) shiftBy = (float)filter3x3(fp, MAXIMUM);//3x3 maximum to remove dust etc. showProgress(0.5); filter3x3(fp, MEAN); //smoothing to remove noise pass++; correctCorners(fp, coeff2, cache, nextPoint); //modify corner data, avoids subtracting corner particles filter1D(fp, X_DIRECTION, coeff2, cache, nextPoint); filter1D(fp, Y_DIRECTION, coeff2, cache, nextPoint); filter1D(fp, X_DIRECTION, coeff2, cache, nextPoint); //redo for better accuracy filter1D(fp, DIAGONAL_1A, coeff2diag, cache, nextPoint); filter1D(fp, DIAGONAL_1B, coeff2diag, cache, nextPoint); filter1D(fp, DIAGONAL_2A, coeff2diag, cache, nextPoint); filter1D(fp, DIAGONAL_2B, coeff2diag, cache, nextPoint); filter1D(fp, DIAGONAL_1A, coeff2diag, cache, nextPoint);//redo for better accuracy filter1D(fp, DIAGONAL_1B, coeff2diag, cache, nextPoint);
/** Background for any image type */ public void run(ImageProcessor ip) { if (isRGB && !separateColors) rollingBallBrightnessBackground((ColorProcessor)ip, radius, createBackground, lightBackground, useParaboloid, doPresmooth, true); else rollingBallBackground(ip, radius, createBackground, lightBackground, useParaboloid, doPresmooth, true); if (previewing && (ip instanceof FloatProcessor || ip instanceof ShortProcessor)) { ip.resetMinAndMax(); } }
/** Create background for a float image by rolling a ball over * the image. */ void rollingBallFloatBackground(FloatProcessor fp, float radius, boolean invert, boolean doPresmooth, RollingBall ball) { float[] pixels = (float[])fp.getPixels(); //this will become the background boolean shrink = ball.shrinkFactor >1; showProgress(0.0); if (invert) for (int i=0; i<pixels.length; i++) pixels[i] = -pixels[i]; if (doPresmooth) filter3x3(fp, MEAN); double[] minmax = Tools.getMinMax(pixels); if (Thread.currentThread().isInterrupted()) return; FloatProcessor smallImage = shrink ? shrinkImage(fp, ball.shrinkFactor) : fp; if (Thread.currentThread().isInterrupted()) return; rollBall(ball, smallImage); if (Thread.currentThread().isInterrupted()) return; showProgress(0.9); if (shrink) enlargeImage(smallImage, fp, ball.shrinkFactor); if (Thread.currentThread().isInterrupted()) return; if (invert) for (int i=0; i<pixels.length; i++) pixels[i] = -pixels[i]; pass++; }
/** Depracated. For compatibility with previous ImageJ versions */ public void subtractBackround(ImageProcessor ip, int ballRadius) { rollingBallBackground(ip, (double)ballRadius, false, lightBackground, false, true, true); }
if (i%50==0) { if (Thread.currentThread().isInterrupted()) return; showProgress(i/(double)nLines); case DIAGONAL_2B: length = Math.min(width, height-i); break; lineSlideParabola(pixels, startPixel, pointInc, length, coeff2, cache, nextPoint, null);
/** Replace the pixels by the mean or maximum in a 3x3 neighborhood. * No snapshot is required (less memory needed than e.g., fp.smooth()). * When used as maximum filter, it returns the average change of the * pixel value by this operation */ double filter3x3(FloatProcessor fp, int type) { int width = fp.getWidth(); int height = fp.getHeight(); double shiftBy = 0; float[] pixels = (float[])fp.getPixels(); for (int y=0; y<height; y++) shiftBy += filter3(pixels, width, y*width, 1, type); for (int x=0; x<width; x++) shiftBy += filter3(pixels, height, x, width, type); return shiftBy/width/height; }
float[] corners = new float[4]; //(0,0); (xmax,0); (ymax,0); (xmax,ymax) float[] correctedEdges = new float[2]; correctedEdges = lineSlideParabola(pixels, 0, 1, width, coeff2, cache, nextPoint, correctedEdges); corners[0] = correctedEdges[0]; corners[1] = correctedEdges[1]; correctedEdges = lineSlideParabola(pixels, (height-1)*width, 1, width, coeff2, cache, nextPoint, correctedEdges); corners[2] = correctedEdges[0]; corners[3] = correctedEdges[1]; correctedEdges = lineSlideParabola(pixels, 0, width, height, coeff2, cache, nextPoint, correctedEdges); corners[0] += correctedEdges[0]; corners[2] += correctedEdges[1]; correctedEdges = lineSlideParabola(pixels, width-1, width, height, coeff2, cache, nextPoint, correctedEdges); corners[1] += correctedEdges[0]; corners[3] += correctedEdges[1]; int diagLength = Math.min(width,height); //length of a 45-degree line from a corner float coeff2diag = 2 * coeff2; correctedEdges = lineSlideParabola(pixels, 0, 1+width, diagLength, coeff2diag, cache, nextPoint, correctedEdges); corners[0] += correctedEdges[0]; correctedEdges = lineSlideParabola(pixels, width-1, -1+width, diagLength, coeff2diag, cache, nextPoint, correctedEdges); corners[1] += correctedEdges[0]; correctedEdges = lineSlideParabola(pixels, (height-1)*width, 1-width, diagLength, coeff2diag, cache, nextPoint, correctedEdges); corners[2] += correctedEdges[0]; correctedEdges = lineSlideParabola(pixels, width*height-1, -1-width, diagLength, coeff2diag, cache, nextPoint, correctedEdges); corners[3] += correctedEdges[0]; if (pixels[0] > corners[0]/3) pixels[0] = corners[0]/3;
int[] xSmallIndices = new int[width]; //index of first point in smallImage float[] xWeights = new float[width]; //weight of this point makeInterpolationArrays(xSmallIndices, xWeights, width, smallWidth, shrinkFactor); int[] ySmallIndices = new int[height]; float[] yWeights = new float[height]; makeInterpolationArrays(ySmallIndices, yWeights, height, smallHeight, shrinkFactor); float[] line0 = new float[width]; float[] line1 = new float[width];
/** Create background for a float image by rolling a ball over * the image. */ void rollingBallFloatBackground(FloatProcessor fp, float radius, boolean invert, boolean doPresmooth, RollingBall ball) { float[] pixels = (float[])fp.getPixels(); //this will become the background boolean shrink = ball.shrinkFactor >1; showProgress(0.0); if (invert) for (int i=0; i<pixels.length; i++) pixels[i] = -pixels[i]; if (doPresmooth) filter3x3(fp, MEAN); double[] minmax = Tools.getMinMax(pixels); if (Thread.currentThread().isInterrupted()) return; FloatProcessor smallImage = shrink ? shrinkImage(fp, ball.shrinkFactor) : fp; if (Thread.currentThread().isInterrupted()) return; rollBall(ball, smallImage); if (Thread.currentThread().isInterrupted()) return; showProgress(0.9); if (shrink) enlargeImage(smallImage, fp, ball.shrinkFactor); if (Thread.currentThread().isInterrupted()) return; if (invert) for (int i=0; i<pixels.length; i++) pixels[i] = -pixels[i]; pass++; }
/** Background for any image type */ public void run(ImageProcessor ip) { if (isRGB && !separateColors) rollingBallBrightnessBackground((ColorProcessor)ip, radius, createBackground, lightBackground, useParaboloid, doPresmooth, true); else rollingBallBackground(ip, radius, createBackground, lightBackground, useParaboloid, doPresmooth, true); if (previewing && (ip instanceof FloatProcessor || ip instanceof ShortProcessor)) { ip.resetMinAndMax(); } }
/** Depracated. For compatibility with previous ImageJ versions */ public void subtractBackround(ImageProcessor ip, int ballRadius) { rollingBallBackground(ip, (double)ballRadius, false, lightBackground, false, true, true); }
if (i%50==0) { if (Thread.currentThread().isInterrupted()) return; showProgress(i/(double)nLines); case DIAGONAL_2B: length = Math.min(width, height-i); break; lineSlideParabola(pixels, startPixel, pointInc, length, coeff2, cache, nextPoint, null);
/** Replace the pixels by the mean or maximum in a 3x3 neighborhood. * No snapshot is required (less memory needed than e.g., fp.smooth()). * When used as maximum filter, it returns the average change of the * pixel value by this operation */ double filter3x3(FloatProcessor fp, int type) { int width = fp.getWidth(); int height = fp.getHeight(); double shiftBy = 0; float[] pixels = (float[])fp.getPixels(); for (int y=0; y<height; y++) shiftBy += filter3(pixels, width, y*width, 1, type); for (int x=0; x<width; x++) shiftBy += filter3(pixels, height, x, width, type); return shiftBy/width/height; }
float[] corners = new float[4]; //(0,0); (xmax,0); (ymax,0); (xmax,ymax) float[] correctedEdges = new float[2]; correctedEdges = lineSlideParabola(pixels, 0, 1, width, coeff2, cache, nextPoint, correctedEdges); corners[0] = correctedEdges[0]; corners[1] = correctedEdges[1]; correctedEdges = lineSlideParabola(pixels, (height-1)*width, 1, width, coeff2, cache, nextPoint, correctedEdges); corners[2] = correctedEdges[0]; corners[3] = correctedEdges[1]; correctedEdges = lineSlideParabola(pixels, 0, width, height, coeff2, cache, nextPoint, correctedEdges); corners[0] += correctedEdges[0]; corners[2] += correctedEdges[1]; correctedEdges = lineSlideParabola(pixels, width-1, width, height, coeff2, cache, nextPoint, correctedEdges); corners[1] += correctedEdges[0]; corners[3] += correctedEdges[1]; int diagLength = Math.min(width,height); //length of a 45-degree line from a corner float coeff2diag = 2 * coeff2; correctedEdges = lineSlideParabola(pixels, 0, 1+width, diagLength, coeff2diag, cache, nextPoint, correctedEdges); corners[0] += correctedEdges[0]; correctedEdges = lineSlideParabola(pixels, width-1, -1+width, diagLength, coeff2diag, cache, nextPoint, correctedEdges); corners[1] += correctedEdges[0]; correctedEdges = lineSlideParabola(pixels, (height-1)*width, 1-width, diagLength, coeff2diag, cache, nextPoint, correctedEdges); corners[2] += correctedEdges[0]; correctedEdges = lineSlideParabola(pixels, width*height-1, -1-width, diagLength, coeff2diag, cache, nextPoint, correctedEdges); corners[3] += correctedEdges[0]; if (pixels[0] > corners[0]/3) pixels[0] = corners[0]/3;
int[] xSmallIndices = new int[width]; //index of first point in smallImage float[] xWeights = new float[width]; //weight of this point makeInterpolationArrays(xSmallIndices, xWeights, width, smallWidth, shrinkFactor); int[] ySmallIndices = new int[height]; float[] yWeights = new float[height]; makeInterpolationArrays(ySmallIndices, yWeights, height, smallHeight, shrinkFactor); float[] line0 = new float[width]; float[] line1 = new float[width];
float coeff2diag = 1.f/radius; //same for diagonal directions where step is sqrt2 showProgress(0.000001); //start the progress bar (only filter1D will increment it) if (invert) for (int i=0; i<pixels.length; i++) shiftBy = (float)filter3x3(fp, MAXIMUM);//3x3 maximum to remove dust etc. showProgress(0.5); filter3x3(fp, MEAN); //smoothing to remove noise pass++; correctCorners(fp, coeff2, cache, nextPoint); //modify corner data, avoids subtracting corner particles filter1D(fp, X_DIRECTION, coeff2, cache, nextPoint); filter1D(fp, Y_DIRECTION, coeff2, cache, nextPoint); filter1D(fp, X_DIRECTION, coeff2, cache, nextPoint); //redo for better accuracy filter1D(fp, DIAGONAL_1A, coeff2diag, cache, nextPoint); filter1D(fp, DIAGONAL_1B, coeff2diag, cache, nextPoint); filter1D(fp, DIAGONAL_2A, coeff2diag, cache, nextPoint); filter1D(fp, DIAGONAL_2B, coeff2diag, cache, nextPoint); filter1D(fp, DIAGONAL_1A, coeff2diag, cache, nextPoint);//redo for better accuracy filter1D(fp, DIAGONAL_1B, coeff2diag, cache, nextPoint);
/** Create or subtract a background, based on the brightness of an RGB image (keeping * the hue of each pixel unchanged) * @param ip The RGB image. On output, it will become the background-subtracted image or * the background (depending on <code>createBackground</code>). * @param radius Radius of the rolling ball creating the background (actually a * paraboloid of rotation with the same curvature) * @param createBackground Whether to create a background, not to subtract it. * @param lightBackground Whether the image has a light background. * @param doPresmooth Whether the image should be smoothened (3x3 mean) before creating * the background. With smoothing, the background will not necessarily * be below the image data. * @param correctCorners Whether the algorithm should try to detect corner particles to avoid * subtracting them as a background. */ public void rollingBallBrightnessBackground(ColorProcessor ip, double radius, boolean createBackground, boolean lightBackground, boolean useParaboloid, boolean doPresmooth, boolean correctCorners) { int width = ip.getWidth(); int height = ip.getHeight(); byte[] H = new byte[width*height]; byte[] S = new byte[width*height]; byte[] B = new byte[width*height]; ip.getHSB(H, S, B); ByteProcessor bp = new ByteProcessor(width, height, B, null); rollingBallBackground(bp, radius, createBackground, lightBackground, useParaboloid, doPresmooth, correctCorners); ip.setHSB(H, S, (byte[])bp.getPixels()); }
/** Create or subtract a background, based on the brightness of an RGB image (keeping * the hue of each pixel unchanged) * @param ip The RGB image. On output, it will become the background-subtracted image or * the background (depending on <code>createBackground</code>). * @param radius Radius of the rolling ball creating the background (actually a * paraboloid of rotation with the same curvature) * @param createBackground Whether to create a background, not to subtract it. * @param lightBackground Whether the image has a light background. * @param doPresmooth Whether the image should be smoothened (3x3 mean) before creating * the background. With smoothing, the background will not necessarily * be below the image data. * @param correctCorners Whether the algorithm should try to detect corner particles to avoid * subtracting them as a background. */ public void rollingBallBrightnessBackground(ColorProcessor ip, double radius, boolean createBackground, boolean lightBackground, boolean useParaboloid, boolean doPresmooth, boolean correctCorners) { int width = ip.getWidth(); int height = ip.getHeight(); byte[] H = new byte[width*height]; byte[] S = new byte[width*height]; byte[] B = new byte[width*height]; ip.getHSB(H, S, B); ByteProcessor bp = new ByteProcessor(width, height, B, null); rollingBallBackground(bp, radius, createBackground, lightBackground, useParaboloid, doPresmooth, correctCorners); ip.setHSB(H, S, (byte[])bp.getPixels()); }