Groovy - How to access area value for an annotation?

400 views
Skip to first unread message

Carlos Moro

unread,
May 30, 2017, 9:37:13 AM5/30/17
to QuPath users
Hello,

When trying .getArea() in a ROI object for an annotation, I can't see the method, even in (https://github.com/qupath/qupath/blob/master/qupath-core/src/main/java/qupath/lib/roi/interfaces/ROI.java).

This is the snippet I'm trying:

def detectedRegions = QP.getAnnotationObjects()  
println "Number of detected regions $detectecRegions.size"

def regionAreas = []
for (aRegion in detectedRegions) {
regionsAreas << aRegion.getROI().getArea() // Doesn't work
}

Best wishes,
Carlos

micros...@gmail.com

unread,
May 30, 2017, 11:00:42 AM5/30/17
to QuPath users
I am not exactly sure about this but... I used the following to get close to what I think you want.

First, this quick script from Pete helps me a lot when looking at these kinds of problems 

// Get an object... any object
def myObject = getSelectedROI()
// An alternative below; this would show what's available with Ctrl+space in the script editor
// def myObject = new qupath.lib.scripting.QPEx()

// Print the methods you can have access to
for (m in myObject.getClass().getMethods()){
    println(m)
}


The following also seems to work for a single selected AWT Area in my project
def selected = getSelectedObject()
def area = selected.getROI().getArea()
println(area)


Finally, changing the code to the following works for me, so I think the problem is in the list you are creating, or writing to the list.  Unfortunately I am not all that good at Groovy so I cannot nail down how to actually make it work.
import qupath.lib.scripting.QP

def regionAreas = 0
for (def aRegion : QP.getAnnotationObjects()) {
regionsAreas = aRegion.getROI().getArea() 
println(regionsAreas)
}


That script should go through all of your areas and print them...  I did have to include the imported library for this to work.

micros...@gmail.com

unread,
May 30, 2017, 11:03:08 AM5/30/17
to QuPath users
Oh, actually I think the problem was just that you have regionsAreas in one place and regionAreas in another!

Carlos Moro

unread,
May 30, 2017, 11:50:04 AM5/30/17
to QuPath users
Thanks a lot! Yes, it worked  :)

Problem was not the typo but I couldn't see the method getArea() recognized by the IDE (Eclipse). I shall give a try IntellliJ as recommended O:)

Running the handy script to see the methods made it clear: 

"INFO: public double qupath.lib.roi.PolygonROI.getArea()"

This method is not defined in interface ROI returned by (getROI) but in class PolygonROI. 
I wasn't aware of differences between Java and Groovy, the latter finds methods defined for an object without need to be specified in every interface  ;)

Best wishes,
Carlos

micros...@gmail.com

unread,
May 30, 2017, 1:50:06 PM5/30/17
to QuPath users
Oh nice!  I am still trying to get Eclipse set up so that I can tinker, but have not been very successful with it yet.  I will keep that in mind once I do.

Carlos Moro

unread,
May 30, 2017, 2:22:45 PM5/30/17
to QuPath users
Works very well!  I have collected a series of screenshots illustrating how to set up Eclipse for QuPath (groovy) scripting, I'll upload in a thread very soon!  ;)

Best wishes,
Carlos

Pete

unread,
May 30, 2017, 3:06:02 PM5/30/17
to QuPath users
Hi,

To explain a bit: the ROI interface doesn’t include getArea(), but the PathArea interface does.  PolygonROI implements the both.

The idea was that some ROIs might not have an area… i.e. a LineROI.  So if you wanted to be extra careful, you could check
if (roi instanceof PathArea)
before requesting the area…. or else just assume that it will probably work and carry on without the cast (Groovy doesn’t insist on it).

However, one warning: getArea() is defined in terms of pixels!  It is a property of the ROI, which doesn’t know anything at all about the image it is part of.  The aim was to keep the ROI class as simple as possible.

With that in mind you might actually want to use the
getScaledArea(double pixelWidth, double pixelHeight)
method.

It's a bit more effort; you could hard-code the pixel sizes if you know them to be constant, or query them in the script.

Here’s a demonstration to show it in action:

def imageData = getCurrentImageData()
def server = imageData.getServer()
def pixelWidthMicrons = server.getPixelWidthMicrons()
def pixelHeightMicrons = server.getPixelHeightMicrons()

def roi = getSelectedROI()
def areaPixels = roi.getArea()
def areaPixels2 = roi.getScaledArea(1, 1)
def areaMicrons = roi.getScaledArea(pixelWidthMicrons, pixelHeightMicrons)
def areaMM = roi.getScaledArea(pixelWidthMicrons/1000, pixelHeightMicrons/1000)

println "Area in pixels: " + areaPixels
println "Scaled area in pixels: " + areaPixels2
println "Area in microns: " + areaMicrons
println "Area in mm: " + areaMM

Pete

unread,
May 30, 2017, 3:08:12 PM5/30/17
to QuPath users
Oh, and this link could be useful:

It describes some of the differences between Groovy and Java.  Number 2 (Multi-Methods) is especially relevant.  I remember that Java's behavior in this surprised me in the past... and Groovy handles things a bit differently.

Carlos Moro

unread,
May 31, 2017, 4:39:44 PM5/31/17
to QuPath users
Hi Pete,

Thanks a lot, very useful and interesting!

Best wishes,
Carlos
Reply all
Reply to author
Forward
0 new messages