Use to advance the slide
[Plugins > Macro > Record...]
is your best friendManual analysis (while sometimes necessary) can be laborious, error prone and not provide the provenance required. Batch processing allows the same processing to be run on multiple images.
The built-in [Process > Batch]
menu has lots of useful functions:
[Plugins > Macros > Record...]
[Plugins > Macros > Run...]
BBBC008_partial.zip
and extract to a known location.
Task1_MacroRec.pdf
in a new tab and follow the instructions there.[File > New > Script...]
(or keyboard shortcut [
)
The Script Editor can can be used to edit, write, and run macros & scripts. It has a number of nice features:
Run
button to easily test macrosHandy shortcuts:
We will be using the ImageJ Macro language. It's the native programming language to ImageJ, is used by the Macro Recorder, and it's fairly simple—an ideal starting point.
Note: If you want to explore other languages on your own, the ImageJ Scripting Guide can be a good place to start.
Variables can store values of different types:
string - a sequence of characters, comprising text
"a", "London", 'X', 'General Assembly'
int - an integer or whole number
1, 5, 9999, -7
float - a floating point number (using a decimal point)
3.14, 1.68, 1.0
bool - boolean; binary true or false values
true, false
Note: ImageJ Macro Language variables are dynamically typed—you don't need to declare the type.
name = "Erick";
height = 1.73;
state = "CT";
Why does running this macro do nothing? 🤔
'Casting' a variable to another type requires some of the built-in functions we have mentioned.
// cast strings into numbers (int and float)
a = parseInt("42");
b = parseFloat("1.69");
// cast a number into a string with specified decimal places
c = d2s(1.5333, 2);
// print the value stored in the variable `c`
print(c);
What would print(c+1);
print? 🤔
Choose 4 things around you and create variables of 4 different types based on them.
If you need to, refer to the variable types slide.
You can process the values in your variables by operators :
= | Assignment: assign a value to a variable |
== | Comparison: are two variables equal? |
!= | Comparison: are two variables not equal? |
<, >, <=, >= |
Less-than, greater-than, less or equal, greater or equal |
+, -, *, / | Mathematical operators |
&&, ||, ! | Logical operators: and, or, not |
Important: the type of the first operand will determine the result!
A few more handy operators:
++ |
Increment; add 1, e.g. i++
|
-- |
Decrement; subtract 1, e.g. i--
|
+=, -=, *=, /= | Perform the operation on the variable and re-assign |
+ |
+ operator on strings concatenates them
|
replace(string, old, new)
|
Take string , replace old occurrences with new
|
split(string, delimiter)
|
Split the string at every delimiter into an array of strings
|
lengthOf(string)
|
Return the length of string
|
endsWith(string, suffix)
|
Return true (1) if string ends with suffix
|
Create two string variables :
first for your first name and last for your last name.
Can you make your full name by combining first and last?
(Cheating encouraged)
we'll only talk about the Array
We can store multiple values in an array:
An array is a ordered sequence of items (between [...]) each with their own index.
b = newArray(1, 3, 9, 4, 884328881);
n = newArray("first", "second", "third", "fourth");
m = Array.concat(b, n);
print(m[6]);
What is the index of the first element of the array? 🤔
// This macro demonstrates how to use the Array.* functions.
a1 = newArray(10, 5, 15, 2, 1.23456);
a2 = Array.copy(a1);
print("Array 2")
Array.print(a2);
a3 = Array.trim(a1, 2);
print("Array 3");
Array.print(a3);
Array.sort(a1);
print("Array 1");
Array.print(a1);
Array.getStatistics(a1, min, max, mean, std);
print("stats");
print(" min: "+min);
print(" max: "+max);
print(" mean: "+mean);
print(" std dev: "+std);
Array.fill(a1, -1);
Array.print(a1);
// Arrays need not contain numbers!
a1 = newArray("one", "two", "three", "four");
print("");
a2 = Array.copy(a1);
Array.print(a1);
a2 = Array.trim(a1, 2);
Array.print(a2);
Array.sort(a1);
Array.print(a1);
"Loops" are a form of "flow of control" (control flow statement) that specifies iteration of a section of code.
That same code block should be repeated a defined number of times or until some condition has been met, etc.
You use loops to repeat a statement.
A for-loop is useful when you know how many times you want to repeat an action (e.g. for every item in an array)
for (start; condition; increment){
do something
}
An example of using a for
loop:
ages = newArray(18, 21, 16, 12);
for(i=0; i< lengthOf(ages); i++){
print(ages[i]);
}
Output:
18
21
16
12
A while-loop is useful when you don’t know how many times you want to run, but you know when you need to stop.
A while-loop statement checks a condition and loops until the condition is no longer satisfied.
while (condition){
do something;
}
An example of a while
loop:
x = 2;
while(x > 0){
print("hooray!");
x = x - random; // `random` is a built-in, returns a random number between 0 and 1
}
How many times will this code print "hooray!"?
Conditionals enable your code to perform different actions/computations based on the boolean value of a specific expression, the condition.
Conditional statements enable you to deal with multiple options.
A part of your code is executed based on the truth value of a condition. You perform conditional checks with: if, else
if(condition){
action
}
else{
final action
}
age = 17;
if(age < 21){
print("no drinks for you");
}
Notice, you don't need an else
, if you don't need one.
Functions are callable units of code with defined interfaces, meant to be invoked multiple times.
They allow you to re-use code, rather than re-writing it!
DRY: Don't Repeat Yourself!
Functions perform a collections of tasks, bundled under a specific name
Take input argument(s), execute statement(s), return output
Input and output can be of all different types
We've already been using various built-in funtions!
name = "Erick Ratamero";
length = lengthOf(name); // `lengthOf` is a built-in function
print(length); // `print` is a built-in function
As a reminder, here is the super handy reference of built-in functions:
https://imagej.net/ij/developer/macro/functions.html
You can also define your own functions like this:
function function_name(argument(s)){
actions with argument(s)
return statement
}
For example, a complex calculation you want to repeat:
// define a function
function calculate(x, y, sigma){
factor = exp(-1.0*(pow(x,2)+pow(y,2))/(2*pow(sigma,2)));
return factor;
}
// call the function
result = calculate(1,2,5);
print(result);
Create a function that takes two numbers and returns "BIG!" if they add up to at least 50, and "SMALL!" otherwise.
Make sure to test that it is working as intended!
(Cheating encouraged)
The macro language provides some built-ins for handling image files.
open(path)
|
Open and display the image located at path . Note the path should be provided as a string (in quotes).
|
getTitle()
|
Returns the title of the current image. |
close(title)
|
Close window with a given title . Note that the string title can contain wild cards.
|
getFileList(path)
|
List the contents of the directory located at path
|
File.separator
|
Returns the platform specific path file separator (e.g. / or \) as a string |
getImageID()
|
Returns the unique ID of an image. Use with selectImage(id) , isOpen(id) , and isActive(id) .
|
Read your code carefully around the problem line. Look for the clues, but they may be one or two lines earlier!
Filename = "experiment1_ch1_t1.tif";
if(startsWith(Filename, "experiment1"){
print("First experiment file:", filename);
}
Let's run a simple threshold and object counting workflow on a folder of files and get a summary table. How would we do this?
BBBC008_partial.zip
and extract to a known location.
Task1_CountMacro.pdf
in a new tab and follow the instructions there.