/* - WEKA-FISH V2 - Fiji * - Virginia Polytechnic Institute and State University * - Biocomplexity Institute - Hauf Lab * - Erod Keaton Baybay * * Disclaimer: * Way more comments than necessary are in use for educational, self-teaching, self-referencing purposes. * Because Erod is extremely forgetful, and tends to forget what certain things do. * * Note that the cleanAll() function will close images without saving. * Please save your work prior to running this Macro. */ requires("1.52e"); // Required FIJI Version var WFv = "3.0b"; // WEKA-FISH Pipeline Version macro "WEKA-FISH" { run("Collect Garbage"); t0 = getTime(); showMessageWithCancel("WEKA-FISH "+WFv, "" +"
WEKA-FISH
" +"
Hauf Lab - Biocomplexity Institute 2018
" +"" +"
Please read accompanying documentation
" +"
[Erod Keaton Baybay - erodb@vt.edu]
"); // Default Parameters cleanAll(); flat = false; limitSize = 5; bins = 20 thresh = 0.99; // ------- Initialization I - File Designation ----------------------------------------------------------------------- showStatus("Initializing WEKA-FISH..."); run("Set Measurements...", "area centroid fit display redirect=None decimal=3"); waitForUser("Please select an Output Directory"); outputDirectory = getDirectory("Choose an Output Directory"); showStatus("Initializing WEKA-FISH... [Autofluorescence Image]"); waitForUser("Please select an Autofluorescence Image (CFP or GFP)"); AFPimage = File.openDialog("Choose Autoflouresence Image"); showStatus("Initializing WEKA-FISH... [DAPI Image]"); waitForUser("Please select a Nuclear Tracking Image (DAPI)"); DAPIimage = File.openDialog("Choose Nuclear Tracking Image"); showStatus("Initializing WEKA-FISH... [Raw Image]"); waitForUser("Please select a Raw Image (FISHRed)"); RAWimage = File.openDialog("Choose Raw Image"); getDateAndTime(year, month, dayOfWeek, dayOfMonth, hour, minute, second, msec); saveID = ""+year+""+month+""+dayOfMonth+"_"+hour+""+minute+"_"+replace(File.getName(RAWimage), ".","_"); logID = ""+year+""+month+""+dayOfMonth+"_"+hour+""+minute; print("WEKA-FISH "+WFv); print("Hauf Lab - Biocomplexity Institute 2018"); print("Main Save ID: "+saveID); directoryMain = outputDirectory+"/"+saveID+"/" if (!File.exists(directoryMain)) File.makeDirectory(directoryMain); directoryData = directoryMain+"/Data/"; if (!File.exists(directoryData)) File.makeDirectory(directoryData); directoryHistogram = directoryData+"/Histograms/"; if (!File.exists(directoryHistogram)) File.makeDirectory(directoryHistogram); directoryROIs = directoryMain+"/ROIs/"; if (!File.exists(directoryROIs)) File.makeDirectory(directoryROIs); directoryImages = directoryMain+"/Images/"; if (!File.exists(directoryImages)) File.makeDirectory(directoryImages); directoryOverlays = directoryImages+"/Overlays/"; if (!File.exists(directoryOverlays)) File.makeDirectory(directoryOverlays); Dialog.create("Run Parameters"); Dialog.addCheckbox("Flatfielded Images", flat); Dialog.addNumber("Pixel Margin: ", limitSize); Dialog.addNumber("Histogram Bins: ", bins); Dialog.addSlider("Training Threshold:", 0.8, 1, thresh); Dialog.show flat = Dialog.getCheckbox(); limitSize = Dialog.getNumber; bins = Dialog.getNumber; thresh = Dialog.getNumber; print("\n[Run Parameters]"); print("Subtract Background: ", flat); print("Pixel Margin: ", limitSize); print("Histogram Bins: ", bins); print("Training Threshold:", thresh); // ------- Phase One - Autoflouresence Preprocessing -------------------------------------------------------------- open(AFPimage); waitForUser("Please select the most in focus slice.\nOnce selected, click OK."); showStatus("Processing Autofluorescence Image..."); run("Duplicate...", " "); // Focused AFP Export AFPfocus = directoryImages+"/IMG0_"+replace(File.getName(RAWimage), ".","_")+"_Focal_Frame_AFP.tif"; if (!File.exists(AFPfocus)) { saveAs(".tiff", AFPfocus); } run("Enhance Contrast...", "saturated=1 normalize"); run("Gaussian Blur...", "sigma=2"); if(!flat) run("Subtract Background...", "rolling=50"); run("Enhance Contrast...", "saturated=1 normalize"); run("Unsharp Mask...", "radius=40 mask=0.30"); // Pre-Process Image Export preProc = directoryImages+"/IMG1_"+replace(File.getName(RAWimage), ".","_")+"_Pre_Processed.tif"; if (!File.exists(preProc)) { saveAs(".tiff", preProc); } print("\n[WEKA Log]"); run("Trainable Weka Segmentation"); showStatus("Running Trainable Weka Segmentation..."); // ------- Phase Two - Autoflouresence Processing -------------------------------------------------------------- waitForUser("Please generate the Probability Map.\nLoad classifier > Get probability\nOnce available, click OK."); selectWindow("Probability maps"); // Probability Map Image Export probMap = directoryImages+"/IMG2_"+replace(File.getName(RAWimage), ".","_")+"_Probability_Map.tif"; if (!File.exists(probMap)) { saveAs(".tiff", probMap); } setSlice(2); run("Duplicate...", " "); setThreshold(thresh,1); run("Convert to Mask"); run("Fill Holes"); run("Erode"); run("Gaussian Blur...", "sigma=5"); run("Make Binary", "method=Otsu background=Default calculate black"); run("Analyze Particles...", "size=20-Infinity circularity=0.00-0.80 exclude clear add"); // Clears ROI Manager // ------- Phase Three - Autoflouresence Postprocessing -------------------------------------------------------------- n = roiManager("count"); roiManager("Show All without labels"); if (n > 0) { for (i = 0; i < n; i++) { showStatus("Sculpting Cell ROIs..."); roiManager("Select", i); run("Enlarge...", "enlarge=25"); run("Enlarge...", "enlarge=-20"); run("Convex Hull"); roiManager("Update"); roiManager("Set Color", "green"); roiManager("Set Line Width", 3); roiManager("Rename", "Cell_"+(i+1)); showStatus("Sculpting Cell ROIs..."); showProgress(i, n-1); } } roiManager("Select", Array.getSequence(roiManager("Count"))); roiManager("Measure"); print("\n[Cell Measurement Report]"); print("Measurements: "+nResults+" Datapoints corresponding to "+roiManager("Count")+" Cells ROIs"); showStatus("Generating Histograms..."); // Cell Size Histogram Export run("Distribution...", "parameter=Area or="+bins+" and=0-0"); histogram1a = directoryHistogram+"/"+replace(File.getName(RAWimage), ".","_")+"_Cell_Size_Histogram.png"; if (!File.exists(histogram1a)) { selectImage("Area Distribution"); saveAs(".png", histogram1a); } // Cell Length Histogram Export run("Distribution...", "parameter=Major or="+bins+" and=0-0"); histogram1b = directoryHistogram+"/"+replace(File.getName(RAWimage), ".","_")+"_Cell_Length_Histogram.png"; if (!File.exists(histogram1b)) { selectImage("Major Distribution"); saveAs(".png", histogram1b); } // Cell Width Histogram Export run("Distribution...", "parameter=Minor or="+bins+" and=0-0"); histogram1c = directoryHistogram+"/"+replace(File.getName(RAWimage), ".","_")+"_Cell_Width_Histogram.png"; if (!File.exists(histogram1c)) { selectImage("Minor Distribution"); saveAs(".png", histogram1c); } // Cell Size File Export resultFile1 = directoryData+"/"+replace(File.getName(RAWimage), ".","_")+"_Cell_Size.csv"; if (!File.exists(resultFile1)) { selectWindow("Results"); saveAs("Results", resultFile1); } // ------- Phase Four - Nuclear Tracking -------------------------------------------------------------- close('*'); run("Clear Results"); open(DAPIimage); waitForUser("Please select the most in focus slice.\nOnce selected, click OK."); s = getSliceNumber(); sMinor = s-5; sMajor = s+5; run("Duplicate...", "duplicate range="+sMinor+"-"+sMajor); run("Z Project...", "projection=[Max Intensity]"); // Focused DAPI Export DAPIfocus = directoryImages+"/IMG3_"+replace(File.getName(RAWimage), ".","_")+"_Focal_Frame_DAPI.tif"; if (!File.exists(DAPIfocus)) { saveAs(".tiff", DAPIfocus); } run("Enhance Contrast...", "saturated=0.3 normalize"); run("Multiply...", "value=1.7"); if(!flat) run("Subtract Background...", "rolling=500"); run("Maximum...", "radius=2"); run("Gamma...", "value=4"); run("Make Binary", "method=Otsu background=Default calculate black"); run("Fill Holes"); // Nuclear Binary Image Export nucBinary = directoryImages+"/IMG4_"+replace(File.getName(RAWimage), ".","_")+"_Nuclear_Binary.tif"; if (!File.exists(nucBinary)) { saveAs(".tiff", nucBinary); } run("Analyze Particles...", "size=100-Infinity circularity=0.50-1.00 exclude add"); // Does not Clear ROI Manager m = roiManager("count") - n; roiManager("Show All without labels"); if (m > 0) { for (i = 0; i < m; i++) { showStatus("Sculpting Nuclear ROIs... "); roiManager("Select", n+i); run("Enlarge...", "enlarge=1"); run("Fit Ellipse"); roiManager("Update"); roiManager("Set Color", "red"); roiManager("Set Line Width", 2); roiManager("Rename", "Nucleus_"+(i+1)); showStatus("Sculpting Nuclear ROIs..."); showProgress(i, m-1); } } roiManager("Select", Array.reverse(Array.trim(Array.reverse(Array.getSequence(roiManager("Count"))), m))); roiManager("Measure"); print("\n[Nucleus Measurement Report]"); print("Measurements: "+nResults+" Datapoints corresponding to "+m+" Nuclear ROIs"); showStatus("Generating Histograms..."); // Unmerged Nuclear Size Histogram Export run("Distribution...", "parameter=Area or="+bins+" and=0-0"); histogram2 = directoryHistogram+"/"+replace(File.getName(RAWimage), ".","_")+"_Nuclear_Size_Histogram.png"; if (!File.exists(histogram2)) { selectImage("Area Distribution"); saveAs(".png", histogram2); } // Unmerged Nuclear Size Table Export resultFile2 = directoryData+"/"+replace(File.getName(RAWimage), ".","_")+"_Nuclear_Size.csv"; if (!File.exists(resultFile2)) { selectWindow("Results"); saveAs("Results", resultFile2); } // ------- Intermission - Manual ROI Screening --------------------------------------------------------- close('*'); showStatus("Manual ROI Screening"); open(DAPIimage); roiManager("Show All without labels"); selectWindow("ROI Manager"); waitForUser("Please maually screen ROIs\nOnce complete, click OK."); n = countROIs('C'); // Recount Cells m = roiManager("count") - n; // ------- Phase Five - Outline Exporting -------------------------------------------------------------- // ROI Export - Unmerged roiFile1 = directoryROIs+"/"+replace(File.getName(RAWimage), ".","_")+"_ROIs.zip"; if (!File.exists(roiFile1)) { roiManager("Save", roiFile1); } deleteList = newArray(); imageWidth = getWidth(); imageHeight = getHeight(); topLimit = limitSize; bottomLimit = imageHeight - limitSize; leftLimit = limitSize; rightLimit = imageWidth - limitSize; run("Text Window...", "name=[Outline] width=100 height=50 monospaced"); print("[Outline]","\\Update:"); print("[Outline]", "FISH-QUANT\t"); print("[Outline]", "\nFile-version\t"); print("[Outline]", "\nRESULTS OF SPOT DETECTION PERFORMED ON\t"); print("[Outline]", "\nCOMMENT Automated outline definition (batch or quick-save)"); print("[Outline]", "\nIMG_Raw\t"+File.getName(RAWimage)); print("[Outline]", "\nIMG_Filtered\t"); print("[Outline]", "\nIMG_DAPI\t"+File.getName(DAPIimage)); print("[Outline]", "\nIMG_TS_label\t"); print("[Outline]", "\nFILE_settings"); print("[Outline]", "\nPARAMETERS"); print("[Outline]", "\nPix-XY\tPix-Z\tRI\tEx\tEm\tNA\tType"); print("[Outline]", "\n-\t-\t-\t-\t-\t-\t-"); for (i = 0; i < n; i++) { x_cell = newArray(); y_cell = newArray(); showStatus("Pairing ROIs..."); showProgress(i, n-1); roiManager("Select", i); roiManager("Set Line Width", 4); getSelectionCoordinates(x_cell, y_cell); nuclearIndex = newArray(); if (neg(x_cell, leftLimit, rightLimit) && neg(y_cell, topLimit, bottomLimit)) { print("[Outline]", "\nCELL_START\t"+call("ij.plugin.frame.RoiManager.getName", i)); print("[Outline]", "\nX_POS\t"+tsv(x_cell)); print("[Outline]", "\nY_POS\t"+tsv(y_cell)); print("[Outline]", "\nZ_POS\t"); print("[Outline]", "\nCELL_END"); for (j = 0; j < m; j++) { x_nucleus = newArray(); y_nucleus = newArray(); k = n+j; roiManager("Select", newArray(i,k)); roiManager("AND"); if ((i!=k)&&(selectionType>-1)) { roiManager("Select", k); getSelectionCoordinates(x_nucleus, y_nucleus); if (neg(x_nucleus, leftLimit, rightLimit) && neg(y_nucleus, topLimit, bottomLimit)) { nuclearIndex = append(nuclearIndex,k); } } } if (nuclearIndex.length == 1) { roiManager("Select", nuclearIndex[0]); roiManager("Rename", "Single_"+call("ij.plugin.frame.RoiManager.getName", i)+"_Nucleus"); getSelectionCoordinates(x_nucleus, y_nucleus); print("[Outline]", "\nNucleus_START\t"+call("ij.plugin.frame.RoiManager.getName", nuclearIndex[0])); print("[Outline]", "\nX_POS\t"+tsv(x_nucleus)); print("[Outline]", "\nY_POS\t"+tsv(y_nucleus)); print("[Outline]", "\nZ_POS\t\t\t"); print("[Outline]", "\nNucleus_END"); } else if (nuclearIndex.length == 2) { // Merging Two Nuclei roiManager("Select", nuclearIndex[0]); getSelectionCoordinates(xa, ya); roiManager("Select", nuclearIndex[1]); getSelectionCoordinates(xb, yb); arr = mergeROIs(xa,ya,xb,yb); mergex = newArray(xa.length+xb.length+2); mergey = newArray(ya.length+yb.length+2); xbNew = cycle(xb,arr[5]); ybNew = cycle(yb,arr[5]); for (v = 0; v < arr[2]; v++) { mergex[v] = xa[v]; mergey[v] = ya[v]; } for (v = 0; v < xbNew.length; v++) { mergex[arr[2]+v] = xbNew[v]; mergey[arr[2]+v] = ybNew[v]; } mergex[arr[2]+xbNew.length] = mergex[arr[2]]; mergey[arr[2]+ybNew.length] = mergey[arr[2]]; for(v = 0; v < (xa.length - arr[2]); v++) { mergex[arr[2]+xbNew.length+1+v] = xa[arr[2]-1+v]; mergey[arr[2]+ybNew.length+1+v] = ya[arr[2]-1+v]; } mergex[xb.length+xa.length+1] = xa[xa.length-1]; mergey[xb.length+xa.length+1] = ya[xa.length-1]; roiManager("Select", nuclearIndex[0]); makeSelection("trace", mergex, mergey); roiManager("Update"); roiManager("Rename", "Merged_"+call("ij.plugin.frame.RoiManager.getName", i)+"_Nucleus"); roiManager("Set Color", "magenta"); roiManager("Set Line Width", 2); deleteList = append(deleteList, nuclearIndex[1]); print("[Outline]", "\nNucleus_START\t"+call("ij.plugin.frame.RoiManager.getName", nuclearIndex[0])); print("[Outline]", "\nX_POS\t"+tsv(mergex)); print("[Outline]", "\nY_POS\t"+tsv(mergey)); print("[Outline]", "\nZ_POS\t\t\t"); print("[Outline]", "\nNucleus_END"); } } else { // Edge Cell Markup roiManager("Set Color", "red"); roiManager("Set Line Width", 4); deleteList = append(deleteList, i); } } for (r = 0; r < roiManager("Count"); r++) { // Exclusion Cleanup showStatus("Deleting Excluded ROIs..."); roiManager("Select", r); if (startsWith(call("ij.plugin.frame.RoiManager.getName", r),'N')) { deleteList = append(deleteList, r); } } print("[Outline]", "\n"); image = getTitle; // Delete Redundant and Excluded ROIs roiManager("Select", deleteList); roiManager("Delete"); // ROI Export - Merged roiFile2 = directoryROIs+"/_FILTERED_"+replace(File.getName(RAWimage), ".","_")+"_ROIs.zip"; if (!File.exists(roiFile2)) { roiManager("Save", roiFile2); } run("Clear Results"); n = countROIs('C'); // Recount Cells m = roiManager("count") - n; roiManager("Select",Array.reverse(Array.trim(Array.reverse(Array.getSequence(roiManager("Count"))), m))); if (m > 0) roiManager("Measure"); print("\n[Nucleus Pairing Report]"); print("Total Cells: " + n); print("Cells - Single Nuclei: " + countROIs("S")+" ("+d2s((countROIs("S")/n*100),3)+"%)"); print("Cells - Merged Nuclei: " + countROIs("M")+" ("+d2s((countROIs("M")/n*100),3)+"%)"); // Merged Nuclear Size Histogram Export run("Distribution...", "parameter=Area or="+bins+" and=0-0"); histogram3 = directoryHistogram+"/_FILTERED_"+replace(File.getName(RAWimage), ".","_")+"Nuclear_Size_Histogram.png"; if (!File.exists(histogram3)) { selectImage("Area Distribution"); saveAs(".png", histogram3); } // Merged Nuclear Size Table Export resultFile3 = directoryData+"/_FILTERED_"+replace(File.getName(RAWimage), ".","_")+"_Nuclear_Size.csv"; if (!File.exists(resultFile3)) { selectWindow("Results"); saveAs("Results", resultFile3); } // Export Outlines outlineFile = directoryMain+"/"+replace(File.getName(RAWimage), ".","_")+"_Outline.txt"; if (!File.exists(outlineFile)) { selectWindow("Outline"); saveAs("Text", outlineFile); } // ------- Final Steps - Filtered Output Generation -------------------------------------------------------------- n = countROIs('C'); // Recount Cells m = roiManager("count") - n; run("Clear Results"); roiManager("Select", Array.getSequence(n)); selectImage(image); roiManager("Measure"); showStatus("Generating Histograms..."); // Filtered Cell Size Histogram Export run("Distribution...", "parameter=Area or="+bins+" and=0-0"); FILhistogram1a = directoryHistogram+"/_FILTERED_"+replace(File.getName(RAWimage), ".","_")+"_Cell_Size_Histogram.png"; if (!File.exists(FILhistogram1a)) { selectImage("Area Distribution"); saveAs(".png", FILhistogram1a); } // Filtered Cell Length Histogram Export run("Distribution...", "parameter=Major or="+bins+" and=0-0"); FILhistogram1b = directoryHistogram+"/_FILTERED_"+replace(File.getName(RAWimage), ".","_")+"_Cell_Length_Histogram.png"; if (!File.exists(FILhistogram1b)) { selectImage("Major Distribution"); saveAs(".png", FILhistogram1b); } // Filtered Cell Width Histogram Export run("Distribution...", "parameter=Minor or="+bins+" and=0-0"); FILhistogram1c = directoryHistogram+"/_FILTERED_"+replace(File.getName(RAWimage), ".","_")+"_Cell_Width_Histogram.png"; if (!File.exists(FILhistogram1c)) { selectImage("Minor Distribution"); saveAs(".png", FILhistogram1c); } // Filtered Cell Size File Export FILresultFile = directoryData+"/_FILTERED_"+replace(File.getName(RAWimage), ".","_")+"_Cell_Size.csv"; if (!File.exists(FILresultFile)) { selectWindow("Results"); saveAs("Results", FILresultFile); } selectWindow(replace(File.getName(RAWimage), ".","_")+"_Outline.txt"); run("Close"); roiManager("Reset"); close('*'); showStatus("Producing Overlays..."); setBatchMode("hide"); // Overlay Production - Axis Annotation open(AFPfocus); run("RGB Color"); setLineWidth(2); for(i = 0; i < nResults; i++) { showProgress(i, nResults-1); x = getResult('X',i); y = getResult('Y',i); d = getResult("Major",i); a = getResult("Angle",i)*PI/180; setColor("blue"); drawLine(x+(d/2)*cos(a),y-(d/2)*sin(a),x-(d/2)*cos(a),y+(d/2)*sin(a)); d = getResult("Minor",i); a = a+PI/2; setColor("red"); drawLine(x+(d/2)*cos(a),y-(d/2)*sin(a),x-(d/2)*cos(a),y+(d/2)*sin(a)); } // Axis Annotation Overlay Export overlay1 = directoryOverlays+"/IMG0_"+replace(File.getName(RAWimage), ".","_")+"_Axis.tif"; if (!File.exists(overlay1)) { saveAs(".tiff", overlay1); } roiManager("Reset"); close('*'); showStatus("Producing Overlays..."); open(DAPIfocus); run("RGB Color"); roiManager("Open", roiFile2); n = countROIs('C'); roiManager("Select", Array.getSequence(n)); roiManager("Delete"); roiManager("Deselect"); run("From ROI Manager"); run("Flatten", "stack"); // Nuclear ROI Overlay on DAPI Export overlay2 = directoryOverlays+"/IMG1_"+replace(File.getName(RAWimage), ".","_")+"_Nuclear_ROIs_DAPI.tif"; if (!File.exists(overlay2)) { saveAs(".tiff", overlay2); } roiManager("Reset"); close('*'); showStatus("Producing Overlays..."); open(RAWimage); run("RGB Color"); roiManager("Open", roiFile2); n = countROIs('C'); m = roiManager("count") - n; roiManager("Select",Array.reverse(Array.trim(Array.reverse(Array.getSequence(roiManager("Count"))), m))); roiManager("Delete"); roiManager("Deselect"); run("From ROI Manager"); run("Flatten", "stack"); // Cell ROI Overlay on RAW Export overlay3 = directoryOverlays+"/IMG2_"+replace(File.getName(RAWimage), ".","_")+"_Cell_ROIs_RAW.tif"; if (!File.exists(overlay3)) { saveAs(".tiff", overlay3); } roiManager("Reset"); close('*'); showStatus("Producing Overlays..."); open(AFPfocus); run("RGB Color"); roiManager("Open", roiFile2); n = countROIs('C'); m = roiManager("count") - n; roiManager("Select",Array.reverse(Array.trim(Array.reverse(Array.getSequence(roiManager("Count"))), m))); roiManager("Delete"); roiManager("Deselect"); run("From ROI Manager"); run("Flatten", "stack"); // Cell ROI Overlay on AFP Export overlay4 = directoryOverlays+"/IMG3_"+replace(File.getName(RAWimage), ".","_")+"_Cell_ROIs_AFP.tif"; if (!File.exists(overlay4)) { saveAs(".tiff", overlay4); } t1 = getTime(); tf = t1 - t0; print("\n[Runtime Report]"); print("Total Runtime: " + d2s(tf/1000,2) + " seconds"); // Log File Export logFile = directoryMain+"/"+logID+"_runLog.txt"; if (!File.exists(logFile)) { selectWindow("Log"); saveAs("Text", logFile); } cleanAll(); waitForUser("Segmentation and Analysis are Complete\nPlease review files in output directory."); } // ------- Function Bank ---------------------------------------------------------------------------------------- // Clean Up Function function cleanAll() { close('*'); run("Clear Results"); roiManager("Reset"); print("\\Clear"); } // Append to Array Function function append(arr, value) { arr2 = newArray(arr.length+1); for (i=0; i upper) qual = false; } return qual; } // Cycles Values to Index function cycle(arr, index) { n = arr.length; cycledArray = newArray(n); if (index < n) { for (i = index; i < n; i++) cycledArray[i-index] = arr[i]; for (i = 0; i < index; i++) cycledArray[n+i-index] = arr[i]; } return cycledArray; } // Find Bridging Coordinates function mergeROIs(x1,y1,x2,y2) { index1 = 0; index2 = 0; bestDistance = 50000; // Some arbitrary large number result = newArray(7); if ((x1.length == y1.length) && (x2.length == y2.length)) { for (i = 0; i < x1.length; i++) { for (j = 0; j < x2.length; j++) { distance = sqrt(pow(x1[i]-x2[j],2)+pow(y1[i]-y2[j],2)); if (distance < bestDistance) { bestDistance = distance; result[0] = x1[i]; // [A] Bridge Point X result[1] = y1[i]; // [A] Bridge Point Y result[2] = i; // [A] Bridge Point index result[3] = x2[j]; // [B] Bridge Point X result[4] = y2[j]; // [B] Bridge Point Y result[5] = j; // [B] Bridge Point index result[6] = bestDistance; // {A,B] Distance between Bridge Points } } } } return result; } // Count ROIs with Matching First Letter function countROIs(firstLetter) { ping = NaN; n = roiManager("Count"); for (i = 0; i < n; i++) { if (startsWith(call("ij.plugin.frame.RoiManager.getName", i),firstLetter)) { if (isNaN(ping)) ping = 1; else ping++; } } return ping; } // Debug Intervene Function - Add inbetween lines to Debug function intervene() { waitForUser("Macro has been halted for debugging."); }