Problems in counting cells in two channels using script

238 views
Skip to first unread message

fuhy...@gmail.com

unread,
Aug 21, 2018, 3:16:18 PM8/21/18
to QuPath users
Hi, I have some problems when I was trying to quantify the cells labeled by two channels at the same time. Here's my script below:

print("Start processing ...")
setImageType('FLUORESCENCE')
runPlugin('qupath.imagej.detect.nuclei.WatershedCellDetection', '{"detectionImageFluorescence": 1,  "backgroundRadius": 15.0,  "medianRadius": 0.0,  "sigma": 3.0,  "minArea": 10.0,  "maxArea": 1000.0,  "threshold": 15.0,  "watershedPostProcess": true,  "cellExpansion": 0.0,  "includeNuclei": true,  "smoothBoundaries": true,  "makeMeasurements": true}')
runPlugin('qupath.imagej.detect.nuclei.WatershedCellDetection', '{"detectionImageFluorescence": 2,  "backgroundRadius": 15.0,  "medianRadius": 0.0,  "sigma": 3.0,  "minArea": 10.0,  "maxArea": 1000.0,  "threshold": 15.0,  "watershedPostProcess": true,  "cellExpansion": 0.0,  "includeNuclei": true,  "smoothBoundaries": true,  "makeMeasurements": true}')
positive = getPathClass('Positive')
negative = getPathClass('Negative')

int positive_count = 0
int negative_count = 0
int total = 0

for (cell in getCellObjects()) {
    ch1 = measurement(cell, 'Cell: Channel 1 mean')
    ch2 = measurement(cell, 'Cell: Channel 2 mean')
    if (ch1 > 25 && ch2 > 25) {
        positive_count += 1
        cell.setPathClass(positive)
    } else {
        negative_count += 1
        cell.setPathClass(negative)
    }
    total += 1
}
fireHierarchyUpdate()

print("Positive cell count: " + positive_count)
print("Negative cell count: " + negative_count)
print("Total cell count: " + total)
print("Done!")

The output once fit the real situation. But then the output is all 0. Here's the output below:

INFO: 
qupath.imagej.detect.nuclei.WatershedCellDetection  {"detectionImageFluorescence": 2,  "backgroundRadius": 15.0,  "medianRadius": 0.0,  "sigma": 3.0,  "minArea": 10.0,  "maxArea": 1000.0,  "threshold": 15.0,  "watershedPostProcess": true,  "cellExpansion": 0.0,  "includeNuclei": true,  "smoothBoundaries": true,  "makeMeasurements": true}
INFO: Positive cell count: 0
INFO: Negative cell count: 0
INFO: Total cell count: 0
INFO: Done!
INFO: Start processing ...
INFO: 376 nuclei detected (processing time: 0.34 seconds)
INFO: Processing complete in 0.35 seconds
INFO: Completed!
INFO: 
qupath.imagej.detect.nuclei.WatershedCellDetection  {"detectionImageFluorescence": 1,  "backgroundRadius": 15.0,  "medianRadius": 0.0,  "sigma": 3.0,  "minArea": 10.0,  "maxArea": 1000.0,  "threshold": 15.0,  "watershedPostProcess": true,  "cellExpansion": 0.0,  "includeNuclei": true,  "smoothBoundaries": true,  "makeMeasurements": true}
INFO: 1207 nuclei detected (processing time: 0.43 seconds)
INFO: Processing complete in 0.44 seconds
INFO: Completed!
INFO: 
qupath.imagej.detect.nuclei.WatershedCellDetection  {"detectionImageFluorescence": 2,  "backgroundRadius": 15.0,  "medianRadius": 0.0,  "sigma": 3.0,  "minArea": 10.0,  "maxArea": 1000.0,  "threshold": 15.0,  "watershedPostProcess": true,  "cellExpansion": 0.0,  "includeNuclei": true,  "smoothBoundaries": true,  "makeMeasurements": true}
INFO: Positive cell count: 0
INFO: Negative cell count: 0
INFO: Total cell count: 0
INFO: Done!

It seems that Qupath can still identify cells in different channels still, but somehow it just can't quantify the number of the cells labeled by two channels. 

Can you tell me what's going on? Thanks!

Sincerely, 
Fuhan

Pete

unread,
Aug 21, 2018, 3:22:16 PM8/21/18
to QuPath users
You need the 'cellExpansion' to be greater than zero to make the measurements across the entire cell.  Otherwise you will only detect the nucleus, and not get any full cell measurements.

Also, if you just detect the nucleus then you need getDetectionObjects() instead of getCellObjects() - because the cell objects are a special case when there is both a nucleus and an outer boundary.

(If I read the script correctly, it runs the cell detection twice - but the second detections will just replace the first)

Hope that helps,

Pete

fuhy...@gmail.com

unread,
Mar 31, 2019, 12:10:11 PM3/31/19
to QuPath users
Hi Pete, 

Sorry it takes so long time for me to reply...It only detects the nucleus now when I changed to getDetectionObjects(). But I cannot find where the script runs the cell detection twice. Is it at "runPlugin('qupath.imagej.detect.nuclei.WatershedCellDetection...." at the beginning? 

Thanks and look forward to your reply!

Fuhan

Pete

