波点壁纸中圆点的计数
去年年末我学习了天津科技大学杨淑莹老师的《数字图像处理》课程,虽然课程有点老,但是内容还是比较经典的。课程最后有好几个数字图像处理的案例,都是基于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)
根据H通道进行阈值分割
img_hsv_1 = color.rgb2hsv(dst)
plt.imshow(img_hsv_1,plt.cm.hsv)
中值滤波去噪
# 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()
这里没有采用迭代阈值分割法或者大津法,而是通过鼠标点击获取对应位置的值,然后感性地选出阈值
# 手动查看鼠标对应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'
# 手动选取阈值
%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)
中值滤波去噪
# 中值滤波去噪
shuffle_ = sfr.median(shuffle, disk(5))
new_img = color.rgb2gray(shuffle_)
io.imshow(new_img)
腐蚀操作去除孤立的点
# 腐蚀操作,去除孤立的点
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)
检测所有图形的轮廓,并计数
本来应该使用细化来数出个数,但是偶然找到一个用来发现轮廓的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)
总结
代码不难,都是skimage库的使用,当然如果有时候达不到自己想要的效果,可以自己写。主要是掌握了使用数字图像处理解决这种问题的思路,数字图像处理不同模块的内容是松耦合的,这门课是计算机视觉的基础课,它是一种工具,一般将它的知识点串行地使用来解决图像的基础问题。