vlambda博客
学习文章列表

图像识别和计数(以硬币为例)

图像识别是人工智能、图像处理等计算机科学领域的一个重要研究方向。近年来,随着人工智能技术和算法不断发展和丰富,越来越多的研究已经把这些新技术,特别是图像识别应用到了生命科学、医学、航天甚至农业等各领域。谈到图像识别时,不得不提的两个软件包就是基于python的opencv和skimage包,它们是图像识别比较著名的两个python包。本文将通过例子对opencv进行一个简单的介绍 (skimage我们后面再学), 希望可以帮助大家了解一下图像识别的应用,并争取应用到自己的研究领域。


例子:识别图像中的硬币并计数, 同时判断出潜在的“不(jia)规(bi)则”的硬币。首先简单看下原图

本次用到的平台是Ubuntu 14.04; Python3.6; python-opencv4.4.0。废话少说,直接开干:


  • 1. 导入需要的python库,并读入本地图像文件

import cv2   # 如果没有安装,先用pip或conda安装python-opencv库import numpy as npimport matplotlib.pyplot as pl# 读取图片,并查看img=cv2.imread("test.png"# 默认按颜色是按BGR通道读取的plt.imshow(img)plt.show()

图像识别和计数(以硬币为例)

  • 2. 彩色图像转为为黑白图像

gray_img=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)#灰度处理plt.imshow(gray_img,'gray')plt.show()

图像识别和计数(以硬币为例)

  • 3. 图像像素二值化

ret,th1=cv2.threshold(gray_img,120,255,cv2.THRESH_BINARY_INV) # 设置阈值,>120的像素点设置为255(白色);<120的像素点设为为0(黑色).最终反向一下,让识别的物体变为白色。plt.imshow(th1,"gray")plt.show()

图像识别和计数(以硬币为例)

  • 4. 图像腐蚀处理,消除噪音像素点

kernel = np.ones((7,7),np.uint8)erosion = cv2.erode(th1,kernel,iterations = 1)#腐蚀腐蚀变换的目的是消除噪点(开运算也可以,只是此处要比较是否腐蚀后图上的各个轮廓是否分离,通过上图可以发现仍有粘连,所以就有了下一步-距离变换)plt.imshow(erosion,"gray")plt.show()

图像识别和计数(以硬币为例)

  • 5. 距离变换去除重叠部分

dist_img = cv2.distanceTransform(erosion, cv2.DIST_L1, cv2.DIST_MASK_3)#距离变换:计算图像中像素点到最近零像素点的距离距离变换后得到轮廓的骨架,通过二值化可以有效的去除重叠部分plt.imshow(dist_img,"gray")plt.show()

图像识别和计数(以硬币为例)

  • 6. 图像归一化

dist_output = cv2.normalize(dist_img, 0, 1.0, cv2.NORM_MINMAX) #归一化:归一化(归一化是一种简化计算的方式,即将有量纲的表达式,经过变换,化为无量纲的表达式,成为标量。)plt.imshow(dist_output*80,"gray"## 此处dist_output*80是因为归一化之后灰度值在0~1.0,不容易观察,所以放大80倍,也可以设其他参数plt.show()

图像识别和计数(以硬币为例)

  • 7. 图像二值化

ret,th2=cv2.threshold(dist_output*80,0.3,255,cv2.THRESH_BINARY)plt.imshow(th2,"gray")plt.show()

图像识别和计数(以硬币为例)

  • 8. 开运算:先进行腐蚀操作,后进行膨胀操作,主要用来去除一些较亮的部分,即先腐蚀掉不要的部分,再进行膨胀

kernel = np.ones((5,5),np.uint8)opening = cv2.morphologyEx(th2, cv2.MORPH_OPEN, kernel)plt.imshow(opening,"gray")plt.show()

图像识别和计数(以硬币为例)

  • 9. 轮廓识别,打印出识别到对象的个数

opening = np.array(opening,np.uint8)contours, hierarchy = cv2.findContours(opening,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)#轮廓提取print(len(contours))

输出:24

  • 10. 循环每个识别到的对象,进行标注,以及判断质量好坏(good or bad)。

font=cv2.FONT_HERSHEY_COMPLEXcount=0for cnt in contours: (x,y),radius = cv2.minEnclosingCircle(cnt) center = (int(x),int(y)) radius = int(radius) circle_img = cv2.circle(opening,center,radius,(255,255,255),1) area = cv2.contourArea(cnt) area_circle = 3.14*radius*radius #print(area/area_circle) if area/area_circle <=0.5: #img = cv2.drawContours(img, cnt, -1, (0,0,255), 5)#差(红色) img = cv2.putText(img,'bad',center,font,0.5,(0,0,255)) elif area/area_circle >=0.6: #img = cv2.drawContours(img, cnt, -1, (0,255,0), 5)#优(绿色) img = cv2.putText(img,'good',center,font,0.5,(0,255,0)) else: #img = cv2.drawContours(img, cnt, -1, (255,0,0), 5)#良(蓝色) img = cv2.putText(img,'normal',center,font,0.5,(255,0,0))    count+=1# 打印识别结果img = cv2.putText(img,('sum='+str(count)),(100,25),font,1,(255,0,0))img = cv2.cvtColor(img,cv2.COLOR_BGR2RGB)plt.imshow(img)plt.show()print('识别到的对象共有:',count)

图像识别和计数(以硬币为例)

哈哈 ,识别结果出来了 ,整体上所有硬币都被成功识别并标注了。然而仔细观察发现 右上角那个硬币被标注了“bad”, 可能是识别的时候或图像本身存在一些 问题,后面可以继续优化

其实图像识别特别是当识别对象在图像中有重叠的时候,图像分割和识别变得很困难,需要不断尝试不同的分割方法以及参数。当然,如果大家有更简单的代码或识别算法可以@生信之道。欢迎大家尝试本例以及尝试去应用到其它图像识别或计数上来,比如种子计数、细胞计数等。

本文参考: https://blog.csdn.net/weixin_43330089/article/details/103910762