likes
comments
collection
share

openCV+python实现视频中的车辆检测

作者站长头像
站长
· 阅读数 4
import numpy as np
import cv2 as cv
import  time
class Car:
    def __init__(self,c_id,c_x,c_y,direction,c_count,c_start_time,c_over_time,c_v):
        self.c_id = c_id
        self.c_x=c_x
        self.c_y=c_y
        self.direction = direction
        self.c_count = c_count
        self.c_start_time = c_start_time
        self.c_over_time = c_over_time
        self.c_v = c_v
    def updateCoords(self,x,y):
        self.c_x= x
        self.c_y=y

count_up = 0
count_down = 0
cars = []
pid = 1
max_v = 0
distance = 10
# 读取视频
vc = cv.VideoCapture(r"C:\Users\zn\Desktop\监控录像_1.mp4")
# 用来设置需要保存视频的格式 XVID是MPEG-4编码类型
fourcc = cv.VideoWriter_fourcc(*'XVID')
# 保存视频
out = cv.VideoWriter('output.avi',fourcc,15, (1920,1080))
# 动态目标检测算法
# history:用于训练背景的帧数,默认为500帧,如果不手动设置learningRate,history就被用于计算当前的learningRate,此时history越大,learningRate越小,背景更新越慢;
# varThreshold:方差阈值,用于判断当前像素是前景还是背景。一般默认16,如果光照变化明显,如阳光下的水面,建议设为25,36,具体去试一下也不是很麻烦,值越大,灵敏度越低;
# detectShadows:是否检测影子,设为true为检测,false为不检测,检测影子会增加程序时间复杂度,如无特殊要求,建议设为false;
BS = cv.createBackgroundSubtractorMOG2(detectShadows=True)
while (vc.isOpened()):
    ret, frame = vc.read()
    # cv.imshow("frame01",frame)
    # cv::cvtColor()用于将图像从一个颜色空间转换到另一个颜色空间的转换(目前常见的颜色空间均支持)
    gray = cv.cvtColor(frame,cv.COLOR_BGR2GRAY)
    # ret,gray = cv.threshold(gray,127,255,cv.THRESH_BINARY)
    fgmask = BS.apply(gray)
    # cv.medianBlur中值滤波,图像模糊处理
    image = cv.medianBlur(fgmask,5)
    # cv.imshow("BS",fgmask)
    # *getStructuringElement*函数会返回指定形状和尺寸的结构元素
    element = cv.getStructuringElement(cv.MORPH_RECT,(5, 5));#创建结构体
    # 利用morphologyEx这个函数可以方便的对图像进行一系列的膨胀腐蚀组合,它被用来去除噪声
    image2 = cv.morphologyEx(image, cv.MORPH_CLOSE,element,iterations=5);#闭运算
    # image3 = cv.erode(image2, element)
    image3 = cv.morphologyEx(image2, cv.MORPH_OPEN, element, iterations=5)
    # cv.imshow('frame1', image3)
    # cv.findContours检测物体的轮廓
    contours, hierarchy = cv.findContours(image3, cv.RETR_TREE, cv.CHAIN_APPROX_NONE)
    # 
    void cv::putText(
		cv::Mat& img, // 待绘制的图像
		const string& text, // 待绘制的文字
		cv::Point origin, // 文本框的左下角
		int fontFace, // 字体 (如cv::FONT_HERSHEY_PLAIN)
		double fontScale, // 尺寸因子,值越大文字越大
		cv::Scalar color, // 线条的颜色(RGB)
		int thickness = 1, // 线条宽度
		int lineType = 8, // 线型(4邻域或8邻域,默认8邻域)
		bool bottomLeftOrigin = false // true='origin at lower left'
	);
