Incorrect positioning of ROI when adding to ROI Manger via script

Hi everyone,

I have noticed that when you programmatically add an ROI that doesn’t have a position set to the ROI Manager, the current position of the active image is assumed to be the ROI position. The position of the ROI, however, seems to be somehow wrong or at least I can’t make a sense of it.

Here is an example Groovy script that shows the described behavior:

import ij.IJ;
import ij.gui.EllipseRoi;
import ij.plugin.frame.RoiManager;

/* Open sample image and set position */
imp = IJ.openImage("http://imagej.nih.gov/ij/images/confocal-series.zip");
imp.show();
imp.setPosition(2, 25, 0);

/* Create ROI without explictly setting position */
r = new EllipseRoi(20, 20, 40, 40, 1);

/* Add ROI to ROI Manager */
roiManager = RoiManager.getInstance();
if ( null == roiManager ) {
	roiManager = new RoiManager();
}
roiManager.addRoi(r);

/* Verify position of ROI */
rVerify = roiManager.getRoi(0);
println(rVerify.getCPosition()); // 0, should print 2
println(rVerify.getZPosition()); // 25
println(rVerify.getTPosition()); // 1, should print 1

Also, if I try to r.setPosition(x, y, z); to some other position, the position of the currently active image overrides. Does anyone know how to solve that issue without changing the position of the image?

Best,
Stefan

Hi @stelfrich

I think the problem lies in your ImagePlus for some magical reason. If you use the HyperstackConverter on the image, it behaves as expected… So the test image you are using is somehow not opening as a ‘proper’ hyperstack and that’s why?

At least you have this as a hack for now but it will be nice to get to the bottom of this.

import ij.IJ;
import ij.gui.EllipseRoi;
import ij.plugin.frame.RoiManager;
import ij.plugin.HyperStackConverter
/* Open sample image and set position */
imp = IJ.openImage("http://imagej.nih.gov/ij/images/confocal-series.zip");
imp = HyperStackConverter.toHyperStack(imp, 2, 25, 1, "default", "Color");
imp.show();
imp.setPosition(2, 25, 0);

/* Create ROI without explictly setting position */
r = new EllipseRoi(20, 20, 40, 40, 1);

/* Add ROI to ROI Manager */
roiManager = RoiManager.getInstance();
if ( null == roiManager ) {
	roiManager = new RoiManager();
}
roiManager.addRoi(r);

/* Verify position of ROI */
rVerify = roiManager.getRoi(0);
println(rVerify.getCPosition()); // 2, should print 2
println(rVerify.getZPosition()); // 25
println(rVerify.getTPosition()); // 1, should print 1
2 Likes

Thanks for looking into it @oburri! The magic part in your “hack” is going from a Composite to a regular color representation of the image. If the ImagePlus is shown as a composite, the channel is set to 0 as to imply the ROI is on all channels. That solves the first part!

Any ideas why r.setPosition(x, y, z) should not override, @oburri?

import ij.IJ;
import ij.gui.EllipseRoi;
import ij.plugin.frame.RoiManager;
import ij.plugin.HyperStackConverter;

/* Open sample image and set position */
imp = IJ.openImage("http://imagej.nih.gov/ij/images/confocal-series.zip");
imp.show();
imp.setDisplayMode(IJ.COLOR);
imp.setPosition(2, 25, 1);

/* Create ROI without explictly setting position */
r = new EllipseRoi(20, 20, 40, 40, 1);
r.setPosition(1, 1, 1);

/* Add ROI to ROI Manager */
roiManager = RoiManager.getInstance();
if ( null == roiManager ) {
	roiManager = new RoiManager();
}
roiManager.addRoi(r);

/* Verify position of ROI */
rVerify = roiManager.getRoi(0);
println(rVerify.getCPosition()); // 2, should print 1
println(rVerify.getZPosition()); // 25, should print 1
println(rVerify.getTPosition()); // 1, should print 1

Seems the RoiManager goes to great lengths to update the imp position based on the ROI so that when the ROI is finally saved into the manager, the position is set from the image.

Roi roiCopy = (Roi)roi.clone();
roiCopy.setPosition(imp);

So if the channel is set to 0 for composites, then no matter what is done before, it will have the wrong channel position.

So the gist is, that in order to add an ROI to the ROI Manager from a scripting language, you have to switch to the position on the active image. imp.setPositionWithoutUpdate(x, y, z) is your friend in that case. And roi.setPosition(x, y, z) only works well in combination with an Overlay.

Hello again everyone!

Adding to this, we (@romainGuiet and I) found some more ImageJ-ik™ (ImageJ Magic :sweat_smile:)

So the thing is that any Rois will have their position overwritten by the RoiManager

IF there is an active image AND it’s a stack AND the RoiManager is visible.

So if you want the RoiManager to not touch your bloody positions, you should make sure that one of those things is false

For example rm.setVisible(false) before using rm.addRoi()

@ctrueden @Wayne @imagejan, the culprit line is at

Which seems to have been added 5 months ago…

This approach works just fine when using the RoiManager as a user (with a GUI) but it really messes things up if all we want to do is add a Roi where we carefully set the positions ourselves.

Perhaps an extra condition being **AND** roi.getPosition() == 0 should be added there so that if the Roi already has a position set, it should be left alone?

Remarks, comments, and help welcome! :smile:

Best

Oli

3 Likes

Hi @stelfrich and @oburri,

This bug is fixed in the latest ImageJ daily build (1.52v7).

Awesome, thanks Wayne!

Oli