Macro programming, headless: merge channels

Hi there,

I’m trying to automize a process which involves overlaying a mask and a grayscale image. Manually, this can be achieved by clicking “Image->Color->MergeChannels…” and converting the resulting image to RGB “Image->Type->RGBColor” with channel4(gray)=grayscale image and channel1(red)=mask. When doing this in macro, it looks like this

run("Merge Channels...", "c1=maskimage c4=inputimage create");
run("RGB Color", "slices");
run("MHD/MHA ...", "save=overlay.mha");

and this also works fine when calling it from macro editor (Plugins->Macros->Edit). However, the system I’m trying to use this macro is a headless server, hence I’d like to run that in headless mode, i.e.

./ImageJ/ImageJ --headless -macro ./overlay.ijm

Now, the two images are merged in an interleaved way, i.e., first frame from image1, first frame from image2, second frame from image1, … but what I want is the image with the mask drawn in.

Am I just things wrong here or is this kind of a bug?


I’ve tried to achieve the same thing using python

redChannelImg = ImagePlus("mask.mha")
grayscaleImg = ImagePlus("gray.mha")
overlay = RGBStackMerge.mergeChannels([redChannelImg, grayscaleImg], False)
overlay.show()

but couldn’t get it working (mergeChannels-call fails). Maybe someone knows how to do that call right.

By looking at the method API, it seems the right call should be something like this:

overlay = RGBStackMerge.mergeChannels([redChannelImg, grayscaleImg, None], False)

In what way does it fail? What’s the error message?


The following python script (using SciJava script parameters) works well for me in an up-to-date Fiji installation (I tried with two copies of the Blobs sample image open):

# @ImagePlus imp1
# @ImagePlus imp2
# @OUTPUT ImagePlus impResult

from ij.plugin import RGBStackMerge

impResult = RGBStackMerge.mergeChannels([imp1, imp2], False)
1 Like

interesting. It works for me, too, but just a single time: If I open both images in ImageJ, run the script, it works fine. If I then close the overlay image, re-run the script, an error occurs:

File "overlay.py", line 19, in <module>
impResult = RGBStackMerge.mergeChannels([redChannelImg, graylevelImg], False)
at ij.ImageStack.getProcessor(ImageStack.java:262)

at ij.plugin.RGBStackMerge.mergeHyperstacks(RGBStackMerge.java:295)
at ij.plugin.RGBStackMerge.mergeChannels(RGBStackMerge.java:29)
at sun.reflect.GeneratedMethodAccessor24.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)

java.lang.IllegalArgumentException: java.lang.IllegalArgumentException: Argument out of range: 1

at org.python.core.PyException.fillInStackTrace(PyException.java:70)
at java.lang.Throwable.<init>(Throwable.java:181)
at java.lang.Exception.<init>(Exception.java:29)
at java.lang.RuntimeException.<init>(RuntimeException.java:32)
[...]

So, in terms of scripting, that would be OK since I only will run it once. However, if I remove the first lines

# @ImagePlus redChannelImg
# @ImagePlus graylevelImg

and add lines to load the images within the script

redChannelImg = ImagePlus("mask.mha")
graylevelImg = ImagePlus(gray.mha")

the same error occurs… :frowning:

1 Like

Indeed, I am able to reproduce this issue on my system as well. It works once, and then I see the Argument out of range: 1 exception.

Interestingly, the following script works for me every time:

# @OUTPUT ImagePlus impResult

from ij import IJ
bridge = IJ.openImage("http://wsr.imagej.net/images/bridge.gif");
boats = IJ.openImage("http://wsr.imagej.net/images/boats.gif");
boats.setRoi(16,14,512,512);
IJ.run(boats, "Crop", "");

from ij.plugin import RGBStackMerge
impResult = RGBStackMerge.mergeChannels([bridge, boats], False)

So maybe this is a bug in ImageJ2’s handling of ImagePlus parameters. Could you please file an issue in imagej/imagej-legacy?

2 Likes

I was revisiting this thanks to this post by @lguerard:

Yes, the bug seems to be in the conversion between ImageJ1 and ImageJ2 data structures.

While the following (Groovy) script works:

import ij.IJ
import ij.plugin.RGBStackMerge
import ij.ImagePlus

imp1 = IJ.createImage("Red", "8-bit white", 100, 100, 1);
imp2 = IJ.createImage("Green", "8-bit black", 100, 100, 1);
imp3 = IJ.createImage("Blue", "8-bit ramp", 100, 100, 1);

impResult = RGBStackMerge.mergeChannels([imp1, imp2, imp3] as ImagePlus[], false)

It doesn’t work if you split it into two parts:

#@output imp1
#@output imp2
#@output imp3

import ij.IJ

imp1 = IJ.createImage("Red", "8-bit white", 100, 100, 1);
imp2 = IJ.createImage("Green", "8-bit black", 100, 100, 1);
imp3 = IJ.createImage("Blue", "8-bit ramp", 100, 100, 1);

and

#@ ImagePlus imp1
#@ ImagePlus imp2
#@ ImagePlus imp3

import ij.plugin.RGBStackMerge
import ij.ImagePlus

impResult = RGBStackMerge.mergeChannels([imp1, imp2, imp3] as ImagePlus[], false)

The second part will run the first time, but fail on subsequent attempts with the Argument out of range: 1 exception.


As nobody seems to have created any issue so far, I filed this one right now:

Relatedly, I stumbled upon a similar but different issue:

2 Likes