【OpenCV学习】(九)目标识别之车辆检测与计数 您所在的位置:网站首页 输入车辆 【OpenCV学习】(九)目标识别之车辆检测与计数

【OpenCV学习】(九)目标识别之车辆检测与计数

2023-09-04 13:17| 来源: 网络整理| 查看: 265

【OpenCV学习】(九)目标识别之车辆检测及计数 背景

本篇将具体介绍一个实际应用项目——车辆检测及计数,在交通安全中是很重要的一项计数;当然,本次完全采用OpenCV进行实现,和目前落地的采用深度学习的算法并不相同,但原理是一致的;本篇将从基础开始介绍,一步步完成车辆检测计数的项目;

一、图像轮廓

本质:具有相同颜色或强度的连续点的曲线;

作用:

1、可用于图形分析;

2、应用于物体的识别与检测;

注意点:

1、为了检测的准确性,需要先对图像进行二值化或Canny操作;

2、画轮廓的时候回修改输入的图像,需要先深拷贝原图;

轮廓查找的函数原型:

findContours(img,mode,ApproximationMode…)

mode

RETR_EXTERNAL=0,表示只检测外轮廓;

RETR_LIST=1,检测的轮廓不建立等级关系;(常用)

RETR_CCOMP=2,每层最多两级;

RETR_TREE=3,按树形结构存储轮廓,从右到左,从大到小;(常用)

ApproximationMode

CHAIN_APPROX_BOBE:保存轮廓上所有的点;

CHAIN_APPROX_SIMPLE:只保存轮廓的角点;

代码实战:

img = cv2.imread('./contours1.jpeg') # 转变成单通道 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化 ret, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY) # 轮廓查找 contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

contours输出结果:

(array([[[ 0, 0]], [[ 0, 435]], [[345, 435]], [[345, 0]]], dtype=int32),)

可以看出,我们找最外层轮廓,找出了一个矩形轮廓的四个点;

当然,我们不需要通过画形状来绘制轮廓,可以通过一个内置函数来绘制轮廓;

绘制轮廓函数原型:

drawContours(img,contours,contoursIdx,color,thickness,…)

contours:表示保存轮廓的数组;contoursIdx:表示绘制第几个轮廓,-1表示所有轮廓;

代码案例:

img = cv2.imread('./contours1.jpeg') img2 = img.copy() # 转变成单通道 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化 ret, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY) # 轮廓查找 contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) cv2.drawContours(img, contours, -1, (0, 0, 255), 1) cv2.drawContours(img2, contours, -1, (0, 0, 255), -1) cv2.imshow('org', img) cv2.imshow('org2', img2) cv2.waitKey(0)

在这里插入图片描述

如上图所示,左图是线宽设置为1,右图为线宽设置为-1,也就是填充的效果;

当然,OpenCV还提供了计算轮廓周长和面积的方法;

轮廓面积函数原型:

contourArea(contour)

轮廓周长函数原型:

arcLength(curve,closed)

curve:表示轮廓;closed:是否是闭合的轮廓;

上述两个函数比较简单,在这就不做代码演示了;

二、多边形逼近与凸包

多边形逼近函数原型:

approxPolyDP(curve,epsilon,closed)

epslion:精度;

凸包的函数原型:

convexHull(points,clockwise,…)

points:轮廓;clockwise:绘制方向,顺时针或逆时针;(不重要)

首先我们看一下基于轮廓查找输出的轮廓形状:

在这里插入图片描述

可以看出轮廓点十分密集,接下来看一下基于多变形逼近和凸包的效果:

代码案例:

img = cv2.imread('./hand.png') img2 = img.copy() # 转变成单通道 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化 ret, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY) # 轮廓查找 contours, hierarchy = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) # cv2.drawContours(img, contours, -1, (0, 0, 255), 1) e = 20 approx = cv2.approxPolyDP(contours[0], e, True) # 多边形逼近 approx = (approx, ) cv2.drawContours(img, approx, 0, (0, 0, 255), 3) hull = cv2.convexHull(contours[0]) hull = (hull, ) cv2.drawContours(img2, hull, 0, (0, 0, 255), 3) # 凸包 cv2.imshow('org', img) cv2.imshow('org2', img2) cv2.waitKey(0)

在这里插入图片描述

这里需要注意一点,绘制轮廓的函数对于轮廓的传入需要为元组,需要将得到的数组放到一个元组中!

当然,多边形逼近这里设置的精度为20,所以比较粗糙,设置小一些可以达到更好的效果;

三、外接矩形

外接矩阵分为最大外接矩阵和最小外接矩阵,如下图所示:

在这里插入图片描述

最小外接矩阵还有一个功能,就是计算旋转角度,从上图的绿框应该可以很明显看出;

最小外接矩阵函数原型:

minAreaRect(points)

返回值:起始点(x,y)、宽高(w,h)、角度(angle)

