Headless copy and paste overlay from Analyze Particles in Python


I want to obtain the overlay from particle analysis and save it to file while executing the script in headless mode. From my understanding it is not possible to run ROI manager headlessly, so it is recommended to use the macro functions Overlay.copy and Overlay.paste instead, as stated in this thread: https://github.com/imagej/imagej-legacy/issues/153
I have been able to do this with ImageJ macro language, but when I try it with Python it does not work. From the Java API it seems that copy and paste are not methods of Overlay so I get an error :
“AttributeError: ‘ij.gui.Overlay’ object has no attribute ‘copy’”

Is there a way to solve this, either by using the macro functions or some other way?

Best wishes,


Hi Hal, welcome to the forum,
I have not much experience with the Overlay class, but a few things you can explore.

What does the recorder returns as command when you select Java as a language ?
You should be able to use them in your jython script, all roi manager commands are not forbidden, mostly the one that rely on GUI operations.

The Overlay class indeed does not have a copy/past methods.
However the ImagePlus class has 2 methods getOverlay and setOverlay which you potentially could use to transfer overlays between some instances of ImagePlus.

Hope that helps !

Thank you for your quick reply LThomas.

I tried your method with getOverlay and setOverlay and it works as intended when running the code with an open GUI - the saved image contains the overlay from particle analysis. However when I run it in headless mode from the terminal I only get a blank image and no overlay. There is no error message either.

Here is the code I have been using:

from ij import IJ, ImagePlus

img = IJ.open("/path/image.tif")
imp = IJ.getImage()
IJ.run(imp, "8-bit", "")
IJ.run(imp, "Auto Threshold", "method=IsoData")
IJ.run(imp, "Watershed", "")
IJ.run(imp, "Analyze Particles...", "size=0-1000 pixel circularity=0.40-1.00 show=Overlay")
overlay = ImagePlus.getOverlay(imp)
IJ.newImage("temp", "RGB white", 1165, 925, 1)
imp2 = IJ.getImage().setOverlay(overlay)
imp2 = IJ.getImage()
imp3 = imp2.flatten()
IJ.saveAs(imp3, "Tiff", "/path/result.tif")

how about something like this?

from ij import IJ
from ij.plugin.frame import RoiManager
img = IJ.open("/path/image.tif")
imp = IJ.getImage()
IJ.run(imp, "Auto Threshold", "method=Mean white")
IJ.run(imp, "Analyze Particles...", "size=10-Infinity display clear add")
rm = RoiManager.getInstance()
mask = imp.createRoiMask()
maskImp = ImagePlus("Mask", mask)
outputPath = "/pathtosomewhere"
name = imp.title
outPath =  os.path.join(outputPath, name).replace("\\","/")
IJ.saveAs(maskImp, "TIFF", outPath)

I have ImageJ installed on linux and use a virtual frame buffer to run headless to get around these kind of problems. I use a command like this:

$ xvfb-run -a ./ImageJ-linux64 --run /fijipythonscript.py

Hi johnmc and thank you for your reply.

I got my code to work eventually. It turns out that I had set a global scale on my images with Analyze -> Set Scale…, which meant that the particles were identified with the scale turned on, but in headless mode the scale is reset to default. To solve this, one can either set a new global scale with
IJ.run("Set Scale...", "distance=<> known=<> pixel=1 unit=<> global")
or change the parameters in the particle analysis.