Using annotations to subtract from parent object

Hello! I am working with images that are pre-annotated by someone else. They used annotations within a parent object to indicate the whitespace in the tissue - aka what should be excluded from the analysis. I’m not sure how I would be able to subtract that area from the parent annotation?

Also, if I want to merge all of the annotations together and still subtract all of the whitespace annotations to ensure that only actual tissue gets analyzed, is there a way to combine it only into one annotation at the end?


Hard to say without seeing an example, but there is a discussion on subtracting here.

From that post, it sounds like you might be able to select the parent annotation last when performing the manual subtraction through the context menu, or you can find a way to select all non-parent annotations and Merge them, then subtract that annotation from the parent. But without knowing whether the annotations are classified or labeled in some way… hard to say more. If the white space annotations are accurate, you might be able to classify them all yourself by using Analyze/Calculate Features/Add Intensity Features.

1 Like

You also might be able to use something like:

annotations = getAnnotationObjects()
    toSubtract = it.getChildObjects()
        //do subtraction here

But in a rush and can’t finish. Might get you started though.

Though that might start cycling through annotations that you have already used, so might not have been the best suggestion for a starting point.

Thank you! I followed what you said in terms of choosing the parent object last and the selection worked!

Ah, oops, just got back to this and realized there was an easier way. Modifying this script to ignore class might work as well, and automatically.

import qupath.lib.roi.*
import qupath.lib.objects.*

classToSubtract = null
def topLevel = getObjects{return it.getLevel()==1 && it.isAnnotation()}
for (parent in topLevel){

    def total = []
    def polygons = []
    subtractions = parent.getChildObjects().findAll{it.isAnnotation() }
    for (subtractyBit in subtractions){
        if (subtractyBit instanceof AreaROI){
           subtractionROIs = PathROIToolsAwt.splitAreaToPolygons(subtractyBit.getROI())
        } else {total.addAll(subtractyBit.getROI())}              
    if (parent instanceof AreaROI){
        polygons = PathROIToolsAwt.splitAreaToPolygons(parent.getROI())
    } else { polygons[1] = parent.getROI()}

    def newPolygons = polygons[1].collect {
    updated = it
    for (hole in total)
         updated = PathROIToolsAwt.combineROIs(updated, hole, PathROIToolsAwt.CombineOp.SUBTRACT)
         return updated
                // Remove original annotation, add new ones
    annotations = newPolygons.collect {new PathAnnotationObject(updated, parent.getPathClass())}


    removeObjects(subtractions, true)
    removeObject(parent, true)
print "done"
1 Like

Oh, okay! Thank you!