项目描述:在截取一段公路上车流量视频,通过OpenCv识别经过的车辆并进行计数统计。
本项目实践目的旨在学习运用OpenCV知识,所以只截取了视频的一部分
目录
一、所用到的OpenCv知识:
1.窗口展示
2.图像/视频的加载
3.基本图像&文本绘制;
车辆识别:
4.基本图像运算与处理
5.形态学
6.轮廓查找
二、项目实现流程
1 将车流量视频加载出来
import cv2
import numpy as np
# 打开摄像头
cap = cv2.VideoCapture('./video.mp4')
# 循环读取视频
while True:
ret, frame = cap.read()
# 读取视频的每一帧,返回“标记”ret和这一帧的数据frame,读到数据ret为TRUE,没读到为Fales
if ret == True:
cv2.imshow('video', frame)
# 用户按ESC退出
key = cv2.waitKey(1)
if key == 27:
break
# 别忘了释放资源
cap.release()
cv2.destroyAllWindows()
代码中video为车辆视频素材
2 通过形态学识别车辆
2.1 前景/背景分割算法
cv2.createBackgroundSubtractorMOG2() # 是 OpenCV 库中用于背景减除的函数
- 背景减除是一种计算机视觉技术,用于从视频序列中分离出前景物体和背景。其基本思想是通过对视频序列中的像素进行分析,建立背景模型,然后将当前帧与背景模型进行比较,将与背景模型差异较大的像素判定为前景像素,从而提取出前景物体。这种技术在视频监控、目标跟踪等诸多领域有广泛的应用。
实例代码
import cv2
import numpy as np
# 加载车辆视频
cap = cv2.VideoCapture('./video.mp4')
# 创建MOG对象
mog = cv2.createBackgroundSubtractorMOG2()
# 循环读取视频
while True:
ret, frame = cap.read()
# 读取视频的每一帧,返回“标记”ret和这一帧的数据frame,读到数据ret为TRUE,没读到为Fales
if ret == True:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
bgmask = mog.apply(frame)
cv2.imshow('bgmask', bgmask)
# 用户按ESC退出
key = cv2.waitKey(1000//120) # 1000//60 可以调帧数
if key & 0xFF == 27:
break
# 最后别忘了释放资源
cap.release()
cv2.destroyAllWindows()
逐帧读取视频,使用 mog.apply(frame)方法将背景减除应用到每一帧上,得到前景掩码fgmask,并显示这个掩码
这样我们就能通过这个算法在视频中找出正在行驶的车辆
2.2 去噪、腐蚀、膨胀以及闭运算操作
首先将上一小节前景分割后的车辆视频进行去噪、腐蚀、膨胀等操作
# 去噪
blur = cv2.GaussianBlur(gray, (13, 13), 15)
bgmask = mog.apply(blur)
# 腐蚀
erode = cv2.erode(bgmask, kernel)
# 膨胀
dialte = cv2.dilate(erode, kernel, iterations=4)
# 消除内部的小方块:闭运算
close = cv2.morphologyEx(dialte, cv2.MORPH_CLOSE, kernel, iterations=1)
测式代码如下
import cv2
import numpy as np
# 加载视频
cap = cv2.VideoCapture('./video.mp4')
# 创建MOG对象
mog = cv2.createBackgroundSubtractorMOG2()
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
# 循环读取视频
while True:
ret, frame = cap.read()
# 读取视频的每一帧,返回“标记”ret和这一帧的数据frame,读到数据ret为TRUE,没读到为Fales
if ret == True:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 去噪
blur = cv2.GaussianBlur(gray, (13, 13), 15)
bgmask = mog.apply(blur)
# 腐蚀
erode = cv2.erode(bgmask, kernel)
# 膨胀
dialte = cv2.dilate(erode, kernel, iterations=4)
# 消除内部的小方块:闭运算
close = cv2.morphologyEx(dialte, cv2.MORPH_CLOSE, kernel, iterations=1)
cv2.imshow('video', close)
# 用户按ESC退出
key = cv2.waitKey(1000//60)
if key & 0xFF == 27:
break
# 释放资源
cap.release()
cv2.destroyAllWindows()
效果如图所示,我们只需要当车辆靠近时检测车辆,所以靠近时呈现出较为饱满的轮廓即可
2.3 识别车辆
获取汽车轮廓
# findContours(image, mode, method[, contours[, hierarchy[, offset]]])
新版本OpenCv返回两个结果,轮廓和层级,老版本返回三个参数,图像,轮廓,和层级
contours, hierarchy = cv2.findContours(close, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
设置检测阈值
min_w = 150
min_h = 150
max_w = 385
max_h = 368
画出所有检测出的轮廓
for contour in contours:
# 最大外接矩形
x, y, w, h = cv2.boundingRect(contour)
is_valid = (min_w < w < max_w) and (min_h < h < max_h )
if not is_valid:
continue
# 绘制矩形,要求坐标点都是整数
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
代码解析:首先对视频每一帧视频的白色区域查找最大外接矩形,然后根据车辆在合理位置的大小给定一个阈值变量 is_valid 得到满足画框的最大和最小边界值,效果如图所示:
3 对车辆进行统计
3.1 实现思路
在离我们摄像头(视频)较近位置放置一条实线,假想当车辆过线时,则对车辆计数。
计数思路:在检测到车辆(矩形框)设置一个中心点,当中心点的高超过我们设定实线的高时,则判定为有车辆经过,车辆计数+1。
3.2 设定统计区域
下面为代码实操
# 定义全局变量
line_high = 535
offset = 3
cars = []
carno= 0
cv2.line(frame, (50, line_high), (1250, line_high), (255, 255, 0), 3)
line_high= 535 为线的高度;
offset = 3是为计数区域设定的阈值,以防多数或少数
cars = [ ]把经过的每辆车的坐标存储到列表里
carno = 0 为车辆计数
生成外接矩形的中心点:
def center(x, y, w, h):
cx = int(x + w/2)
cy = int(y + h/2)
return cx, cy
将检测到车辆的中心坐标存储到cars列表
cpoint = center(x, y, w, h)
cars.append(cpoint)
3.3 对车辆进行计数
遍历列表cars中的中心点坐标,并判断是否在计数区域内,若在区域内则carno+1
# 判断汽车是否过线
for (x, y) in cars:
if y > (line_high - 1) and y < (line_high + offset):
# 落入有效区间
carno +=1
# print(carno)
cars.remove((x, y))
3.4 显示统计信息
cv2.putText(frame, 'Vehicle Count:' + str(carno), (750, 100), cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 255), 5)
效果如图所示
4 整体运行代码
附上整体运行代码,仅供参考
import cv2
import numpy as np
# 打开摄像头
cap = cv2.VideoCapture('./video.mp4')
# 创建MOG对象
mog = cv2.createBackgroundSubtractorMOG2()
# 获取形态学卷积
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5))
min_w = 150
min_h = 150
max_w = 385
max_h = 368
line_high = 535
offset = 3
cars = []
carno= 0
# 生成外接矩形的中心点
def center(x, y, w, h):
cx = int(x + w/2)
cy = int(y + h/2)
return cx, cy
# 循环读取视频
while True:
ret, frame = cap.read()
# 读取视频的每一帧,返回“标记”ret和这一帧的数据frame,读到数据ret为TRUE,没读到为Fales
if ret == True:
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 去噪
blur = cv2.GaussianBlur(gray, (13, 13), 15)
bgmask = mog.apply(blur)
# 腐蚀
erode = cv2.erode(bgmask, kernel)
# 膨胀
dialte = cv2.dilate(erode, kernel, iterations=4)
# 消除内部的小方块:闭运算
close = cv2.morphologyEx(dialte, cv2.MORPH_CLOSE, kernel, iterations=1)
# 获取车辆轮廓
contours, hierarchy = cv2.findContours(close, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cv2.line(frame, (50, line_high), (1250, line_high), (255, 255, 0), 3)
# 画出所有检测出来的轮廓
for contour in contours:
# 最大外接矩形
x, y, w, h = cv2.boundingRect(contour)
is_valid = (min_w < w < max_w) and (min_h < h < max_h )
if not is_valid:
continue
# 绘制矩形,要求坐标点都是整数
cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 2)
cpoint = center(x, y, w, h)
cars.append(cpoint)
# 判断汽车是否过线
for (x, y) in cars:
if y > (line_high - 1) and y < (line_high + offset):
# 落入有效区间
carno +=1
# print(carno)
cars.remove((x, y))
cv2.putText(frame, 'Vehicle Count:' + str(carno), (750, 100), cv2.FONT_HERSHEY_SIMPLEX, 2, (0, 0, 255), 5)
cv2.imshow('frame', frame)
# 用户按ESC退出
key = cv2.waitKey(1000//120) # 1000//60 可以调帧数
if key & 0xFF == 27:
break
print('车辆计数:', carno)
# 最后别忘了释放资源
cap.release()
cv2.destroyAllWindows()
标签:视频,计数,检测,frame,cv2,ret,OpenCv,车辆,line
From: https://blog.csdn.net/agentssl/article/details/144201495