/** * root_tools * * The root tools help to efficiently measure the following characteristics of plant roots: * - the angle of the opening of the whole root * - the depth to which it goes down * - the number of roots at 30 cm depth * - the diameters of the roots at depth * * written 2013 by Volker Baecker (INSERM) at Montpellier RIO Imaging (www.mri.cnrs.fr) */ var helpURL = "http://dev.mri.cnrs.fr/wiki/imagej-macros/Root_Tools"; var KNOWN_DISTANCE = 40; // known distance for spatial calibration (there are 20mm between two nails) var RADIUS=75; // radius of the circle drawn around the root point var ROOT_POINT_LINE_WIDTH = 15; // line width of the circle drawn around the root point var COLOR_ROOT_POINT = "red"; // color of the circle drawn around the root point var COUNT_ROOT_DEPTH = 30; // depth from the root point at which the horizontal line is drawn. The number of roots will be counted at that depth var HALF_LINE_WIDTH = 10; // half of the width of the line drawn at count root depth var WIDTH_DEPTH = 8; // line width of the line drawn at count root depth var COLOR_DEPTH = "cyan"; // color of the line drawn at count root depth var DX_ANGLE = 300; // delta x for the angle tool that is added to the image var DY_ANGLE = 600; // delta y for the angle tool that is added to the image var ANGLE_COLOR = "red"; // the color for marking the measured angle var ANGLE_LINE_WIDTH = 8; // the line width for marking the measured angle var MEASURE_DEPTH_COLOR = "magenta"; // the color of the line indicating the max. depth to which the root goes down var MEASURE_DEPTH_WIDTH = 8; // the line width of the line indicating the max. depth to which the root goes down var ZOOM_RADIUS = 20; // radius of the region around the click that is copied and zoomed var DIAMETER_COLOR = "yellow"; // color of the line indicating the measured root diameters var DIAMETER_WIDTH = 2; // width of the line indicating the measured root diameters var ON_IMAGE_OPEN_ON = false; // if true commands are run when an image is opened var ON_IMAGE_OPEN_COMMANDS = newArray("Rotate 90 Degrees Left", "Enhance Contrast, saturated=0.35"); var USE_GLOBAL_SCALE = true; var rootX; var rootY; var deepX; var deepY; var UNIT = "mm"; var X1; var X2; var Y; var MAX_ROOTS = 20; var DIAMETERS = newArray(MAX_ROOTS); var numberOfRootsAtThirty = 0; var DEPTH = 0; var ID = 0; var ANGLE = 0; var TITLE; var NUMBER = 0; var FOLDER; macro "AutoRun" { script = getJSRemoveAllImageListeners(); runJS(script); ON_IMAGE_OPEN_ON = call("ij.Prefs.get", "roots.on_image_open_on", false); if (ON_IMAGE_OPEN_ON) { script = getJSAddListeners(); runJS(script); } } macro "zoomIn [f1]" { run("In [+]"); } macro "zoomOut [f2]" { run("Out [-]"); } macro "Root Tools Help Action Tool- C134D01D04D06D11D1fD20D2fD3fDcfDd4Dd7De0De2De3De4De5De6De7Df2Df3Df4Df5Df6Df7Df9DfdC345D08D09D18D25D27D32D34D3aD42D43D5fD6dD92Da3Da5Dc5Dc8DdbC334D0fD12D19D30D3bD59D5aD69D6aDa2Da4DadDaeDafDb2Db3DbdDbeDc6Dd8DdeC666D53D54D62D77D7bD7cD7dD7eD91D94D95D9aD9bD9cD9fDa9DbaDcaDcbC234D02D03D05D07D0aD0bD10D2eD4aDb4DbfDceDd0Dd1Dd5Dd6DdfDe8De9DeaDebDecDeeDf8DfbC555D0eD1bD35D36D45D50D51D52D56D6fD7aD90D93D9dDa1Da6Db1Db7DbcDddC345D0cD15D1aD37D3dD40D5cDb5Db6Dc9DfeC777D1cD57D66D71D72D73D74D76D80D82D83D88D89D8aD8eD8fD97D98C234D00Dc4Dd3De1Df0Df1DfaDfcC445D17D29D2bD38D41D46D55D58D65D6bD6eD78D79D9eDa0DacDcdC335D13D14D16D1eD23D24D28D33D3eD4cD5eD68D6cDc7Dd2DefC666D1dD48D61D63D67D70D7fD96D99Da7Da8Db9DbbDccC234D21D2dD3cD4bD4fDc0Dc3Dd9DdaDedC556D0dD26D2aD39D44D47D60D64D75DaaDabDb8DdcC345D22D2cD31D49D4dD4eD5bD5dDb0Dc1Dc2C777D81D84D85D86D87D8bD8cD8dDff" { run('URL...', 'url='+helpURL); } macro "Root Tools Help Action Tool Options" { ON_IMAGE_OPEN_ON = call("ij.Prefs.get", "roots.on_image_open_on", false); Dialog.create("Root Tools - Options"); Dialog.addCheckbox("auto run commands when image opened", ON_IMAGE_OPEN_ON); Dialog.show(); ON_IMAGE_OPEN_ON = Dialog.getCheckbox(); script = getJSRemoveAllImageListeners(); runJS(script); if (ON_IMAGE_OPEN_ON) { call("ij.Prefs.set", "roots.on_image_open_on", true); script = getJSAddListeners(); runJS(script); } else { call("ij.Prefs.set", "roots.on_image_open_on", false); } } macro "Set Scale [f5]" { setScale(); } macro "Define Root Point [f6]" { setTool("Define Root Point Tool"); } macro "Angle [f7]" { measureAngle(); } macro "Measure Depth [f8]" { setTool("Measure Depth Tool"); } macro "Zoom Region [f9]" { setTool("Zoom region Tool"); } macro "Measure Diameter [f10]" { measureDiameter(); } macro "Write Report [f11]" { writeReport(); } macro "Set Scale Action Tool- C000T4b12s"{ setScale(); } macro "Set Scale Action Tool Options" { Dialog.create("Root Tools - Set Scale - Options"); Dialog.addNumber("known distance [cm]: ", KNOWN_DISTANCE); Dialog.addCheckbox("use global scale", USE_GLOBAL_SCALE); Dialog.show(); KNOWN_DISTANCE = Dialog.getNumber(); USE_GLOBAL_SCALE = Dialog.getCheckbox(); } macro "Define Root Point Tool- C000T4b12r" { getCursorLoc(x, y, z, flags); ID = getImageID(); TITLE = getTitle(); FOLDER = getDirectory("image"); run("Remove Overlay"); rootX = x; rootY = y; setColor(COLOR_ROOT_POINT); setLineWidth(ROOT_POINT_LINE_WIDTH); Overlay.drawEllipse(rootX-RADIUS, rootY-RADIUS, 2*RADIUS+1, 2*RADIUS+1); Overlay.show(); run("Select None"); lineAtThirtyCM(); angleSelection(); setTool("Angle tool"); } macro "Define Root Point Tool Options" { Dialog.create("Root Tools - Define Root Point - Options"); Dialog.addNumber("radius: ", RADIUS); Dialog.addNumber("line width: ", ROOT_POINT_LINE_WIDTH); Dialog.addString("root point color: ", COLOR_ROOT_POINT); Dialog.addNumber("depth [cm]: ", COUNT_ROOT_DEPTH); Dialog.addNumber("half of length [cm]: ", HALF_LINE_WIDTH); Dialog.addNumber("line width for depth: ", WIDTH_DEPTH); Dialog.addString("depth line color: ", COLOR_DEPTH); Dialog.addNumber("dx angle: ", DX_ANGLE); Dialog.addNumber("dy angle: ", DY_ANGLE); Dialog.show(); RADIUS = Dialog.getNumber(); ROOT_POINT_LINE_WIDTH = Dialog.getNumber(); COLOR_ROOT_POINT = Dialog.getString(); COUNT_ROOT_DEPTH = Dialog.getNumber(); HALF_LINE_WIDTH = Dialog.getNumber(); WIDTH_DEPTH = Dialog.getNumber(); COLOR_DEPTH = Dialog.getString(); DX_ANGLE = Dialog.getNumber(); DY_ANGLE = Dialog.getNumber(); } macro "Angle Action Tool- C000T4b12a" { measureAngle(); } macro "Angle Action Tool Options" { Dialog.create("Root Tools - Angle - Options"); Dialog.addString("angle color: ", ANGLE_COLOR); Dialog.addNumber("line width: ", ANGLE_LINE_WIDTH); Dialog.show(); ANGLE_COLOR = Dialog.getString(); ANGLE_LINE_WIDTH = Dialog.getNumber(); } macro "Measure Depth Tool- C000T4b12d" { getCursorLoc(x, y, z, flags); deepX = x; deepY = y; DEPTH = deepY - rootY; toScaled(DEPTH); setColor(MEASURE_DEPTH_COLOR); setLineWidth(MEASURE_DEPTH_WIDTH); Overlay.drawLine(rootX, rootY, rootX, deepY); Overlay.drawLine(rootX, deepY, deepX, deepY); Overlay.show(); run("Select None"); setTool("Zoom region Tool"); } macro "Measure Depth Tool Options" { Dialog.create("Root Tools - Measure Depth - Options"); Dialog.addString("line color: ", MEASURE_DEPTH_COLOR); Dialog.addNumber("line width: ", MEASURE_DEPTH_WIDTH); Dialog.show(); MEASURE_DEPTH_COLOR = Dialog.getString(); MEASURE_DEPTH_WIDTH = Dialog.getNumber(); } macro "Zoom region Tool- C000T4b12z" { title = getTitle(); getCursorLoc(x, y, z, flags); makeRectangle(x-ZOOM_RADIUS, y-ZOOM_RADIUS, 2*ZOOM_RADIUS+1, 2*ZOOM_RADIUS+1); run("Duplicate...", "title="+title+"box"); run("Remove Overlay"); run("In [+]"); run("In [+]"); run("In [+]"); run("In [+]"); run("In [+]"); run("In [+]"); setTool("line"); } macro "Zoom region Tool Options" { Dialog.create("Root Tools - Zoom region - Options"); Dialog.addNumber("radius ", ZOOM_RADIUS); Dialog.show(); ZOOM_RADIUS = Dialog.getNumber(); } macro "Measure diameter Action Tool- C000T4b12m" { measureDiameter(); } macro "Measure diameter Action Tool Options" { Dialog.create("Root Tools - Measure diameter - Options"); Dialog.addString("line color: ", DIAMETER_COLOR); Dialog.addNumber("line width", DIAMETER_WIDTH); Dialog.show(); DIAMETER_COLOR = Dialog.getString(); DIAMETER_WIDTH = Dialog.getNumber(); } macro "Write report Action Tool- C000T4b12w" { writeReport(); } function lineAtThirtyCM() { setColor(COLOR_DEPTH); setLineWidth(WIDTH_DEPTH); tenUnscaled = HALF_LINE_WIDTH; toUnscaled(tenUnscaled); thirtyUnscaled = COUNT_ROOT_DEPTH; toUnscaled(thirtyUnscaled); X1 = rootX - tenUnscaled; X2 = rootX + tenUnscaled; Y = rootY + thirtyUnscaled; Overlay.drawLine(X1, Y, X2, Y); Overlay.show(); } function angleSelection() { xCoords = newArray(3); yCoords = newArray(3); xCoords[0] = rootX - DX_ANGLE; xCoords[1] = rootX; xCoords[2] = rootX + DX_ANGLE; yCoords[0] = rootY + DY_ANGLE; yCoords[1] = rootY; yCoords[2] = rootY + DY_ANGLE; makeSelection("angle", xCoords, yCoords); } function setScale() { getLine(x1, y1, x2, y2, lineWidth); dx = x2-x1; dy = y2-y1; length = sqrt(dx*dx+dy*dy); options = "distance=" + length+" known="+KNOWN_DISTANCE+" pixel=1 unit="+UNIT; if (USE_GLOBAL_SCALE) options = options + " global"; run("Set Scale...", options); run("Select None"); setTool("Define Root Point Tool"); } function measureAngle() { run("Measure"); ANGLE = getResult("Angle", nResults-1); selectWindow("Results"); run("Close"); getSelectionCoordinates(xCoordinates, yCoordinates); run("Select None"); setColor(ANGLE_COLOR); setLineWidth(ANGLE_LINE_WIDTH); Overlay.drawLine(xCoordinates[0], yCoordinates[0], xCoordinates[1], yCoordinates[1]); Overlay.drawLine(xCoordinates[1], yCoordinates[1], xCoordinates[2], yCoordinates[2]); Overlay.show(); setTool("Measure Depth Tool"); } function measureDiameter() { getLine(x1, y1, x2, y2, lineWidth); dx = x2-x1; dy = y2-y1; length = sqrt(dx*dx+dy*dy); toScaled(length); DIAMETERS[numberOfRootsAtThirty++] = length; close(); selectImage(ID); getSelectionBounds(x, y, width, height); run("Select None"); setColor(DIAMETER_COLOR); setLineWidth(DIAMETER_WIDTH); Overlay.drawLine(x+x1, y+y1, x+x2, y+y2); Overlay.show(); setTool("Zoom region Tool"); } function writeReport() { NUMBER++; getDateAndTime(year, month, dayOfWeek, dayOfMonth, hour, minute, second, msec); title = "root measurements - " + year + "-" + month + "-" + dayOfMonth + ".txt"; ref = "[" + title + "]"; if (!isOpen(title)) { run("Table...", "name="+ref+" width=250 height=600"); header = "\\Headings:" + "nr." + "\t" + "image" + "\t" + "root x" + "\t" + "root y" + "\t" + "angle" + "\t" + "depth" + "\t" + "nr at 30cm"; for (i=0; i