// This macro takes a multi-channel image as input. // The purpose of this macro is to identify objects in each channel, and determine // which of these objects overlap with each other. // This is a non-destructive alternative to the ROI manager's "AND" operation // // This template is written assuming 3-channel data, with a reference object // in the red channel. Update as needed for your data. // // Search for "TODO" comments for parameters that need to be adjusted // // For general information on image processing (selecting preprocessing techniques) see: // http://imagej.net/Image_Processing_Principles // NOTE: As written, requires the Biomedgroup update site to be enabled. // See http://imagej.net/How_to_follow_a_3rd_party_update_site // *** Start of macro *** //remove previous scales run("Set Scale...", "distance=0 known=0 global"); //TODO rename these to something appropriate for your objects redObject = "Red Object"; blueObject = "Blue Object"; greenObject = "Green Object"; // split images T = getTitle; selectWindow(T); run("Stack to Images"); // cache channel names selectImage(1); redImage = getTitle(); selectImage(2); greenImage = getTitle(); selectImage(3); blueImage = getTitle(); // general preprocessing //TODO If you need to do any high-level image processing, do so here. // For example, you may want to run the imageCalculator to limit the search // scope of an image to regions of overlap. imageCalculator("and", greenImage, redImage); // BLUE channel selectWindow(blueImage); // Preprocessing - BLUE channel // TODO Use the threshold that best fits your data (AutoThreshold > Try all_ // Minimum threshold is fairly aggressive, so it's helpful to Dilate after thresholding setAutoThreshold("Minimum dark"); run("Convert to Mask"); run("Despeckle"); run("Dilate"); // Analysis - BLUE channel // TODO Analyze Particles allows specification of particle size, roundness, and other options. // Adjust these parameters to best fit your data run("Analyze Particles...", " show=Outlines display exclude summarize add"); blueObjectCount = roiManager("count"); setBatchMode("hide"); // hide the UI for this computation to avoid unnecessary overhead of ROI selection // Rename each blue object ROI to keep track of them. for(i=0;i Try all_ setAutoThreshold("Default dark"); run("Convert to Mask"); run("Dilate"); run("Despeckle"); // Analysis - RED channel // TODO Analyze Particles works great in general. However we can also use more specialized plugins to find regions of interest. // For example, the Ridge Detection plugin (http://imagej.net/Ridge_Detection) is great at finding lines, and has options // to preserve lines through intersection. // In this example we'll use Ridge Detection. If Analyze Particles is sufficient for your data though, use it! run("Skeletonize"); run("Invert LUT"); //TODO find the parameters you want for ridge detection. You can record them using the Macro Recorder (Plugins>Macros>Record...) and then paste the command you use below // - replacing the "waitForUser" line. waitForUser("Wait for Ridge Detection...", "Please run Plugins>Ridge Detection.\nTune the parameters as needed - preview mode is recommended.\nAfter ridge detection is complete, click \"OK\" in this dialog to continue."); //run("Ridge Detection", "line_width=2 high_contrast=255 low_contrast=240 estimate_width extend_line show_junction_points show_ids displayresults add_to_manager method_for_overlap_resolution=SLOPE sigma=1.2 lower_threshold=16.83 upper_threshold=40"); setBatchMode("hide"); // hide the UI for this computation to avoid unnecessary overhead of ROI selection // Clean up from Ridge Detection // - Remove junction points // - Coutn red objects redObjectCount = 0; for(i=blueObjectCount;i0 && k>=xPoints.length - maxDist && !found; k--) { x = xPoints[k]; y = yPoints[k]; // Check if the blue object roi contains this skeleton point if (Roi.contains(x, y)) { found = true; index = k; } } if (found) { setResult("Paired " + blueObject, j, i+1); // record link between object indices setResult("Position in skeleton", i, index); // record the position on the skeleton where the overlap was detected } } } } setBatchMode("exit and display"); // End of RED channel // GREEN channel selectWindow(greenImage); // Preprocessing - GREEN channel //TODO adjust threshold as needed run("Auto Threshold", "method=Intermodes white"); run("Convert to Mask"); // Analysis - GREEN channel // TODO in this example, we assume the green channel has noise but our objects of // interest are larger than the background. Thus we bump up the minimum size a bit. run("Analyze Particles...", "size=6-Infinity display exclude summarize add"); setBatchMode("hide"); // hide the UI for this computation to avoid unnecessary overhead of ROI selection // label green objects greenObjectCount = 0; for(i=blueObjectCount + redObjectCount;i 0) { // record that this green object is paired to a blue setResult("Paired " + blueObject, i, blueIndex); // record the position of overlap between green object and red skeleton setResult("Position in skeleton", i, k); blueIndex--; // adjust for object index vs row index // recall the position of the blue object in this skeleton bluePos = getResult("Position in skeleton", blueIndex); // Set the skeletal distance, which is simply the difference in // indices within the skeleton between blue and green objects if (!isNaN(bluePos)) { length = abs(bluePos - k); setResult(greenObject + " to " + blueObject + "i distance", i, length); } } wait(50); // wait briefly when we find a match to ensure the UI has caught up. } } } } } setBatchMode("exit and display"); // End of GREEN channel // End of macro