Fluorescent image analysis

I am a beginner in image analysis and have no experience of scripting. I found the tutorials by @petebankhead very useful in understanding the Qupath workflow and analysis.
I am trying to analyze fluorescent images with four channels. These images are max intensity projected. My sample contains cells of various phenotypes from smaller T-cells to bigger macrophages.
First I tried to segment the nucleus channel and calculate the intensities in other 3 channels, but this method didn’t work because different cell phenotypes have different shapes. I also went through many other posts on this forum that uses sub-cellular detections but also didn’t get good results.
Some of the posts described making detections in each channel followed by colocalization and I think that would work best in my case. Since, it requires some scripting, I try to copy scripts from other users and trying to adapt for my needs.
Example image
test1.tif (3.7 MB)
I want to make a script as follows;

  1. Identifying cells in all 4 channels.
  2. Identify all the overlaps
  3. Based on overlap, classify them as single pos, double pos, and triple pos.

I started modifying the script described in this post (Defining ROI and measuring the area of ROI) and any help in modifying it will be highly appreciated.

//Detect cells of the first type
runPlugin('qupath.imagej.detect.cells.WatershedCellDetection', '{"detectionImage": "Channel 1",  "requestedPixelSizeMicrons": 0.325,  "backgroundRadiusMicrons": 0.0,  "medianRadiusMicrons": 0.0,  "sigmaMicrons": 1.8,  "minAreaMicrons": 20.0,  "maxAreaMicrons": 150.0,  "threshold": 650.0,  "watershedPostProcess": false,  "cellExpansionMicrons": 0.0,  "includeNuclei": true,  "smoothBoundaries": true,  "makeMeasurements": true}');
def detections1 = getCellObjects()

//Detect cells of the second type
runPlugin('qupath.imagej.detect.cells.WatershedCellDetection', '{"detectionImage": "Channel 2",  "requestedPixelSizeMicrons": 0.325,  "backgroundRadiusMicrons": 0.0,  "medianRadiusMicrons": 0.0,  "sigmaMicrons": 2.5,  "minAreaMicrons": 100.0,  "maxAreaMicrons": 200.0,  "threshold": 1500.0,  "watershedPostProcess": false,  "cellExpansionMicrons": 0.0,  "includeNuclei": true,  "smoothBoundaries": true,  "makeMeasurements": true}');
def detections2 = getCellObjects()

//Detect cells of the third type
runPlugin('qupath.imagej.detect.cells.WatershedCellDetection', '{"detectionImage": "Channel 3",  "requestedPixelSizeMicrons": 0.325,  "backgroundRadiusMicrons": 0.0,  "medianRadiusMicrons": 0.0,  "sigmaMicrons": 2.5,  "minAreaMicrons": 20.0,  "maxAreaMicrons": 100.0,  "threshold": 600.0,  "watershedPostProcess": false,  "cellExpansionMicrons": 0.0,  "includeNuclei": true,  "smoothBoundaries": true,  "makeMeasurements": true}');
def detections3 = getCellObjects()

//Detect cells of the fourth type
runPlugin('qupath.imagej.detect.cells.WatershedCellDetection', '{"detectionImage": "Channel 4",  "requestedPixelSizeMicrons": 0.5,  "backgroundRadiusMicrons": 0.0,  "medianRadiusMicrons": 0.0,  "sigmaMicrons": 2.5,  "minAreaMicrons": 20.0,  "maxAreaMicrons": 200.0,  "threshold": 600.0,  "watershedPostProcess": true,  "cellExpansionMicrons": 0.0,  "includeNuclei": true,  "smoothBoundaries": true,  "makeMeasurements": true}');
def detections4 = getCellObjects()