unread,
Mar 31, 2019, 12:14:41 PM3/31/19
to QuPath users
Yes, I added spaces between the first lines of your script and made the two separate cell detections in bold.


print("Start processing ...")

setImageType
('FLUORESCENCE')

runPlugin('qupath.imagej.detect.nuclei.WatershedCellDetection', '{"detectionImageFluorescence": 1,  "backgroundRadius": 15.0,  "medianRadius": 0.0,  "sigma": 3.0,  "minArea": 10.0,  "maxArea": 1000.0,  "threshold": 15.0,  "watershedPostProcess": true,  "cellExpansion": 0.0,  "includeNuclei": true,  "smoothBoundaries": true,  "makeMeasurements": true}')

runPlugin
('qupath.imagej.detect.nuclei.WatershedCellDetection', '{"detectionImageFluorescence": 2,  "backgroundRadius": 15.0,  "medianRadius": 0.0,  "sigma": 3.0,  "minArea": 10.0,  "maxArea": 1000.0,  "threshold": 15.0,  "watershedPostProcess": true,  "cellExpansion": 0.0,  "includeNuclei": true,  "smoothBoundaries": true,  "makeMeasurements": true}')


positive
= getPathClass('Positive')

negative
= getPathClass('Negative')

In practice, this could also mean cell detection is never run if no objects are selected, since the detection requires some objects (annotations or TMA cores) to be selected to define the regions where the detection is applied.

fuhy...@gmail.com

unread,
Mar 31, 2019, 12:24:53 PM3/31/19
to QuPath users
That's true. I always selected annotations before I run this script. The reason that I run the cell detection twice is I need to label the cells in two channels(You can see there is 1 and 2 in detectionImageFluorescence). Because there are two different markers in two channels, and what I need to do is to quantify the number of overlapped cells expressing two markers. If this will cause labeling the same channel in two times, what should I do to label the overlapped cells in two channels?

Thanks!

Fuhan

Pete

unread,
Mar 31, 2019, 12:28:12 PM3/31/19
to QuPath users
Ah, I didn't look closely enough :)
But I'd still expect that the second cell detection simply overrides the first (i.e. deletes all the cells from the first detection, then applies the second detection).  Is this not what happens?

In general, I'd expect that you'd need to detect cells in one channel (typically DAPI) and then classify cells one way or another based on the measurements made in other channels. For fluorescence images, all channels should be measured - but just one is used for detection.

fuhy...@gmail.com

unread,
Mar 31, 2019, 12:42:17 PM3/31/19
to QuPath users
Yes this is what happened, the second cell detection always replace the first one :)

Does that mean cell detection is used for detecting if there is a signal so one-time use is enough? And if I want to classify the cells according to different markers, I should use other functions like classification or measurement?

Can you tell me more about how to realize it? :)

micros...@gmail.com

unread,
Mar 31, 2019, 1:24:39 PM3/31/19
to QuPath users
You might want to consider this set of scripts.

Note that all three separate scripts are in one script for portability, you will want to copy out each part. I used it so that I could use two different cell detection parameters and combine the results. In my case it was sigmas, intensities and sizes, but you could also use it to run two different channels, and then eliminate overlapping results. I have not tested it extensively, so any feedback or issues would be welcome!

Essentially, run one cell detection, export detection results to a file. Run the second cell detection, which wipes out the first cell detection, and then load the original detections back into the image. You will now have some overlapping cells. The third part of the script should eliminate overlapping cells, since one cell will generally be a child object of the other, or at least they were in my case (I also chose one cell expansion to be smaller than the other in order to facilitate this). Good luck!

fuhy...@gmail.com

unread,
Apr 2, 2019, 10:35:43 AM4/2/19
to QuPath users
Thank you for the script. I learned a lot from it. But I have a question. What would be your suggestions to work with ROIs (polygons) and coordinates. for example, does Qupath provide functions for intersection, overlap, polygon covering points operations? I’m trying to do some spatial analysis of my cell ROIs. Do you have some suggestions?

And I was having difficulties finding developers document for Qupath functions and classes. Could you help me with this?

Thank you very much for your time and help!

Pete

unread,
Apr 2, 2019, 10:44:15 AM4/2/19
to QuPath users
Documentation is limited, mostly I am and have been the only developer (but hopefully not for too much longer...), and even I was missing from it for a year. Although I've written some more technical posts at https://petebankhead.github.io/

Spatial analysis is a work in progress. Some of the scripts on the blog involve converting QuPath ROIs into java.awt.Shape objects, and in the v0.2.0 milestones you can also convert ROIs into Java Topology Suite Geometry objects (some information at https://qupath.github.io/QuPath-v0.2.0 ).  More documentation is planned, but there is a lot more to do first on finishing off new features and stabilizing the API.

As you might have seen, the new forum is at https://forum.image.sc/tags/qupath and this Google Group will just hang around for reference.  So image.sc is probably a better place for questions from now on.

micros...@gmail.com

unread,
Apr 2, 2019, 11:18:48 AM4/2/19
to QuPath users
I was playing around with Pete's script, linked here, and created my own variant in one of the lower posts. You can see a bit about intersecting and subtracting ROIs there. Both the original script and figuring out how to modify it were very useful.
Reply all
Reply to author
Forward
0 new messages