首页 > 技术文章 > 细胞识别与分类

Qi-Lin 2022-01-08 13:22 原文

前言

细胞图片数据如下

细胞识别

要想对图片中细胞进行分类,首先就要将图片中的细胞识别出来
首先读入图片,接着转化为灰度图,接着对图片进行高斯模糊化处理,接着采用自适应的阀值将图片转化为二值图像,接着定义椭圆形的核对图像进行先腐蚀后膨胀的操作,用于处理噪声。
效果图如下:
灰度图像

阀值处理为二值图像

腐蚀膨胀去噪后图像

但是依然有一些噪点,所以计算其连通部分,对每一个连通部分计算其像素数量,过滤掉小于100像素的部分
效果图如下:
连通部分展示,不同颜色代表不同连通部分

去像素数量小于100的连通部分后效果如图所示

之后寻找每个连通部分边界,用圆形标记每个部分边界
效果图如下:
每一个圆圈表示识别的一个细胞

但是有一些相邻的细胞被识别成一个,这时我尝试了很多办法,如:重新对图片进行清洗,计算其前景后景,从而运用分水岭算法等都没有 获得很好的提升,所以只能将暂时放弃,之后将这些异常的数据丢弃。

细胞分类

识别细胞后,要进行分类,因为对分类依据并不了解,所以之间识别细胞的颜色和细胞的大小作为分类的特征。采用Kmeans自聚类的方法对细胞进行分类
细胞颜色采用标记区域内颜色的均值,细胞大小采用标记区域的面积
提取细胞数据如图所示,横轴表示细胞面积,竖轴表示细胞的颜色。但是在图中可以看出有三个面积异常大的值,正好就是之前标记细胞出错的位置,所以暂时去除这三个值:

去除三个异常值后如图所示

最后通过Kmeans算法进行自聚类,分为两类,并在原图上进行标记
分类效果如下所示

在图像上进行标记效果,其中标有红点为一类,标有蓝点为一类

完整代码如下所示:

import cv2
import numpy as np
from skimage import measure,color
import collections
import matplotlib.pyplot as plt
from sklearn.cluster import KMeans

image_orign=cv2.imread(r'C:\Users\DELL\Desktop\1.jpg')
gray = cv2.cvtColor(image_orign,cv2.COLOR_BGR2GRAY)
blurred=cv2.GaussianBlur(gray,(11,11),0)
thresh=cv2.adaptiveThreshold(blurred, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY_INV, 11, 2)
kernel=cv2.getStructuringElement(cv2.MORPH_ELLIPSE,(5,5))
erode_img=cv2.erode(thresh,kernel,iterations=1)#腐蚀
dilate_img=cv2.dilate(erode_img,kernel,iterations=1)#膨胀

#分水岭算法
# sure_bg=cv2.dilate(dilate_img,kernel,iterations=3)#膨胀
# cv2.imshow('t',sure_bg)
# cv2.waitKey(0)
# dist_transform=cv2.distanceTransform(dilate_img,cv2.DIST_L2,5)
# ret ,sure_fg=cv2.threshold(dist_transform,0.55*dist_transform.max(),255,0)
# cv2.imshow('t',sure_fg)
# cv2.waitKey(0)
# sure_fg = np.uint8(sure_fg)
# unknow=cv2.subtract(sure_bg,sure_fg)
# ret2,makers=cv2.connectedComponents(sure_fg)
# markers=makers+1
# markers[unknow==0]=255
# markers=cv2.watershed(image_orign,markers)
# dilate_img[markers == 255] =0
# cv2.imshow('t',dilate_img)
# cv2.waitKey(0)

labels=measure.label(dilate_img,connectivity=2,background=1)
dst=color.label2rgb(labels)
image=np.zeros(dilate_img.shape,dtype='uint8')
cell_color=[]
for label in collections.Counter(np.unique(labels)).keys():
    if(label==1):
        continue
    mask=np.zeros(dilate_img.shape,dtype='uint8')
    mask[labels==label]=255
    num_pixel=cv2.countNonZero(mask)
    if(num_pixel>100):
        image=cv2.add(image,mask)

cell_set=[]
cell_size=[]
cont,hierarchy=cv2.findContours(image.copy(),cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
for i in cont:
    x,y,w,h=cv2.boundingRect(i)
    (cx,cy),radius=cv2.minEnclosingCircle(i)
    cv2.circle(image_orign,(int(cx),int(cy)),int(radius),(0,0,0),3)

    cell_set.append((int(cx),int(cy)))
    cell_size.append(np.pi*radius*radius/10)
    roi=np.zeros(gray.shape,dtype='uint8')
    roi = cv2.circle(roi, (int(cx),int(cy)), int(radius), 255, cv2.FILLED)
    mask2=np.ones(gray.shape,dtype='uint8')*255
    area=cv2.bitwise_and(mask2, gray, mask=roi)
    cell_color.append(area.sum()/cv2.countNonZero(area))

value=[]
d=cell_size.copy()
d.sort()
for i in d[len(d)-3:]:
    cell_set.pop(cell_size.index(i))
    cell_color.pop(cell_size.index(i))
    cell_size.remove(i)

for i in range(len(cell_set)):
    value.append([cell_size[i],cell_color[i]])
data=dict(zip(cell_set,value))
plt.scatter(cell_size,cell_color)
plt.show()

pre=KMeans(n_clusters=2).fit_predict(value)
c=[(255,0,0),(0,0,255)]
c2=['red','blue']
for i in range(len(list(pre))):
    plt.scatter(value[i][0],value[i][1],c=c2[pre[i]])
    cv2.circle(image_orign,(cell_set[i][0],cell_set[i][1]),3,c[pre[i]],cv2.FILLED)
cv2.imshow('t',image_orign)
cv2.waitKey(0)
plt.show()

推荐阅读