How to Start Using Coding to Automate Image Analysis Part 1: The Simple Process
Pat yourself on the back, you saw a post with the word “coding” in the title and you didn’t freak out or glaze over. That’s the first step.
Coding seems to have such a stigma attached to it; people tend to think that it’s incomprehensible nonsense that they could never learn, and that it has no practical use for the everyday scientist. Hopefully, by the time you get to the end of this article, you’ll see that this is not the case and be prepared to give it a go yourself.
Don’t worry, I’m gonna keep it simple though. Here, I’ll show you how you can use coding within ImageJ to automate image analysis, freeing up your time for more important things like trying to figure out who keeps stealing your buffers.
Not many people know that ImageJ comes with something called the “command recorder”. This is a handy little tool that follows every action you take within the program and spits out code that will replicate exactly what you just did, but in a single click. This means you can code without actually having to write a single bit of code yourself. So to anyone who says that they could never learn coding, I say you don’t even have to!
For now, let’s run through a simple example and I’ll explain some of the absolute basics of coding. I’m going to use the command recorder to write a macro (a collection of code) that will open a proprietary format image (.zvi), flip it horizontally, save it as a tiff and close it:
You can see how every time I click a command, a new line appears in the command recorder window. At the end of the process, there are four lines of code which is all ImageJ needs to know to repeat that process again. Clicking the Create button exported this code to the macro editor window where we can work with it further.
Making Sense of the Code
So now, I’ve created a macro that looks like this:
But what does it mean? Let’s break that code down into its individual pieces to make it a little easier to understand:
- Each line contains a single action, with a semi-colon to mark the end of that action.
- Each action consists of a “function” and “parameters”.
- Functions are instructions telling ImageJ what to do – these are the first words on each line and are shown in red. They are followed by brackets containing their parameters.
- Parameters tell ImageJ how to do it – these are placed inside the brackets and are separated by commas. These are shown in blue. Functions often only have one parameter, but can have multiple or none at all.
Knowing this, you can see that in this example my macro uses the functions “open”, “run”, “saveAs” and “close”, each followed by parameters containing the extra information ImageJ needs to make those functions do exactly what I just did by clicking through the menus. To break them down further:
- The parameter for “open” is the directory / filename of the image that I opened.
- The parameter for “run” is the command I wanted to run (flip horizontally).
- The “saveAs” function has two parameters; the first is the file type to save as (tiff), and the second is the directory / filename where I wanted to save it.
- There are no parameters added to the “close” function. Any function that doesn’t have parameters assigned is carried out with its default parameters. The default parameter of the “close” function is the name of whatever window is selected at that time, so in my code this line will close the selected window.
If you have no coding experience, you would have no way of knowing those functions or parameters, but the command recorder shows you exactly what code is needed to replicate your actions. You could literally make your first macro in 30 seconds with no previous coding knowledge. It really is that simple.
Now I have a macro to flip my images; the only problem is that the current parameters make it work specifically for Image-0001 in my Images folder. However, I can remove the parameters for “open” and “saveAs” so that it works for any file. So my code now looks like this:
By removing the parameters which tell ImageJ which files to open from and save to, both the “open” and “saveAs” functions will ask me to pick a file name & location each time I run the macro, but then continue with everything else exactly as before.
To save this macro, I can select File –> Save from the macro editor window. Now I can open it to edit further or run this macro again using the Edit… and Run… commands in the Plugins –> Macros menu from the main ImageJ toolbar.
Obviously that is a very simple example and doesn’t really save much time, but the actions you can automate can be much more extensive than just flipping an image. The coding language is comprehensive enough to automate nearly any image processing or data extraction & manipulation with enough practice.
The command recorder is the simplest way to get to grips with the ImageJ coding language, as you can just play around with your images and watch the different commands pop-up on screen. The more you use it, the more you’ll see patterns emerging and the logical structure of the language.
Check back soon for the follow-up article in which I’ll explain how to further automate image analysis and process multiple images in one go with the batch process macro tool.
Leave a Comment
You must be logged in to post a comment.
Thanks for this article – really useful! Do you have suggestions on how to make a macro run for a variable file name? My image has 3 channels so I have to keep selecting dofferent windows before the “run” command. I’m unsure how to make the object a variable (window) that I select. My other options if to Find Replace the file name each time I run the code (very crude but still faster than clicking!). Totally understand if this is coming up in your next segment! Thanks muchly.
If you’re only working with one image at a time, you probably don’t need to specifiy the image name, ImageJ will automatically run the commands on the first open image it finds. If you have more than one open at once though, you could use the “getTitle()” function which returns the title of the currently selected window. You can define a variable (a container that holds a certain value) to store this and recall it whenever you need. So by adding the line “rawImage = getTitle();” you would create a new variable called “rawImage” that would contain the window title. After that, at any point in your macro you could use the “selectWindow(rawImage)” function to select your original image.
I’m not sure on exactly what you need but it sounds like the “setSlice(n)” or “Stack.setChannel(n)” functions would also be helpful. With these, replace “n” with the number of the channel you want to select. The “run(“Split Channels”);” function may also be useful which will split the channels into separate windows.