细胞识别与分类
前言
细胞图片数据如下
细胞识别
要想对图片中细胞进行分类,首先就要将图片中的细胞识别出来
首先读入图片,接着转化为灰度图,接着对图片进行高斯模糊化处理,接着采用自适应的阀值将图片转化为二值图像,接着定义椭圆形的核对图像进行先腐蚀后膨胀的操作,用于处理噪声。
效果图如下:
灰度图像
阀值处理为二值图像
腐蚀膨胀去噪后图像
但是依然有一些噪点,所以计算其连通部分,对每一个连通部分计算其像素数量,过滤掉小于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()