使用OpenCV和Python构建本身的车辆检测模型

做者|PRATEEK JOSHI 编译|Flin 来源|analyticsvidhyapython

概述

  • 你对智慧城市的想法感到兴奋吗?若是是的话,你会喜欢这个关于创建你本身的车辆检测系统的教程的算法

  • 在深刻实现部分以前,咱们将首先了解如何检测视频中的移动目标app

  • 咱们将使用OpenCV和Python构建自动车辆检测器框架

介绍

我喜欢智慧城市的理念。自动智能能源系统、电网、一键接入端口的想法等等。这是一个使人着迷的概念!老实说,这是一个数据科学家的梦想,我很高兴世界上不少城市都在朝着更智能的方向发展。机器学习

智能城市的核心组成部分之一是自动交通管理。这不由让我思考——我能用个人数据科学知识来创建一个车辆检测模型,在智能交通管理中发挥做用吗?ide

想一想看,若是你能在红绿灯摄像头中集成车辆检测系统,你能够轻松地同时跟踪许多有用的东西:函数

  • 白天交通路口有多少辆车?
  • 何时交通堵塞?
  • 什么样的车辆(重型车辆、汽车等)正在经过交叉路口?
  • 有没有办法优化交通,并经过不一样的街道进行分配?

还有不少例子就不一一列举。应用程序是无止境的!学习

咱们人类能够很容易地在一瞬间从复杂的场景中检测和识别出物体。然而,将这种思惟过程转化为机器的思惟,须要咱们学习使用计算机视觉算法进行目标检测。优化

所以在本文中,咱们将创建一个自动车辆检测器和计数器模型。如下视频是你能够期待的体验:ui

https://youtu.be/C_iZ2yivskE

注意:还不懂深度学习和计算机视觉的新概念?如下是两门热门课程,可开启你的深度学习之旅:

目录

  1. 视频中运动目标检测的思想

  2. 视频中目标检测的真实世界用例

  3. 视频目标检测的基本概念

  • 帧差分

  • 图像阈值

  • 检测轮廓

  • 图像膨胀

  1. 利用OpenCV构建车辆检测系统

视频中运动目标检测的思想

目标检测是计算机视觉中一个引人入胜的领域。当咱们处理视频数据时,它达到了一个全新的水平,复杂性上升了一个等级,但也有回报!

咱们可使用目标检测算法来执行超级有用的高价值任务,如监视、交通管理、打击犯罪等。下面的GIF图演示了这个想法:

在目标检测中,咱们能够执行许多子任务,例如计算目标数量、查找目标的相对大小或查找目标之间的相对距离。这些子任务都很重要,由于它们有助于解决一些最棘手的现实问题。

若是你但愿从头开始学习目标检测,我建议你使用如下教程:

让咱们看看一些使人兴奋的现实世界中的目标检测用例。

视频中目标检测的真实世界用例

现在,视频目标检测正被普遍应用于各个行业。使用案例从视频监控到体育广播,再到机器人导航。

好消息是,在将来的视频目标检测和跟踪用例中,可能性是无穷的。这里我列出了一些有趣的应用程序:

视频目标检测的基本概念

在开始构建视频检测系统以前,你应该知道一些关键概念。一旦你熟悉了这些基本概念,就能够为你选择的任何用例构建本身的检测系统。

那么,你但愿如何检测视频中的移动目标?

咱们的目标是捕捉运动物体的坐标并在视频中突出显示该物体。请考虑下面视频中的这一帧:

咱们但愿咱们的模型可以检测视频中的运动目标,如上图所示。检测到移动的汽车,并在汽车周围建立一个边界框。

解决这个问题有多种方法。你能够为目标检测训练一个深度学习模型,也能够选择一个预先训练好的模型并根据你的数据对其进行微调。然而,这些方法都是有监督的学习方法,须要标记数据来训练目标检测模型。

