基于python+opencv的网球识别

今年上报了一个大学生SRTP项目,准备用树莓派作为主控板实现一个智能捡网球机。由于opencv开发库提供了大量图像处理算法的接口,因此只要一定程度上熟悉python语法和opencv库,实现这个程序并不是特别麻烦。本文会主要写程序实现的过程,不会涉及到很多的理论性的知识,有兴趣深入了解的可以自行查找网络上的各种资料。


本项目以网球的颜色作为识别特征。

识别过程为:获取视频帧----转换到HSV颜色空间----规定阈值、切割图像----识别轮廓获得网球位置信息

获取视频帧:

在树莓派上搭载摄像头获取视频帧不用多提,连接上摄像头然后直接opencv调用即可。因为在树莓派上安装opencv可以能涉及到到需要重新编译等各种问题,想避免麻烦的同学可以尝试直接pip opencv-python。树莓派摄像头可以选择官方的CSI摄像头,我为了便于在电脑上进行分析和调试,选用了usb线传输的摄像头模块,这种模块某宝上很多,使用起来也很简单。

转换颜色空间:

在HSV颜色空间下进行颜色识别能够很好地降低调试难度,提高识别精度。就作者本人的理解,RGB空间下的三通道是互相独立互不关联的,而HSV空间下的三通道值之间具有一定的关系或者说是主次区别,更容易分级调试确定阈值和修正因环境光影响产生的阈值偏移问题,同时HSV空间更符合人的视觉习惯。

转换颜色空间可用opencv的cvtColor函数实现。

hsv_img = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)

注意!!!经过cvtColor函数转换后的图像HSV三通道的取值范围与普遍认知下的HSV通道取值范围不同,可能是为了统一数据类型,opencv将原范围(h:0~360°, s:0~1, v:0~1)映射到了(h:0~180, s:0~255, v:0~255)的空间上。

规定阈值、切割图像:

在颜色空间转换完成后,下一步需要确定网球颜色范围。首先用我们的摄像头拍摄一张照片,从中截取出网球部分进行颜色分析,可以调用calcHist函数和matplotlab包快速实现。

cv2.calcHist(images, channels, mask, histSize, ranges[, hist[, accumulate ]]) ->hist

calcHist()是用于计算颜色直方图的函数,参数意义分别是:

images:输入图像。

channels:图像通道。

mask:掩膜,不使用时置None。

histSize:产生的直方图尺寸,一般与通道值范围有关。

ranges:像素值的范围。

calcHist()会返回hist格式数据,可以直接使用plot()函数进行可视化处理。代码如下:

from matplotlib import pyplot as plt

img = cv2.imread('/test.jpg')
hsv_img = cv2.cvtColor(img,cv2.COLOR_BGR2HSV)
hist_H = cv2.calcHist([hsv_img],[0],None,[181],[0,180])    
hist_S = cv2.calcHist([hsv_img],[1],None,[256],[0,255])
hist_V = cv2.calcHist([hsv_img],[2],None,[256],[0,255])    #获得不同通道的颜色直方图
plt.plot(hist_V),plt.xticks(np.arange(0,255,10))           #画图
plt.show()

对截取出的网球图像进行颜色分析得出三通道图:

H通道值
V通道值
S通道值

从图中我们可以直接观察出网球颜色的大致分布区间,先用得到大致分布区间进行图像的预切割。

图像切割函数为:

cv2.inRange(src, lowerb, upperb[, dst]) → dst

参数意义为:

src:输入图像

lowerb:阈值下限

upperb:阈值上限

返回跟原图大小相同的图像矩阵,满足阈值的位置将被置255,其他位置置0。

对图像进行预切割的效果如下(原图来自网络):

原图
预切割效果

从预切割效果图中可以看出,我们直接观察得到的阈值可以把一部分网球提取出来,但由于网球与摄像头距离、角度的不同,初始阈值并不完全适用与所有网球,因此还需要进一步的调整。作者采用的方法是通过滑动条来实现阈值的动态调整。

cv2.namedWindow('value')
cv2.createTrackbar('h','value',0,180,nothing)
cv2.createTrackbar('_h','value',0,50,nothing)
cv2.createTrackbar('s','value',0,255,nothing)
cv2.createTrackbar('_s','value',0,100,nothing)
cv2.createTrackbar('v','value',0,255,nothing)
cv2.createTrackbar('_v','value',0,100,nothing)

while 1:
    k = cv2.waitKey(10)
    if k == ord('m'):
        cv2.destroyAllWindows()
        break
    elif k == ord('n'):
        print(cv2.getTrackbarPos('h', 'value'), cv2.getTrackbarPos('s', 'value'), cv2.getTrackbarPos('v', 'value'))
        lower_green = np.array([15,180,150])
        lower_green = np.array(
       [cv2.getTrackbarPos('h', 'value')-cv2.getTrackbarPos('_h','value'), \
        cv2.getTrackbarPos('s', 'value')-cv2.getTrackbarPos('_s','value'), \
        cv2.getTrackbarPos('v', 'value')-cv2.getTrackbarPos('_v','value')])
        higher_green = np.array([30,255,255])
        higher_green = np.array(
        [cv2.getTrackbarPos('h', 'value') + cv2.getTrackbarPos('_h', 'value'), \
         cv2.getTrackbarPos('s', 'value') + cv2.getTrackbarPos('_s', 'value'), \
         cv2.getTrackbarPos('v', 'value') + cv2.getTrackbarPos('_v', 'value')])
        mask = cv2.inRange(hsv_img, lower_green, higher_green) 
        cv2.imshow("balls", mask)

通过滑动条调整阈值大小,直到程序能够识别出大部分网球且不会出现大量误判为止,大体效果如下:

合适阈值的效果图

记录当前阈值,用于识别程序。

识别轮廓获得图像位置:

经过切割图像后我们获得了含有网球位置信息的黑白掩膜图像,读取出网球的位置信息我们就初步实现了识别程序。黑白掩膜图像是单通道灰度图象,且边缘处像素值突变明显,用轮廓识别函数就可以很简单的获得相关位置信息。轮廓识别函数为:

cv2.findContours(image, mode, method[, contours[, hierarchy[, offset ]]])  

参数意义:

image:输入图像

mode:轮廓识别模式。为了避免网球内部噪点的影响,这里可使用cv2.RETR_EXTERNAL只检测外轮廓。

method:输出的轮廓数据类型。这里我们单纯需要简单位置信息,可以使用cv2.CHAIN_APPROX_SIMPLE获得四点坐标。

findContours()会返回一个轮廓列表,然后利用列表中数据在图中画出识别框。

contours, hierarchy = cv2.findContours(mask,cv2.RETR_EXTERNAL,cv2.CHAIN_APPROX_SIMPLE)
for c in contours:
    x,y,w,h = cv2.boundingRect(c)
    cv2.rectangle(img, (x-d,y-d), (x+w+d,y+h+d),(0,0,255),2)

识别结果如下:

识别效果

目前,我们就大体上完成了网球识别程序,在实际应用过程中光照影响还是比较严重的,使用时可能需要调整阈值范围。可以尝试监听鼠标点击获得当前网球颜色值调整范围等办法,在此就不一一详述了。

  • 9
    点赞
  • 87
    收藏
    觉得还不错? 一键收藏
  • 20
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 20
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值