/** * MRI Analyze Roots Tool * Collaborators: * Philippe NACRY * * The tool allows to * * measure the length and area of the main root * * the number of secondary roots * * the length and area of the whole root * * (c) 2017-2022, INSERM * written by Volker Baecker at Montpellier RIO Imaging (www.mri.cnrs.fr) * */ var _MIN_AREA = 150; var _MAX_ROOT_WIDTH = 25; var _MIN_ROOT_LENGTH = 30; var _STEP_WIDTH = 2; var _MEDIAN_FILTER_RADIUS = 1; var _TIP_DISTANCE = 1; var _ENLARGE_MAIN_ROOT_SELECTION1 = 4; var _MAIN_CENTER_COLOR = "blue"; var _SKELETON_COLOR = "red"; var _MAIN_BORDER_COLOR = "magenta"; var _SEC_ROOT_COLOR = "green"; var _MIN_OBJECT_SIZE = 25; var _REPORT_TITLE = "Roots-measurements"; var _REPORT_HANDLE = "[" + _REPORT_TITLE + "]"; var _CONTROL_FOLDER = "control"; var _ROTATE = false; var _ROTATE_DIRECTION = "Right"; var _FILE_EXTENSION = ".jpg"; var _DO_PREPROCESSING = false; var _TEXT_SIZE = 8; var _THRESHOLDING_METHOD = "IsoData"; var _THRESHOLDING_METHODS = getList("threshold.methods"); var helpURL = "http://dev.mri.cnrs.fr/wiki/imagej-macros/MRI_Analyze_Roots_Tool"; openResultsTable(); analyzeRootsInCurrentImage(); exit; macro "MRI Analyze Roots Tool Help Action Tool - - C0f0D53D63Da4DadDb4Cf00D2bD35D37D38D39D3aD3bD44D45D46D54Db5Db6DbdDbeDc7Dc8Dc9DdaDeaDebC00fD71D72D79D7aD7bD7cD83D84D85D86D87D88D8cD8dD8eD93D94D95D96Cff0D00D01D02D03D04D05D06D07D08D09D0aD0bD0cD0dD0eD0fD10D1fD20D2fD30D3fD40D4fD50D5fD60D6fD70D7fD80D8fD90D9fDa0DafDb0DbfDc0DcfDd0DdfDe0DefDf0Df1Df2Df3Df4Df5Df6Df7Df8Df9DfaDfbDfcDfdDfeDffCf0eD61D62D68D69D6aD6bD6cD6dD73D74D75D76D77D78D7dD7eD81D82D89D8aD8bD92D97D98D99D9bD9cD9dD9eDa2Da3Da5Da6"{ run('URL...', 'url='+helpURL); } macro "Analyze Current Image (f5) Action Tool - C000T4b12a" { openResultsTable(); analyzeRootsInCurrentImage(); } macro 'Analyze Current Image [f5]' { openResultsTable(); analyzeRootsInCurrentImage(); } macro "Batch Process Images (f6) Action Tool - C000T4b12b" { openResultsTable(); batchProcessImages(); } macro 'Batch Process Images [f6]' { openResultsTable(); batchProcessImages(); } macro 'Analyze Current Image (f5) Action Tool Options' { showOptionsDialog(); } macro 'Batch Process Images (f6) Action Tool Options' { showOptionsDialog(); } function showOptionsDialog() { Dialog.create("Analyze Roots Tool Options"); Dialog.addCheckbox("preprocess image", _DO_PREPROCESSING); Dialog.addChoice("auto-thresholding method: ", _THRESHOLDING_METHODS, _THRESHOLDING_METHOD); Dialog.addNumber("min. area: ", _MIN_AREA); Dialog.addNumber("max. root width: ", _MAX_ROOT_WIDTH); Dialog.addNumber("min. root length: ", _MIN_ROOT_LENGTH); Dialog.addNumber("step width: ", _STEP_WIDTH); Dialog.addNumber("median filter radius: ", _MEDIAN_FILTER_RADIUS); Dialog.addNumber("tip distance: ", _TIP_DISTANCE); Dialog.addNumber("enlarge main root selection: ", _ENLARGE_MAIN_ROOT_SELECTION1); Dialog.addNumber("min. object size: ", _MIN_OBJECT_SIZE); Dialog.addNumber("text size: ", _TEXT_SIZE); Dialog.addString("center color of main root: ", _MAIN_CENTER_COLOR); Dialog.addString("border color of main root: ", _MAIN_BORDER_COLOR); Dialog.addString("skeleton color of secondary roots: ", _SKELETON_COLOR); Dialog.addString("base color of secondary roots: ", _SEC_ROOT_COLOR); Dialog.addChoice("rotate image into direction: ", newArray("Right", "Left", "None"), _ROTATE_DIRECTION); Dialog.addString("file extension: ", _FILE_EXTENSION); Dialog.show(); _DO_PREPROCESSING = Dialog.getCheckbox(); _THRESHOLDING_METHOD = Dialog.getChoice(); _MIN_AREA = Dialog.getNumber(); _MAX_ROOT_WIDTH = Dialog.getNumber(); _MIN_ROOT_LENGTH = Dialog.getNumber(); _STEP_WIDTH = Dialog.getNumber(); _MEDIAN_FILTER_RADIUS = Dialog.getNumber(); _TIP_DISTANCE = Dialog.getNumber(); _ENLARGE_MAIN_ROOT_SELECTION1 = Dialog.getNumber(); _MIN_OBJECT_SIZE = Dialog.getNumber(); _TEXT_SIZE = Dialog.getNumber(); _MAIN_CENTER_COLOR = Dialog.getString(); _MAIN_BORDER_COLOR = Dialog.getString(); _SKELETON_COLOR = Dialog.getString(); _SEC_ROOT_COLOR = Dialog.getString(); _ROTATE_DIRECTION = Dialog.getChoice(); if (_ROTATE_DIRECTION=="None") _ROTATE = false; else _ROTATE = true; _FILE_EXTENSION = Dialog.getString(); } function openResultsTable() { if (!isOpen(_REPORT_TITLE)){ run("Table...", "name="+_REPORT_HANDLE+" width=800 height=600"); print(_REPORT_HANDLE, "\\Headings:nr\tmain root length\tmain root area\tnr. of 2-order roots\ttotal area\ttotal length\timage"); } } function batchProcessImages() { getDateAndTime(year, month, dayOfWeek, dayOfMonth, hour, minute, second, msec); startTimeStamp = "" + year + "-" + (month + 1)+"-"+dayOfMonth+"--"+hour+"."+minute+"."+second+"."+msec; dir = getDirectory("Please select the input folder!"); files = getFileList(dir); images = newArray(); print("\\Clear"); print(startTimeStamp); print("Start analyzing roots"); for(i=0; i= 0) { run("Enlarge...", "enlarge=20"); run("Enlarge...", "enlarge=-30"); } getStatistics(area, mean); run("Create Mask"); firstMaskID = getImageID(); run("Fill Holes"); run("Create Selection"); selectImage(inputImageID); run("Restore Selection"); selectImage(firstMaskID); close(); selectImage(inputImageID); run("Make Inverse"); setForegroundColor(mean, mean, mean); run("Fill", "slice"); run("Select None"); } function analyzeRootsInCurrentImage() { setBackgroundColor(255,255,255); run("Set Measurements...", "area bounding area_fraction stack display redirect=None decimal=3"); roiManager("Reset"); run("Select None"); inputImageID = getImageID(); inputTitle = getTitle(); if (_DO_PREPROCESSING) preprocessImage(); run("8-bit"); run("Duplicate...", " "); maskImage = getImageID(); setAutoThreshold(_THRESHOLDING_METHOD); setOption("BlackBackground", false); run("Convert to Mask"); findTips(); selectImage(inputImageID); traceMainRoots(); smoothTracings(); selectImage(maskImage); boxStartIndex = roiManager("count"); run("Analyze Particles...", "size="+_MIN_AREA+"-Infinity add"); boxEndIndex = roiManager("count"); nrOfRoots = boxEndIndex-boxStartIndex; xCoordinates = newArray(nrOfRoots); counter = 0; for(i=boxStartIndex; i0) { roiManager("add"); last = roiManager("count") - 1; roiManager("Select", last); roiManager("Rename", rootNR + "-skeletons"); roiManager("Set Color", _SKELETON_COLOR); } run("Select None"); measurements[rootNR-1] = "" + length + "\t" + area +"\t" + nrOfSecondOrderRoots + "\t" + totalArea + "\t" + totalLength + "\t" + inputTitle; } close(); // remove left and right border selections for(i=0; i0) { ul = getPixel(x-1, y-1); um = getPixel(x, y-1); ur = getPixel(x+1, y-1); l = getPixel(x-1, y); r = getPixel(x+1, y); ll = getPixel(x-1, y+1); lm = getPixel(x, y+1); lr = getPixel(x+1, y+1); if (um>0) straightCounter++; if (l>0) straightCounter++; if (r>0) straightCounter++; if (lm>0) straightCounter++; if (ul>0 && l==0 && um==0) diagonalCounter++; if (ur>0 && r==0 && um==0) diagonalCounter++; if (ll>0 && l==0 && lm==0) diagonalCounter++; if (lr>0 && r==0 && lm==0) diagonalCounter++; } } } straightCounter = straightCounter / 2.0; diagonalCounter = diagonalCounter / 2.0; result = straightCounter + (diagonalCounter * sqrtOfTwo); getPixelSize(unit, pw, ph, pd); result = result * pw; return result; }