在本文中,咱们将重点讨论视频中无监督的目标检测方法,即不使用任何标记数据的目标检测。咱们将使用帧差分技术。让咱们了解它是如何工做的!

帧差分

视频是一组按正确顺序堆叠在一块儿的帧。因此,当咱们看到一个物体在视频中移动时,这意味着这个物体在每个连续的帧上都处于不一样的位置。

若是咱们假设除了该目标以外,在一对连续的帧中没有其余物体移动,那么第一帧与第二帧的像素差将突出显示移动目标的像素。如今,咱们获得了移动物体的像素和坐标。这就是帧差分法的工做原理。

举个例子。考虑视频中的如下两个帧:

你能看出这两帧的区别吗?

握笔的手的位置从第1帧变为第2帧。其他的物体根本没有移动。因此,正如我前面提到的,为了定位移动目标,咱们将执行帧差分。结果以下:

你能够看到高亮或白色区域,这是手最初出现的地方。除此以外,记事本的边缘也会突出显示一点。这多是因为手的移动改变了光照。建议不要对静止物体进行没必要要的检测。所以,咱们须要对帧执行某些图像预处理步骤。

图像阈值

在这种方法中,灰度图像的像素值根据阈值被指定为表示黑白颜色的两个值之一。所以,若是一个像素的值大于一个阈值,它被赋予一个值,不然它被赋予另外一个值。

在本例中,咱们将对上一步骤中帧差分的输出图像应用图像阈值:

你能够看到,不须要的高亮区域的大部分已经消失了。高亮显示的“记事本”边缘再也不可见。合成的图像也能够称为二值图像,由于其中只有两种颜色。在下一个步骤中,咱们将看到如何捕获这些高亮区域。

检测轮廓

轮廓用于识别图像中具备相同颜色或强度的区域的形状。轮廓就是目标区域周围的边界。所以,若是咱们在阈值步骤后对图像应用轮廓检测,咱们将获得如下结果:

白色区域被浅灰色的边界所包围,这些边界就是轮廓。咱们很容易获得这些轮廓的坐标。这意味着咱们能够获得高亮区域的位置。

请注意,有多个高亮显示区域,每一个区域由轮廓包围。在咱们的例子中,具备最大面积的轮廓是咱们指望的区域。所以,轮廓最好尽量少。

在上图中,仍然有一些没必要要的白色区域碎片。还有改进的余地。咱们的想法是合并附近的白色区域以得到更少的轮廓,为此,咱们可使用另外一种称为图像膨胀的技术。

图像膨胀

这是对图像的卷积操做,其中核心(矩阵)传递到整个图像上。为了给你直觉,右边的图像是左边图像的放大版本:

因此,让咱们对咱们的图像进行图像膨胀,而后咱们将再次找到轮廓:

事实证实,许多支离破碎的区域已经相互融合。如今咱们能够再次在这张图片中找到轮廓:

在这里,咱们只有四个候选轮廓,从中咱们能够选择一个有最大面积的轮廓。也能够在原始帧上绘制这些轮廓,以查看轮廓围绕移动目标的状况:

用OpenCV和Python构建车辆检测系统

