(image-segmentation:voronoi-otsu-labeling=)

Voronoi-Otsu标记#

这种图像分割工作流是一种相当简单但功能强大的方法,例如用于检测和分割荧光显微镜图像中的细胞核。细胞核标记物如核GFP、DAPI或组蛋白RFP与各种显微技术结合使用可以生成适当类型的图像。

from skimage.io import imread, imshow
import matplotlib.pyplot as plt
import pyclesperanto_prototype as cle
import napari_segment_blobs_and_things_with_membranes as nsbatwm

为了演示这个工作流程,我们使用来自Broad生物图像挑战的图像数据: 我们使用了图像集BBBC022v1 Gustafsdottir et al., PLOS ONE, 2013,该数据集可从Broad生物图像基准集合获得 Ljosa et al., Nature Methods, 2012

input_image = imread("../../data/BBBC022/IXMtest_A02_s9.tif")[:,:,0]

input_crop = input_image[0:200, 200:400]

fig, axs = plt.subplots(1, 2, figsize=(15, 15))
cle.imshow(input_image, plot=axs[0])
cle.imshow(input_crop, plot=axs[1])
../_images/bf69dc66f331ad66f2ca4567db95415d6269d30eb08c53f71c25e93ad9d38fa7.png

应用算法#

Voronoi-Otsu标记是clesperanto中的一个命令,需要两个sigma参数。第一个sigma控制检测到的细胞可以有多接近(spot_sigma),第二个控制分割对象的轮廓精确度(outline_sigma)。

sigma_spot_detection = 5
sigma_outline = 1

segmented = cle.voronoi_otsu_labeling(input_image, spot_sigma=sigma_spot_detection, outline_sigma=sigma_outline)
segmented_crop = segmented[0:200, 200:400]

fig, axs = plt.subplots(1, 2, figsize=(15, 15))
cle.imshow(segmented, labels=True, plot=axs[0])
cle.imshow(segmented_crop, labels=True, plot=axs[1])
../_images/538916549cc4a2b0af64468a723c080bd652a2fb99cd0b928d05bc259f6fcdfd.png

它是如何工作的?#

Voronoi-Otsu标记工作流是高斯模糊、斑点检测、阈值处理和二值分水岭的组合。感兴趣的读者可以查看开源代码。这种方法类似于对二值图像应用种子分水岭,例如在MorphoLibJscikit-image中。然而,种子是自动计算的,不能传入。

为了演示目的,我们只在上面显示的2D裁剪图像上进行操作。如果将此算法应用于3D数据,建议首先使其等方。

image_to_segment = input_crop
print(image_to_segment.shape)
(200, 200)

作为第一步,我们用给定的sigma对图像进行模糊处理,并在结果图像中检测最大值。

blurred = cle.gaussian_blur(image_to_segment, sigma_x=sigma_spot_detection, sigma_y=sigma_spot_detection, sigma_z=sigma_spot_detection)

detected_spots = cle.detect_maxima_box(blurred, radius_x=0, radius_y=0, radius_z=0)

number_of_spots = cle.sum_of_all_pixels(detected_spots)
print("检测到的斑点数量", number_of_spots)

fig, axs = plt.subplots(1, 2, figsize=(15, 15))
cle.imshow(blurred, plot=axs[0])
cle.imshow(detected_spots, plot=axs[1])
number of detected spots 29.0
../_images/9cbb6a7f36c42313cc4c4dcbffe4707c7240a9559c28cad3ec957e28aa6fa122.png

此外,我们再次从裁剪后的图像开始,用不同的sigma再次进行模糊处理。之后,我们使用大津阈值法(Otsu et al 1979)对图像进行阈值处理。

blurred = cle.gaussian_blur(image_to_segment, sigma_x=sigma_outline, sigma_y=sigma_outline, sigma_z=sigma_outline)

binary = cle.threshold_otsu(blurred)

fig, axs = plt.subplots(1, 2, figsize=(15, 15))
cle.imshow(blurred, plot=axs[0])
cle.imshow(binary, plot=axs[1])
../_images/ba7efc7ae9e340ac9ee90c8548ba08f0c4cace70582da1ec689bb82e03803aa4.png

之后,我们取二值斑点图像和二值分割图像,应用binary_and操作以排除在背景区域检测到的斑点。这些可能对应于噪声。

selected_spots = cle.binary_and(binary, detected_spots)

number_of_spots = cle.sum_of_all_pixels(selected_spots)
print("选中的斑点数量", number_of_spots)

fig, axs = plt.subplots(1, 3, figsize=(15, 15))
cle.imshow(detected_spots, plot=axs[0])
cle.imshow(binary, plot=axs[1])
cle.imshow(selected_spots, plot=axs[2])
number of selected spots 11.0
../_images/04a050b1fbbf0500e6180ee8778ae37eab7cab5bffc0bd4c750b4aa093a8099f.png

接下来,我们使用Voronoi图在选定的斑点之间分割图像空间,该图限制在二值图像的正像素中。

voronoi_diagram = cle.masked_voronoi_labeling(selected_spots, binary)

fig, axs = plt.subplots(1, 3, figsize=(15, 15))
cle.imshow(selected_spots, plot=axs[0])
cle.imshow(binary, plot=axs[1])
cle.imshow(voronoi_diagram, labels=True, plot=axs[2])
../_images/000b45cf1f03acfbbfd364c033bf107ab68da2cbca54e346ba9b08149ce783ad.png

其他Voronoi-Otsu标记实现#

在可脚本化的napari插件napari-segment-blobs-and-things-with-membranes中有该算法的另一种实现。

这里的代码与上面的代码几乎相同。主要区别在于我们调用nsbatwm.voronoi_otsu_labeling()而不是cle.voronoi_otsu_labeling()

sigma_spot_detection = 5
sigma_outline = 1

segmented2 = nsbatwm.voronoi_otsu_labeling(input_image, spot_sigma=sigma_spot_detection, outline_sigma=sigma_outline)

segmented_crop2 = segmented2[0:200, 200:400]

fig, axs = plt.subplots(1, 2, figsize=(15, 15))
cle.imshow(segmented2, labels=True, plot=axs[0])
cle.imshow(segmented_crop2, labels=True, plot=axs[1])
../_images/fb9f7b8500682ab39e50278adefaff958914f3fbfe0ef57d4ceb1867228a8247.png