Launch binder

Cell-segmentation for fluorescence images

This example shows how to use the high resolution tissue images to segment nuclei.

This information can be used to compute additional image features like cell count and cell size per spot (see Extract segmentation features). This example shows how to use squidpy.im.segment() and explains the parameters you can use.

We provide a built-in segmentation model squidpy.im.SegmentationWatershed. In addition, you can use a custom segmentation function, like a pre-trained tensorflow.keras model, to perform the segmentation utilizing squidpy.im.SegmentationCustom.

Note that when using the provided segmentation model ‘watershed’, the quality of the cell-segmentation depends on the quality of your tissue images. In this example we use the DAPI stain of a fluorescence dataset to compute the segmentation. For harder cases, you may want to provide your own pre-trained segmentation model.

See also

import squidpy as sq

import numpy as np

import matplotlib.pyplot as plt

# load fluorescence tissue image
img = sq.datasets.visium_fluo_image_crop()

We crop the image to a smaller segment. This is only to speed things up, squidpy.im.segment() can also process very large images (see Process a high-resolution image).

crop = img.crop_corner(1000, 1000, size=1000)

The tissue image in this dataset contains four fluorescence stains. The first one is DAPI, which we will use for the nuclei-segmentation.

crop.show("image", channelwise=True)
image:0, image:1, image:2

We segment the image with squidpy.im.segment() using watershed segmentation (method = 'watershed'). With the arguments layer and channel we define the image layer and channel of the image that should be segmented.

With kwargs we can provide keyword arguments to the segmentation model. For watershed segmentation, we need to set a threshold to create the mask image. You can either set a manual threshold, or use automated Otsu thresholding. For this fluorescence image example, Otsu’s thresh works very well, thus we will use thresh = None. See Cell-segmentation for H&E stains for an example where we use a manually defined threshold.

In addition, we can specify if the values greater or equal than the threshold should be in the mask (default) or if the values smaller to the threshold should be in the mask (geq = False).

sq.im.segment(img=crop, layer="image", channel=0, method="watershed", thresh=None, geq=True)

The segmented crop is saved in the layer segmented_watershed. This behavior can be changed with the arguments copy and layer_added. The result of the segmentation is a label image that can be used to extract features like the number of cells from the image.

print(crop)
print(f"Number of segments in crop: {len(np.unique(crop['segmented_watershed']))}")

fig, axes = plt.subplots(1, 2)
crop.show("image", channel=0, ax=axes[0])
_ = axes[0].set_title("DAPI")
crop.show("segmented_watershed", cmap="jet", interpolation="none", ax=axes[1])
_ = axes[1].set_title("segmentation")
DAPI, segmentation

Out:

ImageContainer[shape=(1000, 1000), layers=['image', 'segmented_watershed']]
Number of segments in crop: 580

Total running time of the script: ( 0 minutes 7.161 seconds)

Estimated memory usage: 305 MB