Problems with selecting only objects touching annotations with a script

Dear all,

I have parkinsons tissue where I am looking at Lewy bodies in the cortex. Lewy bodies can be both intracellular as extracellular. Now, in my research, I want to only look at intracellular Lewy bodies. I thought of a method which will exclude all the extracellular Lewy bodies.

I found in an other forum a nice script from Sara McCardle to select objects touching an annotation. My strategy is to make annotations of all the cells in my parent annotation/ROI. Plus, I make detections of the Lewy bodies in that same parent annotation/ROI. Thus in theory, I select only the intracellular lewy bodies (because they will be in contact with my cells).

import static qupath.lib.gui.scripting.QPEx.*

def islets=getDetectionObjects()
def isletsgeos=islets.collect{it.getROI().getGeometry()}
def outsidegeo=getAnnotationObjects().find{it.getPathClass()==getPathClass("Neurons")}.getROI().getGeometry()

def intersections=[]
isletsgeos.eachWithIndex{entry,idx->
    if (entry.intersects(outsidegeo)){
        intersections<<idx
    }
}

print(intersections)
getCurrentHierarchy().getSelectionModel().selectObjects(islets[intersections])

However, When I run the script I don’t get an error, instead I get: INFO: [ ]. That’s it. It does not seem to work.

Can somebody help me try to figure out what I am doing wrong here, I am using the 0.2.3. version of QuPath?

Best,

1 Like

Hi @Lydian ,

I’ve never used this script, but at first glance maybe the reason for which it doesn’t print anything could be:

  1. You don’t have detections objects?
  2. You don’t have annotations?
  3. You have annotations but none have Neurons as PathClass?
2 Likes

Hi Melvin,

Thanks for you quick response!

I made two screenshots inside my detection. Here you can see that the cells are annotated in blue. I gave them the class: Neurons. The purple things are the lewybodies which are objects classified as Lewy bodies.

123

So I definitely have both annotations and detection objects…

I suspect the problem is that @smcardle wrote this for a specific situation where you have one annotation object. To use this script you need to select all of your Neuron class annotations and merge them, as it is only expecting one annotation, thus the “find” function, not “findAll.”

And you can’t simply change it to findAll since then you would not be checking intersections against one object. You might be able to create a geometry from the collection of annotation ROIs, and check that, but that would need a little extra code that I don’t know off the top of my head.

The quick way (in terms of coding time)


selectObjectsByClassification("Neurons")

mergeSelectedAnnotations()
//Some code to check intersection
//
//...

selectObjectsByClassification("Neurons")
runPlugin('qupath.lib.plugins.objects.SplitAnnotationsPlugin', '{}');

Two things, this will delete and create NEW annotations, so any modifications you made to the old annotations, like measurements, will be gone. It also may be slow if you have a million annotations, and it would be faster to work through geometries.

Thanks @Research_Associate, this was the problem!

What I struggle with now (and am not sure if you can help me with) is that I only want to keep the Intracellular Lewy Bodies. So, the objects that intersect with the annotations. The rest of the objects that do not intersect with annotations I want to delete. Is there a command which can solve this?

Best, Lydian

Once you have your list of “intersections” you can use
removeObjects(intersections, true)

Oh, reading back, you need to collect the objects, so the script is structured incorrectly as you have the geometries (outlines, not the objects) in your intersections list.

def intersections=[]
isletsgeos.eachWithIndex{entry,idx->
    if (entry.intersects(outsidegeo)){
        intersections<<idx
    }
}

Needs to be

def intersections=[]
islets.eachWithIndex{entry,idx->
entrygeo = entry.getROI().getGeometry()
    if (entrygeo.intersects(outsidegeo)){
        intersections<<entry
    }
}

Now your intersections list is a list of objects, not a list of geometries or indexes.

Oh thanks! This was an easier solution than I thought it would be!

You might also be able to use

removeObjects(islets[intersections],true)

Probably try this one first since it would involve the least amount of change.

This one worked! Thanks!

1 Like

I’m so sorry to bother you again @Research_Associate, but I noticed now that in the script you gave me the intracellular lewy bodies are being deleted and the extracellular lewy bodies are being kept.

the issue that I have now is that I actually want the islets[intersections] to be kept, and all the rest to be deleted. I tried to think of a way to do it myself, but couldn’t figure it out…

Can you help me with this issue?
Best,
Lydian

If you want to reverse the logic, all you need to do is “not” keep the intersections, which in Groovy is an exclamation mark.

becomes
if (!entry.intersects(outsidegeo)){