先推荐下自己的公众号——Joe学习笔记,公众号上会不定期更新一些文章,主要是自己平时学到的知识,内容包括自动驾驶、计算机视觉、人工智能和机器人技术。我会第一时间把文章更新在公众号上,欢迎大家订阅和分享!文章是从公众号搬过来的。
邀请朋友在公众号上分享了一篇云台摄像头跟踪的教程。看了教程,跟着做了摄像头部分的功能,发现说的比较简洁,来具体分析一下。
这个颜色检测是在HSV颜色空间下进行的。首先把红色跟踪过程封装成函数,单独建个color_trace.py文件,代码如下:
1 import cv2
2 import numpy as np
3 import imutils
4
5 def color_trace(color_lower, color_upper, img):
6 img_hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV) # RGB图像转HSV图像
7 cv2.imshow('hsv', img_hsv)
8 # 创建掩膜,在(color_lower, color_upper)之间的像素设为255,其它为0
9 mask = cv2.inRange(img_hsv, color_lower, color_upper)
10 cv2.imshow('mask', mask)
11
12 # 腐蚀
13 mask_erode = cv2.erode(mask, None, iterations = 2)
14 cv2.imshow('erode', mask_erode)
15 # 膨胀
16 mask_dilate = cv2.dilate(mask_erode, (5, 5), iterations = 2)
17 cv2.imshow('dilate', mask_dilate)
18
19 # 高斯滤波
20 mask_gaussian = cv2.GaussianBlur(mask_dilate, (3, 3), 0)
21 cv2.imshow('mask_gaussian', mask_gaussian)
22
23 # 寻找轮廓
24 cnts = cv2.findContours(mask_gaussian.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
25 cnts = cnts[0] if imutils.is_cv2() else cnts[1]
26 #center = None
27 print(len(cnts))
28 if len(cnts) > 0:
29 # 取出最大轮廓
30 c = max(cnts, key=cv2.contourArea)
31 # 得到物体中心和物体半径
32 ((x, y), radius) = cv2.minEnclosingCircle(c)
33 # 检测半径大于20像素的物体
34 if radius > 20:
35 x, y = int(x), int(y)
36 # 以物体最小半径画圆
37 cv2.circle(img, (x, y), int(radius), (0, 255, 255), 2)
38 return img
测试用的图片如下图所示:
1-3行代码为导入一些需要的模块,第5行代码定义了一个函数,输入的参数分别为需要检测的颜色的下限、上限和图片。第6行和第7行代码是将RGB图像转HSV图像并显示图像。显示的效果如下:
第9行和第10行为创建一个mask并显示,在mask中将原图红色的区域用白色表示,其它的区域用黑色表示:
接着第12-17行,分别对图像进行了腐蚀和膨胀处理。观察上图的mask,除了红球以外的地方也有一些白点,腐蚀可以很好的去除这些小的白点,效果如下:
腐蚀在去除白点的同时也让圆球变小,膨胀操作可以恢复原样,并连通圆球内部的区域,具体的膨胀和腐蚀原理网上有很多教程,就不介绍了。膨胀效果如下:
第24-25行是用opencv自带的函数寻找图片中的轮廓,特别说明下25行,24行的寻找轮廓函数在opencv2中的返回值为两个,第1个为轮廓;在opencv3中的返回值为3个,第二个为轮廓。25行中的imutils.is_cv2()用来判断我们用的是opencv2还是opencv3,然后根据判断结果取第1个还是第2个返回值。
第30-37行代码找出面积最大的轮廓并得到轮廓的半径和中心,然后在输入的图像上画出圆,最后的效果如下图所示:
可以看出效果还是非常棒的。主函数的代码如下:
1 import cv2
2 import numpy as np
3 from color_trace import*
4
5 red_lower = np.array([170, 43, 46]) # 红色下限
6 red_upper = np.array([180, 255, 255]) # 红色上限
7
8 img = cv2.imread('red1.jpg')
9 cv2.imshow('red ball', img)
10 img_result = color_trace(red_lower, red_upper, img)
11 cv2.imshow('img_result', img_result)
12 cv2.waitKey(-1)
第3行类似c语言的头文件,把刚才的color_trace.py文件导入。第5、6行定义了要跟踪的颜色的上限和下限,然后调用函数就可以了。
没有摄像头,但是可以打开笔记本的摄像头来玩一下,新建一个vedio_trace.py文件,代码如下:
1 import cv2
2 import numpy as np
3 from color_trace import*
4
5 red_lower = np.array([170, 43, 46]) # 红色下限
6 red_upper = np.array([180, 255, 255]) # 红色上限
7
8 cap=cv2.VideoCapture(0) # #创建一个VideoCapture对象,笔记本摄像头设为0
9 while True:
10 # 逐帧捕获
11 #第一个参数返回一个布尔值(True / False),代表有没有读取到图片;第二个参数表示截取到一帧的图片
12 ret, frame = cap.read()
13 img_result = color_trace(red_lower, red_upper, frame)
14 cv2.imshow("img_result", img_result)
15 if cv2.waitKey(1) & 0xFF == ord('q'):
16 break
17 #当一切结束后,释放VideoCapture对象
18 cap.release()
19 cv2.destroyAllWindows()
我试了一下发现笔记本的摄像头拍摄的照片颜色有偏差,效果不理想,可能需要调节下红色的上下限。大家可以自己试着玩一下。