# cv.line -   在图像 `img` 上的两点 `pt1`, `pt2` 之间画一条线段
# -   `img`:要在上面画线段的图像
# -   `pt1`:线段的第 1 个点
# -   `pt2`:线段的第 2 个点
# -   `color`:线段的颜色
# -   `thickness`:线段的粗细
# -   `lineType`:线段的类型
# -   `shift`:坐标精确到小数点后第几位
    cv.line(frame, (0, 700), (1920, 700), (0, 255, 0), 3)
    cv.line(frame, (0, 400), (1920, 400), (0, 255, 0), 3)
    cv.line(frame, (0, 800), (1920, 800), (255, 255, 255), 2)
    cv.line(frame, (0, 300), (1920, 300), (255, 255, 255), 2)
    cv.putText(frame,"Up:"+str(count_up),(1100,100),cv.FONT_HERSHEY_COMPLEX,2,(255,0,0),3)
    cv.putText(frame, "Down:" + str(count_down),(700, 100), cv.FONT_HERSHEY_COMPLEX, 2, (255, 0, 0), 3)
    cv.putText(frame, "max_v:" + str('%.2f' %(max_v*3.6))+'km/h', (50, 100), cv.FONT_HERSHEY_COMPLEX, 1.5, (255, 0, 0), 2)
    null = True #如果这一帧没有检测到任何车,则将cars置空,减小误差,设置初始变量null设为True
    for cnt in contours:
        # cv.boundingRect 用一个最小的矩形,把找到的形状包起来
        x, y, w, h = cv.boundingRect(cnt)
        cx = int(x + w / 2)
        cy = int(y + h / 2)
        if 300<int(y+(h/2))<800 and 400<int(x+(w/2))<1800:
            # cv.contourArea主要用于计算图像轮廓的面积
            if cv.contourArea(cnt) < 13000 or w < 100 or h < 100:
                continue
            null = False #有车时不会清空
            new = True  #是否创建车辆
            for i in cars:
                if  abs(cx-i.c_x) <100 and abs(cy - i.c_y)<100:#找到这辆车与上一帧中最近的车
                    # cv.putText(frame, 'cid:' + str(i.c_id), (x, y-10), cv.FONT_HERSHEY_COMPLEX, 1, (255, 0, 0), 2)
                    # cv.putText(frame, "now_v:" + str('%.4f' % (i.c_v)) + 'm/s', (x, y-10),
                    #            cv.FONT_HERSHEY_COMPLEX, 1,
                    #            (255, 0, 0), 2)
                    new = False
                    i.updateCoords(cx,cy)#更新车辆位置信息
                    if 700<=i.c_y<=720 and i.direction =='down' and i.c_count ==False:
                        i.c_over_time = time.time()
                        i.c_v = distance/(i.c_over_time - i.c_start_time)
                        if i.c_v>max_v:
                            max_v = i.c_v
                        count_down+=1
                        i.c_count=True
                    if 380<=i.c_y<=400 and i.direction =='up' and (i.c_count == False):
                        i.c_over_time = time.time()
                        i.c_v = distance/ (i.c_over_time - i.c_start_time)
                        if i.c_v > max_v:
                            max_v = i.c_v
                        count_up+=1
                        i.c_count=True
                if i.c_y>720 or i.c_y<380:
                    cars.remove(i) #超过一定范围,删除对象

            if new == True and 340<cy<760: #符合一定条件,创建对象
                start_time = time.time()
                p = Car(pid, cx, cy, 'unknow', False, start_time ,0,0)
                if p.c_x <1000:
                    p.direction = 'down'
                else:
                    p.direction = 'up'
                cars.append(p)
                pid += 1
            cv.circle(frame, (cx, cy), 5, (0, 0, 255), -1)
            cv.rectangle(frame, (x, y), (x + w, y + h), (0, 0, 255), 3)
    if null == True:    #该帧没车,清空cars
        cars = []
    # cv.putText(frame, 'cars:' + str(len(cars)), (100, 100), cv.FONT_HERSHEY_COMPLEX, 2, (255, 0, 0), 3)
    cv.imshow("frame",frame)
    out.write(frame)
    #cv.imshow('frame2', image3)
    # print(max_v*3.6)
    #cv.WaitKey**(**int k**)函数的功能是刷新图像,其中参数k单位是毫秒,表示刷新频率
    k = cv.waitKey(30) & 0xff
    if k == 27:
        break
vc.release()
cv.destroyAllWindows()