统计图像中的细胞数量。

7
我需要计算图像中粉色细胞的数量的代码,使用阈值分割和分水岭方法。请仅计算粉色的细胞。图片链接如下:enter image description here
import cv2
from skimage.feature import peak_local_max
from skimage.morphology import watershed
from scipy import ndimage
import numpy as np
import imutils

image = cv2.imread("cellorigin.jpg")

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255,
    cv2.THRESH_BINARY_INV | cv2.THRESH_OTSU)[1]
cv2.imshow("Thresh", thresh)


D = ndimage.distance_transform_edt(thresh)
localMax = peak_local_max(D, indices=False, min_distance=20,
    labels=thresh)
cv2.imshow("D image", D)

markers = ndimage.label(localMax, structure=np.ones((3, 3)))[0]
labels = watershed(-D, markers, mask=thresh)
print("[INFO] {} unique segments found".format(len(np.unique(labels)) -     1))

for label in np.unique(labels):
    # if the label is zero, we are examining the 'background'
    # so simply ignore it
    if label == 0:
        continue

    # otherwise, allocate memory for the label region and draw
    # it on the mask
    mask = np.zeros(gray.shape, dtype="uint8")
    mask[labels == label] = 255

    # detect contours in the mask and grab the largest one
    cnts = cv2.findContours(mask.copy(), cv2.RETR_EXTERNAL,
        cv2.CHAIN_APPROX_SIMPLE)
    cnts = imutils.grab_contours(cnts)
    c = max(cnts, key=cv2.contourArea)

    # draw a circle enclosing the object
    ((x, y), r) = cv2.minEnclosingCircle(c)
    cv2.circle(image, (int(x), int(y)), int(r), (0, 255, 0), 2)
    cv2.putText(image, "#{}".format(label), (int(x) - 10, int(y)),
        cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 255), 2)



cv2.imshow("input",image

cv2.waitKey(0)

我无法正确地将粉色细胞分割开来。在某些地方,两个粉色细胞粘在一起,它们也应该被分开。

输出:

输入图像描述


这个回答解决了你的问题吗?如何计算细胞核数量? - Cris Luengo
部分我也看到了@CrisLuengo的问题。 - Ajith
1个回答

8

由于细胞看起来与细胞核(深紫色)和背景(浅粉色)不太相同,因此颜色阈值处理应该可以起作用。思路是将图像转换为HSV格式,然后使用下限和上限颜色阈值来隔离细胞,从而得到一个二进制掩模,我们可以使用它来计算细胞数量。


我们首先将图像转换为HSV格式,然后使用下限/上限颜色阈值创建二进制掩模。从这里开始,我们进行形态学操作以平滑图像并消除小的噪点。

enter image description here

现在我们有了掩模,使用cv2.RETR_EXTERNAL参数找到轮廓以确保只获取外部轮廓。我们定义了几个面积阈值来过滤掉细胞。

minimum_area = 200
average_cell_area = 650
connected_cell_area = 1000
minimum_area 的阈值确保我们不会计算细小的细胞区域。由于一些细胞是连接在一起的,因此某些轮廓可能表示多个连接的细胞,为了更好地估计细胞数目,我们定义了一个average_cell_area参数来估计单个细胞的面积。而connected_cell_area参数检测连接的细胞,使用math.ceil()函数对连接细胞轮廓进行估计,以确定该轮廓中有多少个细胞。要计算细胞数量,我们遍历轮廓并根据它们的面积加总轮廓。以下是突出显示为绿色的检测到的细胞。enter image description here
Cells: 75

代码

import cv2
import numpy as np
import math

image = cv2.imread("1.jpg")
original = image.copy()
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)

hsv_lower = np.array([156,60,0])
hsv_upper = np.array([179,115,255])
mask = cv2.inRange(hsv, hsv_lower, hsv_upper)
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
opening = cv2.morphologyEx(mask, cv2.MORPH_OPEN, kernel, iterations=1)
close = cv2.morphologyEx(opening, cv2.MORPH_CLOSE, kernel, iterations=2)

cnts = cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]

minimum_area = 200
average_cell_area = 650
connected_cell_area = 1000
cells = 0
for c in cnts:
    area = cv2.contourArea(c)
    if area > minimum_area:
        cv2.drawContours(original, [c], -1, (36,255,12), 2)
        if area > connected_cell_area:
            cells += math.ceil(area / average_cell_area)
        else:
            cells += 1
print('Cells: {}'.format(cells))
cv2.imshow('close', close)
cv2.imshow('original', original)
cv2.waitKey()

你可以在连接的细胞上使用分水岭算法,但由于它们不是“标准”的圆形,因为细胞的形状可能差异很大,所以我怀疑你会得到好的结果。在最理想的情况下,分水岭可能会给出细胞轮廓的估计。如果你查看当前的分水岭结果,它会将两个连接的细胞检测为单个轮廓。对于人类来说,很难准确地确定两个细胞之间的分界线,因此分水岭也会遇到困难。最多只能得到一个粗略的估计。我建议你查看其他属性,例如区域或长宽比。 - nathancy
我会研究这些方法,它们会给你最好的结果。 - nathancy
我还没有尝试过。不过,我认为开运算(cv2.MORPH_OPEN)可以将这些连接的细胞分开。你有什么看法? - cuongptnk
@cuongptnk 是的,你可以简单地进行形态学开运算,但是你也会侵蚀连接细胞的很多细节。斑点会变得越来越小,直到出现多个轮廓。这样做是可行的,但会损失一些细节。 - nathancy
1
随着每次迭代,对象的面积都会减小,因此最终对象将消失。每次膨胀并不能恢复相同数量的细节损失,当连接关节很小时,闭合可能有效,但在它们几乎重叠的情况下,您必须不断侵蚀/膨胀,直到细胞变得极小(细节丢失)。 - nathancy
显示剩余5条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接