How to programmatically stack and montage list of images with Python

python
fiji
macro
Tags: #<Tag:0x00007fb87a4cd800> #<Tag:0x00007fb87a4cd620> #<Tag:0x00007fb87a4cd1e8>

#1

I have three images:

FigA.png

FigB.png

FigC.png

What I want to do is to stack them and make final montage that looks like this:

How can I do it programmatically with Python?
I’m stuck with the following code

## /Applications/Fiji.app/Contents/MacOS/ImageJ-macosx mycode.py
from ij import IJ

def stack_images(infilelist):
    """
    Description of stack_image
    """
    infile_A = infilelist[0]
    infile_B = infilelist[1]
    infile_C = infilelist[2]
    imp = IJ.openImage(infile_A)
    imp.show()
    imp = IJ.openImage(infile_B)
    imp.show()
    imp = IJ.openImage(infile_C)
    imp.show()
    IJ.run(imp, "Images to Stack", "name=Stack title=[] use")
    IJ.run(imp, "Make Montage...", "columns=3 rows=1 scale=0.25  label")
    IJ.run(imp, "Save", "save=/Users/pdubois/Desktop/Montage_X.tif")


def main():
    """
    Description of main
    """
    filelist = [ "/Users/pdubois/Desktop/FigA.png",
                 "/Users/pdubois/Desktop/FigB.png",
                 "/Users/pdubois/Desktop/FigC.png"]

    stack_images(filelist)


if __name__ == '__main__':
    main()

Which produce no final Montage image.
What’s the right way to do it?

I have hundreds of image in set of 3 (A, B, C) which I need to process
programatically.


#2

Hi @Peverall_Dubois,

The first argument in an IJ.run() command should be the image you want to process.

Right now, the Montage command is trying to process imp, which stands for the 3rd image opened.

This probably happened because the macro recorder doesn’t properly handle references to windows for Python/Javascript, so you have to replace those generic imps with references to specific windows, namely the Stack (to make the montage) and the Montage (to save).

Here is a version that should work.

from ij import IJ, WindowManager

def stack_images(infilelist):
    """
    Description of stack_image
    """
    infile_A = infilelist[0]
    infile_B = infilelist[1]
    infile_C = infilelist[2]
    imp = IJ.openImage(infile_A)
    imp.show()
    imp = IJ.openImage(infile_B)
    imp.show()
    imp = IJ.openImage(infile_C)
    imp.show()
    IJ.run(imp, "Images to Stack", "name=Stack title=[] use")
    imp2 = WindowManager.getCurrentImage() # the Stack
    IJ.run(imp2, "Make Montage...", "columns=3 rows=1 scale=0.25  label")
    imp3 = WindowManager.getCurrentImage() # the Montage
    IJ.run(imp3, "Save", "save=/Users/pdubois/Desktop/montage.tif")

def main():
    """
    Description of main
    """
    filelist = [ "/Users/pdubois/Desktop/FigA.png",
                 "/Users/pdubois/Desktop/FigB.png",
                 "/Userls/pdubois/Desktop/FigC.png"]

# for testing
#    filelist = [ "http://imagej.nih.gov/ij/images/Dot_Blot.jpg",
#                 "http://imagej.nih.gov/ij/images/Dot_Blot.jpg",
#                 "http://imagej.nih.gov/ij/images/Dot_Blot.jpg"]

    stack_images(filelist)


if __name__ == '__main__':
    main()

#3

@tswayne Thanks. But I get this message after running your code:

Stack required
There are no images open.

Please note that I would like to run the code from command line (not macro menu).

## /Applications/Fiji.app/Contents/MacOS/ImageJ-macosx mycode.py

And is it possible to construct your code as loop?


#4

Hi @Peverall_Dubois,

You’re right, I did not try it from the command line.
There may be special considerations for the headless mode that I’m not aware of.

The error message suggests the Montage command is still not “seeing” the Stack window. Unfortunately, I’m not sure why.

Yes, it is… to do this, you need to:

  • define the subgroups of images that you want to montage (do the filenames follow a pattern?)
  • save the montages in a separate folder, outside the folder being processed.

There are some very useful templates in the Script Editor: [open a script, then] Templates > BAR > Batch Processors > Process Folder PY. This gives you a loop over all the images in a folder. It’s designed to operate on one image at a time, so you would need to tweak it to open groups of images.

If you’re not successful in finding answers here, I recommend searching for similar plugins by others, and learning from their code.

Best of luck!