opencv——python细胞计数实现
程序员文章站
2024-03-08 12:44:10
...
opencv——python细胞计数实现
写程序萌新(不准备干程序员),上周看公司同事在学python,因为公司最近没什么事做(实际因为公司业务萎缩裁员降薪正融资)作为产品我也很无奈,公司程序基本裁完了,想着反正闲着也是闲着,就在周末找个python视频看看,就看了个基础教程,想着用opencv实现个细胞计数功能,周末看了看python基础语法,这两天看了看opencv基本操作,总共入门5天时间,就想试试看,非常膨胀,看了几篇文章就开干,得感谢赶上好时候,百度解决一切。
首先,先对图片进行处理,步骤就是: 原图——灰度图——腐蚀膨胀——二值化阈值——滤波操作。
import cv2
import numpy as np
img=cv2.imread(r'D:\imge\cell.jpg',1) #读取图片
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #将图片变为灰度图片
kernel=np.ones((2,2),np.uint8) #进行腐蚀膨胀操作
erosion=cv2.erode(gray,kernel,iterations=5)
dilation=cv2.dilate(erosion,kernel,iterations=5)
ret, thresh = cv2.threshold(dilation, 150, 255, cv2.THRESH_BINARY) # 阈值处理 二值化 用150不用255是因为有些细胞就直接变白
thresh1 = cv2.GaussianBlur(thresh,(3,3),0)# 高斯滤波
然后,找出连通域对连通域进行操作。因为处理后图仍有细小的杂文无法去除,通过观察细胞大小确定面积,将小值过滤。
#对连通域面积进行比较
area=[] #建立空数组,放连通域面积
contours1=[] #建立空数组,放减去后的数组
for i in contours:
# area.append(cv2.contourArea(i))
# print(area)
if cv2.contourArea(i)>30: # 计算面积 去除面积小的 连通域
contours1.append(i)
print(len(contours1)-1) #计算连通域个数
draw=cv2.drawContours(img,contours1,-1,(0,255,0),1) #描绘连通域
其次,因为数数的问题,每个细胞要显示数字。做法就是求每个连通域的重心,将数字绘制在重心上即可。
#求连通域重心 以及 在重心坐标点描绘数字
for i,j in zip(contours1,range(len(contours1))):
M = cv2.moments(i)
cX=int(M["m10"]/M["m00"])
cY=int(M["m01"]/M["m00"])
draw1=cv2.putText(draw, str(j), (cX, cY), 1,1, (255, 0, 255), 1) #在中心坐标点上描绘数字
最后展示图即可
cv2.imshow("draw",draw1)
cv2.imshow("thresh1",thresh1)
cv2.waitKey()
cv2.destroyWindow()
最后源代码
import cv2
import numpy as np
img=cv2.imread(r'D:\imge\cell.jpg',1) #读取图片
gray = cv2.cvtColor(img,cv2.COLOR_BGR2GRAY) #将图片变为灰度图片
kernel=np.ones((2,2),np.uint8) #进行腐蚀膨胀操作
erosion=cv2.erode(gray,kernel,iterations=5) #膨胀
dilation=cv2.dilate(erosion,kernel,iterations=5) #腐蚀
ret, thresh = cv2.threshold(dilation, 150, 255, cv2.THRESH_BINARY) # 阈值处理 二值法
thresh1 = cv2.GaussianBlur(thresh,(3,3),0)# 高斯滤波
contours,hirearchy=cv2.findContours(thresh1, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)# 找出连通域
#对连通域面积进行比较
area=[] #建立空数组,放连通域面积
contours1=[] #建立空数组,放减去最小面积的数
for i in contours:
# area.append(cv2.contourArea(i))
# print(area)
if cv2.contourArea(i)>30: # 计算面积 去除面积小的 连通域
contours1.append(i)
print(len(contours1)-1) #计算连通域个数
draw=cv2.drawContours(img,contours1,-1,(0,255,0),1) #描绘连通域
#求连通域重心 以及 在重心坐标点描绘数字
for i,j in zip(contours1,range(len(contours1))):
M = cv2.moments(i)
cX=int(M["m10"]/M["m00"])
cY=int(M["m01"]/M["m00"])
draw1=cv2.putText(draw, str(j), (cX, cY), 1,1, (255, 0, 255), 1) #在中心坐标点上描绘数字
#展示图片
cv2.imshow("draw",draw1)
cv2.imshow("thresh1",thresh1)
cv2.waitKey()
cv2.destroyWindow()
有不完美的地方,最大的连通域不知道怎么形成的,如果知道可以告诉下,让我修改下程序,thanks。