在计算机视觉领域,运动目标检测是众多应用的基础,如安防监控、自动驾驶、智能机器人等。OpenCV 作为开源计算机视觉库,提供了高效且便捷的工具,助力开发者实现复杂的视觉任务。本文将对一段利用 OpenCV 实现视频运动目标检测的 Python 代码进行详细解读,帮助大家理解其原理与应用。

代码详细解析

1. 导入库与初始化

import cv2

cap = cv2.VideoCapture('test.avi')

首先,使用import cv2导入 OpenCV 库,它包含了丰富的计算机视觉函数和算法。cv2.VideoCapture('test.avi')用于创建一个视频捕获对象cap,该对象将用于读取指定的视频文件test.avi。如果视频文件路径不正确或文件损坏,后续读取操作将出现异常,因此在实际应用中建议添加文件存在性检查。

2. 形态学核与背景减除器初始化

kernel = cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))

fgbg = cv2.createBackgroundSubtractorMOG2()

cv2.getStructuringElement(cv2.MORPH_CROSS, (3, 3))创建一个大小为 3x3 的十字形结构元素kernel。在后续的形态学操作中,这个结构元素将用于处理图像,比如去除噪声、平滑边缘等。形态学操作基于集合论原理,通过对图像中像素集合的操作来改变图像的形状和结构。

cv2.createBackgroundSubtractorMOG2()初始化一个基于高斯混合模型(GMM)的背景减除器fgbg。高斯混合模型通过对视频序列中像素值的统计分析,学习背景模型,并将与背景模型差异较大的像素识别为前景(即运动目标)。该算法能够适应一定的光照变化和背景动态变化。

3. 视频帧处理循环

while True:

ret, frame = cap.read()

if not ret:

break

cv2.imshow('frame', frame)

fgmask = fgbg.apply(frame)

cv2.imshow('fgmask', fgmask)

fgmask_new = cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel)

cv2.imshow('fgmask1', fgmask_new)

进入一个无限循环,逐帧读取视频。cap.read()函数返回两个值,ret表示是否成功读取到视频帧(True表示成功,False表示失败,如视频结束),frame则是读取到的当前视频帧图像。如果ret为False,则跳出循环,结束视频处理。

cv2.imshow('frame', frame)显示原始视频帧,方便我们直观查看处理过程。fgbg.apply(frame)将当前视频帧输入到背景减除器中,返回一个前景掩码fgmask。在这个掩码图像中,白色像素(值为 255)表示检测到的运动目标,黑色像素(值为 0)表示背景。cv2.imshow('fgmask', fgmask)显示前景掩码图像。

cv2.morphologyEx(fgmask, cv2.MORPH_OPEN, kernel)对前景掩码fgmask进行开运算处理。开运算先执行腐蚀操作(缩小前景区域,去除小的噪声点和孤立像素),再执行膨胀操作(扩大前景区域,恢复目标的大小和形状)。通过这一操作,可以使前景目标的轮廓更加清晰,减少噪声干扰。处理后的掩码存储在fgmask_new中,并通过cv2.imshow('fgmask1', fgmask_new)显示。

4. 轮廓检测与目标框选

_, contours, h = cv2.findContours(fgmask_new, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

for c in contours:

perimeter = cv2.arcLength(c, True)

if perimeter > 188:

x, y, w, h = cv2.boundingRect(c)

fgmask_new_rect = cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)

cv2.findContours(fgmask_new, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)在处理后的前景掩码fgmask_new中查找轮廓。cv2.RETR_EXTERNAL参数表示只检索最外层的轮廓,忽略内部嵌套的轮廓;cv2.CHAIN_APPROX_SIMPLE参数表示对轮廓进行压缩,只保留轮廓的端点信息,减少数据量。找到的轮廓存储在contours列表中。

通过遍历contours中的每个轮廓c,使用cv2.arcLength(c, True)计算轮廓的周长perimeter。设置周长阈值 188,只有周长大于该阈值的轮廓才被认为是有效的运动目标轮廓。对于满足条件的轮廓,通过cv2.boundingRect(c)获取其外接矩形的左上角坐标(x, y)以及宽高(w, h),然后使用cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)在原始视频帧frame上绘制绿色(RGB 值为 (0, 255, 0))、线宽为 2 的矩形框,标记出运动目标。

5. 显示结果与退出

cv2.imshow('fgmask_new_rect', fgmask_new_rect)

k = cv2.waitKey(1)

if k == 27:

break

cv2.imshow('fgmask_new_rect', fgmask_new_rect)显示标记了运动目标的视频帧。cv2.waitKey(1)等待 1 毫秒,检查是否有按键按下。如果按下的键的 ASCII 码为 27(即 ESC 键),则跳出循环,释放资源并结束程序。

完整代码

import cv2
cap=cv2.VideoCapture('test.avi')
kernel=cv2.getStructuringElement(cv2.MORPH_CROSS,(3,3))
fgbg=cv2.createBackgroundSubtractorMOG2()
while True:
    ret,frame=cap.read()
    if not ret:
        break
    cv2.imshow('frame',frame)
    fgmask=fgbg.apply(frame)
    cv2.imshow('fgmask',fgmask)
    fgmask_new=cv2.morphologyEx(fgmask,cv2.MORPH_OPEN,kernel)
    cv2.imshow('fgmask1',fgmask_new)
    _,contours, h = cv2.findContours(fgmask_new, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    for c in contours:
        perimeter = cv2.arcLength(c, True)
        if perimeter > 188:
            x,y,w,h =cv2.boundingRect(c)
            fgmask_new_rect=cv2.rectangle(frame,(x,y),(x+w,y+h),(0,255,0),2)
    cv2.imshow('fgmask_new_rect', fgmask_new_rect)
    k=cv2.waitKey(1)
    if k ==27:
        break

总结与拓展

通过以上代码,我们实现了基于 OpenCV 的视频运动目标检测。在实际应用中,可根据具体场景调整参数,如背景减除器的历史帧数、阈值等,以优化检测效果。此外,还可以结合其他计算机视觉技术,如光流法、深度学习目标检测模型,进一步提升检测的准确性和鲁棒性。希望本文的代码解析能为大家在计算机视觉领域的学习和实践提供帮助,欢迎在评论区交流讨论!

上述博客全面剖析了运动目标检测代码。若你在代码运行中遇到问题,或想对代码进行拓展,都能随时和我交流。

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