基于OpenCv的车辆检测&计数

项目描述:在截取一段公路上车流量视频,通过OpenCv识别经过的车辆并进行计数统计。

汽车视频素材MP4

 本项目实践目的旨在学习运用OpenCV知识,所以只截取了视频的一部分

目录

一、所用到的OpenCv知识:

二、项目实现流程

1 将车流量视频加载出来

2 通过形态学识别车辆

2.1 前景/背景分割算法

2.2 去噪、腐蚀、膨胀以及闭运算操作

2.3 识别车辆

3 对车辆进行统计

3.1 实现思路

3.2 设定统计区域

3.3 对车辆进行计数

3.4 显示统计信息

4 整体运行代码


一、所用到的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()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Shark_L0ng

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值