Snippets
Dave Mason Analysis of Aorta Images from Ilastik Masks (See Chim et al. "Micromechanical and structural properties of elastin to predict the aetiology of ascending aortic aneurysm" for details)
Created by
Dave Mason
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 | // @File(label="Input directory", description="Select the directory with input images", style="directory") inPath // @String(label="Scale Factor", description="Scale to this fraction. Runs faster but less accurate", choices={"1","0.5","0.25"}, default="0.25",persist=false ) scaleFrac // @String(label="Verbose Level", description="Higher number prints more info", choices={"0","1","2"}, default="0",persist=false ) verbose // // -------------------------------------------------- // Analysis of Elastin in Aorta sections // -------------------------------------------------- // // Script which analyses pre-segmented images by skeletonisation. // Requires images pre-processed with Ilastik to produce Simple Segmentation masks // in 8-bit tif format. // // Regions labelled '1' will be used for further processing, BG can be anything else. // // // - Dave Mason [dnmason@liv.ac.uk] // Centre for Cell Imaging, Liverpool [http://cci.liv.ac.uk] // //--------------------------------------------------- //-- RUN OPTIONS: //------------------------------------ //-- Define verbosity: // 0= Finished message only // 1= File Processing (show images, give updates on processing) // 2= Full debug output (as above but also lists arrays) verbose=parseInt(verbose); //verbose=0; //------------------------------------ if (verbose==0){setBatchMode(true);} //------------------------------------ //-- When refining the mask, only include objects bigger than this (pixels) minObjSize=80; //------------------------------------ //--------------------------------//------------------------------------ //-- PART 1: Get file list and specify arrays //--------------------------------//------------------------------------ saveSettings(); if (verbose>0){print("------------------------");} if (verbose>0){print("Processing "+inPath);} dirListAll = getFileList(inPath); if (verbose>0){print("Found "+dirListAll.length+" total files");} if (verbose>1){Array.print(dirListAll);} //-- Refine dirList to only include requested filetypes dirList=newArray("removeMe"); for (q = 0; q < dirListAll.length; q++) { if(endsWith(dirListAll[q], "tif")){ dirList=Array.concat(dirListAll[q],dirList); if (verbose>1){print("Including "+dirListAll[q]);} }else{ if (verbose>1){print("Excluding "+dirListAll[q]);} } } //-- Sanity check, dirList will always have at least one entry if (dirList.length==1){ //-- No eligible files found if (verbose>0){ print("[ERROR] No eligible files found. Quitting."); exit("No eligible files found!") } }else{ //-- Remove the dummy line and continue dirList=Array.trim(dirList,dirList.length-1); } if (verbose>0){print("Found "+dirList.length+" eligible files");} if (verbose>1){Array.print(dirList);} //breakplease //-- Register arrays here with the length equal to dirList arrCount=newArray(dirList.length); arrNumBranchAV=newArray(dirList.length); arrNumBranchSD=newArray(dirList.length); arrBranchLenAV=newArray(dirList.length); arrBranchLenSD=newArray(dirList.length); arrMaxBranchLenAV=newArray(dirList.length); arrMaxBranchLenSD=newArray(dirList.length); arrLSP_AV=newArray(dirList.length); arrLSP_SD=newArray(dirList.length); //-- and a second set for the cropped regions arrCount_crop=newArray(dirList.length); arrNumBranchAV_crop=newArray(dirList.length); arrNumBranchSD_crop=newArray(dirList.length); arrBranchLenAV_crop=newArray(dirList.length); arrBranchLenSD_crop=newArray(dirList.length); arrMaxBranchLenAV_crop=newArray(dirList.length); arrMaxBranchLenSD_crop=newArray(dirList.length); arrLSP_AV_crop=newArray(dirList.length); arrLSP_SD_crop=newArray(dirList.length); //--------------------------------//------------------------------------ //-- PART 2: Loop through file list //--------------------------------//------------------------------------ for (i=0; i<dirList.length; i++){ //-- check requirements for brackets here (to deal with filenames containing spaces) open(inPath+File.separator+dirList[i]); if (verbose>0){ print("------------------------"); print("Processing file ["+(i+1)+"/"+dirList.length+"]: "+inPath+File.separator+dirList[i]);} title=getTitle(); //-- Check whether the image is horizontal or vertical and rotate as necessary getDimensions(w, h, c, s, f); if (w>h){ if (verbose>0){print("Image is landscape, rotating");} run("Rotate 90 Degrees Right"); getDimensions(w, h, c, s, f); } if (w<h){ if (verbose>0){print("Image is portrait");} } //-- Convert from a count mask (Ilastik Output) to a binary mask setThreshold(1, 1); setOption("BlackBackground", true); run("Convert to Mask"); //-- Refine mask on full size image run("Erode"); run("Analyze Particles...", "size="+minObjSize+"-Infinity pixel show=Masks in_situ"); //-- [Optionally] Scale the image to speed up runtime if (scaleFrac<1){ run("Scale...", "x="+scaleFrac+" y="+scaleFrac+" interpolation=None create title=scaled"); close(title); selectWindow("scaled"); rename(title); //-- Refresh with new dimensions so the medial crop works getDimensions(w, h, c, s, f); } //-- Duplicate the mask to run total vs central analysis run("Duplicate...", "title=medial"); medialFrac=0.15; boxHeight=floor(h*medialFrac); run("Specify...", "width="+w+" height="+boxHeight+" x=0 y="+(floor(h/2)-floor(boxHeight/2) ) ); run("Crop"); //-- set up a loop to run the analysis on the whole image (j==0) or the medial subset (j==1) for (j=0;j<2;j++){ if (j==0){selectWindow(title);if (verbose>0){print("Processing whole image...");}} if (j==1){selectWindow("medial");if (verbose>0){print("Processing cropped image...");}} run("Skeletonize"); run("Analyze Skeleton (2D/3D)", "prune=none calculate"); //-- Add the summary stats to the end of the results table run("Summarize"); //-- catch zero results in first image (no results table) and no skeletons found //if (isOpen("Results") | nResults>0) { //-- Record the stats into an array which can be saved at the end as a summary if (j==0){ //-- Check that there are more than 1 segment (with only one or zero, summarise doesn't work) if (nResults>1){ arrCount[i]=nResults-4; arrNumBranchAV[i]=getResult("# Branches",nResults-4); //-- Mean arrNumBranchSD[i]=getResult("# Branches",nResults-3); //-- SD arrBranchLenAV[i]=getResult("Average Branch Length",nResults-4)/scaleFrac; //-- Mean arrBranchLenSD[i]=getResult("Average Branch Length",nResults-3)/scaleFrac; //-- SD arrMaxBranchLenAV[i]=getResult("Maximum Branch Length",nResults-4)/scaleFrac; //-- Mean arrMaxBranchLenSD[i]=getResult("Maximum Branch Length",nResults-3)/scaleFrac; //-- SD arrLSP_AV[i]=getResult("Longest Shortest Path",nResults-4)/scaleFrac; //-- Mean arrLSP_SD[i]=getResult("Longest Shortest Path",nResults-3)/scaleFrac; //-- SD if (verbose>0){print("Number of Results: "+arrCount[i]);} } //-- nResults>0 } if (j==1){ //-- Check for no-segments here (empty results table) if (nResults>0){ arrCount_crop[i]=nResults-4; arrNumBranchAV_crop[i]=getResult("# Branches",nResults-4); //-- Mean arrNumBranchSD_crop[i]=getResult("# Branches",nResults-3); //-- SD arrBranchLenAV_crop[i]=getResult("Average Branch Length",nResults-4)/scaleFrac; //-- Mean arrBranchLenSD_crop[i]=getResult("Average Branch Length",nResults-3)/scaleFrac; //-- SD arrMaxBranchLenAV_crop[i]=getResult("Maximum Branch Length",nResults-4)/scaleFrac; //-- Mean arrMaxBranchLenSD_crop[i]=getResult("Maximum Branch Length",nResults-3)/scaleFrac; //-- SD arrLSP_AV_crop[i]=getResult("Longest Shortest Path",nResults-4)/scaleFrac; //-- Mean arrLSP_SD_crop[i]=getResult("Longest Shortest Path",nResults-3)/scaleFrac; //-- SD if (verbose>0){print("Number of Results: "+arrCount_crop[i]);} } //-- nResults>0 } //-- Set correct output for per-file data if (j==0){ outFile=substring(dirList[i], 0, lastIndexOf(dirList[i], "."))+"_alldata.csv"; } if (j==1){ outFile=substring(dirList[i], 0, lastIndexOf(dirList[i], "."))+"_cropped.csv"; } saveAs("Results", checkPath(inPath,outFile)); run("Clear Results"); } //-- close main/medial loop close("*"); } //-- Close file Loop if (verbose>0){print("------------------------");print("Done processing "+dirList.length+" files");} //--------------------------------//------------------------------------ // PART 3: Concat and save out the Summary Table //--------------------------------//------------------------------------ call("ij.plugin.filter.Analyzer.setPrecision", 1); Array.show("Results (indexes)",dirList,arrCount,arrNumBranchAV,arrNumBranchSD,arrBranchLenAV,arrBranchLenSD,arrMaxBranchLenAV,arrMaxBranchLenSD,arrLSP_AV,arrLSP_SD,arrCount_crop,arrNumBranchAV_crop,arrNumBranchSD_crop,arrBranchLenAV_crop,arrBranchLenSD_crop,arrMaxBranchLenAV_crop,arrMaxBranchLenSD_crop,arrLSP_AV_crop,arrLSP_SD_crop); saveAs("Results", checkPath(inPath,"Summary.csv")); restoreSettings(); //-- restore original settings if (isOpen("Results")) { selectWindow("Results"); run("Close"); } setBatchMode(false); print("------------------------"); print("Finished"); print("------------------------"); //----------------------------------------------------------------------------------------------- // OTHER FUNCTIONS //----------------------------------------------------------------------------------------------- function checkPath(path,file){ //-- Check if an output file already exists. //-- NO: return full path //-- YES: return full path including a timestamp with grainularity to the second wholePath=path+File.separator+file; if (File.exists(wholePath)==0){ //print("File does not exist"); return wholePath; }else{ //-- Create a unique timestamp (to the second) getDateAndTime(year, month, week, day, hour, min, sec, msec); //-- Initialse the variable with a string ts=d2s(year,0); //-- Add the rest on, zero padding - NOTE: MONTH IS ZERO INDEXED ts=ts+IJ.pad(month+1,2)+IJ.pad(day,2)+IJ.pad(hour,2)+IJ.pad(min,2)+IJ.pad(sec,2); //print("File exists"); return substring(wholePath, 0, lastIndexOf(wholePath, "."))+"_"+ts+substring(wholePath,lastIndexOf(wholePath, ".")); } } |
Comments (0)
You can clone a snippet to your computer for local editing. Learn more.