void createMask(ImagePlus imp) { Roi roi = imp.getRoi(); boolean useInvertingLut = Prefs.useInvertingLut; Prefs.useInvertingLut = false; if (roi == null || !(roi.isArea() || roi.getType() == Roi.POINT)) { createMaskFromThreshold(imp); Prefs.useInvertingLut = useInvertingLut; return; } ImagePlus maskImp = null; Frame frame = WindowManager.getFrame("Mask"); if (frame != null && (frame instanceof ImageWindow)) maskImp = ((ImageWindow) frame).getImagePlus(); if (maskImp == null) { ImageProcessor ip = new ByteProcessor(imp.getWidth(), imp.getHeight()); if (!Prefs.blackBackground) ip.invertLut(); maskImp = new ImagePlus("Mask", ip); maskImp.show(); } ImageProcessor ip = maskImp.getProcessor(); ip.setRoi(roi); ip.setValue(255); ip.fill(ip.getMask()); maskImp.updateAndDraw(); Prefs.useInvertingLut = useInvertingLut; }
public ImageProcessor expandImage(ImageProcessor ipOld, int wNew, int hNew, int xOff, int yOff) { ImageProcessor ipNew = ipOld.createProcessor(wNew, hNew); if (zeroFill) ipNew.setValue(0.0); else ipNew.setColor(Toolbar.getBackgroundColor()); ipNew.fill(); ipNew.insert(ipOld, xOff, yOff); return ipNew; }
boolean eraseOutsideRoi(ImageProcessor ip, Rectangle r, ImageProcessor mask) { int width = ip.getWidth(); int height = ip.getHeight(); ip.setRoi(r); if (excludeEdgeParticles && polygon != null) { ImageStatistics stats = ImageStatistics.getStatistics(ip, MIN_MAX, null); if (fillColor >= stats.min && fillColor <= stats.max) { double replaceColor = level1 - 1.0; if (replaceColor < 0.0 || replaceColor == fillColor) { replaceColor = level2 + 1.0; int maxColor = imageType == BYTE ? 255 : 65535; if (replaceColor > maxColor || replaceColor == fillColor) { IJ.error("Particle Analyzer", "Unable to remove edge particles"); return false; } } for (int y = minY; y < maxY; y++) { for (int x = minX; x < maxX; x++) { int v = ip.getPixel(x, y); if (v == fillColor) ip.putPixel(x, y, (int) replaceColor); } } } } ip.setValue(fillColor); if (mask != null) { mask = mask.duplicate(); mask.invert(); ip.fill(mask); } ip.setRoi(0, 0, r.x, height); ip.fill(); ip.setRoi(r.x, 0, r.width, r.y); ip.fill(); ip.setRoi(r.x, r.y + r.height, r.width, height - (r.y + r.height)); ip.fill(); ip.setRoi(r.x + r.width, 0, width - (r.x + r.width), height); ip.fill(); ip.resetRoi(); // IJ.log("erase: "+fillColor+" "+level1+" "+level2+" "+excludeEdgeParticles); // (new ImagePlus("ip2", ip.duplicate())).show(); return true; }
ImageProcessor expand(ImageProcessor ip, boolean hasEdgePixels) { if (hasEdgePixels) { ImageProcessor ip2 = ip.createProcessor(ip.getWidth() + 2, ip.getHeight() + 2); if (foreground == 0) { ip2.setColor(255); ip2.fill(); } ip2.insert(ip, 1, 1); // new ImagePlus("ip2", ip2).show(); return ip2; } else return ip; }
public ImageStack expandStack(ImageStack stackOld, int wNew, int hNew, int xOff, int yOff) { int nFrames = stackOld.getSize(); ImageProcessor ipOld = stackOld.getProcessor(1); java.awt.Color colorBack = Toolbar.getBackgroundColor(); ImageStack stackNew = new ImageStack(wNew, hNew, stackOld.getColorModel()); ImageProcessor ipNew; for (int i = 1; i <= nFrames; i++) { IJ.showProgress((double) i / nFrames); ipNew = ipOld.createProcessor(wNew, hNew); if (zeroFill) ipNew.setValue(0.0); else ipNew.setColor(colorBack); ipNew.fill(); ipNew.insert(stackOld.getProcessor(i), xOff, yOff); stackNew.addSlice(stackOld.getSliceLabel(i), ipNew); } return stackNew; }
private static Image5D createImage5D(CMMCore core, String wndTitle) throws Exception { core_ = core; ImageProcessor ip; int type = 0; int width_ = (int) core_.getImageWidth(); int height_ = (int) core_.getImageHeight(); long byteDepth = core_.getBytesPerPixel(); long channels = core_.getNumberOfChannels(); if (byteDepth == 1 && channels == 1) { type = ImagePlus.GRAY8; ip = new ByteProcessor(width_, height_); if (contrastSettings8_.getRange() == 0.0) ip.setMinAndMax(0, 255); else ip.setMinAndMax(contrastSettings8_.min, contrastSettings8_.max); } else if (byteDepth == 2 && channels == 1) { type = ImagePlus.GRAY16; ip = new ShortProcessor(width_, height_); if (contrastSettings16_.getRange() == 0.0) ip.setMinAndMax(0, 65535); else ip.setMinAndMax(contrastSettings16_.min, contrastSettings16_.max); } else if (byteDepth == 0) { throw (new Exception(logError("Imaging device not initialized"))); } else if (byteDepth == 1 && channels == 4) { // assuming RGB32 format ip = new ColorProcessor(width_, height_); if (contrastSettings8_.getRange() == 0.0) ip.setMinAndMax(0, 255); else ip.setMinAndMax(contrastSettings8_.min, contrastSettings8_.max); } else { String message = "Unsupported pixel depth: " + core_.getBytesPerPixel() + " byte(s) and " + channels + " channel(s)."; throw (new Exception(logError(message))); } ip.setColor(Color.black); if (currentColorModel_ != null) ip.setColorModel(currentColorModel_); ip.fill(); Image5D img5d = new Image5D(wndTitle, type, width_, height_, 1, 1, 1, false); @SuppressWarnings("unused") Image5DWindow i5dw = new Image5DWindow(img5d); return img5d; }
void createMask(ImagePlus imp) { Roi roi = imp.getRoi(); boolean useInvertingLut = Prefs.useInvertingLut; Prefs.useInvertingLut = false; boolean selectAll = roi != null && roi.getType() == Roi.RECTANGLE && roi.getBounds().width == imp.getWidth() && roi.getBounds().height == imp.getHeight() && imp.isThreshold(); if (roi == null || !(roi.isArea() || roi.getType() == Roi.POINT) || selectAll) { createMaskFromThreshold(imp); Prefs.useInvertingLut = useInvertingLut; return; } ImagePlus maskImp = null; Frame frame = WindowManager.getFrame("Mask"); if (frame != null && (frame instanceof ImageWindow)) maskImp = ((ImageWindow) frame).getImagePlus(); if (maskImp == null) { ImageProcessor ip = new ByteProcessor(imp.getWidth(), imp.getHeight()); if (!Prefs.blackBackground) ip.invertLut(); maskImp = new ImagePlus("Mask", ip); maskImp.show(); } ImageProcessor ip = maskImp.getProcessor(); ip.setRoi(roi); ip.setValue(255); ip.fill(ip.getMask()); Calibration cal = imp.getCalibration(); if (cal.scaled()) { Calibration cal2 = maskImp.getCalibration(); cal2.pixelWidth = cal.pixelWidth; cal2.pixelHeight = cal.pixelHeight; cal2.setUnit(cal.getUnit()); } maskImp.updateAndRepaintWindow(); Prefs.useInvertingLut = useInvertingLut; }
public void run(ImageProcessor ip) { int w = ip.getWidth(); // Get width of image int h = ip.getHeight(); // Get height of image /** * ------------------------------------------------------------------ BEGIN PRELIMINARY STEPS * ------------------------------------------------------------------* */ /** * ----------------------------------- BEGIN: CREATE IMAGES THAT WILL BE USED IN COMPUTATIONS * -----------------------------------* */ // Create the smoothed image to be used for the different edge images ImageProcessor Smoothed_Ip_xf = new FloatProcessor(w, h); ImageProcessor Smoothed_Ip_yf = new FloatProcessor(w, h); ImageProcessor Smoothed_Ip_45f = new FloatProcessor(w, h); ImageProcessor Smoothed_Ip_135f = new FloatProcessor(w, h); // Create the edge image detecting vertical edges ImageProcessor G_xf_Ip = new FloatProcessor(w, h); // Create the edge image detecting horizontal edges ImageProcessor G_yf_Ip = new FloatProcessor(w, h); // Create the edge image detecting 135 degree edges ImageProcessor G_45f_Ip = new FloatProcessor(w, h); // Create the edge image detecting 45 degree edges ImageProcessor G_135f_Ip = new FloatProcessor(w, h); // Create the gradient magnitude image ImageProcessor GMag_Ip = new ByteProcessor(w, h); // Byte version ImageProcessor GMagf_Ip = new FloatProcessor(w, h); // Floating point version // Create the gradient direction image ImageProcessor GDir_Ip = new ByteProcessor(w, h); // Byte version ImageProcessor GDirf_Ip = new FloatProcessor(w, h); // Floating point version // Create the edge image (output from non-maximal suppression) ImageProcessor Edge_Ip = new ByteProcessor(w, h); // Byte Version Edge_Ip.setValue(0); // 0 = Black Edge_Ip.fill(); // Fill Edge_Ip all black ImageProcessor Copy_Edge_Ip = new ByteProcessor(w, h); // Byte Version Copy_Edge_Ip.setValue(0); // 0 = Black Copy_Edge_Ip.fill(); // Fill Edge_Ip all black ImageProcessor Edgef_Ip = new FloatProcessor(w, h); // Floating Point version Edgef_Ip.setValue(0); // 0 = Black Edgef_Ip.fill(); // Fill Edge_Ip all black ImageProcessor Copy_Edgef_Ip = new FloatProcessor(w, h); // Floating Point version Copy_Edgef_Ip.setValue(0); // 0 = Black Copy_Edgef_Ip.fill(); // Fill Edge_Ip all black // Create the Threshold with Hysteresis image ImageProcessor Threshold_Ip = new ByteProcessor(w, h); Threshold_Ip.setValue(0); // 0 = Black Threshold_Ip.fill(); // Fill Edge_Ip all black /** * ----------------------------------- END: CREATE IMAGES THAT WILL BE USED IN COMPUTATIONS * -----------------------------------* */ /** * ----------------------------------------------------- BEGIN: USER INPUT * -----------------------------------------------------* */ double STDDev = 0, TLow = 0, THigh = 0; // Declare and initialize variables for the standard deviation, low threshold, and // high threshold int Size = 0; // Initialize size of Gaussian Filter boolean EdgeStrengthImage; // specifies whether edge strength image should be shown GenericDialog gd = new GenericDialog("User Inputs"); gd.addNumericField( "Size of Gaussian Filter (Odd Integer)", Size, 0); // Field for Size of Gaussian Filter gd.addNumericField("Standard Deviation", STDDev, 0); // Field for Standard Deviation gd.addNumericField("Low Threshold (1 - 255)", TLow, 0); // Field for Low Threshold gd.addNumericField("High Threshold (1 - 255)", THigh, 0); // Field for High Threshold gd.showDialog(); if (gd.wasCanceled()) { return; } else { Size = (int) gd .getNextNumber(); // Set Size variable from user input. This allows the user to // set the size of the Gaussian Filter STDDev = gd.getNextNumber(); // Set STDDev variable from user input TLow = gd.getNextNumber(); // Set TLow variable from user input THigh = gd.getNextNumber(); // Set THigh variable from user input } /** * ----------------------------------------------------- END: USER INPUT * -----------------------------------------------------* */ /** * ------------------------------------------------------------------ END PRELIMINARY STEPS * ------------------------------------------------------------------* */ /** * ------------------------------------------------------------------ BEGIN CANNY EDGE DETECTION * ------------------------------------------------------------------* */ /** * ----------------------------------------------------- BEGIN STEP 1: NOISE REDUCTION VIA * GAUSSIAN ----------------------------------------------------- * */ ImageProcessor ipf = ip.convertToFloat(); // Convert original image to floating point int SizeSquared = (int) Math.pow(Size, 2); // Square the size of Gaussian Kernel int HalfSize = (Size - 1) / 2; // Cut the size of the Gaussian Kernel almost in half float pix; // Temporary storage to be used throughout code to store pixel values float[] GaussianFilter = new float[SizeSquared]; // Initialize Gaussian Filter to be used in the convolution double[] GaussianFilterD = new double [SizeSquared]; // Initialize Gaussian Filter to be used...this filter will be composed // of numbers of type double double Constant = 1 / (2 * Math.PI * Math.pow(STDDev, 2)); // Compute 1/(2*pi*sigma^2) double ExponentDenom = 2 * Math.pow(STDDev, 2); // Compute 2*sigma^2 double Value; // Temporary storage to store the computations that will form the Gaussian Filter // FOR LOOP TO FORM GaussianFilterD for (int i = 0; i < Size; i++) { for (int j = 0; j < Size; j++) { Value = Math.exp( -1 * (Math.pow(j - HalfSize, 2) + Math.pow(i - HalfSize, 2)) / (ExponentDenom)); // Set Value = e^(-(i^2 + j^2)/(2*sigma^2)) GaussianFilterD[Size * i + j] = Constant * Value; // Place Value in GaussianFilterD } } // FOR LOOP TO FORM GaussianFilter using GaussianFilterD for (int i = 0; i < Math.pow(Size, 2); i++) { GaussianFilter[i] = (float) GaussianFilterD[i]; // Convert double values to float one by one } // CONVOLVE IMAGE WITH GAUSSIAN Convolver cv = new Convolver(); // Create the convolver cv.setNormalize(true); // Normalize the filter cv.convolve( ipf, GaussianFilter, Size, Size); // Apply the GaussianFilter using convolution on the image ipf // For loop to create 4 smoothed images to be used in detecting the 4 edges: 0 deg, 45 deg, 90 // deg, 135 deg for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { pix = ipf.getf(i, j); Smoothed_Ip_xf.setf( i, j, pix); // Smoothed image to convolve with Sobel filter in x-direction (detects vertical // edges) Smoothed_Ip_yf.setf( i, j, pix); // Smoothed image to convolve with Sobel filter in y-direction (detects horizontal // edges) Smoothed_Ip_45f.setf( i, j, pix); // Smoothed image to convolve with Sobel filter in 45 degree direction (detects // 135 degree edges) Smoothed_Ip_135f.setf( i, j, pix); // Smoothed image to convolve with Sobel filter in 135 degree direction (detects // 45 degree edges) } } /** * ----------------------------------------------------- END STEP 1: NOISE REDUCTION VIA * GAUSSIAN ----------------------------------------------------- * */ /** * ----------------------------------------------------- BEGIN STEP 2: COMPUTE GRADIENT * MAGNITUDE AND DIRECTION IMAGES ----------------------------------------------------- * */ // Sobel Filters to detect edges float[] G_x = {-1, 0, 1, -2, 0, 2, -1, 0, 1}; // Sobel operator in x direction float[] G_y = {-1, -2, -1, 0, 0, 0, 1, 2, 1}; // Sobel operator in y direction float[] G_135 = {2, 1, 0, 1, 0, -1, 0, -1, -2}; // Sobel operator in 135 degree direction float[] G_45 = {0, 1, 2, -1, 0, 1, -2, -1, 0}; // Sobel operator in 45 degree direction // CONVOLVE IMAGE USING SOBEL FILTERS cv.convolve( Smoothed_Ip_xf, G_x, 3, 3); // Apply the Sobel filter in x-direction using convolution on the smoothed image cv.convolve( Smoothed_Ip_yf, G_y, 3, 3); // Apply the Sobel filter in y-direction using convolution on the smoothed image cv.convolve( Smoothed_Ip_45f, G_45, 3, 3); // Apply the Sobel filter in 45 degree direction using convolution on the smoothed image cv.convolve( Smoothed_Ip_135f, G_135, 3, 3); // Apply the Sobel filter in 135 degree direction using convolution on the smoothed // image // For loop to define the 4 floating point images G_xf_Ip, G_yf_Ip, G_45f_Ip, G_135f_Ip for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { pix = Smoothed_Ip_xf.getf(i, j); G_xf_Ip.setf(i, j, pix); pix = Smoothed_Ip_yf.getf(i, j); G_yf_Ip.setf(i, j, pix); pix = Smoothed_Ip_45f.getf(i, j); G_45f_Ip.setf(i, j, pix); pix = Smoothed_Ip_135f.getf(i, j); G_135f_Ip.setf(i, j, pix); } } // COMPUTE THE GRADIENT MAGNITUDE IMAGE GMagf_Ip float pix1, pix2; // Variables to store pixel values of G_xf_Ip and G_yf_Ip for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { pix1 = G_xf_Ip.getf(i, j); // Get pixel value pix2 = G_yf_Ip.getf(i, j); // Get Pixel Value pix = (float) Math.sqrt( pix1 * pix1 + pix2 * pix2); // Take the square root of the sum of the squares of both pixel // values GMagf_Ip.setf( i, j, 255 * pix); // Place in (i,j) position of GMagf_Ip and scale by 255 to view } } // COMPUTE THE GRADIENT DIRECTION IMAGE double v1, v2, v3, v4; // Temporary storage for the abs. value of pixel vlaues int pixi; // Temporary storage for pixel values double[][] GDir = new double[h] [w]; // Define 2D Array to store gradient direction values. Will use this during Step 3 // Non-Maximal Suppression instead of the gradient direction image // For loop to compute gradient direction image for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { // Obtain the absolute value of each pixel in the following four floating point images v1 = Math.abs(G_xf_Ip.getf(i, j)); v2 = Math.abs(G_yf_Ip.getf(i, j)); v3 = Math.abs(G_45f_Ip.getf(i, j)); v4 = Math.abs(G_135f_Ip.getf(i, j)); // If statements to find the maximal response (strongest edge direction) if (v1 > v2 && v1 > v3 && v1 > v4) // Vertical edge orientation { GDir_Ip.putPixel(i, j, 0); GDir[j][i] = 0; // 0 stands for vertical edge orientation } else if (v3 > v1 && v3 > v2 && v3 > v4) // 45 degree edge orientation { GDir_Ip.putPixel(i, j, 1); GDir[j][i] = 1; // 1 stands for 45 degree edge orientation } else if (v2 > v1 && v2 > v3 && v2 > v4) // Horizontal edge orientation { GDir_Ip.putPixel(i, j, 2); GDir[j][i] = 2; // 2 stands for horizontal edge orientation } else if (v4 > v1 && v4 > v2 && v4 > v3) // 135 degree edge orientation { GDir_Ip.putPixel(i, j, 3); GDir[j][i] = 3; // 3 stands for 135 degree edge orientation } pixi = (int) (255.0 / 3.0) * GDir_Ip.getPixel( i, j); // Scale the gradient direction image so we can actually see it GDir_Ip.putPixel( i, j, pixi); // Place pixi in the (i,j) location of GDir_Ip...we can now view the gradient // direction image } } // OUTPUT GRADIENT DIRECTION IMAGE String DirTitle = "Gradient Direction"; ImagePlus GDir_Im = new ImagePlus(DirTitle, GDir_Ip); GDir_Im.show(); // OUTPUT GRADIENT MAGNITUDE IMAGE (need to convert to ByteProcessor to view first) GMagf_Ip.resetMinAndMax(); GMag_Ip.insert(GMagf_Ip.convertToByte(true), 0, 0); String MagTitle = "Gradient Magnitude"; ImagePlus GMag_Im = new ImagePlus(MagTitle, GMag_Ip); GMag_Im.show(); /** * ----------------------------------------------------- BEGIN STEP 2: COMPUTE GRADIENT * MAGNITUDE AND DIRECTION IMAGES ----------------------------------------------------- * */ /** * ----------------------------------------------------- BEGIN STEP 3: NON-MAXIMAL SUPPRESSION * -----------------------------------------------------* */ // Ignoring boundaries for convenience float Magnitude; // Storage for magnitude double Direction; // Storage for direction // FOR LOOP TO COMPUTE NON-MAXIMAL SUPPRESSION IMAGE for (int i = 1; i < w - 1; i++) { for (int j = 1; j < h - 1; j++) { Magnitude = GMagf_Ip.getf( i, j); // Get the magnitude in the (i,j) position of the gradient magnitude image if (Magnitude != 0) // If the magnitude is non-zero then we find the direction of the edge { Direction = GDir[j][i]; // Obtain the direction float n1GradMag = 0, n2GradMag = 0; // Initialize storage for the magnitude of the 2 neighboring pixels if (Direction == 0) // If Direction is 0 get the magnitude in the columns to the left and right { n1GradMag = GMagf_Ip.getf(i - 1, j); n2GradMag = GMagf_Ip.getf(i + 1, j); } else if (Direction == 1) // If Direction is 45 degree get the magnitude in adjacent pixels { n1GradMag = GMagf_Ip.getf(i + 1, j - 1); n2GradMag = GMagf_Ip.getf(i - 1, j + 1); } else if (Direction == 2) // If Direction is 2 get the magnitude in the rows above and below { n1GradMag = GMagf_Ip.getf(i, j - 1); n2GradMag = GMagf_Ip.getf(i, j + 1); } else if (Direction == 3) // If Direction is 135 degrees get the magnitude in adjacent pixels { n1GradMag = GMagf_Ip.getf(i - 1, j - 1); n2GradMag = GMagf_Ip.getf(i + 1, j + 1); } if (Magnitude > n1GradMag && Magnitude > n2GradMag) // Check to see if the magnitude of pixel under inspection is the // largest relative to its adjacent pixels { pix = GMagf_Ip.getf(i, j); // Store magnitude in (i,j) position in pix variable Edgef_Ip.setf( i, j, pix); // Place this pixel value in the (i,j) position of Edge Image (Edge Image is // output from non-maximal suppression) Copy_Edgef_Ip.setf( i, j, pix); // Place this pixel value in the (i,j) position of Copy Edge Image (this will // be used for thresholding with hysteresis) } else { } // Else do nothing since edge image was already filled with 0's at beginning of code } else { } // Do nothing if magnitude is 0 } } Copy_Edgef_Ip.resetMinAndMax(); Copy_Edge_Ip.insert(Copy_Edgef_Ip.convertToByte(true), 0, 0); // Display edge magnitude image but we need to convert to ByteProcessor first Edgef_Ip.resetMinAndMax(); Edge_Ip.insert(Edgef_Ip.convertToByte(true), 0, 0); String cTitle = "Non-Maximal Suppression"; ImagePlus Edge_Im = new ImagePlus(cTitle, Edge_Ip); Edge_Im.show(); /** * ----------------------------------------------------- END STEP 3: NON-MAXIMAL SUPPRESSION * -----------------------------------------------------* */ /** * ----------------------------------------------------- BEGIN STEP 4: THRESHOLDING WITH * HYSTERESIS -----------------------------------------------------* */ int count = 0; // Initialize counter to be used in while loop int IterationCount = 500; // Number of iterations to perform // Scan through all pixels in the edge image and mark all edges with magnitude above the high // threshold as a true edge otherwise if the magnitude is below the low threshold // then we delete that pixel (set it to zero) for (int i = 0; i < w; i++) { for (int j = 0; j < h; j++) { Magnitude = Copy_Edge_Ip.getPixel(i, j); // Obtain magnitude in edge image if (Magnitude > THigh) // If Magnitude is larger than the high threshold then make pixel white { Threshold_Ip.putPixel(i, j, 255); // True edge (Updates Threshold image to be output) Copy_Edge_Ip.putPixel( i, j, 255); // True edge (Updates edge image which will be used in the iterative // thresholding) } else if (Magnitude < TLow) // Else if magnitude is below the low threshold then make pixel black { Threshold_Ip.putPixel(i, j, 0); // Not an edge (Updates Threshold image to be output) Copy_Edge_Ip.putPixel( i, j, 0); // Not an edge (Updates edge image which will be used in the iterative // thresholding) } } } while (count < IterationCount) // Iterate again and again { // Ignore boundary pixels for convenience for (int i = 1; i < w - 1; i++) { for (int j = 1; j < h - 1; j++) { Magnitude = Copy_Edge_Ip.getPixel(i, j); // Obtain magnitude in edge image if (Magnitude == 255) // If we reach a true edge then we look at its 8 neighbors { // Obtain the magnitude in the 8 neighbors int n1, n2, n3, n4, n5, n6, n7, n8; n1 = Copy_Edge_Ip.getPixel(i - 1, j); n2 = Copy_Edge_Ip.getPixel(i - 1, j - 1); n3 = Copy_Edge_Ip.getPixel(i, j - 1); n4 = Copy_Edge_Ip.getPixel(i + 1, j - 1); n5 = Copy_Edge_Ip.getPixel(i + 1, j); n6 = Copy_Edge_Ip.getPixel(i + 1, j + 1); n7 = Copy_Edge_Ip.getPixel(i, j + 1); n8 = Copy_Edge_Ip.getPixel(i - 1, j + 1); if (n1 >= TLow) // If n1 is greater than or equal to the low threshold then we mark it as // an edge { Copy_Edge_Ip.putPixel(i - 1, j, 255); // Update edge image Threshold_Ip.putPixel( i - 1, j, 255); // Update threshold image (This is the output image from thresholding with // hysteresis) } if (n2 >= TLow) // If n2 is greater than or equal to the low threshold then we mark it as // an edge { Copy_Edge_Ip.putPixel(i - 1, j - 1, 255); // Update edge image Threshold_Ip.putPixel( i - 1, j - 1, 255); // Update threshold image (This is the output image from thresholding with // hysteresis) } if (n3 >= TLow) // If n3 is greater than or equal to the low threshold then we mark it as // an edge { Copy_Edge_Ip.putPixel(i, j - 1, 255); // Update edge image Threshold_Ip.putPixel( i, j - 1, 255); // Update threshold image (This is the output image from thresholding with // hysteresis) } if (n4 >= TLow) // If n4 is greater than or equal to the low threshold then we mark it as // an edge { Copy_Edge_Ip.putPixel(i + 1, j - 1, 255); // Update edge image Threshold_Ip.putPixel( i + 1, j - 1, 255); // Update threshold image (This is the output image from thresholding with // hysteresis) } if (n5 >= TLow) // If n5 is greater than or equal to the low threshold then we mark it as // an edge { Copy_Edge_Ip.putPixel(i + 1, j, 255); // Update edge image Threshold_Ip.putPixel( i + 1, j, 255); // Update threshold image (This is the output image from thresholding with // hysteresis) } if (n6 >= TLow) // If n6 is greater than or equal to the low threshold then we mark it as // an edge { Copy_Edge_Ip.putPixel(i + 1, j + 1, 255); // Update edge image Threshold_Ip.putPixel( i + 1, j + 1, 255); // Update threshold image (This is the output image from thresholding with // hysteresis) } if (n7 >= TLow) // If n7 is greater than or equal to the low threshold then we mark it as // an edge { Copy_Edge_Ip.putPixel(i, j + 1, 255); // Update edge image Threshold_Ip.putPixel( i, j + 1, 255); // Update threshold image (This is the output image from thresholding with // hysteresis) } if (n8 >= TLow) // If n8 is greater than or equal to the low threshold then we mark it as // an edge { Copy_Edge_Ip.putPixel(i - 1, j + 1, 255); // Update edge image Threshold_Ip.putPixel( i - 1, j + 1, 255); // Update threshold image (This is the output image from thresholding with // hysteresis) } } } } count++; // Update counter and continue iterations } // Display the threshold with hysteresis image. String ThreshTitle = "Threshold with Hysteresis"; ImagePlus Threshold_Im = new ImagePlus(ThreshTitle, Threshold_Ip); Threshold_Im.show(); /** * ----------------------------------------------------- END STEP 4: THRESHOLDING WITH * HYSTERESIS -----------------------------------------------------* */ /** * ------------------------------------------------------------------ END CANNY EDGE DETECTION * ------------------------------------------------------------------* */ }
public void run(ImageProcessor ip) { String[] imageNames = getOpenImageNames(); if (imageNames[0] == "None") { IJ.error("need at least 2 binary open images"); return; } double previousMinOverlap = Prefs.get("BVTB.BinaryFeatureExtractor.minOverlap", 0); boolean previousCombine = Prefs.get("BVTB.BinaryFeatureExtractor.combine", false); GenericDialog gd = new GenericDialog("Binary Feature Extractor"); gd.addChoice("Objects image", imageNames, imageNames[0]); gd.addChoice("Selector image", imageNames, imageNames[1]); gd.addNumericField("Object_overlap in % (0=off)", previousMinOverlap, 0, 9, ""); gd.addCheckbox("Combine objects and selectors", previousCombine); gd.addCheckbox("Count output", true); gd.addCheckbox("Analysis tables", false); gd.showDialog(); if (gd.wasCanceled()) { return; } String objectsImgTitle = gd.getNextChoice(); String selectorsImgTitle = gd.getNextChoice(); double minOverlap = gd.getNextNumber(); boolean combineImages = gd.getNextBoolean(); boolean showCountOutput = gd.getNextBoolean(); boolean showAnalysis = gd.getNextBoolean(); if (gd.invalidNumber() || minOverlap < 0 || minOverlap > 100) { IJ.error("invalid number"); return; } Prefs.set("BVTB.BinaryFeatureExtractor.minOverlap", minOverlap); Prefs.set("BVTB.BinaryFeatureExtractor.combine", combineImages); if (objectsImgTitle.equals(selectorsImgTitle)) { IJ.error("images need to be different"); return; } ImagePlus objectsImp = WindowManager.getImage(objectsImgTitle); ImageProcessor objectsIP = objectsImp.getProcessor(); ImagePlus selectorsImp = WindowManager.getImage(selectorsImgTitle); ImageProcessor selectorsIP = selectorsImp.getProcessor(); if (!objectsIP.isBinary() || !selectorsIP.isBinary()) { IJ.error("works with 8-bit binary images only"); return; } if ((objectsImp.getWidth() != selectorsImp.getWidth()) || objectsImp.getHeight() != selectorsImp.getHeight()) { IJ.error("images need to be of the same size"); return; } // close any existing RoiManager before instantiating a new one for this analysis RoiManager oldRM = RoiManager.getInstance2(); if (oldRM != null) { oldRM.close(); } RoiManager objectsRM = new RoiManager(true); ResultsTable objectsRT = new ResultsTable(); ParticleAnalyzer analyzeObjects = new ParticleAnalyzer(analyzerOptions, measurementFlags, objectsRT, 0.0, 999999999.9); analyzeObjects.setRoiManager(objectsRM); analyzeObjects.analyze(objectsImp); objectsRM.runCommand("Show None"); int objectNumber = objectsRT.getCounter(); Roi[] objectRoi = objectsRM.getRoisAsArray(); ResultsTable measureSelectorsRT = new ResultsTable(); Analyzer overlapAnalyzer = new Analyzer(selectorsImp, measurementFlags, measureSelectorsRT); ImagePlus outputImp = IJ.createImage("output", "8-bit black", objectsImp.getWidth(), objectsImp.getHeight(), 1); ImageProcessor outputIP = outputImp.getProcessor(); double[] measuredOverlap = new double[objectNumber]; outputIP.setValue(255.0); for (int o = 0; o < objectNumber; o++) { selectorsImp.killRoi(); selectorsImp.setRoi(objectRoi[o]); overlapAnalyzer.measure(); measuredOverlap[o] = measureSelectorsRT.getValue("%Area", o); if (minOverlap != 0.0 && measuredOverlap[o] >= minOverlap) { outputIP.fill(objectRoi[o]); finalCount++; } else if (minOverlap == 0.0 && measuredOverlap[o] > 0.0) { outputIP.fill(objectRoi[o]); finalCount++; } } // measureSelectorsRT.show("Objects"); selectorsImp.killRoi(); RoiManager selectorRM = new RoiManager(true); ResultsTable selectorRT = new ResultsTable(); ParticleAnalyzer.setRoiManager(selectorRM); ParticleAnalyzer analyzeSelectors = new ParticleAnalyzer(analyzerOptions, measurementFlags, selectorRT, 0.0, 999999999.9); analyzeSelectors.analyze(selectorsImp); selectorRM.runCommand("Show None"); int selectorNumber = selectorRT.getCounter(); if (combineImages) { outputImp.updateAndDraw(); Roi[] selectorRoi = selectorRM.getRoisAsArray(); ResultsTable measureObjectsRT = new ResultsTable(); Analyzer selectorAnalyzer = new Analyzer(outputImp, measurementFlags, measureObjectsRT); double[] selectorOverlap = new double[selectorNumber]; outputIP.setValue(255.0); for (int s = 0; s < selectorNumber; s++) { outputImp.killRoi(); outputImp.setRoi(selectorRoi[s]); selectorAnalyzer.measure(); selectorOverlap[s] = measureObjectsRT.getValue("%Area", s); if (selectorOverlap[s] > 0.0d) { outputIP.fill(selectorRoi[s]); } } selectorRoi = null; selectorAnalyzer = null; measureObjectsRT = null; } // selectorRT.show("Selectors"); outputImp.killRoi(); String outputImageTitle = WindowManager.getUniqueName("Extracted_" + objectsImgTitle); outputImp.setTitle(outputImageTitle); outputImp.show(); outputImp.changes = true; if (showCountOutput) { String[] openTextWindows = WindowManager.getNonImageTitles(); boolean makeNewTable = true; for (int w = 0; w < openTextWindows.length; w++) { if (openTextWindows[w].equals("BFE_Results")) { makeNewTable = false; } } TextWindow existingCountTable = ResultsTable.getResultsWindow(); if (makeNewTable) { countTable = new ResultsTable(); countTable.setPrecision(0); countTable.setValue("Image", 0, outputImageTitle); countTable.setValue("Objects", 0, objectNumber); countTable.setValue("Selectors", 0, selectorNumber); countTable.setValue("Extracted", 0, finalCount); countTable.show("BFE_Results"); } else { IJ.renameResults("BFE_Results", "Results"); countTable = ResultsTable.getResultsTable(); countTable.setPrecision(0); countTable.incrementCounter(); countTable.addValue("Image", outputImageTitle); countTable.addValue("Objects", objectNumber); countTable.addValue("Selectors", selectorNumber); countTable.addValue("Extracted", finalCount); IJ.renameResults("Results", "BFE_Results"); countTable.show("BFE_Results"); } } if (showAnalysis) { ResultsTable extractedRT = new ResultsTable(); ParticleAnalyzer analyzeExtracted = new ParticleAnalyzer( ParticleAnalyzer.CLEAR_WORKSHEET | ParticleAnalyzer.RECORD_STARTS, measurementFlags, extractedRT, 0.0, 999999999.9); analyzeExtracted.analyze(outputImp); objectsRT.show("Objects"); selectorRT.show("Selectors"); extractedRT.show("Extracted"); } else { objectsRT = null; selectorRT = null; } objectsRM = null; measureSelectorsRT = null; analyzeObjects = null; overlapAnalyzer = null; objectRoi = null; selectorRM = null; objectsImp.killRoi(); objectsImp.changes = false; selectorsImp.changes = false; }
void drawRoiFilledParticle(ImageProcessor ip, Roi roi, ImageProcessor mask, int count) { int grayLevel = (count < 65535) ? count : 65535; ip.setValue((double) grayLevel); ip.setRoi(roi.getBounds()); ip.fill(mask); }
void drawFilledParticle(ImageProcessor ip, Roi roi, ImageProcessor mask) { // IJ.write(roi.getBounds()+" "+mask.length); ip.setRoi(roi.getBounds()); ip.fill(mask); }
void analyzeParticle(int x, int y, ImagePlus imp, ImageProcessor ip) { // Wand wand = new Wand(ip); ImageProcessor ip2 = redirectIP != null ? redirectIP : ip; wand.autoOutline(x, y, level1, level2, wandMode); if (wand.npoints == 0) { IJ.log("wand error: " + x + " " + y); return; } Roi roi = new PolygonRoi(wand.xpoints, wand.ypoints, wand.npoints, roiType); Rectangle r = roi.getBounds(); if (r.width > 1 && r.height > 1) { PolygonRoi proi = (PolygonRoi) roi; pf.setPolygon(proi.getXCoordinates(), proi.getYCoordinates(), proi.getNCoordinates()); ip2.setMask(pf.getMask(r.width, r.height)); if (floodFill) ff.particleAnalyzerFill(x, y, level1, level2, ip2.getMask(), r); } ip2.setRoi(r); ip.setValue(fillColor); ImageStatistics stats = getStatistics(ip2, measurements, calibration); boolean include = true; if (excludeEdgeParticles) { if (r.x == minX || r.y == minY || r.x + r.width == maxX || r.y + r.height == maxY) include = false; if (polygon != null) { Rectangle bounds = roi.getBounds(); int x1 = bounds.x + wand.xpoints[wand.npoints - 1]; int y1 = bounds.y + wand.ypoints[wand.npoints - 1]; int x2, y2; for (int i = 0; i < wand.npoints; i++) { x2 = bounds.x + wand.xpoints[i]; y2 = bounds.y + wand.ypoints[i]; if (!polygon.contains(x2, y2)) { include = false; break; } if ((x1 == x2 && ip.getPixel(x1, y1 - 1) == fillColor) || (y1 == y2 && ip.getPixel(x1 - 1, y1) == fillColor)) { include = false; break; } x1 = x2; y1 = y2; } } } ImageProcessor mask = ip2.getMask(); if (minCircularity > 0.0 || maxCircularity < 1.0) { double perimeter = roi.getLength(); double circularity = perimeter == 0.0 ? 0.0 : 4.0 * Math.PI * (stats.pixelCount / (perimeter * perimeter)); if (circularity > 1.0) circularity = 1.0; // IJ.log(circularity+" "+perimeter+" "+stats.area); if (circularity < minCircularity || circularity > maxCircularity) include = false; } if (stats.pixelCount >= minSize && stats.pixelCount <= maxSize && include) { particleCount++; if (roiNeedsImage) roi.setImage(imp); stats.xstart = x; stats.ystart = y; saveResults(stats, roi); if (showChoice != NOTHING) drawParticle(drawIP, roi, stats, mask); } if (redirectIP != null) ip.setRoi(r); ip.fill(mask); }
/** * 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; }
void apply(ImagePlus imp, ImageProcessor ip) { // this.setCursor(wait); // IJ.showStatus("Bandpassing slice "+previousSlice); java.awt.Color col; if (invert.getState()) col = Toolbar.getForegroundColor(); else col = Toolbar.getBackgroundColor(); ip.setColor(col); int fill = ip.BLACK; int keep = 0; if (bandPassH.getState() && bandPassS.getState() && bandPassB.getState()) { // PPP All pass for (int j = 0; j < numPixels; j++) { int hue = hSource[j] & 0xff; int sat = sSource[j] & 0xff; int bri = bSource[j] & 0xff; if (((hue < minHue) || (hue > maxHue)) || ((sat < minSat) || (sat > maxSat)) || ((bri < minBri) || (bri > maxBri))) fillMask[j] = fill; else fillMask[j] = keep; } } else if (!bandPassH.getState() && !bandPassS.getState() && !bandPassB.getState()) { // SSS All stop for (int j = 0; j < numPixels; j++) { int hue = hSource[j] & 0xff; int sat = sSource[j] & 0xff; int bri = bSource[j] & 0xff; if (((hue >= minHue) && (hue <= maxHue)) || ((sat >= minSat) && (sat <= maxSat)) || ((bri >= minBri) && (bri <= maxBri))) fillMask[j] = fill; else fillMask[j] = keep; } } else if (bandPassH.getState() && bandPassS.getState() && !bandPassB.getState()) { // PPS for (int j = 0; j < numPixels; j++) { int hue = hSource[j] & 0xff; int sat = sSource[j] & 0xff; int bri = bSource[j] & 0xff; if (((hue < minHue) || (hue > maxHue)) || ((sat < minSat) || (sat > maxSat)) || ((bri >= minBri) && (bri <= maxBri))) fillMask[j] = fill; else fillMask[j] = keep; } } else if (!bandPassH.getState() && !bandPassS.getState() && bandPassB.getState()) { // SSP for (int j = 0; j < numPixels; j++) { int hue = hSource[j] & 0xff; int sat = sSource[j] & 0xff; int bri = bSource[j] & 0xff; if (((hue >= minHue) && (hue <= maxHue)) || ((sat >= minSat) && (sat <= maxSat)) || ((bri < minBri) || (bri > maxBri))) fillMask[j] = fill; else fillMask[j] = keep; } } else if (bandPassH.getState() && !bandPassS.getState() && !bandPassB.getState()) { // PSS for (int j = 0; j < numPixels; j++) { int hue = hSource[j] & 0xff; int sat = sSource[j] & 0xff; int bri = bSource[j] & 0xff; if (((hue < minHue) || (hue > maxHue)) || ((sat >= minSat) && (sat <= maxSat)) || ((bri >= minBri) && (bri <= maxBri))) fillMask[j] = fill; else fillMask[j] = keep; } } else if (!bandPassH.getState() && bandPassS.getState() && bandPassB.getState()) { // SPP for (int j = 0; j < numPixels; j++) { int hue = hSource[j] & 0xff; int sat = sSource[j] & 0xff; int bri = bSource[j] & 0xff; if (((hue >= minHue) && (hue <= maxHue)) || ((sat < minSat) || (sat > maxSat)) || ((bri < minBri) || (bri > maxBri))) fillMask[j] = fill; else fillMask[j] = keep; } } else if (!bandPassH.getState() && bandPassS.getState() && !bandPassB.getState()) { // SPS for (int j = 0; j < numPixels; j++) { int hue = hSource[j] & 0xff; int sat = sSource[j] & 0xff; int bri = bSource[j] & 0xff; if (((hue >= minHue) && (hue <= maxHue)) || ((sat < minSat) || (sat > maxSat)) || ((bri >= minBri) && (bri <= maxBri))) fillMask[j] = fill; else fillMask[j] = keep; } } else if (bandPassH.getState() && !bandPassS.getState() && bandPassB.getState()) { // PSP for (int j = 0; j < numPixels; j++) { int hue = hSource[j] & 0xff; int sat = sSource[j] & 0xff; int bri = bSource[j] & 0xff; if (((hue < minHue) || (hue > maxHue)) || ((sat >= minSat) && (sat <= maxSat)) || ((bri < minBri) || (bri > maxBri))) fillMask[j] = fill; else fillMask[j] = keep; } } ip.fill(fillMask); if (threshold.getState()) { ip.invert(); for (int j = 0; j < numPixels; j++) { if (fillMask[j] == fill) fillMask[j] = keep; else fillMask[j] = fill; } ip.fill(fillMask); ip.invert(); } }