Check if one annotation is inside the other

Is there any efficient way for large annotations on whole slide images to check whether one is inside the other? I’ve seen .contains() method for Shapes or Areas (I am not sure currently). I want to check whether an annotation is contained by an other with the same label.

Also a side note, as I am writing an extension I see that the getArea() method is not present on ROIs, is there a way to get the actual pixel area of an annotation?

Thanks in advance!

getArea() is present on some ROIs… namely those that implement the PathArea interface. The ones that don’t are points and lines.

Admittedly, it might be easier to just always have a getArea() method and return zero for the other ROIs… curious as to what you think. Checking for the interface is a bit annoying.

Regarding testing inside, it’s always troublesome… the best solution will be to use roi.getGeometry() and then test with Java Topology Suite. But this doesn’t exist in v0.1.2 and I’ve found a bug here in the implementation affecting v0.2.0-m2.

I think I’ve got a workaround for the bug, but currently lack the time to work on this and put together a new release. But depending on the kind of shapes you’re testing, the bug might not cause you trouble.

One fun workaround might be a variant of this code or the variety of scripts here that uses the getArea functions based off of one of Pete’s scripts.

If you are pairwise checking every two objects, and you add their Areas (not their areas :slight_smile: ), the result should only be the same size as the smaller of the two objects if one is contained within the other.

By that logic I quickly hacked off a part of Pete’s script and got:

The script itself takes an annotation, expands it by a set amount, and then tests adding the original and expanded areas together. Due to the first area being entirely inside the second, they have the same final “area” once being converted back into an ROI. At no point do I actually do any creating of this ROI object I was using for testing.
Probably not necessary, but as a reference, here’s the code. And so Pete can pick out any potential flaws in my logic.

import qupath.lib.roi.PathROIToolsAwt

def server = getCurrentImageData().getServer()

double expandMarginMicrons = 300
double expandPixels = expandMarginMicrons / server.getAveragedPixelSizeMicrons()
def selected = getSelectedObject()
def roiOriginal = selected.getROI()
println "Starting ROI Area       " + roiOriginal.getArea()
def areaTumor = PathROIToolsAwt.getArea(roiOriginal)

def areaOuter = PathROIToolsAwt.shapeMorphology(areaTumor, expandPixels)
def roiOuter = PathROIToolsAwt.getShapeROI(areaOuter, roiOriginal.getC(), roiOriginal.getZ(), roiOriginal.getT())

println "Expanded ROI Area       " + roiOuter.getArea()


def testForInside = PathROIToolsAwt.getShapeROI(areaOuter, roiOriginal.getC(), roiOriginal.getZ(), roiOriginal.getT())
println "Sum of two Area objects "+testForInside.getArea()

Slightly more complex area.

Intended failed area