Want to create an overlay of ellipses using csv results data exported from imagej

I am a newb and have little coding experience.

I have a csv file (https://pastebin.com/1aM7wDXX) exported from ImageJ that describes ellipses that were drawn and measured in ImageJ. I want to import these ellipses into an overlay and save the overlay so I can visualise these ellipses and manipulate some of them.

I have tried a few ways but I am struggling to understand alot of what I am reading. Can anyone provide me with a solution? Thanks in advance

For each row of a results table, you can create an ellipse ROI by scripting and making use of the ResultsTable and Overlay classes.

The Groovy script below (runnable from the script editor after selecting Language > Groovy) illustrates how to do that. You just need to have loaded your csv file in a results table (e.g. by renaming it as *.tsv and dragging onto ImageJ) and have your image opened.

#@ ImagePlus imp
#@ ResultsTable rt

import ij.gui.OvalRoi
import ij.gui.Overlay

x = rt.getColumnAsDoubles(rt.getColumnIndex("X"))
y = rt.getColumnAsDoubles(rt.getColumnIndex("Y"))
width = rt.getColumnAsDoubles(rt.getColumnIndex("Major"))
height = rt.getColumnAsDoubles(rt.getColumnIndex("Minor"))

ovl = new Overlay()

[x, y, width, height].transpose().each { xc,yc, w, h ->
	ovl.add(new OvalRoi(xc, yc, w, h))
}

imp.setOverlay(ovl)

The drawback is that a standard ImageJ 1.x ellipse ROI cannot be rotated arbitrarily (it just has a width and height parameter), so you might need to create mask or polygon ROIs instead…

Also, if your measurements are in calibrated units, you’ll have to convert them to pixel units when creating the overlay, by dividing by pixel width and height where appropriate.

1 Like

To get the rotated ellipse, you could use @imagejan’s code, but before this line:

imp.setOverlay(ovl)

add a line to retrieve the measured angle and rotate the Oval ROI by that angle (but I’m not sure how to do this in Groovy).

This was done in the macro language by @Lucie in this post.

Hope it helps!

1 Like

Oh yes, thanks for pointing to this post!

In Groovy (or any other scripting language), you can use the RoiRotator class (that’s what is used internally by the Edit > Selection > Rotate… command, as you can find out using the command finder):

import ij.plugin.RoiRotator

...

angles = rt.getColumnAsDoubles(rt.getColumnIndex("Angle"))

...

[x, y, width, height, angles].transpose().each { xc,yc, w, h, angle ->
    roi = new OvalRoi(xc, yc, w, h)
    rotatedRoi = RoiRotator.rotate(roi, angle)
    ovl.add(rotatedRoi)
}

Note however that the measured angle is different from the angle you need to rotate: for example, when you rotate horizontal ellipse by 15 degrees, the measured angle is close to 165 degrees. You’ll need to do some math conversion.

1 Like

@imagejan, could you kindly answer another Groovy newb question – what does transpose do here?

I assume that the following would not work:

ovl.add(new OvalRoi(x, y, width, height))

But why? So far, Googling tells me that transpose would convert the ‘flat’ list of parameters into four 1-element lists, but that still leaves me confused as to why it’s needed.

Many thanks!

I probably mis-named x, y, width and height in my script: these are column vectors, i.e. arrays holding all the values of the given column in the results table.

The transpose trick I learned from stackoverflow (I think) when looking for a way to loop through several arrays of same size, similiar to how zip(a,b) works in python.

So if you have a table (four column vectors) like this:

 X  Y Major Minor
 0  0    30    10
10 10    25    10

transpose() will make them a list of two row vectors:

[[ 0,  0, 30, 10],
 [10, 10, 25, 10]]

which then are assigned to the variables xc, yc, w, h in each iteration of the each loop. The input to the loop, the entire section between the braces {}, is called a closure.

1 Like

Thank you! I missed that you got the whole column of Results values. Very neat!

I have now imported the ovals into file using your method. I had to run a 180-angle calculation to get the angle correct (did this in excel as I couldn’t work out why it errored when I added 180 to angle in the code). I now have a problem of getting the XY correctly as the ovals are drawn as the XY are in the topd left corner, whilst the XY in file are centroid XY’s. I will attempt do some trig math to work this out. Thanks alot for your help :slight_smile: