Watershed cell detection (partly) fails with high number of annotations

I have several WSIs with multiple (10 - 1000) small (about 10x10 um^2) annotations for which I wish to run watershed nucleus detection. However, Qupath fails to perform this for about 1-20% of the annotations. I’ve tried expanding the annotations, reselecting the unprocessed ones, unlocking all, etc. etc. but nothing works, except if I manually select the unsuccessful annotations with no detections and run cell detection again - this produces a detection. Not sure what’s wrong - anyone?

Example image of the size of the annotations (about 10-1000 of these per image):

Script:

setImageType('BRIGHTFIELD_H_E');
setColorDeconvolutionStains('{"Name" : "H&E default", "Stain 1" : "Hematoxylin", "Values 1" : "0.65111 0.70119 0.29049 ", "Stain 2" : "Eosin", "Values 2" : "0.2159 0.8012 0.5581 ", "Background" : " 255 255 255 "}');

selectAnnotations();
runPlugin('qupath.lib.plugins.objects.SplitAnnotationsPlugin', '{}');

selectAnnotations();
resolveHierarchy()
getSelectedObjects().each {
   it.setLocked(false)
}
fireHierarchyUpdate()
resetSelection();

selectAnnotations();
runPlugin('qupath.lib.plugins.objects.DilateAnnotationPlugin', '{"radiusMicrons": -5.5,  "lineCap": "Round",  "removeInterior": false,  "constrainToParent": true}');
clearSelectedObjects(true);
clearSelectedObjects();

selectAnnotations();
runPlugin('qupath.lib.plugins.objects.DilateAnnotationPlugin', '{"radiusMicrons": 6.5,  "lineCap": "Round",  "removeInterior": false,  "constrainToParent": false}');
clearSelectedObjects(true);
clearSelectedObjects();

selectAnnotations();
runPlugin('qupath.imagej.detect.cells.WatershedCellDetection', '{"detectionImageBrightfield": "Hematoxylin OD",  "requestedPixelSizeMicrons": 0.0,  "backgroundRadiusMicrons": 8.0,  "medianRadiusMicrons": 0.0,  "sigmaMicrons": 1.5,  "minAreaMicrons": 5.0,  "maxAreaMicrons": 400.0,  "threshold": 0.24,  "maxBackground": 2.0,  "watershedPostProcess": true,  "cellExpansionMicrons": 5.0,  "includeNuclei": true,  "smoothBoundaries": true,  "makeMeasurements": true}');

selectDetections();
runPlugin('qupath.lib.algorithms.IntensityFeaturesPlugin', '{"pixelSizeMicrons": 2.0,  "region": "ROI",  "tileSizeMicrons": 25.0,  "colorOD": true,  "colorStain1": true,  "colorStain2": true,  "colorStain3": true,  "colorRed": true,  "colorGreen": true,  "colorBlue": true,  "colorHue": true,  "colorSaturation": true,  "colorBrightness": true,  "doMean": true,  "doStdDev": true,  "doMinMax": true,  "doMedian": true,  "doHaralick": true,  "haralickDistance": 1,  "haralickBins": 32}');
resetSelection();

Error message:

