使用OpenCV的车辆检测和计数系统

磐创AI

    概述
    在本文中,我们将编写一个车辆计数和检测系统。我们将使用OpenCV进行所有图像处理操作,并制作用于分类汽车和公交车的 haar 级联分类器,还可以制作你自己的 haar 级联分类器。
    
    范围
    1. 帮助交警:车辆检测和计数系统对交警来说是有益的,因为他们可以从一个地方监控的所有东西,只需要知道有多少车辆和哪些车辆通过了这个收费站。
    2. 维护记录:由于车辆实时经过,因此某些人很难记录所有车辆。这不像一个人正在观看视频,他们可以暂停它并对其进行注释,因此为了消除此限制,此应用程序可以非常熟练地以达到节省时间并实现自动化。
    3. 交通监控:由于此应用程序可以安装在任何地方,因为它只需要一个摄像头或一些电线(用于建立与中央系统的连接),因此如果某个地方的交通量很大,那么在该区域,员工可以对其进行监控并将信息转发给下一位收费员,以便他们提前做好准备。
    导入所需的库
    # Import libraries
    from PIL import Image
    import cv2
    import numpy as np
    import requests
    接下来,我们将从互联网上获取图像。然后我们将调整图像大小并将其转换为 NumPy 数组。
    从 URL 读取图像
    image = Image.open(requests.get('https://a57.foxnews.com/media.foxbusiness.com/BrightCove/854081161001/201805/2879/931/524/854081161001_5782482890001_5782477388001-vs.jpg', stream=True).raw)
    image = image.resize((450,250))
    image_arr = np.array(image)
    image
    输出:
    
    为了获得更好的输出,我们将对图像进行一些转换。在这里,我们将图像转换为灰度。
    灰度
    grey = cv2.cvtColor(image_arr,cv2.COLOR_BGR2GRAY)
    Image.fromarray(grey)
    输出:
    
    接下来,我们将应用高斯模糊去除图像中的噪声。
    高斯模糊是图像处理的技术之一。它也广泛用于图形设计,用于降低噪声和平滑图像,以便进行进一步的预处理,从而产生更好的输出。
    除了减少图像中的噪声,高斯模糊技术还减少了图像的细节。为了应用这种预处理技术,我们将使用 GaussianBlur() 函数。
    高斯模糊
    blur = cv2.GaussianBlur(grey,(5,5),0)
    Image.fromarray(blur)
    输出:
    
    在这里,我们将应用图像膨胀,膨胀是一种形态学技术,我们尝试用元素填充像素,也称为内核(结构化块),以在需要时填充图像的缺失部分。
    注意:它与腐蚀正好相反。膨胀
    dilated = cv2.dilate(blur,np.ones((3,3)))
    Image.fromarray(dilated)
    输出:
    
    现在我们将使用内核执行形态学转换。在这里,我们使用了一种Morphology-Ex技术,它告诉函数需要对其进行哪些图像处理操作。
    第二个参数是关于必须完成哪些操作,你 可能需要椭圆/圆形内核。为了使用 OpenCV 实现 Morphology-Ex 方法,我们将使用 getStructuringElement 方法。
    Morphology-Ex,结构元素
    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (2, 2))
    closing = cv2.morphologyEx(dilated, cv2.MORPH_CLOSE, kernel) 
    Image.fromarray(closing)
    使用汽车级联检测汽车
    现在我们需要一个汽车级联来检测汽车。所以,我们首先需要将它们上传到collab(如果你是在collab里做的),如果你是在本地机器里做的,那就把cascade文件添加到同一个文件夹中,并指定路径 car_cascade_src。
    这里我们将使用 CascadeClassifier 函数,即 OpenCV 的预定义函数,从预训练的 XML 文件(级联文件 - 汽车)中训练图像。我们需要检测多个对象,即汽车,才能使用 detectMultiScale。
    car_cascade_src = 'cars.xml'
    car_cascade = cv2.CascadeClassifier(car_cascade_src)
    cars = car_cascade.detectMultiScale(closing, 1.1, 1)
    cars
    输出:
    array([[376,   1,  22,  22],
                          [307,   4,  27,  27],
                          [196,  10,  28,  28],
                          [ 35,   2,  30,  30],
                          [150, 163,  68,  68],
                          [318, 121,  82,  82],
                          [101,   3,  43,  43],
                          [317,  66,  66,  66],
                          [274,  20,  38,  38],
                          [256,  52,  79,  79],
                          [245,  24,  20,  20],
                          [250,  35,  25,  25],
                          [ 63,  40,  22,  22],
                          [209,  88,  54,  54],
                          [ 13,  25,  43,  43],
                          [384,  84,  59,  59],
                          [145,  91,  53,  53],
                          [ 52,  44,  39,  39],
                          [237,  38,  49,  49],
                          [362,  43,  46,  46],
                          [268, 106,  60,  60]], dtype=int32)
    我们将使用上面返回的轮廓并在检测到的汽车周围绘制一个矩形。
    在这里,我们将看到它将在检测到的每辆车周围创建一个带有红色边框的矩形。
    cnt = 0
    for (x,y,w,h) in cars:
          cv2.rectangle(image_arr,(x,y),(x+w,y+h),(255,0,0),2)
          cnt += 1
    print(cnt, " cars found")
    Image.fromarray(image_arr)
    输出:
    21  cars found
    
    公交车检测
    现在我们将使用另一个图像,即公交车图像,我们将从互联网上获取该图像。我们将调整图像大小,将其存储为 NumPy 数组,并将其转换为灰度。
    # Reading image form url
    image2 = Image.open(requests.get('https://qph.fs.quoracdn.net/main-qimg-b5c4e39dcd48dddd9e609e6022f74d85', stream=True).raw)
    image2 = image2.resize((450,250))
    image_arr2 = np.array(image2)
    grey2 = cv2.cvtColor(image_arr2,cv2.COLOR_BGR2GRAY)
    我们在这里处理公交车图像,所以我们需要级联来检测公交车。我们将使用Bus_front 级联从图像中识别公交车,我们将执行与上述类似的操作。
    bus_cascade_src = 'Bus_front.xml'
    bus_cascade = cv2.CascadeClassifier(bus_cascade_src)
    bus = bus_cascade.detectMultiScale(grey2, 1.1, 1)
    正如我们在汽车级联中所做的类似,我们将对公交车图像执行相同的轮廓操作,并在检测到任何公交车时在公交车周围创建一个矩形。
    cnt = 0
    for (x,y,w,h) in bus:
            cv2.rectangle(image_arr2,(x,y),(x+w,y+h),(255,0,0),2)
            cnt += 1
    print(cnt, " bus's found")
    Image.fromarray(image_arr2)
    输出:
    1  bus's found
    
    现在我们将在视频中执行车辆检测和计数。
    为了从帧或图像创建输出视频, 我们需要 cv2.VideoWriter() 方法。它以带扩展名的路径作为第一个参数;第二个参数是输出格式的编解码器,还需要传递每秒帧数和高度和宽度。
    cascade_src = 'cars.xml'
    video_src = 'Cars.mp4'
    cap = cv2.VideoCapture(video_src)
    car_cascade = cv2.CascadeClassifier(cascade_src)
    video = cv2.VideoWriter('result.avi',cv2.VideoWriter_fourcc(*'DIVX'), 15, (450,250))
    现在我们将从输入视频中一一读取帧,将它们转换为灰度,并使用汽车级联来检测该特定帧中的所有汽车。最后,我们使用 video.write() 方法编写这个视频,video.release() 将这个视频保存到给定的路径。
    while True:
         ret, img = cap.read()
         if (type(img) == type(None)):
              break
               gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
               cars = car_cascade.detectMultiScale(gray, 1.1, 2)
       
        for (x,y,w,h) in cars:
                       cv2.rectangle(img,(x,y),(x+w,y+h),(0,255,255),2)
    video.write(img) 
    video.release()
    结论
    我们首先下载我们将要处理的图像并执行不同的操作。我们看到了如何使用用于物体检测的 haar 级联,以及如何使用不同的 haar 级联进行汽车检测和公交车检测。同样,你可以使用许多预训练的 haar 级联进行其他对象检测。
    由于 haar 级联用于对象检测,因此我们的范围很广。它可用于对象检测,我们还可以为特定对象创建自定义 haar 级联。
    尾注
    这是这篇文章的repo链接: