Jython ROI manager deletion by index

So this is a problem in a small part of my FRET analysis pipeline. I don’t have much time to spend fixing all the dirty code, so I resigned to waitforuser ROI deletion. But the point is for the script to run without user interaction.

My problem is with deleting ROIs by index in a jython script for Fiji/ImageJ2. Mainly that it deletes everything… I have verified that the count is correct, the size is correct, the selection of the count(i) is correct…

It might be a bug, but it’s probably just something stupid. Hopefully someone more experienced will spot my glaring mistake.

Sometimes everything is deleted, sometimes upon repeated iterations more and more are deleted…

Usually this is the result of the prints, yet everything is still deleted:

The commented out commands are just a few things I tested FYI. I also tried using rm.getIndex(), no luck. Why so many deselects? I have tried many combinations as I figured it was probably a selection issue… but it doesn’t seem to be.

from ij.plugin.frame import RoiManager
from ij import IJ
from ij import IJ, WindowManager, ImagePlus	

def ROIstuff():
	
	rm = RoiManager().getInstance()

	# This selects the intended ROI..
	#rm.select(3)

	
	# This deselects successfully..
	#rm.runCommand('Deselect')

	total_rois = rm.getCount()
	print "count = ", total_rois
	

	for roi in range(total_rois):
		print "ROI# = ", str(roi)
		rm.runCommand('Deselect')	

		# This gets the correct size (float).. only one image is open.
		imp = WindowManager.getCurrentImage()
		rm.select(roi)	
		size = imp.getStatistics().area
		print "Size = ", size
		
		rm.runCommand('Deselect')
				
		if size < 140:
			print "Too small, Deleting"
			rm.select(roi)
			rm.runCommand('Delete')
			rm.runCommand('Deselect')
		elif size > 1000:
			print "Too large, deleting"
			rm.select(roi)
			rm.runCommand('Delete')
			rm.runCommand('Deselect')
		else:
			rm.runCommand("Deselect")
			continue
	
ROIstuff()

Thank you for your attention,

Sverre

Hey @Sverre,

which operating system are you running? I couldn’t reproduce the issue on macOS 10.12.4 with an up-to-date Fiji. Although, I have to click in the seemingly empty ROI list in the Roi Manager, to show the contents of that panel after running your Jython script. Is it possible that the same thing is happening to you?

Best,
Stefan

Hello Stefan, thanks for testing it. I am running windows 7 enterprise.

I have been clicking remind me later on the Fiji updater for a month… but I can’t imagine this is a bug that appeared and was fixed in such a short window… I will update everything now.

I don’t believe so. First of all when I run commands subsequently using these ROIs I get ROI manager is empty. I also tried clicking it like you suggested just now, no difference.

Aha! :smiley: The issue is that you are iterating the list of ROIs from the beginning. Whenever you delete a ROI from the beginning, the remaining indices will be updated s.t. they fall into the range [0, numberOfRois-1]. You can remedy that issue by changing your loop to for roi in reversed(range(total_rois)):. This way, the IDs of the remaining ROIs will not be updated…

4 Likes

You spotted my glaring mistake, thank you Stefan! Of course it makes perfect sense now that you pointed it out… :blush:

I had a very long and frustrating morning while imaging and trying to fix this between scans… This is great :slight_smile:

1 Like

@Sverre,
Already solved, but I played with it some for fun. If you want to do things a bit more “pythonic,” you can iterate your for loop over a list of ROIs (for roi in roi_list). It’s not necessary for function, but it reads nicely. See below. A list of ROIs gets created outside the ROI manager, then you loop over that list. Deleting them from the ROI manager doesn’t shift things around in your list.

from ij.plugin.frame import RoiManager
from ij import IJ
from ij import IJ, WindowManager, ImagePlus	

def ROIstuff():
	rm = RoiManager().getInstance()
	imp = WindowManager.getCurrentImage()

	roi_list = rm.getRoisAsArray()
	for roi in roi_list:
		rm.select(rm.getRoiIndex(roi))
		size = imp.getStatistics().area
		print "Size = ", size

		if size < 140:
			print "Too small, Deleting"
			rm.runCommand('Delete')
		elif size > 1000:
			print "Too large, deleting"
			rm.runCommand('Delete')

ROIstuff()

(I also streamlined things a bit by assigning imp only once outside the loop, and removing the Deselect commands, as it runs fine for me without them.)

3 Likes

Thanks for playing around with it @jimpassmore! I ended up with the below, this morning, which still uses the count… maybe I will change to your more elegant style :slight_smile:

And yes, the deselects were redundant… an artefact of my clumsy troubleshooting.

from ij.plugin.frame import RoiManager
from ij import IJ
from ij.measure import ResultsTable
from ij import WindowManager, ImagePlus	

def ROIstuff():
	
	rm = RoiManager().getInstance()
	total_rois = rm.getCount()
	imp = WindowManager.getCurrentImage()
	
	for roi in reversed(range(total_rois)):
		rm.select(roi)
		size = imp.getStatistics().area		
		if size < 250:
			rm.select(roi)
			rm.runCommand('Delete')
		elif size > 1000:
			rm.select(roi)
			rm.runCommand('Delete')


	
ROIstuff()
1 Like

Nice! You can even streamline a bit more by using SciJava script parameters, by avoiding RoiManager object instantiation (leave away the () when calling a static method), and by stripping the unnecessary imports:

# @ImagePlus imp

from ij.plugin.frame import RoiManager

def ROIstuff():
	rm = RoiManager.getInstance()

	roi_list = rm.getRoisAsArray()
	for roi in roi_list:
		rm.select(rm.getRoiIndex(roi))
		size = imp.getStatistics().area
		print "Size = ", size

		if size < 140:
			print "Too small, Deleting"
			rm.runCommand('Delete')
		elif size > 1000:
			print "Too large, deleting"
			rm.runCommand('Delete')

ROIstuff()

For the sake of comparison, here’s the same in Groovy:

// @ImagePlus imp

import ij.plugin.frame.RoiManager

def ROIstuff() {
	rm = RoiManager.getInstance()

	rm.getRoisAsArray().each { roi ->
		rm.select(rm.getRoiIndex(roi))
		size = imp.getStatistics().area
		println "Size = $size"

		if (size < 140) {
			println "Too small, Deleting"
			rm.runCommand('Delete')
		} else if (size > 1000) {
			println "Too large, deleting"
			rm.runCommand('Delete')
		}
	}
}

ROIstuff()
2 Likes

Yes, very similar. Glad you have something working!

  • script parameters: Haven’t had time to learn proper use, but it’s on my todo list.
  • call to static method: blew right past this one without even thinking. Oops!
  • automatic imports: A while back I had to add explicit imports when previous auto imports went away. Didn’t even know they were back. Something else to dig into!
1 Like