for (cell1 in detections1) {
def cell1_roi = cell1.getROI()

for (cell2 in detections2) {
    def cell1_area = PathROIToolsAwt.getArea(cell1_roi)
    def cell2_roi = cell2.getROI()
    def cell2_area = PathROIToolsAwt.getArea(cell2_roi)

    def intersected_roi = PathROIToolsAwt.getShapeROI(cell1_area, cell1_roi.getC(), cell1_roi.getZ(), cell1_roi.getT())
    def intersected_cell = new PathDetectionObject(intersected_roi)
    intersected_cells << intersected_cell

It looks like you’re using QuPath v0.1.2 (or at least that’s what the script you posted is for). It can handle fluorescence, but isn’t particularly good for that on its own - it’s something I’m actively working on, and there are some major improvements coming soon.

In the meantime, @Research_Associate is really the master of clever workarounds with the existing software - although others might also have good suggestions.

From your post it’s not clear to me if you’re working with whole slide images or if you should also consider Fiji/CellProfiler/something else as well. If you can describe more fully what kind of data (and number of images) you have then there might be more ideas.

However, three things about your test image make it pretty much unsuitable for quantitative analysis. With links to explanations, these are:

  • your image is quite severely clipped (see here)
  • your test image is RGB (3 channels), which isn’t great for fluorescence and means you can’t really quantify 4 channels (see here)
  • max projections aren’t great for analysis either (a little info here)

These issues need addressed, regardless of what software you use.

Thanks @petebankhead for your detailed reply.
In my first post, I didn’t explain it properly.
I am using the current release of QuPath (m8). I am trying to adapt the scripts written for earlier versions for this version.
Thickness of tissue sections is 10um and I am imaging using 20xOil lens. I take 5 z-slices at a spacing of 2um, so that I cover the thickness of tissue. In order to image the whole section, sometimes I divide the section in 2-3 bigger panels (when the section is too big).
Out of 5 z-slices, at least 1-2 are out of focus so I do maximum projection followed by stitching. You can find one example at this link (https://drive.google.com/file/d/1GyUveSdPbJPZtggyedy9k6drKf8egFHf/view?usp=sharing).

I’m fairly certain that will accomplish just about the same thing as subcellular detections. Giving you overlaps between two channels.

In case either of you want it, the ome.tiff version is muuuch easier to work with.

Once it opens smoothly, I can really see the toll the Zstack Max intensity projection has taken on the segment-ability of the image. I don’t disagree that you get more information from this, but it is also impossible to separate cells when nuclei start overlapping in the Z axis, which happens a lot here.
That aside, there would need to be a lot of cleanup of any cell detection due the the autofluorescence contaminating the nuclear channel (4). I got rid of the worst of these by removing cells with channel 2 mean intensity greater than 9000, but there are plenty of small background blips causing problems. I suspect that use of Sudan Black or other autofluorescence suppression options might improve this.

Lack of stitching and focal plane changes are slightly problematic as well.
I would probably get rid of those with classified subcellular detections, but just taking a quick swing at this for now.
Using a combination of subcellular spot detection and the multiplex classifier, I was able to get some decent classification. Though more time spent would definitely improve the removal of false positives, and I’m not an expert on the biology of your images, your thresholds may vary.

runPlugin('qupath.imagej.detect.cells.WatershedCellDetection', '{"detectionImage": "Channel 4",  "requestedPixelSizeMicrons": 0.3,  "backgroundRadiusMicrons": 0.0,  "medianRadiusMicrons": 0.0,  "sigmaMicrons": 1.5,  "minAreaMicrons": 10.0,  "maxAreaMicrons": 400.0,  "threshold": 2000.0,  "watershedPostProcess": true,  "cellExpansionMicrons": 3.0,  "includeNuclei": true,  "smoothBoundaries": true,  "makeMeasurements": true}');
runPlugin('qupath.imagej.detect.cells.SubcellularDetection', '{"detection[Channel 1]": 1800.0,  "detection[Channel 2]": 9000.0,  "detection[Channel 3]": 6000.0,  "detection[Channel 4]": -1.0,  "doSmoothing": false,  "splitByIntensity": false,  "splitByShape": true,  "spotSizeMicrons": 1.0,  "minSpotSizeMicrons": 0.5,  "maxSpotSizeMicrons": 2.0,  "includeClusters": true}');
//some classification here

You might need to give some more examples of what you want to accomplish though in order to improve the classifier. And, as I mentioned, weed out all of the quadruple positive autofluorescence :slight_smile:
One more random section where the red/blue double positive cells are colored purple

Thanks @Research_Associate.
I checked sub-cellular detection option as you described. It worked for some of my images and I am testing now on more complex images to see how it works.
I will update soon. Thanks again :slight_smile:

1 Like