(1)利用摄像头,根据物体颜色,实现目标检测
(2)根据目标移动轨迹,绘制跟踪路径
(3)参考OpenCV中文官方文档(http://woshicver.com/),了解opencv在python中的应用
(4)思维导图:
目标检测与跟踪项目是利用opencv2模块,通过颜色选择器提取出需要跟踪的颜色在HSV颜色空间中的具体数值范围,将提出出的数值以列表形式输入主函数参数里,再调用摄像头探测的该颜色的物体并计算出物体中心点,进行跟踪并绘制出其移动轨迹。
① OpenCV 是其支持多语言、跨平台,功能强大。OpenCV-Python为OpenCV提供了Python接口,旨在解决计算机视觉问题的Python专用库。使得使用者在Python中能够调用C/C++,在保证易读性和运行效率的前提下,实现所需的功能。
② NumPy是Python的一种开源的数值计算扩展。这种工具可用来存储和处理大型矩阵,比Python自身的嵌套列表结构要高效的多(该结构也可以用来表示矩阵),支持大量的维度数组与矩阵运算,此外也针对数组运算提供大量的数学函数库。
① HSI与 HSV非常相似,仅用亮度替代了明度。二者区别在于,一种纯色的明度等于白色的明度,而纯色的亮度等于中度灰的亮度。
② RGB和CMY颜色空间都是面向硬件的,而HSV颜色空间是面向用户的。 HSV模型对应于圆柱坐标系的一个圆锤形子集。圆锤的顶面对应于V=1,代表的颜色较亮。色调H由绕V轴的旋转角给定,红色对应于角度0°,绿色对应于角度120°,蓝色对应于角度240°。每一种颜色和它的补色相差180°
③ HSV的色相范围为[0,179],饱和度范围为[0,255],值范围为[0,255]
该部分主要功能是用于选择跟踪物体的HSV颜色范围值并提取出来
1、导入代码需要使用的第三方库:cv2和numpy。
2、利用VideoCapture函数调用电脑摄像头,并设置视频流中帧的宽度和高度以及图像的亮度。
3、定义回调函数:
回调函数主要是为了降低函数之间调用的耦合性,即模块及模块之间信息或参数依赖的程度,从而实现解耦。
4、创建名为“HSV”的窗口,并设置其长宽。
5、设置窗口滑动条,设置数值上下界,以及滑块初始位置:
涉及两个函数,分别是:cv2.createTrackbar()和cv2.getTrackbarPos(),前者可用于创建一个可以调整数值的滑动条,后者用于更新当前滑块在轨迹的位置。
createTrackbar(参数1,参数2,参数3,参数4,参数5)
getTrackbarPos(参数1,参数2,参数3,参数4,参数5)
参数1:滑动条轨迹名
参数2:滑动条依附的窗口名
参数3:滑块的位置,创建时,滑块初始位置就是这个变量当前的值
参数4:轨迹的最大值
参数5:回调函数
6、利用循环,读取视频每一帧,并将其转变为HSV颜色模型,调节滑动块数值,分别将调节的HSV最小值和最大值转换为一个一维数组。
7、创建掩膜,利用上一步得到的一维数组设置HSV的阈值。
8、将掩膜和图像逐像素相加,并将掩膜转换为BGR颜色模型。
9、按水平方向堆叠,利用hstack函数将原图,掩膜和前两者相加后的视频帧显示出来。
10、完成所有操作后,释放系统资源。
相关代码:
import cv2 as cv
import numpy as np
cap = cv.VideoCapture(0)
cap.set(3, 200) # 宽
cap.set(4, 200) # 高
cap.set(10, 1000) # 亮度
def nothing(a):
pass
cv.namedWindow('HSV')
cv.resizeWindow('HSV', 640, 280)
cv.createTrackbar('H_min', 'HSV', 0, 179, nothing)
cv.createTrackbar('S_min', 'HSV', 0, 255, nothing)
cv.createTrackbar('V_min', 'HSV', 0, 255, nothing)
cv.createTrackbar('H_max', 'HSV', 179, 179, nothing)
cv.createTrackbar('S_max', 'HSV', 255, 255, nothing)
cv.createTrackbar('V_max', 'HSV', 255, 255, nothing)
ret = True
while ret == True:
ret, img = cap.read() # 读取帧
imgHSV = cv.cvtColor(img, cv.COLOR_BGR2HSV)
h_min = cv.getTrackbarPos('H_min', 'HSV')
s_min = cv.getTrackbarPos('S_min', 'HSV')
v_min = cv.getTrackbarPos('V_min', 'HSV')
h_max = cv.getTrackbarPos('H_max', 'HSV')
s_max = cv.getTrackbarPos('S_max', 'HSV')
v_max = cv.getTrackbarPos('V_max', 'HSV')
print([h_min, s_min, v_min, h_max, s_max, v_max])
# 选取颜色范围
lower = np.array([h_min, s_min, v_min]) # 转换为一维数组
upper = np.array([h_max, s_max, v_max])
mask = cv.inRange(imgHSV, lower, upper) # 设置HSV的阈值
result = cv.bitwise_and(img, img, mask=mask) # 将掩膜和图像逐像素相加
mask = cv.cvtColor(mask, cv.COLOR_GRAY2BGR)
show = np.hstack([img, mask, result]) # 按水平方向(列顺序)堆叠数组构成一个新的数组堆叠的数组需要具有相同的维度
cv.imshow('show', show)
if cv.waitKey(1)& 0xFF == ord('q'):
break
# 完成所有操作后,释放捕获器
cap.release()
cv.destroyAllWindows()
利用颜色选择器所提取的数值,对摄像头所检测到的对应物体进行跟踪并绘制其移动轨迹
1、创建列表,用于存放颜色选择器得到的HSV数值以及设置对应的用于绘制移动轨迹的RGB颜色数值。
2、将列表里对应的HSV最小值和最大值转换为一个一维数组,并创建掩膜。
3、利用findContours函数找出图像轮廓
contours, hierarchy = cv.findContours(参数1,参数2,参数3)
参数1:单通道图像矩阵,
参数2:cv.RETR_EXTERNAL只检测最外围轮廓,包含在外围轮廓内的内围轮廓被忽略
参数3:cv.CHAIN_APPROX_NONE 保存物体边界上所有连续的轮廓点到contours向量内
4、计算轮廓面积,并判断面积大于500时,利用drawContours()函数画出图像轮廓。
5、利用boundingRect函数计算轮廓最外面的矩形边框,并计算出矩形的中心点坐标值。
6、通过返回的中心点坐标值,在视频帧的对应位置画出来
7、利用循环,更新视频流帧中每帧中心点位置,形成目标移动轨迹
相关核心代码:
import cv2 as cv
import numpy as np
cap = cv.VideoCapture(0)
cap.set(3, 800) # 宽
cap.set(4, 600) # 高
cap.set(10, 1000) # 亮度
# 通过颜色选择器提取的颜色:橙,紫,绿
"""mycolors = [[5, 107, 0, 19, 255, 255],
[133, 56, 0, 159, 156, 255],
[57, 76, 0, 100, 255, 255],
[90, 48, 0, 118, 255, 255]]
mycolorvalues = [[51, 153, 255],
[255, 0, 255],
[0, 255, 0],
[255, 0, 0]]"""
mycolors = [[0, 24, 41, 27, 186, 198]]
mycolorvalues = [[51, 153, 255]]
mypoints = [] # [x, y, color_id]
def findcolor(img, mycolors, mycolorvalues):
imgHSV = cv.cvtColor(img, cv.COLOR_BGR2HSV)
count = 0
newpoints = []
for color in mycolors:
lower = np.array(color[0:3])
upper = np.array(color[3:6])
mask = cv.inRange(imgHSV, lower, upper)
# getContours(mask)
x, y = getContours(mask)
cv.circle(imgresult, (x, y), 5, mycolorvalues[count], cv.FILLED) # 图片,中心点,半径,颜色,cv.FILLED为填充
if x != 0 and y != 0:
newpoints.append([x, y, count])
count += 1
# print(getContours(mask))
# cv.imshow(str(color), mask)
return newpoints
def getContours(img):
contours, hierarchy = cv.findContours(img, cv.RETR_EXTERNAL, cv.CHAIN_APPROX_NONE) # 找出图像轮廓
x, y, w, h = 0, 0, 0, 0
for cnt in contours:
area = cv.contourArea(cnt) # 计算轮廓面积
if area > 500:
cv.drawContours(imgresult, cnt, -1, (255, 0, 0), cv.FILLED) # 画出图像轮廓
peri = cv.arcLength(cnt, True) # 计算轮廓周长 参数2:表示轮廓是否封闭
approx = cv.approxPolyDP(cnt, 0.02*peri, True)
x, y, w, h = cv.boundingRect(approx)
return x+w//2, y+h//2
def drawoncanvas(mypoints, mycolorvalues):
for point in mypoints:
cv.circle(imgresult, (point[0], point[1]), 5, mycolorvalues[point[2]], cv.FILLED)
while True:
success, img = cap.read()
imgresult = img.copy()
newpoints = findcolor(img, mycolors, mycolorvalues)
if len(newpoints) != 0:
for newp in newpoints:
mypoints.append(newp)
if len(mypoints) != 0:
drawoncanvas(mypoints, mycolorvalues)
cv.imshow("Video", imgresult)
if cv.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv.destroyAllWindows()
(1)首先利用颜色选择器选出手机黑屏状态下的颜色,将得到的HSV数值加入主函数mycolors参数列表中([51, 17, 29, 163, 251, 69]),并在mycolorvalues参数中添加跟踪点的bgr颜色值([0, 0, 255])
(2)运行主函数,由图可知,蓝色区域为跟踪物体,红色为物体中心点,随着物体移动,红色中心点连成一条线,即物体移动轨迹:
初始态:
手机移动的轨迹:
(3)再次利用颜色选择器选出天猫精灵的颜色,将得到的HSV数值加入主函数mycolors参数列表中([170, 104, 89, 179, 255, 255]),并在mycolorvalues参数中添加跟踪点的bgr颜色值([0, 255, 0])
(4)运行主函数,此次将上述的两样物体同时展示,下图可知此程序也能很好的实现多物体检测与跟踪。检测结果容易受摄像头中其他同颜色的事物所影响,后续还需要继续加以改进。