Project

General

Profile

Files » root_tools.txt

use two lines for angle / m closes only the box-window - Volker Baecker, 06/12/2013 02:08 PM

 
/**
* 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 = 4; // 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 ON_IMAGE_OPEN_COMMANDS_CHECKED = newArray(true, true);
var USE_GLOBAL_SCALE = true;
var rootX;
var rootY;
var deepX;
var deepY;
var UNIT = "cm";
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);
for (i=0; i<lengthOf(ON_IMAGE_OPEN_COMMANDS_CHECKED); i++) {
Dialog.setInsets(0, 40, 0);
Dialog.addCheckbox(ON_IMAGE_OPEN_COMMANDS[i], ON_IMAGE_OPEN_COMMANDS_CHECKED[i]);
}
Dialog.show();
ON_IMAGE_OPEN_ON = Dialog.getCheckbox();
for (i=0; i<lengthOf(ON_IMAGE_OPEN_COMMANDS_CHECKED); i++) {
ON_IMAGE_OPEN_COMMANDS_CHECKED[i] = 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 ["+UNIT+"]: ", 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" {
width = getWidth();
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.drawLine(0, rootY, width, rootY);
Overlay.show();
run("Select None");
lineAtThirtyCM();
setTool("Straight Line");
}

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() {
if (roiManager("count")!=2) {
waitForUser("Please add two lines to the roi-manager first.");
return;
}
roiManager("select", 0);
getSelectionCoordinates(xCoordinates1, yCoordinates1);
roiManager("select", 1);
getSelectionCoordinates(xCoordinates2, yCoordinates2);
roiManager("Deselect");
run("Set Measurements...", " redirect=None decimal=3");
run("Clear Results");
roiManager("Measure");
roiManager("Delete");
a1 = 180 + getResult("Angle", 0);
a2 = -1 * getResult("Angle", 1);
ANGLE = 180 - a1 - a2;
selectWindow("Results");
run("Close");
run("Select None");
setColor(ANGLE_COLOR);
setLineWidth(ANGLE_LINE_WIDTH);
Overlay.drawLine(xCoordinates1[0], yCoordinates1[0], xCoordinates1[1], yCoordinates1[1]);
Overlay.drawLine(xCoordinates2[0], yCoordinates2[0], xCoordinates2[1], yCoordinates2[1]);
Overlay.show();
setTool("Measure Depth Tool");
}

function measureDiameter() {
title = getTitle();
if (indexOf(title, "box")==-1) return;
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<MAX_ROOTS; i++) {
header = header + "\t" + "d" + (i+1);
}
print(ref, header);
}
row = "" + NUMBER + "\t" + TITLE + "\t" + rootX + "\t" + rootY + "\t" + ANGLE + "\t" + DEPTH + "\t" + numberOfRootsAtThirty;
for (i=0; i<numberOfRootsAtThirty; i++) {
row = row + "\t" + DIAMETERS[i];
}
print(ref, row);
resetMeasurements();
if (!File.exists(FOLDER + "/" + "control/")) File.makeDirectory(FOLDER + "/" + "control/");
path = FOLDER + "/" + "control/" + TITLE;
saveAs("tiff", path);
Overlay.remove;
setTool("line");
}

function resetMeasurements() {
numberOfRootsAtThirty = 0;
DIAMETERS = newArray(MAX_ROOTS);
}

function getJSAddListeners() {
events = newArray("imageOpened", "imageUpdated", "imageClosed");
event = "imageOpened";
commands = ON_IMAGE_OPEN_COMMANDS;
commandFlags = ON_IMAGE_OPEN_COMMANDS_CHECKED;
script = "listenerImpl = {";
for (i=0; i<lengthOf(events); i++) {
script = script + events[i] + ": function(imp){";
if (events[i]==event) {
for (j=0; j<lengthOf(commands); j++) {
if (commandFlags[j]) {
components = split(commands[j],",");
if (lengthOf(components)==1)
script = script + "IJ.run(\"" + commands[j] + "\");";
else
script = script + "IJ.run(\"" + components[0] + "\",\""+components[1] +"\");";
}
}
}
script = script + "}";
if (i<lengthOf(events)-1) script = script + ",";
}
script = script + "}; listener = new ImageListener(listenerImpl); ImagePlus.addImageListener(listener);";
return script;
}

function runJS(script) {
eval("script", script);
}

function getJSRemoveAllImageListeners() {
script = "cl = new ImagePlus().getClass(); df = cl.getDeclaredField(\"listeners\"); df.setAccessible(true); df.get(null).removeAllElements();";
return script;
}

(2-2/3)