Script for counting objects


I uses Qupath for counting brightfield-ISH spots (DAB) in the tumor sections (hematoxylin counterstain).

Thus far, I’ve gotten to classifying cells into “Tumor” vs “Others”, followed by Subcellular Detection batch-ran with a script only in “Tumor” cells.

I want to generate a list of results for the 700+ images in my project using a script, but the output does not seem to tally. e.g. Annotation manager showed Num Subcellular spot: DAB object as 3827 in 3465 tumor cells, but in script editor, it was shown as 8486 and 4659 respectively.

selectObjects { p -> p.getPathClass() == getPathClass(“Tumor”) }
detections = getDetectionObjects()
cells = getCellObjects()
name = getProjectEntry().getImageName()

print 'filename: ’ + name
print ’ annotation objects: ’ + getAnnotationObjects().size()
print 'cell size- no of tumor cells: ’ + cells.size()
print ‘detection size - ISH spots:’ + detections.size() - cells.size()
print 'Annotation objects: ’ + getAnnotationObjects().size()


I’ve spent some hours looking for relevant posts and tutorials, but still no luck. Would greatly appreciate if someone can help with directing me to relevant tutorials.


This is a complete guess (made from a phone, unable to check) but I’d suggest doing the subtraction separately before printing - or at least within parentheses. I think combining it with string concatenation is problematic.

Might try going direct to
def clusters = getObjects({p -> p.class == qupath.imagej.detect.cells.SubcellularDetection.SubcellularObject.class})

from this script.

Many other scripting examples here and here.

Note that this will not give you an accurate spot count, it will give you an accurate count of spot objects. Depending on how you set up your subcellular detection, each subcellular object may represent far more than one spot. It would be more accurate to take the Estimated Num Spots for DAB and sum that among all cells.

Thanks guys- the counting for subcellular is working nicely and i managed to utilise some lines from the scripting examples.

I’m puzzled that one of the script is showing different cell count compared to annotation manager though.
This is the script i adapted to print “Tumor” cell count:

def tumor = getObjects { p -> p.getPathClass() == getPathClass(“Tumor”) }
print 'tumor objects= ’ + tumor.size()

Result shown as 2424, but on my full frame annotation (PathAnnotationObject), there’s only 2418 cells classified as Tumor. Any idea why did that script generate additional 6 objects or a good place to start investigating?

appreciate if anyone can help with this


Are you using v0.1.2? I recall there was a bug with the (optional) boundary smoothing of the cell detection that meant that, in rare circumstances, the boundary of cell or nucleus could get ‘smoothed away’ to nothing. Such a cell may not then be identified as being inside the annotation, but still accessible to other scripts.

I believe I fixed this and it shouldn’t occur in the milestone releases, or if you don’t choose the smooth boundaries option.

Thanks pete, i’m using v0.1.2 currently and this might be it

Actually I’m not sure that’s the explanation, at least I couldn’t replicate the issue.

However, note that

def tumor = getObjects { p -> p.getPathClass() == getPathClass("Tumor") }

will return all objects classified as tumor, including annotations (not just cells). If you just want cells, you could use

def tumor = getCellObjects().findAll { p -> p.getPathClass() == getPathClass("Tumor") }
1 Like