咱们准备创建咱们的车辆检测系统!在这个实现中,咱们将大量使用计算机视觉库OpenCV(4.0.0版)(https://www.analyticsvidhya.com/blog/2019/03/opencv-functions-computer-vision-python/?utm_source=blog&utm_medium=vehicle-detection-opencv-python) 。咱们先导入所需的库和模块。

导入库
import os
import re
import cv2 # opencv library
import numpy as np
from os.path import isfile, join
import matplotlib.pyplot as plt
导入视频帧

请今后连接下载原始视频的帧。

https://drive.google.com/file/d/1P0yiO5KlnU8dGgB_L68KB_hjIvUec55f/view

将框架保存在工做目录中名为“frames”的文件夹中。从该文件夹中,咱们将导入帧并将其保存在列表中:

# get file names of the frames
col_frames = os.listdir('frames/')

# sort file names
col_frames.sort(key=lambda f: int(re.sub('\D', '', f)))

# empty list to store the frames
col_images=[]

for i in col_frames:
    # read the frames
    img = cv2.imread('frames/'+i)
    # append the frames to the list
    col_images.append(img)
数据探索

让咱们显示两个连续的帧:

# plot 13th frame
i = 13

for frame in [i, i+1]:
    plt.imshow(cv2.cvtColor(col_images[frame], cv2.COLOR_BGR2RGB))
    plt.title("frame: "+str(frame))
    plt.show()

很难在这两个框架中找到区别,不是吗?如前所述,获取两个连续帧的像素值的差值将有助于咱们观察移动目标。那么,让咱们在上面两个帧上使用该技术:

# convert the frames to grayscale
grayA = cv2.cvtColor(col_images[i], cv2.COLOR_BGR2GRAY)
grayB = cv2.cvtColor(col_images[i+1], cv2.COLOR_BGR2GRAY)

# plot the image after frame differencing
plt.imshow(cv2.absdiff(grayB, grayA), cmap = 'gray')
plt.show()

如今咱们能够清楚地看到第13帧和第14帧中的移动目标。其余没有移动的东西都被减去了。

图像预处理

让咱们看看对上面的图像应用阈值后会发生什么:

diff_image = cv2.absdiff(grayB, grayA)

# perform image thresholding
ret, thresh = cv2.threshold(diff_image, 30, 255, cv2.THRESH_BINARY)

# plot image after thresholding
plt.imshow(thresh, cmap = 'gray')
plt.show()

如今,移动物体(车辆)看起来更像咱们指望看到的那样了,大部分噪音(不但愿出现的白色区域)都消失了。可是,突出显示的区域有点零碎。所以,咱们能够对该图像应用图像膨胀:

# apply image dilation
kernel = np.ones((3,3),np.uint8)
dilated = cv2.dilate(thresh,kernel,iterations = 1)

# plot dilated image
plt.imshow(dilated, cmap = 'gray')
plt.show()

移动的物体有更多的实心高亮区域。但愿帧中每一个目标的轮廓数不超过3。

可是,咱们不会使用整个框架来检测移动的车辆。咱们将首先选择一个区域,若是车辆进入该区域,则仅检测到该区域。

那么,让我向你展现咱们将会使用的区域:

# plot vehicle detection zone
plt.imshow(dilated)
cv2.line(dilated, (0, 80),(256,80),(100, 0, 0))
plt.show()

水平线y = 80如下的区域是咱们的车辆检测区域。咱们将只检测在这个区域发生的任何移动。你还能够建立本身的检测区。

如今让咱们在上述帧的检测区域中找到轮廓:

# find contours
contours, hierarchy = cv2.findContours(thresh.copy(),cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)

上面的代码查找整个图像中的全部轮廓,并将它们保存在变量"contours"中。因为咱们只须要找到检测区域中存在的轮廓,咱们将对发现的轮廓进行两次检查。

第一个检查是轮廓左上角的y坐标是否应大于等于80(我这里包括另外一个检查,x坐标小于等于200)。另外一个检查是轮廓的面积应该大于等于25。在cv2.courtoArea()函数的帮助下,你能够找到轮廓区域。

valid_cntrs = []

for i,cntr in enumerate(contours):
    x,y,w,h = cv2.boundingRect(cntr)
    if (x <= 200) & (y >= 80) & (cv2.contourArea(cntr) >= 25):
        valid_cntrs.append(cntr)

# count of discovered contours        
len(valid_cntrs)

接下来,让咱们绘制轮廓和原始帧:

dmy = col_images[13].copy()

cv2.drawContours(dmy, valid_cntrs, -1, (127,200,0), 2)
cv2.line(dmy, (0, 80),(256,80),(100, 255, 255))
plt.imshow(dmy)
plt.show()

太酷了!只有位于检测区域内的车辆轮廓可见。这就是咱们在整个画面中检测车辆的方法

视频中的车辆检测

如今是时候对全部帧应用相同的图像变换和预处理操做,并找到所需的轮廓。重申一下,咱们将遵循如下步骤:

  1. 对每对连续帧应用帧差分

  2. 对上一步的输出图像应用图像阈值

  3. 对上一步的输出图像进行图像放大

  4. 在上一步的输出图像中查找轮廓

  5. 检测区域出现的候选轮廓

  6. 保存帧与最终轮廓

# kernel for image dilation
kernel = np.ones((4,4),np.uint8)

# font style
font = cv2.FONT_HERSHEY_SIMPLEX

# directory to save the ouput frames
pathIn = "contour_frames_3/"

for i in range(len(col_images)-1):
    
    # frame differencing
    grayA = cv2.cvtColor(col_images[i], cv2.COLOR_BGR2GRAY)
    grayB = cv2.cvtColor(col_images[i+1], cv2.COLOR_BGR2GRAY)
    diff_image = cv2.absdiff(grayB, grayA)
    
    # image thresholding
    ret, thresh = cv2.threshold(diff_image, 30, 255, cv2.THRESH_BINARY)
    
    # image dilation
    dilated = cv2.dilate(thresh,kernel,iterations = 1)
    
    # find contours
    contours, hierarchy = cv2.findContours(dilated.copy(), cv2.RETR_TREE,cv2.CHAIN_APPROX_NONE)
    
    # shortlist contours appearing in the detection zone
    valid_cntrs = []
    for cntr in contours:
        x,y,w,h = cv2.boundingRect(cntr)
        if (x <= 200) & (y >= 80) & (cv2.contourArea(cntr) >= 25):
            if (y >= 90) & (cv2.contourArea(cntr) < 40):
                break
            valid_cntrs.append(cntr)
            
    # add contours to original frames
    dmy = col_images[i].copy()
    cv2.drawContours(dmy, valid_cntrs, -1, (127,200,0), 2)
    
    cv2.putText(dmy, "vehicles detected: " + str(len(valid_cntrs)), (55, 15), font, 0.6, (0, 180, 0), 2)
    cv2.line(dmy, (0, 80),(256,80),(100, 255, 255))
    cv2.imwrite(pathIn+str(i)+'.png',dmy)
准备视频

在这里,咱们为全部帧中的全部移动车辆添加了轮廓。如今是时候堆叠帧并建立视频了:

# specify video name
pathOut = 'vehicle_detection_v3.mp4'

# specify frames per second
fps = 14.0

接下来,咱们将阅读列表中的最后一帧:

frame_array = []
files = [f for f in os.listdir(pathIn) if isfile(join(pathIn, f))]
files.sort(key=lambda f: int(re.sub('\D', '', f)))
for i in range(len(files)):
    filename=pathIn + files[i]
    
    #read frames
    img = cv2.imread(filename)
    height, width, layers = img.shape
    size = (width,height)
    
    #inserting the frames into an image array
    frame_array.append(img)

最后,咱们将使用如下代码制做目标检测视频:

out = cv2.VideoWriter(pathOut,cv2.VideoWriter_fourcc(*'DIVX'), fps, size)

for i in range(len(frame_array)):
    # writing to a image array
    out.write(frame_array[i])

out.release()

恭喜你学会了车辆目标检测!

尾注

在本教程中,咱们学习了如何使用帧差分技术在视频中执行移动目标检测。咱们还讨论了目标检测和图像处理的一些概念。而后咱们用OpenCV创建了本身的运动目标检测系统。

我确信,使用在本文中学习的技术和方法,你将构建本身版本的目标检测系统。

原文连接:https://www.analyticsvidhya.com/blog/2020/04/vehicle-detection-opencv-python/

欢迎关注磐创AI博客站: http://panchuang.net/

sklearn机器学习中文官方文档: http://sklearn123.com/

欢迎关注磐创博客资源汇总站: http://docs.panchuang.net/

相关文章
相关标签/搜索