使用OpenCV处理路口监控摄像头视频实现车辆的识别主要分为视频加载,形态学处理,逻辑处理,显示信息四个模块
一、视频加载模块:
1.获取视频文件
利用cap = cv.VideoCapture("1.mp4")获取视频文件
2.循环读取视频帧显示在窗口
读取视频帧-循环处理视频的每一帧
while True:
ret,frame = cap.read()#读取视频返回值ret和frame
ret: 布尔值,表示是否成功读取帧
frame: 当前帧的图像数据
if (ret == True):#判断是否成功读取
cv.imshow("video",frame) #读取的每一帧显示在窗口上
3.键盘控制窗口关闭
#按ESC退出
key = cv.waitKey(1)
if(key == 27):
break
4.释放视频及窗口
释放视频捕获对象 cap.release()
关闭所有OpenCV窗口 cv.destroyAllWindows()
二、形态学处理模块
1.创建背景减除器和形态学内核
背景减除器-用于从视频中提取前景(移动物体)bgsubmog = cv.createBackgroundSubtractorMOG2()
形态学操作的内核-用于后续的图像处理操作 kernel = cv.getStructuringElement(cv.MORPH_RECT,(5,5))
2.帧预处理:
将帧转换为灰度图像
cv.cvtColor(frame,cv.COLOR_BGR2GRAY)
3.高斯模糊去噪
应用高斯模糊去噪 - 减少图像噪声,提高后续处理的准确性
参数: 输入图像, 核大小(3x3), 标准差(5)
blue = cv.GaussianBlur(frame,(3,3),5)
4.去背景
对模糊后的图像应用背景减除
mask = bgsubmog.apply(blue)
5.形态学操作(腐蚀、膨胀、闭操作)以优化前景掩码
腐蚀,去掉图中小斑块 erode = cv.erode(mask,kernel)
膨胀-还原被腐蚀的物体,并放大特征 dilate = cv.dilate(erode,kernel,iterations = 3)
闭操作-先膨胀后腐蚀,用于填充物体内部的小空洞 close = cv.morphologyEx(dilate,cv.MORPH_CLOSE,kernel)
6.查找、遍历、绘制轮廓
查找轮廓 - 在二值图像中查找物体的轮廓
cnts,h = cv.findContours(close,cv.RETR_TREE,cv.CHAIN_APPROX_SIMPLE)
cnts: 轮廓列表 h: 层次结构信息
遍历所有检测到的轮廓
for(i,c)in enumerate(cnts):
(x,y,w,h)=cv.boundingRect(c)获取轮廓的边界矩形
绘制矩形框标记检测到的车辆 - 红色框,线宽为2像素
cv.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2)
三、逻辑处理模块
1.计算车辆中心点坐标
def center(x,y,w,h):
计算矩形区域的中心点坐标 参数: x, y: 矩形左上角坐标 w, h: 矩形的宽度和高度 返回: (cx, cy): 矩形中心点坐标
x1 = int(w/2)计算宽度的一半
y1 = int(h/2)计算高度的一半
cx = x + x1计算中心点的x坐标
cy = y + y1计算中心点的y坐标
return cx,cy返回中心点坐标
利用上面定义函数计算车辆中心点 cpoint = center(x,y,w,h)
将中心点添加到车辆列表中 cars.append(cpoint)
2.判断检测到的物体是否为有效车辆(基于尺寸阈值)
min_w = 90最小车辆宽度阈值(像素)
min_h = 90最小车辆高度阈值(像素)
#检查矩形尺寸是否满足车辆的最小尺寸要求
isValid = (w>=min_w) and (h>=min_h) 对车辆宽高进行判断
验证是否是有效的车辆
if(not isValid):
continue
3.实现车辆计数逻辑(检测车辆是否通过检测线)
line_high = 900#检测线高度
offset = 9#线的偏移
carno = 0#统计车的数量
cars = []#存放有效车辆的数组
检查所有已检测车辆是否通过检测线
cv.line(frame,(10,line_high),(18000,line_high),(0,0,255),3)
for(x,y) in cars:
cv.imshow("video",frame)
是OpenCV库中用于显示视频帧的重要函数。该函数通常与视频捕获功能配合使用,可以实现实时视频流的显示和处理。以下是完整的视频帧读取和显示流程:
- 首先需要创建视频捕获对象:
cap = cv.VideoCapture(0) # 0表示默认摄像头,也可以是视频文件路径
- 然后使用循环持续读取视频帧:
while True:
ret, frame = cap.read() # ret表示读取是否成功,frame是当前帧图像
if not ret:
break # 如果读取失败则退出循环
# 在这里可以对frame进行各种图像处理
cv.imshow('video', frame) # 显示当前帧
if cv.waitKey(1) & 0xFF == ord('q'): # 按q键退出
break
- 最后需要释放资源:
cap.release()
cv.destroyAllWindows()
应用场景包括:
- 实时视频监控系统
- 视频会议应用
- 计算机视觉项目开发
- 视频内容分析
注意事项:
- 帧率会根据硬件性能有所不同
- 在高分辨率下可能需要优化处理算法
- 可以添加各种图像处理操作在显示前
- 在多线程应用中需要注意资源管理
if((y> line_high - offset) and (y<line_high + offset)):
carno += 1检查车辆中心点是否在检测线的偏移范围内
cars.remove((x,y))增加车辆计数
print(carno)从列表中移除已计数的车辆
打印当前车辆计数
四、显示信息模块
1.绘制检测线
在帧上绘制检测线-红色线,线宽为3像素
cv.line(frame,(10,line_high),(18000,line_high),(0,0,255),3)
2.显示车辆计数信息
在帧上显示车辆计数 - 蓝色文字,大小为2,线宽为5
cv.putText(frame,"Cars Count:" + str(carno),(500,60),cv.FONT_HERSHEY_SIMPLEX,2,(255,0,0),5)
3.显示处理后的视频帧
cv.imshow("video",frame)
源代码如下:
import cv2 as cv # 参数配置 min_w = 90#最小车辆宽度阈值(像素) min_h = 90#最小车辆高度阈值(像素) line_high = 900#检测线高度 offset = 9#线的偏移 carno = 0#统计车的数量 cars = []#存放有效车辆的数组 def center(x,y,w,h): """ 计算矩形区域的中心点坐标 参数: x, y: 矩形左上角坐标 w, h: 矩形的宽度和高度 返回: (cx, cy): 矩形中心点坐标 """ x1 = int(w/2)#计算宽度的一半 y1 = int(h/2)#计算高度的一半 cx = x + x1#计算中心点的x坐标 cy = y + y1#计算中心点的y坐标 return cx,cy#返回中心点坐标 #视频加载 cap = cv.VideoCapture("1.mp4") # 创建背景减除器-用于从视频中提取前景(移动物体) bgsubmog = cv.createBackgroundSubtractorMOG2() #创建形态学操作的内核-用于后续的图像处理操作 kernel = cv.getStructuringElement(cv.MORPH_RECT,(5,5)) #读取视频帧-循环处理视频的每一帧 while True: # ret: 布尔值,表示是否成功读取帧 # frame: 当前帧的图像数据 ret,frame = cap.read() if (ret == True): mask = bgsubmog.apply(frame) cv.imshow("video",mask)#显示前景掩码 #将帧转换为灰度图像(但这里没有保存结果,所以这行代码实际上没有效果) cv.cvtColor(frame,cv.COLOR_BGR2GRAY) # 应用高斯模糊去噪 - 减少图像噪声,提高后续处理的准确性 # 参数: 输入图像, 核大小(3x3), 标准差(5) blue = cv.GaussianBlur(frame,(3,3),5) #对模糊后的图像应用背景减除 mask = bgsubmog.apply(blue) #腐蚀,去掉图中小斑块 erode = cv.erode(mask,kernel) #膨胀操作-还原被腐蚀的物体,并放大特征 #iterations=3 表示进行3次膨胀操作 dilate = cv.dilate(erode,kernel,iterations = 3) #闭操作-先膨胀后腐蚀,用于填充物体内部的小空洞 close = cv.morphologyEx(dilate,cv.MORPH_CLOSE,kernel) # 查找轮廓 - 在二值图像中查找物体的轮廓 # cnts: 轮廓列表 # h: 层次结构信息(这里使用_表示我们不使用这个变量) cnts,h = cv.findContours(close,cv.RETR_TREE,cv.CHAIN_APPROX_SIMPLE) # 在帧上绘制检测线-红色线,线宽为3像素 cv.line(frame,(10,line_high),(18000,line_high),(0,0,255),3) # 遍历所有检测到的轮廓 for(i,c)in enumerate(cnts): # 获取轮廓的边界矩形 (x,y,w,h)=cv.boundingRect(c) # 检查矩形尺寸是否满足车辆的最小尺寸要求 isValid = (w>=min_w) and (h>=min_h) #对车辆宽高进行判断 #验证是否是有效的车辆 if(not isValid): continue #到这里都是有效的车 # 绘制矩形框标记检测到的车辆 - 红色框,线宽为2像素 cv.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 2) # 计算车辆中心点 cpoint = center(x,y,w,h) # 将中心点添加到车辆列表中 cars.append(cpoint) # 检查所有已检测车辆是否通过检测线 for(x,y) in cars: #检查车辆中心点是否在检测线的偏移范围内 if((y> line_high - offset) and (y<line_high + offset)): carno += 1#增加车辆计数 cars.remove((x,y))#从列表中移除已计数的车辆 print(carno) #打印当前车辆计数 # 在帧上显示车辆计数 - 蓝色文字,大小为2,线宽为5 cv.putText(frame,"Cars Count:" + str(carno),(500,60),cv.FONT_HERSHEY_SIMPLEX,2,(255,0,0),5) # 显示处理后的帧 cv.imshow("video",frame) #ESC退出 key = cv.waitKey(1) if(key == 27): break # 释放视频捕获对象 cap.release() # 关闭所有OpenCV窗口 cv.destroyAllWindows()
原视频:
OpenCV处理后: