OpenCV-Python读取视频,识别物体

前言

打球的时候,我们常常要用眼睛去识别球的位置,确定球的落点和轨迹。用摄像头和视频捕捉物体的位置,确定中心坐标,绘制轮廓边框,就成为了基于Python的OpenCV(Opencv for Python)要处理的重要问题。

思路

1.获取原视频

cap=cv2.VideoCapture('ballsvideo.mp4')#获取原视频
cv2.namedWindow('processed_video', cv2.WINDOW_NORMAL)  #创建一个可调整大小的窗口
cv2.resizeWindow('processed_video', 500, 800)#设置窗口宽度为500,高度为800

2.逐帧读取原视频

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

3.逐帧处理

把RGB图像转变成HSV图像
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)#在图像副本上写字  
注意事项tips

除了OpenCV库之外,我们还要导入numpy库,最基本的原因是要用numpy.array()描述颜色空间,参见本文代码。

要确定视频中物体的HSV值,你也许需要查阅表格、反复调试才能得到最适合的HSV范围,或者,用一些自动化脚本来寻找HSV范围。

颜色掩码功能的inrange()函数生成的是二值图像,而不是彩色图像。我们只是利用二值图像来确定坐标位置,最后要在彩色图像上绘制字体和边框。

原来的图像是RGB图像,我们要用copy()方法创建图像的RGB副本用于绘制。如果用HSV图像绘制,显示效果就会不一样。

视频里可能会有一些杂乱的颜色光点,影响到我们对图像的识别。有的朋友用了先膨胀后腐蚀的形态学运算;我用了中值滤波去噪音高斯滤波平滑边缘,最后加了一个面积阈值,用来除去面积太小的杂质,最后处理出来的效果是一样的。

4.退出

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()#关闭窗口

  • 16
    点赞
  • 26
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值