There is a very extensive compilation of all the functions available in the macro language on the ImageJ website (http://rsbweb.nih.gov/ij/developer/macro/functions.html). In this section, we are offering a brief explanation of some of the operations that you are most likely to use. Instead of just listing the name of the necessary functions, we will ask some common questions and then answer them using code.
Note that finding out what command does a specific function is very easy: just start the recorder and run the command you are interested on running in your macro. You can then copy and paste the resulting line and modify the parameters accordingly.
There are two ways to open an image file from your hard disk (or from a URL). For an interactive way (you need input from the user, typically the file path) just run the following line:
open();
A dialog will appear asking you for the file location inside your hard disk. Just double click on it and the image will be opened.
The non-interactive way, in which you know in advance the file location, is very similar:
open(path);
Here path
is the location of the file (for example, C:/temp/image1.jpg
).
It may happen that you want to store the image path into a variable to open it using a different method (for example, importing a raw image). In that case, we can use the File.openDialog(message)
function. It opens a file browser dialog and returns the path of the selected file. The following code does the same by simply calling open()
, but will also store the path in the mypath
variable using the following code:
mypath = File.openDialog("Select a file"); open(mypath);
The number of images currently open in the ImageJ system is stored in a variable called nImages
. It updates itself every time a new image is opened. Duplicate images are count as a just another image. Try the following macro:
print(nImages); // No images: 0. run("Dot Blot (7K)"); print(nImages); // One image: 1. run("Dot Blot (7K)"); print(nImages); // Two images: 2.
As you can see when you run this code, the run("DotBlot(7K)")
line causes ImageJ to open the Dot Blot
sample image.
There are several ways of doing that. If you want individual dimensions, you can use the getHeight()
and getWidth()
functions. Also, the nSlices
variable stores the number of slices in the active stack. If you need all the information at once, you can run the getDimensions(width,height,channels,slices,frames)
function. This function is a bit different from the other functions we have already seen. Instead of returning a value, it sets the width
variable to the width of the image, the height
variable to the height of the image, and so on. That is, after calling it you will have five new variables.
As you may have noted, the coordinates for width and height of a given image start at 0. An image with a matrix size of 100 x 200 will have the x coordinate ranging from 0 to 99 and y coordinate from 0 to 199. However, the notation for slices, frames, and channels is different, as they always start at 1
. Consider the following macro:
run("T1 Head (2.4M, 16-bits)"); for(i = 1; i<= nSlices; i++) { Stack.setSlice(i); value = getPixel(100, 100); print("Pixel (100, 100) in slice", i, "=", value); wait(200); // Wait 200 miliseconds }
Let's stop for a moment on it, as it is using most of the concepts we have learned so far. First, it opens a sample image (T1Head
) and then it uses a for
loop to iterate through its slices using one of the Stack
functions (take a look at the macro functions reference to see more stack operations). Note that the index variable used, i
, starts at one and makes the loop run until (and including) its value is equal to nSlices
. It then grabs the pixel value placed in the coordinates (100, 100
) and prints it. When you run this macro, you will see how ImageJ goes through all the slices of the stack, and the pixel selected values printed in the log window. We have added a small waiting time (200
milliseconds) as the parameter of the wait
function, so that you can clearly see what is going on.
Try this: modify the preceding macro so that it only iterates through the even slices of the image. Also, try changing the starting loop value to 0
. You would expect an error message, but it selects slice 1
instead. This may cause an incorrect measurement if you iterate a given image this way, as you will process the first slice twice!
Other useful Stack
functions are Stack.setFrame(frame)
and Stack.setChannel(channel)
, which will allow you to select specific frames or channels, as we have just done with the slices.
There are two important aspects to be learned for running the preceding macro:
getPixel(x,y)
function grabs the pixel value of the currently selected slice for the provided x and y coordinates. Note that the stack selection is done prior to getting the pixel value, and we are not providing any slice information to the getPixel(x,y)
function.Macro functions, unless specified, are applied to the image being displayed and selected, as we just saw. It may be the case that you have several images opened and want to apply different operations to each one of them or use information from one to modify another. There are several ways for selecting an opened image from the ImageJ macro language, which are as follows:
selectImage(id)
function. This function is called with an argument that can mean two different things, depending on its value:getImageID()
.selectImage(1)
will select the image that was opened before any other one, from the list of images currently opened (not really the first one in absolute terms, as the first image opened in that session could have been closed).selectWindow(name)
function, where name
is a string that contains the window name you want to select.The following macro opens two images and switches between them using all the approaches explained previously. We recommend running it line-by-line to understand how it works:
// Open two sample images. run("Clown (14K)"); run("Leaf (36K)"); // How many images are there? You can also see this variable in the debug window print(nImages + " opened"); // Select the first opened image. This is the clown image, by opening order. selectImage(1); // Is it really the clown image? clownTitle = getTitle(); print("Image selected: " + clownTitle); // Select an image by name selectWindow(clownTitle); // Get the image ID of the selected image. This is a negative number that you normally do not // know in advance (as opposed to the opening order number). clownID = getImageID(); print("clown.jpg image ID: " + clownID); // Select the leaf image (the second image opened). selectImage(2); // Go back to the clown image using the image ID, not the opening order selectImage(clownID);
For complicated operations or processes that involve switching between several images, macros can be quite slow. The best way to speed up your macro is to use the
setBatchMode(arg)
function. This function stops ImageJ from displaying on the screen the operations being performed on the image, thus allowing the macro to run upto 20 times faster, according to the official documentation. This function receives an argument, which has to be true
(for entering the batch mode) or false
(for exiting it). When the macro finishes, the batch mode is set to false
automatically.
You have to run setBatchMode(true)
before opening the image or the images you wish to process to enjoy this speed bump. Setting it after the images are being processed and shown on the screen will have no impact on its execution.
You also have the option of programming a plugin or use some scripting language instead of a macro. Plugins are a more advanced topic that will be covered in the final two chapters of this book, and they generally require you to have some programming skills. Scripts are not covered in this book, but if you have knowledge in Python, for instance, you might want to take a look at them.