Skip to content

Spot detection

Pete edited this page Jan 2, 2017 · 2 revisions

This section describes the use of an 'experimental' command added in QuPath v0.1.2. Depending on feedback and usefulness, this command may be changed in a later version.

Many analysis applications involve the detection and quantification of spots, clusters, or other small, subcellular components. This might be one of the various forms of ISH... or something else.

The Analyze → Cell analysis → Subcellular detection (experimental) command is intended for this kind of scenario.

Note that QuPath's Subcellular detection has not been written for any one particular application, but rather to help provide the detection capability that may be applied or adapted for a wide range of applications.

The idea

What the Subcellular detection command will do is loop through all previously-detected cells, and threshold a specified color channel (or channels) with the aim of identifying spots within each cell. Additionally, a range of sizes can be input to exclude small or large subcellular detections, or to treat large structures as clusters rather than individual spots.

The command is designed to work with brightfield images with one or two chromogenic stains (in addition to hematoxylin), or fluorescence with multiple stains.

Sample usage

The first step is to open an image for analysis, and then to detect cells, e.g. using the Analyze → Cell analysis → Cell detection command.

Image containing cells and spots

Original image with spots visible

Detected cells

Detected cells

Once the cells have been detected, Analyze → Cell analysis → Subcellular detection (experimental) can be run.

Subcellular detection command dialog

Subcellular detection dialog

This produces a dialog box containing options.

At the top, one or more Detection thresholds can be set. The available thresholds will depend upon which type of image (fluorescence or brightfield) and the number of stains present. In this case, only a DAB-stained channel is suitable for thresholding.

By default, the Detection threshold for all channels is set to -1, which really means that no threshold will be applied. This is useful whenever multiple channels are present, but the detection is only required on a subset of the channels.

Here, detection in the DAB channel is required - and therefore the threshold is set to an optical density value of 0.1.

In general, it is best to run the command without any cells selected; then a dialog box will appear giving the option of applying the detection to all cells (which will then be processed in parallel).

Detected spots & clusters

All detected spots

The other Detection parameters can be adjusted experimentally to see what they do; in general, smoothing can help for noisy images, while splitting (either by intensity, shape, or both) an help whenever neighboring spots are clustered together, but ideally they would be detected separately.

Detected spots & clusters with intensity splitting

All detected spots, split by intensity

Below the Detection parameters are Spot & cluster parameters. These are used to help filter out very small detections (too small to be 'true' spots), and either ignore large detections or treat them as 'clusters'. If they are treated as clusters, then the area of the cluster will be divided by the 'Expected spot size' (which is defined as an area) to give an estimated number of spots.

Sometimes it can be difficult to see subcellular structures due to the thickness of the lines drawn around cells. When this happens, try changing the Detection line thickness option in the Preferences .

Sample scripts

Due to the general nature of the subcellular detection command, it may not immediately provide the output you desire. However, when combined with other commands, or a short script, the results can be adapted for a wide range of applications.

Several example scripts are provided below.

Classifying positive cells (easy)

To classify cells as positive or negative based upon the estimated number of spots is straightforward, requiring a script that consists of a single line:

setCellIntensityClassifications("Subcellular: DAB: Num spots estimated", 2)

Note that the exact name of the measurement depends upon the staining used, and therefore may need to be adjusted.

To find out the measurement name, double-click on a cell to select it and view the available measurements within the Hierarchy tab of the Analysis panel (on the left of the screen).

The benefit of this is that QuPath's built-in dynamic measurements to calculate the percentage of positive cells will then apply, thereby immediately giving summary measurements regarding the positive cells within an area.

Cells classified as positive or negative

Classifying positive cells (harder)

More complex criteria can also be used to classify cells as positive or not... albeit requiring more complex scripts. For example, the following script will classify a cell as positive if it contains at least one cluster, or at least five single spots.

import qupath.lib.objects.classes.PathClassFactory

// Loop through all available cells
for (cell in getCellObjects()) {
    // Determine the current classification, with any intensity component removed
    def pathClass = PathClassFactory.getNonIntensityAncestorClass(cell.getPathClass())
    // Determine how many single spots and clusters we have
    double numSingleSpots = measurement(cell, "Subcellular: DAB: Num single spots")
    double numClusters = measurement(cell, "Subcellular: DAB: Num clusters")
    // Apply the new classification
    if (numClusters >= 1 || numSingleSpots >= 5)
        cell.setPathClass(getDerivedPathClass(pathClass, "Positive"))
    else
        cell.setPathClass(getDerivedPathClass(pathClass, "Negative"))
}
// Ensure the GUI is updated
fireHierarchyUpdate()

Binning cells according to spot counts

It might also be desirable to bin cells according to ranges of spots or clusters that they contain.

This is similar to QuPath's binning of cells according to staining intensity as negative, 1+, 2+ or 3+ - from which H-scores can be calculated.

A one-line script to do this is given below:

setCellIntensityClassifications("Subcellular: DAB: Num spots estimated", 1, 4, 10)

Cells binned according to spot counts

Spot localization

It might also be useful to know the location of spots/clusters relative to the nucleus.

The following script sets the classification of each spot or cluster based upon whether its centroid overlaps the nucleus ROI or not.

It is also available here.

// Note: This sets the class according to spot/cluster location,
// but does not try to set meaningful colors at this point

// Get all spots/clusters
def clusters = getObjects({p -> p.class == qupath.imagej.detect.cells.SubcellularDetection.SubcellularObject.class})

// Loop through all clusters
for (c in clusters) {
    // Find the containing cell
    def cell = c.getParent()
    // Check the current classification - remove the last part if it
    // was generated by a previous run of this command
    def pathClass = c.getPathClass()
    if (["Nuclear", "Cytoplasmic"].contains(c.getName())) {
        pathClass = pathClass.getParentClass()
    }
    // Check the location of the cluster centroid relative to the nucleus,
    // and classify accordingly
    def nucleus = cell.getNucleusROI()
    if (nucleus != null && nucleus.contains(c.getROI().getCentroidX(), c.getROI().getCentroidY())) {
        c.setPathClass(getDerivedPathClass(c.getPathClass(), "Nuclear"))
    } else
        c.setPathClass(getDerivedPathClass(c.getPathClass(), "Cytoplasmic"))
}
fireHierarchyUpdate()

A warning about adding/removing spots

None of the scripts shown above add or remove spots or clusters. Doing so is not advisable... at least not without more care and attention.

This is because each cell stores the value of the number of spots/clusters that it contains, and this value is set during the detection phase. For reasons of efficiency this is not a dynamic measurement, and therefore it will not be automatically updated if spots are removed through some other method (e.g. manual deletion, or in a script).

This means that if spots are removed from or added to a cell by any method other than through the Subcellular detection command itself, then the actual number of spots available might no longer match the measurement value stored in the cell.

This should be kept in mind as a current limitation: if you need to add or remove spots, then a more complex script is required that also updates the measurement list for the cell.

Note: If useful, a script to update spot counts may be added here later...

Clone this wiki locally