【openCV学习】38.车辆检测计数项目 您所在的位置:网站首页 opencv计数大树上叶片物体数量 【openCV学习】38.车辆检测计数项目

【openCV学习】38.车辆检测计数项目

2024-06-20 17:33| 来源: 网络整理| 查看: 265

一.总体思路: (一).图像的预处理

这里把视频的每一帧截取出来当作图像逐帧处理

1.图像变成灰度图之后利用高斯滤波去噪(图像通道的转变以及高斯滤波)

                                                变成灰度图后的视频截图

                                                高斯滤波去噪后的视频截图

2.去噪后消除背景,在计算机视觉中,不动的叫背景,移动的叫前景(这里使用到了一个新的API,是关于去除视频背景的)

                                        进行视频背景去除后的视频截图

3.去掉背景后的视频,不动的地方是黑色的,移动的地方会显现出白色,会发现有黑色的背景有时会出现白色的小方块的噪声,因此采用腐蚀操作去除噪声(腐蚀)

4.因为腐蚀操作会把白色的移动过程中的汽车轮廓给缩小,因此还需要用膨胀操作让汽车变大,更加便于之后的车辆检测,由于车越大更加好判断,因此可以把膨胀操作的iterations设为2,让它膨胀两次,这也是不把3和4合并成一次开运算操作的原因(膨胀)

5.经过观察,白色的移动过程中的车辆中会有黑色的小方块的噪声,因此进行一次闭运算来去除,但是效果不太明显(闭运算)

                                        经过腐蚀膨胀以及闭运算后的视频截图

(二).车辆的查找以及绘制车辆轮廓

6.经过上述的处理后,噪声去除的差不多了,可以直接查找轮廓了(轮廓的查找)

7.把所有的轮廓的最大外接矩形都绘制出来(最大外接矩形的绘制)

8.经过观察,会发现,由于车内有车灯,车牌等物件,可能会在大车的轮廓框内包含一些小的车灯的,车牌的轮廓框,因此我们设置当宽和高大于某一个值的时候,才绘制出显示框,这样就可以把车灯和车牌等干扰项给排除掉

(三).车辆的计数

车辆的计数采取的方法是:找每个车辆的轮廓框的中心点,这个中心点经过一条检测线,就表示有一辆车从这条道路上驶过,车辆数目加一

用人眼做到这一点很容易,但是只用openCV,是无法将视频的这一帧和下一帧联系到一起的,只能单独对一张张的图片处理,因此我们设置一个阈值h,当这一帧检测线上下h的范围内存在上述的中心点,就代表这辆车经过了这条线

因此,设置这个阈值还是很重要的,如果设置小了,可能无法捕捉到中心点出现在那个范围内的一帧,如果设置大了,可能这一帧一辆车的中心点在这个范围内,下一帧同一辆车还没走出这个范围,造成重复计数

9.绘制出车辆轮廓的中心点(简单的数学计算以及圆点的绘制)

10.绘制检测线(直线的绘制)

11.车辆计数

12.在屏幕上显示车辆的数目

                                                        最终效果截图

二.背景消除

上述步骤中只有背景消除是前面没有学到的,因此在此记录一下

这里使用MOG算法进行背景消除,使用方法如下:

#1.创建对象 bgs = cv2.createBackgroundSubtractorMOG2() #2.调用函数即可,其中fream是要处理的图像,是视频加载器read()函数返回的第二个值,返回值fgmask是背景去除后的图像 fgmask = bgs.apply(blur)

 

