/* * Macro template to process multiple images in a folder */ // input parameters #@ File (label = "Input directory", style = "directory") input #@ File (label = "Output directory", style = "directory") output #@ Integer (label = "Channel for nuclei", value = 1, style = "spinner") nucleus_channel #@ Integer (label = "Channel for FISH", value = 2, style = "spinner") FISH_channel #@ Integer (label = "Kernel size for Gaussian blur before applying Cellpose", value = 5, style = "spinner") gaussian_blur #@ Integer (label = "Nucleus size for Cellpose", value = 120, style = "spinner") nucleus_scale_parameter #@ Float (label = "Threshold for Cellpose", value = 0.0, style="format:#.##") nucleus_threshold #@ Float (label = "Threshold for z stitching", value = 0.1, style="format:#.##") stitch_threshold #@ Integer (label = "Minimum nucleus size", value = 5000, style = "spinner") min_size_nuclei #@ Float (label = "LoG radius for mRNA transcripts", value = 3.0, style="format:#.##") LoG_radius #@ Float (label = "LoG quality for mRNA transcripts", value = 20.0, style="format:#.##") LoG_quality #@ String (label = "File suffix", value = ".tif") suffix // call to the main function "processFolder" processFolder(input); // function to scan folders/subfolders/files to find files with correct suffix function processFolder(input) { ///////////// initial cleaning ///////////////// // close all images run("Close All"); // reset ROI manager roiManager("Reset"); // clear results run("Clear Results"); ///////////// apply pipeline to input images ///////////////// // get the files in the input folder list = getFileList(input); list = Array.sort(list); // loop over the files for (i = 0; i < list.length; i++) { // if current file ends with the suffix given as input parameter, call function "processFile" to process it if(endsWith(list[i], suffix)) processFile(input, output, list[i]); } // reset ROI manager roiManager("Reset"); } function processFile(input, output, file) { // open image open(input + File.separator + file); // rename rename("Input"); // split channels run("Split Channels"); // Gaussian blur selectImage("C" + nucleus_channel + "-Input"); run("Duplicate...", "title=C" + nucleus_channel + "-InputForSegmentation duplicate"); run("Gaussian Blur...", "sigma=" + gaussian_blur + " stack"); // segment nuclei with cellpose run("Cellpose Advanced", "diameter=" + nucleus_scale_parameter + " cellproba_threshold=" + nucleus_threshold + " flow_threshold=10.0 anisotropy=1.0 diam_threshold=12.0 model=nuclei nuclei_channel=1 cyto_channel=-1 dimensionmode=2D stitch_threshold=" + stitch_threshold + " omni=false cluster=false additional_flags=4"); // size filtering run("Label Size Filtering", "operation=Greater_Than size=" + min_size_nuclei + ""); // connected components run("Connected Components Labeling", "connectivity=6 type=[16 bits]"); rename("Nuclei"); // get number of slices getDimensions(width, height, channels, slices, frames); // get number of nuclei setSlice(slices); getStatistics(area, mean, min, nb_nuclei, std, histogram); // run LoG selectImage("C" + FISH_channel + "-Input"); // change image properties Stack.setXUnit("pix"); run("Properties...", "channels=1 slices=" + slices +" frames=1 pixel_width=1 pixel_height=1 voxel_depth=1"); run("LoG Trackmate", "radius=" + LoG_radius + " quality=" + LoG_quality + ""); if (isOpen("LoGOutputCenters")){ // FISH measurements // loop over the slices current_row = 0; nb_FISH_in_nucleus = newArray(nb_nuclei); for (k=1 ; k<=slices; k++) { // duplicate slice #i for LoG output selectImage("LoGOutputCenters"); run("Duplicate...", "title=FISHCenters_currentSlice_noLabel duplicate range=" + k + "-" + k + ""); // connected components run("Connected Components Labeling", "connectivity=4 type=[16 bits]"); rename("FISHCenters_currentSlice"); // dilation run("Morphological Filters", "operation=Dilation element=Disk radius=" + LoG_radius + ""); rename("FISH_currentSlice"); // duplicate slice #i for fish channel selectImage("C" + FISH_channel + "-Input"); run("Duplicate...", "title=FISHChannel_currentSlice duplicate range=" + k + "-" + k + ""); // duplicate slice #i for nuclei selectImage("Nuclei"); run("Duplicate...", "title=Nuclei_currentSlice duplicate range=" + k + "-" + k + ""); // nuclei measurements // for each nucleus, get number of FISH in the nucleus run("3D Numbering", "main=Nuclei_currentSlice counted=FISHCenters_currentSlice"); // rename measurements as Results if (isOpen("Numbering")){ Table.rename("Numbering", "Results"); updateResults(); for (i = 0; i < nResults; i++) { nucleus_label = getResult("Value", i); nb_FISH_in_nucleus[nucleus_label-1] = nb_FISH_in_nucleus[nucleus_label-1] + getResult("NbObjects", i); } // close results table selectWindow("Results"); run("Close"); } // FISH measurements // measure average and max intensity for each FISH run("Intensity Measurements 2D/3D", "input=[FISHChannel_currentSlice] labels=FISH_currentSlice mean max"); // rename measurements as Results Table.rename("FISHChannel_currentSlice-intensity-measurements", "Results"); // get average and max intensity for each FISH current_nb_FISH = nResults; if(current_nb_FISH>0) { FISH_mean = newArray(current_nb_FISH); FISH_max = newArray(current_nb_FISH); for (i = 0; i < current_nb_FISH; i++) { FISH_mean[i] = getResult("Mean", i); FISH_max[i] = getResult("Max", i); } // close results table selectWindow("Results"); run("Close"); // for each mRNA, evaluate if inside nucleus or not run("3D Numbering", "main=FISHCenters_currentSlice counted=Nuclei_currentSlice"); // rename measurements as Results Table.rename("Numbering", "Results"); updateResults(); wait(200); Table.deleteColumn("VolObjects"); Table.deleteColumn("PercObjects"); Table.deleteColumn("Channel"); Table.deleteColumn("Frame"); Table.deleteColumn("Label"); Table.renameColumn("NbObjects", "In a nucleus"); // add intensity measurements to distance table if (k==1){ for (i = 0; i < current_nb_FISH; i++) { setResult("Avg intensity", i, FISH_mean[i]); setResult("Max intensity", i, FISH_max[i]); setResult("Frame", i, k); } updateResults(); current_row = current_nb_FISH; Table.rename("Results", "FinalFISHResults"); updateResults(); selectImage("FISHCenters_currentSlice"); rename("FISHCenters"); selectImage("FISH_currentSlice"); rename("FISH"); } else{ // concatenate images run("Concatenate...", " title=FISHCenters open image1=FISHCenters image2=FISHCenters_currentSlice image3=[-- None --]"); run("Concatenate...", " title=FISH open image1=FISH image2=FISH_currentSlice image3=[-- None --]"); // concatenate results current_inside = newArray(current_nb_FISH); for (i = 0; i < current_nb_FISH; i++) { current_inside[i] = getResult("In a nucleus", i); } selectWindow("Results"); updateResults(); run("Close"); if(isOpen("FinalFISHResults")){ Table.rename("FinalFISHResults", "Results"); for (i = 0; i < current_nb_FISH; i++) { setResult("Value", i+current_row, i+1); setResult("In a nucleus", i+current_row, current_inside[i]); setResult("Avg intensity", i+current_row, FISH_mean[i]); setResult("Max intensity", i+current_row, FISH_max[i]); setResult("Frame", i+current_row, k); } updateResults(); current_row = nResults; Table.rename("Results", "FinalFISHResults"); updateResults(); } else{ for (i = 0; i < current_nb_FISH; i++) { setResult("Avg intensity", i, FISH_mean[i]); setResult("Max intensity", i, FISH_max[i]); setResult("Frame", i, k); } updateResults(); current_row = current_nb_FISH; Table.rename("Results", "FinalFISHResults"); updateResults(); } } } else{ if (k==1) { selectImage("FISHCenters_currentSlice"); rename("FISHCenters"); selectImage("FISH_currentSlice"); rename("FISH"); } else{ // concatenate images run("Concatenate...", " title=FISHCenters open image1=FISHCenters image2=FISHCenters_currentSlice image3=[-- None --]"); run("Concatenate...", " title=FISH open image1=FISH image2=FISH_currentSlice image3=[-- None --]"); } } // wait to make sure we gonna close the images wait(200); // close images selectImage("Nuclei_currentSlice"); run("Close"); selectImage("FISHChannel_currentSlice"); run("Close"); selectImage("FISHCenters_currentSlice_noLabel"); run("Close"); } // convert FISH into stack selectImage("FISH"); run("Stack to Hyperstack...", "order=xyczt(default) channels=1 slices=" + slices + " frames=1 display=Color"); // save results wait(200); Table.rename("FinalFISHResults", "Results"); file_name = replace(file, ".tif", "_FISH_results.csv"); saveAs("Results", output + File.separator + file_name); // close results table selectWindow("Results"); run("Close"); // get volume and centroid coordinates for each nucleus selectImage("Nuclei"); run("Analyze Regions 3D", "volume centroid surface_area_method=[Crofton (13 dirs.)] euler_connectivity=6"); // rename table Table.rename("Nuclei-morpho", "Results"); // add number of FISH in and out the nucleus, for each nucleus for (i = 0; i < nb_nuclei; i++) { setResult("#FISH in nucleus", i, nb_FISH_in_nucleus[i]); } updateResults(); // save results file_name = replace(file, ".tif", "_nuclei_results.csv"); saveAs("Results", output + File.separator + file_name); // close results table selectWindow("Results"); run("Close"); // use names as labels for ROIs roiManager("UseNames", "true"); // select image with all nuclei selectImage("Nuclei"); // update nuclei colors setSlice(slices); resetMinAndMax(); // duplicate first slice for visual inspection run("Duplicate...", "title=CurrentNuclei duplicate range=" + 1 + "-" + 1 + ""); // label to ROIs run("Label image to composite ROIs", "rm=[RoiManager]"); // loop over ROIs for (k=0 ; k