赞
踩
打球的时候,我们常常要用眼睛去识别球的位置,确定球的落点和轨迹。用摄像头和视频捕捉物体的位置,确定中心坐标,绘制轮廓边框,就成为了基于Python的OpenCV(Opencv for Python)要处理的重要问题。
cap=cv2.VideoCapture('ballsvideo.mp4')#获取原视频 cv2.namedWindow('processed_video', cv2.WINDOW_NORMAL) #创建一个可调整大小的窗口 cv2.resizeWindow('processed_video', 500, 800)#设置窗口宽度为500,高度为800
while True: ret,frame=cap.read()#读取原视频每帧 if not ret:#直到视频没有下一帧了才结束 break processed_frame=process(frame)#处理每帧 cv2.imshow('processed_video',processed_frame)#逐帧播放新视频 if cv2.waitKey(1) & 0xFF == ord('q'):#按q键退出视频播放 break
hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)
在利用OpenCV进行颜色识别时,通常会将图像从RGB(红绿蓝)颜色空间转换到HSV(色调、饱和度、亮度)颜色空间。
HSV颜色空间能够更好地分离颜色信息(通过色调Hue),而RGB颜色空间中的颜色信息是分散在三个通道中的。在HSV空间中,色调(H)通道表示颜色,而饱和度(S)和亮度(V)通道表示颜色的强度和亮度,这使得颜色分析和识别更为简单直接。而且HSV颜色空间对光照变化具有较好的稳定性。在RGB空间中,光照变化会影响R、G和B三个通道的值,而在HSV空间中,光照变化主要影响V通道的值,而H通道(颜色)的值相对稳定。
#颜色掩码 #绿色掩码 lower_green, upper_green = numpy.array([35, 50, 50]), numpy.array([85, 255, 255]) green_mask = cv2.inRange(hsv, lower_green, upper_green) #红色掩码 #红色在hsv颜色空间有两个范围 lower_red1, upper_red1 = numpy.array([0, 50, 50]), numpy.array([10, 255, 255]) lower_red2, upper_red2 = numpy.array([170, 50, 50]), numpy.array([180, 255, 255]) mask1 = cv2.inRange(hsv, lower_red1, upper_red1) mask2 = cv2.inRange(hsv, lower_red2, upper_red2) red_mask = cv2.bitwise_or(mask1, mask2) #蓝色掩码 lower_blue, upper_blue = numpy.array([100, 50, 40]), numpy.array([130, 255, 255]) blue_mask = cv2.inRange(hsv, lower_blue, upper_blue)
cv2.inRange函数用于检查输入数组(图像)的元素是否在两个指定的值之间。如果元素的值在指定的范围内,该元素在输出数组中的值将被设置为255(白色),否则将被设置为0(黑色)。
参数src
(源图像): 输入图像,通常是一个多通道图像,例如RGB或HSV图像。lowerb
(下界): 表示颜色范围的下界,是一个数组,包含了每个通道的最小值。upperb
(上界): 表示颜色范围的上界,是一个数组,包含了每个通道的最大值。
输出是一个二值图像,其中的像素值要么是0(黑色),要么是255(白色)。如果输入图像中的某个像素的颜色在指定的范围内,对应的输出图像中的像素值将为255,否则为0。
#创建掩码列表用于for循环 masks = [(red_mask, (0, 0, 255), 'red'), (green_mask, (0, 255, 0), 'green'), (blue_mask, (255, 0, 0), 'blue')] for mask, color, label in masks: mask_blurred = cv2.GaussianBlur(mask, (3, 3), 0)#高斯滤波平滑边缘 edges = cv2.Canny(mask_blurred, 10, 200)#边缘检测 contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)#寻找轮廓 min_area_threshold = 500#确定面积阈值 for contour in contours:#处理多个轮廓 if cv2.contourArea(contour) > min_area_threshold:#如果轮廓面积大于面积阈值,就绘制 x, y, w, h = cv2.boundingRect(contour) centerX, centerY = int(x + w//2), int(y + h//2)#确定中心位置 cv2.rectangle(result_img, (x, y), (x+w, y+h), color, 2)#画框 text = '{}({},{})'.format(label, centerX, centerY)#设置文本内容 position = (x, y)#设置写字坐标位置(刚好在框上面) font, font_scale = cv2.FONT_HERSHEY_SIMPLEX, 1#设置字体风格和大小 cv2.putText(result_img, text, position, font, font_scale, color)#在图像副本上写字
除了OpenCV库之外,我们还要导入numpy库,最基本的原因是要用numpy.array()描述颜色空间,参见本文代码。
要确定视频中物体的HSV值,你也许需要查阅表格、反复调试才能得到最适合的HSV范围,或者,用一些自动化脚本来寻找HSV范围。
颜色掩码功能的inrange()函数生成的是二值图像,而不是彩色图像。我们只是利用二值图像来确定坐标位置,最后要在彩色图像上绘制字体和边框。
原来的图像是RGB图像,我们要用copy()方法创建图像的RGB副本用于绘制。如果用HSV图像绘制,显示效果就会不一样。
视频里可能会有一些杂乱的颜色光点,影响到我们对图像的识别。有的朋友用了先膨胀后腐蚀的形态学运算;我用了中值滤波去噪音,高斯滤波平滑边缘,最后加了一个面积阈值,用来除去面积太小的杂质,最后处理出来的效果是一样的。
cap.release()#释放内存 cv2.destroyAllWindows()#关闭窗口
cap.release()是用于释放与视频捕获相关的所有内存资源。在OpenCV中,当你打开一个视频文件或连接到一个摄像头时,它会分配一些内存来处理视频流。cap.release()确保所有这些内存资源都被正确地释放,以避免内存泄漏。
cv2.destroyAllWindows()是用于关闭所有的OpenCV窗口。之前,我们创建了一个名为processed_video的窗口来显示处理过的视频帧,不再需要这个窗口时,应该使用cv2.destroyAllWindows()来关闭它。
如果你不调用cap.release()和cv2.destroyAllWindows(),可能会出现一些问题:
内存泄漏:不释放视频捕获对象可能会导致内存泄漏。内存泄漏可能会随着时间的推移而累积,最终导致应用程序崩溃或系统变慢。
窗口无法关闭:如果不调用cv2.destroyAllWindows(),OpenCV窗口可能会保持打开状态,即使程序已经结束。这可能会让用户感到困惑,而且可能需要手动关闭这些窗口。
物体识别
#一.导入库 import cv2 import numpy #二.定义函数处理每一帧 def process(frame): hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)#把RGB转化成HSV hsv = cv2.medianBlur(hsv, 5)#中值滤波去噪音 result_img = frame.copy()#创建图像rgb副本用于绘制(用hsv副本会变色) #颜色掩码 #绿色掩码 lower_green, upper_green = numpy.array([35, 50, 50]), numpy.array([85, 255, 255]) green_mask = cv2.inRange(hsv, lower_green, upper_green) #红色掩码 #红色在hsv颜色空间有两个范围 lower_red1, upper_red1 = numpy.array([0, 50, 50]), numpy.array([10, 255, 255]) lower_red2, upper_red2 = numpy.array([170, 50, 50]), numpy.array([180, 255, 255]) mask1 = cv2.inRange(hsv, lower_red1, upper_red1) mask2 = cv2.inRange(hsv, lower_red2, upper_red2) red_mask = cv2.bitwise_or(mask1, mask2) #蓝色掩码 lower_blue, upper_blue = numpy.array([100, 50, 40]), numpy.array([130, 255, 255]) blue_mask = cv2.inRange(hsv, lower_blue, upper_blue) #创建掩码列表用于for循环 masks = [(red_mask, (0, 0, 255), 'red'), (green_mask, (0, 255, 0), 'green'), (blue_mask, (255, 0, 0), 'blue')] for mask, color, label in masks: mask_blurred = cv2.GaussianBlur(mask, (3, 3), 0)#高斯滤波平滑边缘 edges = cv2.Canny(mask_blurred, 10, 200)#边缘检测 contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)#寻找轮廓 min_area_threshold = 500#确定面积阈值 for contour in contours:#处理多个轮廓 if cv2.contourArea(contour) > min_area_threshold:#如果轮廓面积大于面积阈值,就绘制 x, y, w, h = cv2.boundingRect(contour) centerX, centerY = int(x + w//2), int(y + h//2)#确定中心位置 cv2.rectangle(result_img, (x, y), (x+w, y+h), color, 2)#画框 text = '{}({},{})'.format(label, centerX, centerY)#设置文本内容 position = (x, y)#设置写字坐标位置(刚好在框上面) font, font_scale = cv2.FONT_HERSHEY_SIMPLEX, 1#设置字体风格和大小 cv2.putText(result_img, text, position, font, font_scale, color)#在图像副本上写字 return result_img #三.主函数 if __name__=='__main__': cap=cv2.VideoCapture('ballsvideo.mp4')#获取原视频 cv2.namedWindow('processed_video', cv2.WINDOW_NORMAL) #创建一个可调整大小的窗口 cv2.resizeWindow('processed_video', 500, 800)#设置窗口宽度为500,高度为800 while True: ret,frame=cap.read()#读取原视频每帧 if not ret:#直到视频没有下一帧了才结束 break processed_frame=process(frame)#处理每帧 cv2.imshow('processed_video',processed_frame)#逐帧播放新视频 if cv2.waitKey(1) & 0xFF == ord('q'):#按q键退出视频播放 break cap.release()#释放内存 cv2.destroyAllWindows()#关闭窗口
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。