目录
1. 项目总览
1.1 项目简述
车辆统计是一项常见的交通监控任务,用于分析道路上的车流量,以优化交通管理。通过OpenCV,可以高效实现车辆检测与计数,适用于道路摄像头监控的实际应用。实现步骤如下:
- 加载视频。
- 降噪和背景去除:去除与统计无关的干扰项。
- 形态学处理:确认车辆位置,以及绘制外接矩形。
- 实现车辆统计逻辑,绘制检测线以及统计结果。
1.2 车辆统计项目所需的知识点
OpenCV基础:视频的采集、读取与录制_cv2.videocapture cap.read-CSDN博客
OpenCV基础:绘制基本图形_opencv画形状-CSDN博客
OpenCV:图像处理中的低通滤波_图像低通滤波-CSDN博客
1.3 最终效果
2. 项目实现过程
2.1 加载视频
此阶段目的是加载视频资源。
代码如下:
import cv2
cap = cv2.VideoCapture('D:\\resource\\filter\\video.mp4')
while True:
ret, frame = cap.read()
if (ret == True):
cv2.imshow('car stats', frame)
key = cv2.waitKey(1)
if (key == ord('q')):
break
cap.release()
cv2.destroyAllWindows()
2.2 降噪和背景去除
此阶段的目的是让图像中只留下行驶的车辆,删除与统计项无关的物体。
2.2.1 安装扩展模块
去掉视频背景需要用到bgsegm,安装OpenCV Contrib扩展模块:
pip install opencv-contrib-python
安装过程:
2.2.2 接口说明
需要使用的接口为:
cv2.bgsegm.createBackgroundSubtractorMOG(history=200, nmixtures=5, backgroundRatio=0.7, noiseSigma=0)
以下是关于此接口的说明:
cv2.bgsegm.createBackgroundSubtractorMOG() 是 OpenCV 提供的一个用于背景建模和背景减除的函数,它实现了经典的 Mixture of Gaussians (MOG) 背景建模算法。该函数属于 OpenCV 的 bgsegm 模块,它是背景分割的一个实现扩展。
函数作用:
背景减除是一种用于检测视频中的前景物体(如行人、车辆等)的技术。cv2.bgsegm.createBackgroundSubtractorMOG() 通过对视频帧序列进行建模,将静态部分(背景)与动态部分(前景)区分开来。
适用场景:
- 交通监控:检测道路上的车辆和行人。
- 视频分析:提取动态前景物体,用于后续目标识别或跟踪。
- 行为分析:在静态背景中分离动态目标,分析其行为。
注意事项:
- 动态背景:如果背景是动态的(如树叶摆动、水流),算法可能会误检测为前景。
- 可以尝试调整 history 和 nmixtures 参数,或使用其他更高级的背景建模方法(如 MOG2 或 KNN)。
- 光照变化:MOG 对光照变化敏感,需适当调整 backgroundRatio 或选择其他鲁棒算法。
- bgsegm 模块:该模块可能需要在安装 OpenCV 的扩展版本(如 opencv-contrib-python)后才能使用。
2.2.3 参数说明
history:
- 背景模型中保留的帧数(即时间窗口大小)。
- 默认值为 200。
- 数值越大,背景模型的更新速度越慢;数值越小,模型对动态背景的适应速度越快。
nmixtures:
- 高斯混合模型的高斯分布个数。
- 默认值为 5。
- 控制模型的复杂度,较高的值可更好地处理复杂场景。
backgroundRatio:
- 决定背景的高斯模型概率阈值,范围为 0~1。
- 默认值为 0.7。
- 较高的值表示更严格的背景建模。
noiseSigma:
- 添加的高斯噪声标准差,用于处理噪声。
- 默认值为 0。
- 较大的值可更好地处理具有较多噪声的场景。
返回值
- 返回一个背景减除器对象,用于从输入视频中提取前景。
2.2.4 代码示例
以下是降噪和背景去除代码:
import cv2
cap = cv2.VideoCapture('D:\\resource\\filter\\video.mp4')
bgsubmog = cv2.bgsegm.createBackgroundSubtractorMOG()
while True:
ret, frame = cap.read()
if (ret == True):
#转为灰度图
cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
#高斯降噪
blur = cv2.GaussianBlur(frame, (3,3), 5)
#去背景
mask = bgsubmog.apply(blur)
cv2.imshow('car stats', mask)
key = cv2.waitKey(1)
if (key == ord('q')):
break
cap.release()
cv2.destroyAllWindows()
代码说明:
- 读取一帧后,先转为灰度图,然后使用高斯降噪;
- 使用bssegm组件去除背景。
只去除背景,不进行高斯降噪时:
降噪后,去除背景:
先降噪,再去背景,画面会干净很多。
2.3 形态学处理
本阶段主要是通过形态学操作确定车辆所在的位置,将车辆的外接矩形画出来。
代码实现:
import cv2
cap = cv2.VideoCapture('D:\\resource\\filter\\video.mp4')
bgsubmog = cv2.bgsegm.createBackgroundSubtractorMOG()
#形态学结构元素
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
while True:
ret, frame = cap.read()
if (ret == True):
#转为灰度图
cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
#高斯降噪
frame_blur = cv2.GaussianBlur(frame, (3,3), 5)
#去背景
frame_mask = bgsubmog.apply(frame_blur)
#形态学操作
#腐蚀
frame_erode = cv2.erode(frame_mask, kernel)
#膨胀
frame_dilate = cv2.dilate(frame_erode, kernel, iterations=3)
#闭运算,去除物体内部的孔洞
frame_close = cv2.morphologyEx(frame_dilate, cv2.MORPH_CLOSE, kernel)
frame_close = cv2.morphologyEx(frame_close, cv2.MORPH_CLOSE, kernel)
#查找轮廓、绘制矩形
contours, _ = cv2.findContours(frame_close, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for (i,con) in enumerate(contours):
x,y,w,h = cv2.boundingRect(con)
cv2.rectangle(frame, (x,y), (x+w,y+h), (0,0,255), 2)
#显示画面
cv2.imshow('car stats', frame)
key = cv2.waitKey(1)
if (key == ord('q')):
break
cap.release()
cv2.destroyAllWindows()
代码说明:
- 去掉背景之后,进行腐蚀操作,目的是为了进一步减少车辆周围的小噪点;
- 腐蚀之后车辆会缩小,进行膨胀操作的目的是放大车辆,让车辆更加明显;
- 然后进行闭运算,目的是去掉膨胀操作后车辆内部出现的孔洞;
- 最后进行轮廓查找,将车辆的外接矩形画出来。
运行效果:
2.4 统计逻辑处理
以下是统计逻辑的处理,基本已经完成了车辆统计功能,代码如下:
import cv2
# 获取中心点
def center(x, y, w, h):
x1 = int(w/2)
y1 = int(h/2)
cx = x + x1
cy = y + y1
return cx, cy
cap = cv2.VideoCapture('D:\\resource\\filter\\video.mp4')
bgsubmog = cv2.bgsegm.createBackgroundSubtractorMOG()
# 形态学结构元素
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
# 定义车辆的宽高
min_w = 90
min_h = 90
# 检测线的位置
line_high = 550
# 线的偏移
offset = 7
# 统计数量
car_count = 0
# 存放有效车辆
cars = []
while True:
ret, frame = cap.read()
if (ret == True):
# 转灰度
cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
# 高斯降噪
frame_blur = cv2.GaussianBlur(frame, (3,3), 5)
# 去背景
frame_mask = bgsubmog.apply(frame_blur)
# 形态学操作
# 腐蚀
frame_erode = cv2.erode(frame_mask, kernel)
# 膨胀
frame_dilate = cv2.dilate(frame_erode, kernel, iterations=3)
# 闭运算,去除物体内部的孔洞
frame_close = cv2.morphologyEx(frame_dilate, cv2.MORPH_CLOSE, kernel)
frame_close = cv2.morphologyEx(frame_close, cv2.MORPH_CLOSE, kernel)
# 查找轮廓、绘制矩形
contours, _ = cv2.findContours(frame_close, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
for (i,con) in enumerate(contours):
x,y,w,h = cv2.boundingRect(con)
# 对车辆的尺寸进行判断
valid = (w >= min_w) and ( h >= min_h)
if (not valid):
continue
# 有效物体
cv2.rectangle(frame, (x, y), (x+w, y+h), (0,0,255), 2)
cpoint = center(x, y, w, h)
cars.append(cpoint)
cv2.circle(frame, (cpoint), 5, (0,0,255), -1)
for (x, y) in cars:
if( (y > line_high - offset) and (y < line_high + offset) ):
car_count +=1
cars.remove((x, y))
# 画检测线
cv2.line(frame, (30, line_high), (1160, line_high), (0, 0, 255), 3)
# 显示统计数据
cv2.putText(frame, "Count: " + str(car_count), (900, 60), cv2.FONT_HERSHEY_SIMPLEX, 2, (0,0,255), 5)
# 显示画面
cv2.imshow('car stats', frame)
key = cv2.waitKey(1)
if (key == ord('q')):
break
cap.release()
cv2.destroyAllWindows()
代码说明:
- 在形态学处理之后,将有效物体的外接矩形画出来;
- 绘制外接矩形的中心点,然后保存坐标;
- 遍历坐标,判断该坐标是否跨过检测线,满足条件则计数加1;
- 画检测线与统计结果。
运行结果:
3. 优化与扩展
3.1 优化方案
车辆跟踪:当前方案依赖外接矩形中心点判断,可能存在重复计数的问题。可以引入 卡尔曼滤波 或 KNN 跟踪算法,增强准确性。
3.2 扩展功能
类别识别:引入目标检测模型(如 YOLO 或 Faster R-CNN),区分小车、卡车、摩托车等不同车辆类型。
4. 总结
通过OpenCV相关接口以及统计逻辑处理,可以快速实现车辆计数。以下是关键点:
- 背景去除:排除背景干扰。
- 图像预处理:通过降噪和形态学操作增强目标。
- 轮廓检测与计数:基于矩形中心点穿越计数线进行车辆计数。
此方案适用于普通道路监控场景,结合跟踪算法和深度学习技术可进一步提升性能与适用性。
5. 资源以及代码下载
通过网盘分享的文件:opencv_car_stats.zip
链接: https://pan.baidu.com/s/1GPa1f0OibfgLmjbomvDtWA?pwd=open 提取码: open