opencv案例: 车辆检测

opencv案例: 车辆检测

说明:这是在哔哩哔哩上看李超老师的视频时,他讲的案例,我是搬运工。

  • 实现功能:
    1、识别出图片中的汽车对象
    2、对车辆进行统计,并将统计结果展示出来

  • 涉及到的知识点:
    图像和视频的加载、展示;
    基本图像绘制;
    基本图像运算与处理;
    形态学处理(比如降噪、腐蚀膨胀);
    轮廓查找。

  • 实现代码
    import cv2
    import numpy as np
    
    cap = cv2.VideoCapture(r'C:\Users\25584\Desktop\video.mp4')   #加载视频文件, 第十九章知识点  
    bgsubmog = cv2.bgsegm.createBackgroundSubtractorMOG()         #视频去背景,第二十一章知识点
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))     #设置形态学处理的kernel,5x5的矩形即可,第八章知识点
    
    min_w = 90    #大轮廓和小轮廓的分界点
    min_h = 90    #大轮廓和小轮廓的分界点
    cars = []     #汽车轮廓的中心点坐标
    line_height = 580   #红计数线位置
    offset = 7          #计数线上下的偏移量
    carnum = 0          #车辆计数
    
    #------------用while循环读取视频中的图像帧并处理------------
    while True:                  #如果读取成功就将捕获的视频帧显示在video窗口里,如果读取不成功就打印出warning,并退出循环
        ret, frame = cap.read()  #cap对象的.read()方法
        if ret:
            cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)     #转成灰度图像
            blur = cv2.GaussianBlur(frame, (3,3), 5,5)  #高斯平滑去噪,第七章知识点
            mask = bgsubmog.apply(blur)                 #去背景,背景去掉后,留下都是动的物体,比如汽车、刮风动的树、草等,下面是形态学处理去除树和草
            erode = cv2.erode(mask, kernel)             #腐蚀,去掉小的斑块,腐蚀后草就不见了,树有时还能看到
            dilate = cv2.dilate(erode, kernel, iterations=3)  #膨胀3次,还原放大,因为腐蚀后物体变小了,不利于我们计算。
            close = cv2.morphologyEx(dilate, cv2.MORPH_CLOSE, kernel, iterations=2)      #闭操作2次,去掉汽车内部的小块   A
            
            cnts, h = cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)   #查找轮廓,就是找到每一个移动的汽车了
            
            for c in cnts:               #遍历这些轮廓
                (x,y, w,h) = cv2.boundingRect(c)    #给每个轮廓圈上矩形框,这样轮廓就变成xywh四个参数了
                
                isValid = (w>=min_w) and (h>=min_h)    #去除小轮廓,比如车灯的轮廓,我们不需要。判断如果矩形框的最小宽高小于90,就是小轮廓,就忽略continue
                if not isValid:
                    continue   #宽高小于90的就忽略,跳过,继续循环;如果大于90,就是有效的车辆,就把这个矩形框的中心点记下来
                    
                cv2.rectangle(frame, (x,y), (x+w, y+h), (0,0,255), 2)   #在原图上,把大轮廓用红色矩形框圈出来
                
                x1 = int(w/2)  #计算大轮廓的中心点,也就是矩形框的中心点,并把中心点都放到cars里面
                y1 = int(h/2)
                cx = x + x1
                cy = y + y1
                cpoint = (cx, cy)
                cars.append(cpoint)
    
            cv2.line(frame, (10,line_height), (1200, line_height), (255,255,0),2)   #画一条计数线,穿过计数线的车就计数
            
            for (x,y) in cars:    #看cars里面的中心点是否在计数线的附近,就是车经过了这个计数线我们就计数  
                if (y<(line_height+offset) and y>(line_height-offset)):
                    carnum +=1
            cars=[]
            cv2.putText(frame, 'Cars Count:'+str(carnum), (100, 70), cv2.FONT_HERSHEY_SIMPLEX, 2, (255,0,255), 5)  #第18章知识点,讲计数结果显示在视频上
            cv2.imshow('video', frame) 
            
        else:
            print('warning: video is not load correctly or the video is finished')
            break
            
        key = cv2.waitKey(1)   #每一帧图像就显示一毫秒就可以,然后继续循环
        if key == 27:          #27是esc的ascall码
            break
    cap.release()              #释放视频资源
    cv2.destroyAllWindows()    #释放窗口资源

    解释:A:膨胀3次后我们发现汽车中间还有一些小斑块,这些斑块也要去掉,因为这些小斑块影响后面对汽车画轮廓,有斑块轮廓就很乱,所以要把汽车内部的小斑块也去掉,就用闭操作去斑块。

    总结: 本案例的车辆检测方法是最传统的一种方法,如果车辆计数不准确了,要么是我们的计数线设置的位置不合适,位置太低,从下往上的车可能就检测不到;要么就是计数线上下的偏移量设置得不合适,过宽会出现重复计数,过窄容易漏计。所以这种方法的效果也是一般,最主要的原因还是我们在统计车辆的时候,无法对每个车辆做一个唯一的标识。由于视频是连续的,如果车辆行驶的过快,我们很可能捕捉不到,出现漏计;如果车辆行驶的很慢,我们就可能捕捉它两次甚至更多次,就出现重复计数。这是传统车辆检测方法的最重要的一个弊端。现在我们一般都采用深度学习算法去检测,我们通过训练数据建立一个模型,用模型判断每辆车并且判断从进入视野到出了视野同一辆车有唯一一个标识,也就是现实车辆的追踪的效果,这样就不会漏记和重复计数。

猜你喜欢

转载自blog.csdn.net/friday1203/article/details/125543607