作者 |PRATEEK JOSHI
编译 |Flin
起源 |analyticsvidhya
概述
- 你对智慧城市的想法感到兴奋吗?如果是的话,你会喜爱这个对于建设你本人的车辆检测零碎的教程的
- 在深刻实现局部之前,咱们将首先理解如何检测视频中的挪动指标
- 咱们将应用 OpenCV 和 Python 构建主动车辆检测器
介绍
我喜爱智慧城市的理念。主动智能能源零碎、电网、一键接入端口的想法等等。这是一个令人着迷的概念!诚实说,这是一个数据科学家的幻想,我很快乐世界上很多城市都在朝着更智能的方向倒退。
智能城市的外围组成部分之一是主动交通管理。这不禁让我思考——我能用我的数据科学知识来建设一个车辆检测模型,在智能交通管理中发挥作用吗?
想想看,如果你能在红绿灯摄像头中集成车辆检测零碎,你能够轻松地同时跟踪许多有用的货色:
- 白天交通路口有多少辆车?
- 什么时候交通堵塞?
- 什么样的车辆(重型车辆、汽车等)正在通过交叉路口?
- 有没有方法优化交通,并通过不同的街道进行调配?
还有很多例子就不一一列举。应用程序是无止境的!
咱们人类能够很容易地在一瞬间从简单的场景中检测和辨认出物体。然而,将这种思维过程转化为机器的思维,须要咱们学习应用计算机视觉算法进行指标检测。
因而在本文中,咱们将建设一个主动车辆检测器和计数器模型。以下视频是你能够期待的体验:
https://youtu.be/C_iZ2yivskE
留神:还不懂深度学习和计算机视觉的新概念?以下是两门热门课程,可开启你的深度学习之旅:
- 深度学习根底(https://courses.analyticsvidh…)
- 利用深度学习的计算机视觉(https://courses.analyticsvidh…)
目录
- 视频中静止指标检测的思维
- 视频中指标检测的真实世界用例
-
视频指标检测的基本概念
- 帧差分
- 图像阈值
- 检测轮廓
- 图像收缩
- 利用 OpenCV 构建车辆检测零碎
视频中静止指标检测的思维
指标检测是计算机视觉中一个引人入胜的畛域。当咱们解决视频数据时,它达到了一个全新的程度,复杂性回升了一个等级,但也有回报!
咱们能够应用指标检测算法来执行超级有用的高价值工作,如监督、交通管理、打击犯罪等。上面的 GIF 图演示了这个想法:
在指标检测中,咱们能够执行许多子工作,例如计算指标数量、查找指标的绝对大小或查找指标之间的绝对间隔。这些子工作都很重要,因为它们有助于解决一些最辣手的事实问题。
如果你心愿从头开始学习指标检测,我倡议你应用以下教程:
- 逐渐介绍根本的指标检测算法(https://www.analyticsvidhya.c…)
- 利用 SlimYOLOv3 进行实时指标检测(https://www.analyticsvidhya.c…)
- 其余指标检测物品和资源(https://www.analyticsvidhya.c…)
让咱们看看一些令人兴奋的事实世界中的指标检测用例。
视频中指标检测的真实世界用例
现在,视频指标检测正被广泛应用于各个行业。应用案例从视频监控到体育播送,再到机器人导航。
好消息是,在将来的视频指标检测和跟踪用例中,可能性是无穷的。这里我列出了一些乏味的应用程序:
- 人群计数(https://www.analyticsvidhya.c…)
- 车牌检测与辨认
- 静止中的球跟踪(https://www.analyticsvidhya.c…)
- 机器人学
- 交通管理(咱们将在本文中看到这个想法)
视频指标检测的基本概念
在开始构建视频检测零碎之前,你应该晓得一些要害概念。一旦你相熟了这些基本概念,就能够为你抉择的任何用例构建本人的检测零碎。
那么,你心愿如何检测视频中的挪动指标?
咱们的指标是捕获静止物体的坐标并在视频中突出显示该物体。请思考上面视频中的这一帧:
咱们心愿咱们的模型可能检测视频中的静止指标,如上图所示。检测到挪动的汽车,并在汽车四周创立一个边界框。
解决这个问题有多种办法。你能够为指标检测训练一个深度学习模型,也能够抉择一个事后训练好的模型并依据你的数据对其进行微调。然而,这些办法都是有监督的学习办法,须要标记数据来训练指标检测模型。
在本文中,咱们将 重点探讨视频中无监督的指标检测办法,即不应用任何标记数据的指标检测 。咱们将应用 帧差分技术。让咱们理解它是如何工作的!
帧差分
视频是一组按正确程序重叠在一起的帧。所以,当咱们看到一个物体在视频中挪动时,这意味着这个物体在每一个间断的帧上都处于不同的地位。
如果咱们假如除了该指标之外,在一对间断的帧中没有其余物体挪动,那么第一帧与第二帧的像素差将突出显示挪动指标的像素。当初,咱们失去了挪动物体的像素和坐标。这就是帧差分法的工作原理。
举个例子。思考视频中的以下两个帧:
你能看出这两帧的区别吗?
握笔的手的地位从第 1 帧变为第 2 帧。其余的物体基本没有挪动。所以,正如我后面提到的,为了定位挪动指标,咱们将执行帧差分。后果如下:
你能够看到高亮或红色区域,这是手最后呈现的中央。除此之外,记事本的边缘也会突出显示一点。这可能是因为手的挪动扭转了光照。倡议不要对静止物体进行不必要的检测。因而,咱们须要对帧执行某些图像预处理步骤。
图像阈值
在这种办法中,灰度图像的像素值依据阈值被指定为示意黑白色彩的两个值之一。因而,如果一个像素的值大于一个阈值,它被赋予一个值,否则它被赋予另一个值。
在本例中,咱们将对上一步骤中帧差分的输入图像利用图像阈值:
你能够看到,不须要的高亮区域的大部分曾经隐没了。高亮显示的“记事本”边缘不再可见。合成的图像也能够称为二值图像,因为其中只有两种色彩。在下一个步骤中,咱们将看到如何捕捉这些高亮区域。
检测轮廓
轮廓用于辨认图像中具备雷同色彩或强度的区域的形态。轮廓就是指标区域四周的边界。因而,如果咱们在阈值步骤后对图像利用轮廓检测,咱们将失去以下后果:
红色区域被浅灰色的边界所突围,这些边界就是轮廓。咱们很容易失去这些轮廓的坐标。这意味着咱们能够失去高亮区域的地位。
请留神,有多个高亮显示区域,每个区域由轮廓突围。在咱们的例子中,具备最大面积的轮廓是咱们冀望的区域。因而,轮廓最好尽可能少。
在上图中,依然有一些不必要的红色区域碎片。还有改良的余地。咱们的想法是合并左近的红色区域以取得更少的轮廓,为此,咱们能够应用另一种称为图像收缩的技术。
图像收缩
这是对图像的卷积操作,其中外围(矩阵)传递到整个图像上。为了给你直觉,左边的图像是右边图像的放大版本:
所以,让咱们对咱们的图像进行图像收缩,而后咱们将再次找到轮廓:
事实证明,许多四分五裂的区域曾经互相交融。当初咱们能够再次在这张图片中找到轮廓:
在这里,咱们只有四个候选轮廓,从中咱们能够抉择一个有最大面积的轮廓。也能够在原始帧上绘制这些轮廓,以查看轮廓围绕挪动指标的状况:
用 OpenCV 和 Python 构建车辆检测零碎
咱们筹备建设咱们的车辆检测零碎!在这个实现中,咱们将大量应用计算机视觉库 OpenCV(4.0.0 版)(https://www.analyticsvidhya.c…。咱们先导入所需的库和模块。
导入库
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…
将框架保留在工作目录中名为“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()
太酷了!只有位于检测区域内的车辆轮廓可见。这就是咱们在整个画面中检测车辆的办法
视频中的车辆检测
当初是时候对所有帧利用雷同的图像变换和预处理操作,并找到所需的轮廓。重申一下,咱们将遵循以下步骤:
- 对每对间断帧利用帧差分
- 对上一步的输入图像利用图像阈值
- 对上一步的输入图像进行图像放大
- 在上一步的输入图像中查找轮廓
- 检测区域呈现的候选轮廓
- 保留帧与最终轮廓
# 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.c…
欢送关注磐创 AI 博客站:
http://panchuang.net/
sklearn 机器学习中文官网文档:
http://sklearn123.com/
欢送关注磐创博客资源汇总站:
http://docs.panchuang.net/