Remove detected objects touching annotations border

Hello,

is there a way to remove detected objects touching the border of any annotations? (to avoid bias regarding the truncated areas for instance). It should not be based on centroïds but really on “common pixels”.

I have tried to erode the annotation but it didn’t work…

ROI = getAnnotationObjects().findAll {it.getPathClass() == getPathClass("ROI")}
selectObjectsByClassification("ROI");
runPlugin('qupath.lib.plugins.objects.DilateAnnotationPlugin', '{"radiusMicrons": -5.0,  "lineCap": "Square",  "removeInterior": true,  "constrainToParent": false}');
removeObjects(ROI,true)
resetSelection()
ROI_border = getAnnotationObjects().findAll {it.getPathClass() == getPathClass("ROI")}
def hierarchy = getCurrentHierarchy()
selectObjectsByClassification("ROI")
def parent = getSelectedObject()
print parent
def objects = hierarchy.getObjectsForROI(null, parent.getROI())
    .findAll { it.isDetection() }
hierarchy.getObjectsForROI(qupath.lib.objects.PathDetectionObject, parent.getROI())

Excuse my lack of QuPath knowledge… I hope it is just a stupid mistake that I cannot see :slight_smile:

I have the impression that my approach is too complicated somehow…
Thank you very much in advance!

Well actually I have tried to adapt this other piece of code, but it is working fine only for one annotation.
However it seems that this is exactly what I would need.
I am kind of lost with what should be modified in the “eachWithIndex loop”… one more time sorry but I feel lost without documentation…

ROI = getAnnotationObjects().findAll {it.getPathClass() == getPathClass("ROI")}
selectObjectsByClassification("ROI");
runPlugin('qupath.lib.plugins.objects.DilateAnnotationPlugin', '{"radiusMicrons": -5.0,  "lineCap": "Square",  "removeInterior": true,  "constrainToParent": false}');
removeObjects(ROI,true)
resetSelection()
ROI_border = getAnnotationObjects().findAll {it.getPathClass() == getPathClass("ROI")}

import static qupath.lib.gui.scripting.QPEx.*
def fibers=getDetectionObjects()
def fibersgeos=fibers.collect{it.getROI().getGeometry()}

//get a single annotation this one is working fine
//def ROI_border_geo=getAnnotationObjects().find{it.getPathClass()==getPathClass("ROI")}.getROI().getGeometry()
//get all the annotations
ROI_border_geo = ROI_border.collect{it.getROI().getGeometry()};

def intersections=[]
//ROI_border_geo does not work here with all the annotations but only with a single one
fibersgeos.eachWithIndex{entry,idx->
    if (entry.intersects(ROI_border_geo)){
        intersections<<idx
    }
}

removeObjects(ROI_border,true)
addObjects(ROI)

getCurrentHierarchy().getSelectionModel().selectObjects(fibers[intersections])
clearSelectedObjects();

It sounds like you might want to cycle through ROI_border.each{
and within that particular border, find the objects that intersect.

You might also check out the code here that calculates distances between object edges.

If you have a border class, and the distance between a fiber and a border is 0… you can remove it. Can be slow though if you have a lot of objects.

Also, your erosion method in the first post could have worked, but you would have needed to remove the objects that were now outside the annotation after the erosion (after resolving the hierarchy, their level would now be 1 - if there were no further annotations). Or possibly check each cell to see if getParent was still the right class after the erosion.

Hi @TreyRollit, I’ve written a script that may be worth a try:

Note there are a couple of parameters you can adjust.

I haven’t tested it very much, please let me know if it works for you. I suspect this could be useful enough to deserve becoming a built-in command in the future.

2 Likes
// We need to get separate line strings for each polygon (since otherwise we get distances of zero when inside)

Now that is cool. And a nice option for finding distances to annotation from within an annotation… without creating an inverse annotation in situations where that is awkward.

@Research_Associate Yes, it will probably be required if you are ever to get that signed distance transform you’ve been wanting…

1 Like

Signed, sealed, and delivered?

Maybe some day, but for now, scripts!

1 Like

Wow! thank you @petebankhead your script is exactly doing what I was expecting!
Thank you also @Research_Associate for your help and advice.

Indeed such a feature is extremely useful.

One more time a big thank you!

2 Likes