发布时间:2022-09-03 08:00
写在开头,接触opencv也有很长一段时间了,中间还接触了halcon。但都是基于C++实现,发现如果有什么idea,还是使用python可以快速实现。基于C++版本的后期会有更新。
首先,这个案例是一个老生常谈的问题-车辆识别。首先我们要理解,车辆识别所需要的opencv知识点都有什么?并不是说拿到项目就是一顿狂干,首先要做分析-需求分析,然后才是概要设计,详细设计等…
先不考虑使用QT实现界面,就仅仅以opencv为基准,包括:窗口的展示,图像/视频的加载;基本图形的绘制;车辆的识别。车辆的识别包括基本图像运算和处理,形态学基础,轮廓的查找,文字显示等其次考虑需要的功能:1、加载车辆视频;2、通过形态学识别车辆;3、对车辆进行统计;4、显示车辆统计信息。
import cv2
import numpy as np
cap = cv2.VideoCapture('./img/Video.wmv')
if cap is None:
print("路径问题")
else:
while True:
#读取视频帧
ret,frame = cap.read()
if(ret == True):
cv2.imshow('cap',frame)
key = cv2.waitKey(10)
if(key == 27):
break
#释放缓存资源
cap.release()
#释放所有窗口
cv2.destroyAllWindows()
结果如下图:
2. 去除背景:以上图为例,可以分为前景和背景,公路和花坛这些对比起车辆来说是固定不变的,变得是来来往往的车辆。所以呢,公路和花坛可以认定为背景。来来往往的车辆可以认定为前景。我们需要去除背景,单独处理各种车辆才能准确识别车辆。这也是这一步骤的存在意义。
当然去除背景会有很多的噪点存在如图:
所以我们还需要进行图像灰度化和高斯去噪。经过测试发现,去除背景之前进行灰度化和高斯去噪效果会好很多。具体代码如下:
高斯数值需要自己根据自己视频尝试修改
import cv2
import numpy as np
cap = cv2.VideoCapture('./img/Video.wmv')
#引入去背景函数
bgsubmog = cv2.bgsegm.createBackgroundSubtractorMOG()
if cap is None:
print("路径问题")
else:
while True:
#读取视频帧
ret,frame = cap.read()
if(ret == True):
gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
#去除背景
##高斯去噪
blur = cv2.GaussianBlur(gray,(7,7),sigmaX=5)
##使用函数去背景
mask = bgsubmog.apply(blur)
cv2.imshow('mask',mask)
key = cv2.waitKey(10)
if(key == 27):
break
#释放缓存资源
cap.release()
#释放所有窗口
cv2.destroyAllWindows()
import cv2
import numpy as np
cap = cv2.VideoCapture('./img/Video.wmv')
#引入去背景函数
bgsubmog = cv2.bgsegm.createBackgroundSubtractorMOG()
if cap is None:
print("路径问题")
else:
while True:
#读取视频帧
ret,frame = cap.read()
if(ret == True):
gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
#去除背景
blur = cv2.GaussianBlur(gray,(7,7),sigmaX=5)
mask = bgsubmog.apply(blur)
#卷积核
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
kernel2 = cv2.getStructuringElement(cv2.MORPH_RECT,(7,7))
#腐蚀操作-去除背景中较小的噪点
erode = cv2.erode(mask,kernel,iterations=2)
#膨胀操作:还原放大车辆
dilate = cv2.dilate(erode,kernel,iterations=3)
#闭运算-填补车辆像素空隙
close1 = cv2.morphologyEx(dilate,cv2.MORPH_CLOSE,kernel2)
close2 = cv2.morphologyEx(close1,cv2.MORPH_CLOSE,kernel2)
#发现轮廓
cnts,hi = cv2.findContours(close2,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
#取出轮廓点绘图
for (i,c) in enumerate(cnts):
x,y,w,h = cv2.boundingRect(c)
cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)
cv2.imshow('frame',frame)
#cv2.imshow('dilate',dilate)
key = cv2.waitKey(10)
if(key == 27):
break
#释放缓存资源
cap.release()
#释放所有窗口
cv2.destroyAllWindows()
结果如图所示:
4. 车辆的统计
此步骤主要是优化上一步骤出现的车辆在运行过程中出现一辆车多个识别框。可能是车窗、车牌等。首先,我们设置一个最小宽度和高度的矩形作为判断依据,这边我设置的是100,大于100的可以作为真实的车辆,否则就是车牌或者车窗。接着,我们不能出现车辆就判断,因为车辆是运动的,所以需要一条检测线,在检测线上下做一个判断范围,只要各个有效车辆所代表的的矩形框进去这个区间,就代表有一辆车辆行驶过。既简单来说就是,线有一个范围,根据矩形中心点在进入这个范围就代表有车辆经过。
import cv2
import numpy as np
#判断是否是车辆的最小矩形
min_w = 100
min_h = 100
#检测线的高度
line_high = 300
#统计有效车的数组
cars = []
#线的偏移量
offset = 6
#统计数量
carno = 0
#计算中心点函数
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('./img/Video.wmv')
#引入去背景函数
bgsubmog = cv2.bgsegm.createBackgroundSubtractorMOG()
if cap is None:
print("路径问题")
else:
while True:
#读取视频帧
ret,frame = cap.read()
#print(frame.shape)
if(ret == True):
gray = cv2.cvtColor(frame,cv2.COLOR_BGR2GRAY)
#去除背景
blur = cv2.GaussianBlur(gray,(7,7),sigmaX=5)
mask = bgsubmog.apply(blur)
#卷积核
kernel = cv2.getStructuringElement(cv2.MORPH_RECT,(5,5))
kernel2 = cv2.getStructuringElement(cv2.MORPH_RECT,(9,9))
#腐蚀操作-去除背景中较小的噪点
erode = cv2.erode(mask,kernel,iterations=2)
#膨胀操作:还原放大车辆
dilate = cv2.dilate(erode,kernel2,iterations=1)
#闭运算-填补车辆像素空隙
close1 = cv2.morphologyEx(dilate,cv2.MORPH_CLOSE,kernel2)
#close2 = cv2.morphologyEx(close1,cv2.MORPH_CLOSE,kernel2)
#发现轮廓
cnts,hi = cv2.findContours(close1,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
#检测线
cv2.line(frame,(10,line_high),(1316,line_high),(255,255,8),3)
#取出轮廓点绘图
for (i,c) in enumerate(cnts):
x,y,w,h = cv2.boundingRect(c)
#对车辆的宽高进行判断,验证是否是有效的车辆
isValid = (w>=min_w) & (h>=min_h)
if(not isValid):
continue
#得到有效车辆信息
cv2.rectangle(frame,(x,y),(x+w,y+h),(255,0,0),2)
#计算有效车辆的中心点
cpoint = center(x,y,w,h)
cars.append(cpoint)
for(x,y) in cars:
if(y>line_high-offset & y<line_high+offset):
carno +=1
cars.remove((x,y))
print(carno)
cv2.imshow('frame',frame)
#cv2.imshow('dilate',dilate)
key = cv2.waitKey(10)
if(key == 27):
break
#释放缓存资源
cap.release()
#释放所有窗口
cv2.destroyAllWindows()
4. 文字显示
这个为最后一个步骤就是让得到的车辆信息,使用文字实时显示出来,使用代码如下
cv2.putText(frame,"Cars Count:"+str(carno),(500,50),cv2.FONT_HERSHEY_SIMPLEX,2,(0,255,0),2)
综上,就是使用python实现基于opencv的车辆识别系统的操作。其中对opencv中形态学的使用较为重要。后期别的案例也是对此处内容重复使用。
**
**