三.完整代码 import cv2 import numpy as np """创建两个变量,分别为检测为车的最小宽度和高度,为最后的车辆检测而使用的""" min_w = 100#宽度最小为100像素才能认为是车 min_h = 90#高度最小为90像素才能认为是车 """检测线的位置""" line_high = 700#检测线画在y坐标为700的地方 """偏移量""" offset = 20#一帧视频,在检测线上线20的范围内出现了车辆,认为该车辆经过了检测线 """用来存放车辆坐标信息的列表""" cars = [] """记录车辆的数量""" num = 0 """计算外接矩形的中心点,为了美观封装成了一个函数""" def center(x,y,w,h): x1 = int(w/2) y1 = int(h/2) cx = int(x) + x1 cy = int(y) + y1 return cx,cy """获取腐蚀的卷积核,方便以后去噪(膨胀,腐蚀,闭运算等形态学操作)使用""" kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5)) """创建去除背景的对象""" bgs = cv2.createBackgroundSubtractorMOG2() """加载视频""" cap = cv2.VideoCapture("image/video2.mp4") while True: ret,fream = cap.read() if ret ==True: """图像的预处理,可以先去噪再消除背景也可以反过来""" #变成灰度图,然后去噪 gray = cv2.cvtColor(fream,cv2.COLOR_BGR2GRAY) #高斯滤波去噪 blur = cv2.GaussianBlur(gray,(3,3),5) #应用bgs来消除背景,经过处理后,不动的背景变成黑色,动的前景变成白色 fgmask = bgs.apply(blur) #经过高斯滤波消除噪声后,还有一些比较大块的噪声,用腐蚀操作消除 eroad = cv2.erode(fgmask,kernel) #腐蚀之后对车的部分造成了影响,再膨胀回来,并且希望车能够膨胀的更大一点,因此膨胀迭代两次,这也是不直接用开运算的原因 dilate = cv2.dilate(eroad,kernel,iterations=2) #消除车内黑色的小噪声,闭运算 close = cv2.morphologyEx(dilate,cv2.MORPH_CLOSE,kernel) """画出检测线,绘制都是在原图上绘制了""" cv2.line(fream,(10,line_high),(1880,line_high),(255,255,0),3) "查找并绘制轮廓" contours,h = cv2.findContours(close,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) for contour in contours:#因为同一帧有多辆车,有多个轮廓,因此需要用for循环这个列表 #绘制轮廓的最大外界矩形 (x,y,w,h) = cv2.boundingRect(contour) if (w < min_w)|(h < min_h):#只要有一个小于阈值,就认为不是车,continue掉,去判断下一个轮廓 continue #绘制轮廓,其中点的坐标都是整数 cv2.rectangle(fream,(int(x),int(y)),(int(x+w),int(y+h)),(0,0,255),2) """车辆计数""" #找到每个矩形的中心点 cpoint = center(x,y,w,h) #cars是一个列表,用于存储当前每个可以判定为车辆 的矩形的中心点 cars.append(cpoint) cv2.circle(fream,(cpoint),5,(0,0,255),-1) #如果该中心点在当前这一帧处于判断线附近,可以认为经过了判断线,这个范围offset需要调试 for (x,y) in cars: if y > (line_high-offset) and y < (line_high + offset): num+=1 #print(num) cars.remove((x,y)) """显示文字""" cv2.putText(fream,"Vehicle Count:"+str(num),(300,60),cv2.FONT_HERSHEY_SIMPLEX,2,(0,0,255),5) """最终显示的还是原图,而不是经过背景去除和去噪之后的图,背景去除和去噪只是为了查找车辆的轮廓位置""" cv2.imshow("video",fream) key = cv2.waitKey(30) if key == 27:#esc键 break #最后释放资源 cap.release() cv2.destroyAllWindows()

 

四.缺点

需要比较清晰并且比较干净的视频才行,因为毕竟是只用opencv实现,当地上车辆的影子经过斑马线的时候,可能斑马线会被误判成移动的物体,造成影响

并且需要车辆不是那么密集的视频,因为离得近会因为车辆影子的覆盖造成两辆车判断成一辆车

其次公路上车辆的速度有快有慢,因此偏移量offset无论怎么设都肯定会有重复计数和漏计的情况,只不过一个好的参数能适当减少这种情况

总之只用opencv来做这个东西效果并不好,真要达到很好的效果还是需要yolo加上一些其他的算法才能实现只能起到复习练手的目的,做这个的目的主要是为了复习之前的学习的知识点和练手



【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

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