最大外接矩形函数原型:

boundingRect(array)

返回值:起始点(x,y)、宽高(w,h)

代码案例:

img = cv2.imread('./hello.jpeg') img2 = img.copy() # 转变成单通道 gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) # 二值化 ret, binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY) # 轮廓查找 contours, hierarchy = cv2.findContours(binary, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE) # 获取最小外接矩形 r = cv2.minAreaRect(contours[1]) box = cv2.boxPoints(r) # 提取其中的点 box = np.int0(box) # 将浮点型转换为整型 cv2.drawContours(img, (box, ), 0, (0, 0, 255), 2) # 获取最大外接矩形 x, y, w, h = cv2.boundingRect(contours[1]) cv2.rectangle(img2, (x, y), (x+w, y+h), (0, 0, 255), 2) cv2.imshow('org', img) cv2.imshow('org2', img2) cv2.waitKey(0)

在这里插入图片描述

四、车辆统计实战

涉及的知识点:

窗口展示图像、视频的加载基本图形的绘制基本图像运算与处理形态学轮廓查找

实现流程:

加载视频 —— 通过形态学识别车辆 —— 对车辆进行统计 —— 显示统计信息

1、加载视频

这里就是一个简单加载视频的实现:

cap = cv2.VideoCapture('video.mp4') while True: ret, frame = cap.read() if(ret == True): cv2.imshow('video', frame) key = cv2.waitKey(1) if(key == 27): # Esc退出 break cap.release() cv2.destroyAllWindows() 2、去除背景

函数原型:

createBackgroundSubtractorMOG()

history:缓冲,表示多少毫秒,可不指定参数,用默认的即可;

具体实现原理比较复杂,用到了一些视频序列关联信息,把像素值不变的认为是背景;

注意:在opencv中已经不支持该函数,而是用createBackgroundSubtractorMOG2()替代;如果需要使用可以安装opencv_contrib模块,在其中的bgsegm中保留了该函数;

代码实现:

cap = cv2.VideoCapture('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('video', mask) key = cv2.waitKey(1) if(key == 27): # Esc退出 break cap.release() cv2.destroyAllWindows()

在这里插入图片描述

这里尽量采用旧版的MOG函数,新版的MOG2函数比较精细,会将树叶等信息输出,去除效果没那么好;

3、形态处理

这里主要是为了处理一些小的噪声点以及目标中的黑色块;

代码实现:

cap = cv2.VideoCapture('video.mp4') bgsubmog = cv2.bgsegm.createBackgroundSubtractorMOG() # 形态学kernel kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) 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) # 腐蚀 erode = cv2.erode(mask, kernel) # 膨胀 dilate = cv2.dilate(erode, kernel, 3) # 闭操作 close = cv2.morphologyEx(dilate, cv2.MORPH_CLOSE, kernel) close = cv2.morphologyEx(close, cv2.MORPH_CLOSE, kernel) contours, h = cv2.findContours(close, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE,) for (i, c) in enumerate(contours): (x, y, w, h) = cv2.boundingRect(c) cv2.rectangle(frame, (x, y), (x+w, y+h), (0,0,255), 2) cv2.imshow('video', frame) key = cv2.waitKey(1) if(key == 27): # Esc退出 break cap.release() cv2.destroyAllWindows()

在这里插入图片描述

从图中效果来看,还是会有很多小的检测框,接下来就是处理重合检测框以及去掉一些多余的检测框,类似于NMS去重,当然原理还不太一样;

4、车辆统计

首先需要过滤一些小的矩形,已经检测框的长和宽,设定一些阈值即可;

代码实现:

cap = cv2.VideoCapture('video.mp4') bgsubmog = cv2.bgsegm.createBackgroundSubtractorMOG() # 保存车辆中心点信息 cars = [] # 统计车的数量 car_n = 0 # 形态学kernel kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5, 5)) 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) # 腐蚀 erode = cv2.erode(mask, kernel) # 膨胀 dilate = cv2.dilate(erode, kernel, 3) # 闭操作 close = cv2.morphologyEx(dilate, cv2.MORPH_CLOSE, kernel) close = cv2.morphologyEx(close, cv2.MORPH_CLOSE, kernel) contours, h = cv2.findContours(close, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE,) # 画一条线 cv2.line(frame, (10, 550), (1200, 550), (0, 255, 255), 3) for (i, c) in enumerate(contours): (x, y, w, h) = cv2.boundingRect(c) # 过滤小的检测框 isshow = (w >= 90) and (h >= 90) if(not isshow): continue # 保存中心点信息 cv2.rectangle(frame, (x, y), (x+w, y+h), (0,0,255), 2) centre_p = (x + int(w/2), y + int(h/2)) cars.append(centre_p) cv2.circle(frame, (centre_p), 5, (0,0,255), -1) for (x, y) in cars: if(593


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有