波点壁纸中圆点的计数

去年年末我学习了天津科技大学杨淑莹老师的《数字图像处理》课程,虽然课程有点老,但是内容还是比较经典的。课程最后有好几个数字图像处理的案例,都是基于Visual C++的,我使用Python实现其中的“细胞个数统计”,并进行了一定的探索。杨老师的视频在哔哩哔哩和MOOC都能获取。

解决思路:

  • 转换色彩空间至HSV
  • 根据H通道进行阈值分割
  • 中值滤波去噪
  • 腐蚀操作去除孤立的点
  • 检测所有图形的轮廓,并计数

如果使用Python,可以选择的图像处理库有
1、工业级的图像处理库:Opencv
2、PIL
3、Skimage
我使用的是Skimage,因为它和numpy联和的比较紧密,使用较为方便,能暂时满足我基本需求。

转换色彩空间至HSV

我选取的图片是一张波点照片,背景和前景的照片颜色信息差别很大,因此转换到了HSV色彩空间,其中色调(H),饱和度(S),明度(V)。想利用它的色调差别,来进行前景和背景的分离。

@adapt_rgb(each_channel)
def median_each(image):
    return sfr.median(image, disk(3))

img_path = '波点壁纸.jpg'
img_data = io.imread(img_path)

dst = median_each(img_data)
plt.figure('filters',figsize=(20,20))

plt.subplot(121)
plt.title('origin image')
plt.imshow(img_data)

plt.subplot(122)
plt.title('Smoothed image')
plt.imshow(dst)

Python实验21细胞计数_中值滤波

根据H通道进行阈值分割

img_hsv_1 = color.rgb2hsv(dst)
plt.imshow(img_hsv_1,plt.cm.hsv)

Python实验21细胞计数_中值滤波_02

中值滤波去噪

# H通道直方图
img = img_hsv_1[:,:,0]
plt.figure("hist")
arr=img.flatten()
plt.hist(arr, bins=256, normed=1,facecolor='r',edgecolor='r',hold=1)
plt.show()

Python实验21细胞计数_中值滤波_03

这里没有采用迭代阈值分割法或者大津法,而是通过鼠标点击获取对应位置的值,然后感性地选出阈值

# 手动查看鼠标对应H值
%matplotlib qt5
loop_num = 5
plt.imshow(img)
pos=plt.ginput(loop_num)
for i in range(loop_num):
    x,y = int(pos[i][1]),int(pos[i][0])
    print '第%d个点击的 x,y:' % int(i+1) ,'(', x , y,')'
    print '对应的H值为:',img[x,y],'\n'

Python实验21细胞计数_去噪_04

# 手动选取阈值
%matplotlib inline
rows,cols=img.shape
labels=np.zeros([rows,cols])
for i in range(rows):
    for j in range(cols):
        if(img[i,j]<0.53 or img[i,j]>0.60):# 0.53 0.65
            labels[i,j]=0
        else:
            labels[i,j]=1
shuffle =  color.rgb2gray(labels)
io.imshow(shuffle)

Python实验21细胞计数_Python实验21细胞计数_05

中值滤波去噪

# 中值滤波去噪
shuffle_ = sfr.median(shuffle, disk(5))
new_img = color.rgb2gray(shuffle_)
io.imshow(new_img)

Python实验21细胞计数_中值滤波_06

腐蚀操作去除孤立的点

# 腐蚀操作,去除孤立的点
new_img_fat = sm.erosion(new_img,sm.square(5))

plt.figure('filters',figsize=(20,20))

plt.subplot(131)
plt.title('origin image')
io.imshow(new_img)

plt.subplot(132)
plt.title('fat image')
io.imshow(new_img_fat)

plt.subplot(133)
plt.title('fat - orgin')
io.imshow(new_img_fat - new_img)

Python实验21细胞计数_阈值分割_07

检测所有图形的轮廓,并计数

本来应该使用细化来数出个数,但是偶然找到一个用来发现轮廓的api,取了点巧

#检测所有图形的轮廓
contours = measure.find_contours(new_img_fat, 0.5)

#绘制轮廓
fig, (ax0,ax1) = plt.subplots(1,2,figsize=(16,16))
ax0.imshow(new_img_fat,plt.cm.gray)
ax1.imshow(new_img_fat,plt.cm.gray)

for n, contour in enumerate(contours):
    ax1.plot(contour[:, 1], contour[:, 0], linewidth=2)
ax1.axis('image')
ax1.set_xticks([])
ax1.set_yticks([])
plt.show()
print '总共有多少个⭕️:',len(contours)

Python实验21细胞计数_阈值分割_08


总结

代码不难,都是skimage库的使用,当然如果有时候达不到自己想要的效果,可以自己写。主要是掌握了使用数字图像处理解决这种问题的思路,数字图像处理不同模块的内容是松耦合的,这门课是计算机视觉的基础课,它是一种工具,一般将它的知识点串行地使用来解决图像的基础问题。