INFO: 1 nucleus detected (processing time: 0.29 seconds)
INFO: 1 nucleus detected (processing time: 0.29 seconds)
INFO: 1 nucleus detected (processing time: 0.29 seconds)
INFO: 1 nucleus detected (processing time: 0.30 seconds)
INFO: 1 nucleus detected (processing time: 0.30 seconds)
INFO: 2 nuclei detected (processing time: 0.30 seconds)
INFO: 1 nucleus detected (processing time: 0.31 seconds)
INFO: 1 nucleus detected (processing time: 0.31 seconds)
INFO: 1 nucleus detected (processing time: 0.31 seconds)
INFO: 3 nuclei detected (processing time: 0.31 seconds)
INFO: 2 nuclei detected (processing time: 0.04 seconds)
INFO: 3 nuclei detected (processing time: 0.04 seconds)
INFO: 2 nuclei detected (processing time: 0.04 seconds)
INFO: 1 nucleus detected (processing time: 0.05 seconds)
INFO: 2 nuclei detected (processing time: 0.08 seconds)
INFO: 2 nuclei detected (processing time: 0.08 seconds)
INFO: 1 nucleus detected (processing time: 0.10 seconds)
INFO: 1 nucleus detected (processing time: 0.09 seconds)
INFO: 2 nuclei detected (processing time: 0.04 seconds)
INFO: 1 nucleus detected (processing time: 0.06 seconds)
INFO: 2 nuclei detected (processing time: 0.06 seconds)
INFO: 2 nuclei detected (processing time: 0.10 seconds)
INFO: 1 nucleus detected (processing time: 0.10 seconds)
INFO: 1 nucleus detected (processing time: 0.02 seconds)
INFO: 3 nuclei detected (processing time: 0.07 seconds)
INFO: 1 nucleus detected (processing time: 0.03 seconds)
INFO: 2 nuclei detected (processing time: 0.04 seconds)
INFO: 1 nucleus detected (processing time: 0.04 seconds)
INFO: 2 nuclei detected (processing time: 0.05 seconds)
INFO: 2 nuclei detected (processing time: 0.04 seconds)
INFO: 2 nuclei detected (processing time: 0.04 seconds)
INFO: 2 nuclei detected (processing time: 0.04 seconds)
INFO: 2 nuclei detected (processing time: 0.04 seconds)
INFO: 1 nucleus detected (processing time: 0.02 seconds)
INFO: 2 nuclei detected (processing time: 0.04 seconds)
INFO: 2 nuclei detected (processing time: 0.05 seconds)
INFO: 1 nucleus detected (processing time: 0.02 seconds)
INFO: 3 nuclei detected (processing time: 0.03 seconds)
INFO: 1 nucleus detected (processing time: 0.02 seconds)
INFO: 2 nuclei detected (processing time: 0.03 seconds)
INFO: 2 nuclei detected (processing time: 0.02 seconds)
INFO: 2 nuclei detected (processing time: 0.02 seconds)
INFO: 1 nucleus detected (processing time: 0.02 seconds)
INFO: 2 nuclei detected (processing time: 0.02 seconds)
INFO: 1 nucleus detected (processing time: 0.03 seconds)
INFO: 1 nucleus detected (processing time: 0.04 seconds)
INFO: 1 nucleus detected (processing time: 0.03 seconds)
INFO: 2 nuclei detected (processing time: 0.03 seconds)
INFO: 2 nuclei detected (processing time: 0.03 seconds)
INFO: 1 nucleus detected (processing time: 0.03 seconds)
INFO: 1 nucleus detected (processing time: 0.05 seconds)
INFO: 2 nuclei detected (processing time: 0.03 seconds)
INFO: 2 nuclei detected (processing time: 0.03 seconds)
ERROR: Error running plugin: java.lang.NullPointerException
    at java.base/java.util.concurrent.FutureTask.report(Unknown Source)
    at java.base/java.util.concurrent.FutureTask.get(Unknown Source)
    at qupath.lib.plugins.AbstractPluginRunner.awaitCompletion(AbstractPluginRunner.java:199)
    at qupath.lib.plugins.AbstractPluginRunner.runTasks(AbstractPluginRunner.java:158)
    at qupath.lib.gui.plugins.PluginRunnerFX.runTasks(PluginRunnerFX.java:99)
    at qupath.lib.plugins.AbstractPlugin.runPlugin(AbstractPlugin.java:164)
    at qupath.lib.gui.scripting.QPEx.runPlugin(QPEx.java:212)
    at qupath.lib.gui.scripting.QPEx.runPlugin(QPEx.java:232)
    at qupath.lib.gui.scripting.QPEx$runPlugin.callStatic(Unknown Source)
    at org.codehaus.groovy.runtime.callsite.CallSiteArray.defaultCallStatic(CallSiteArray.java:55)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:217)
    at org.codehaus.groovy.runtime.callsite.AbstractCallSite.callStatic(AbstractCallSite.java:240)
    at Script1.run(Script1.groovy:36)
    at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:317)
    at org.codehaus.groovy.jsr223.GroovyScriptEngineImpl.eval(GroovyScriptEngineImpl.java:155)
    at qupath.lib.gui.scripting.DefaultScriptEditor.executeScript(DefaultScriptEditor.java:926)
    at qupath.lib.gui.scripting.DefaultScriptEditor.executeScript(DefaultScriptEditor.java:859)
    at qupath.lib.gui.scripting.DefaultScriptEditor.executeScript(DefaultScriptEditor.java:782)
    at qupath.lib.gui.scripting.DefaultScriptEditor$2.run(DefaultScriptEditor.java:1271)
    at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
    at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
    at java.base/java.lang.Thread.run(Unknown Source)
  Caused by null        at qupath.imagej.tools.IJTools.convertToUncalibratedImagePlus(IJTools.java:608)
        at qupath.imagej.tools.IJTools.convertToImagePlus(IJTools.java:681)
        at qupath.imagej.tools.IJTools.convertToImagePlus(IJTools.java:719)
        at qupath.imagej.detect.cells.WatershedCellDetection$CellDetector.runDetection(WatershedCellDetection.java:189)
        at qupath.lib.plugins.DetectionPluginTools$DetectionRunnable.run(DetectionPluginTools.java:112)
        at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
        at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
        at java.base/java.util.concurrent.Executors$RunnableAdapter.call(Unknown Source)
        at java.base/java.util.concurrent.FutureTask.run(Unknown Source)
        at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(Unknown Source)
        at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(Unknown Source)
        at java.base/java.lang.Thread.run(Unknown Source)
INFO: 0 nuclei detected (processing time: 0.04 seconds)
INFO: 0 nuclei detected (processing time: 0.02 seconds)
INFO: 0 nuclei detected (processing time: 0.03 seconds)
INFO: 0 nuclei detected (processing time: 0.02 seconds)
INFO: 0 nuclei detected (processing time: 0.01 seconds)
INFO: 0 nuclei detected (processing time: 0.01 seconds)
INFO: 0 nuclei detected (processing time: 0.02 seconds)
INFO: 0 nuclei detected (processing time: 0.03 seconds)
INFO: Processing complete in 0.98 seconds
INFO: Completed with error java.lang.NullPointerException
INFO: Processing complete in 0.46 seconds
INFO: Completed!

No idea really, but the first two things I would try are sticking:

guiscript=true

at the top of the script (has to be first line) and see if forcing it to a single thread changes anything. Next thing I would change is the background radius - I am not sure if there is some issue with the small size of the annotation area or if cell detection ignores the annotation boundaries.

This is 0.2.3?

Also, I guess the other question is why are you doing this, and might there be an easier way?

Thanks. Yes, it’s 2.3. I think it might be a problem with some of the annotations being imported outside the limits of the image border (they are imported json files from a paper). I think just doing a simple pixel thresholder might be a good solution. Thanks for the reply!

That fits with the error message – the problem comes from the requested image region being null, which would be expected if it is outside the image bounds.

1 Like