使用OpenCV进行YOLO对象检测

在本教程中,您将学习如何使用YOLO对象检测器使用Deep Learning,OpenCV和Python检测图像和视频流中的对象。

通过应用目标检测,你不仅能够确定什么是图像中,也其中一个给定对象所在!

我们首先简要讨论YOLO物体探测器,包括物体探测器的工作原理。

从那里我们将使用OpenCV,Python和深度学习:

  1. 将YOLO物体检测器应用于图像
  2. 将YOLO应用于视频流

我们将通过讨论YOLO对象检测器的一些限制和缺点来结束本教程,包括我的一些个人提示和建议。

要了解如何使用YOLO进行OpenCV对象检测,请继续阅读!

寻找这篇文章的源代码?
跳到下载部分。

使用OpenCV进行YOLO对象检测

 

在本教程的其余部分中,我们将:

  • 讨论YOLO物体探测器的模型和架​​构
  • 利用YOLO检测图像中的对象
  • 应用YOLO检测视频流中的对象
  • 讨论YOLO物体探测器的一些限制和缺点

我们潜入吧!

什么是YOLO物体探测器?

图1: YOLO对象检测器流水线()的简化图示。我们将在此博客文章中使用YOLO和OpenCV。

当涉及基于深度学习的物体检测时,您将遇到三种主要物体检测器:

  • R-CNN及其变体,包括原始R-CNN,快速R-CNN和更快的R-CNN
  • 单发探测器(SSD)
  • YOLO

R-CNN是第一个基于深度学习的物体检测器之一,并且是两级检测器的示例

  1. 在第一个R-CNN出版物中,Rich特征层次结构用于精确的对象检测和语义分割,(2013)Girshick等。提出了一种对象检测器,它需要诸如选择性搜索(或等效物)之类的算法来提出可能包含对象的候选边界框。
  2. 然后将这些区域传递到CNN进行分类,最终导致第一个基于深度学习的物体探测器之一。

标准R-CNN方法的问题在于它很并且不是完整的端到端物体检测器。

Girshick等。2015年发表了第二篇论文,名为Fast R-CNN。快速R-CNN算法对原始R-CNN进行了相当大的改进,即提高准确度并减少执行正向传递所花费的时间; 但是,该模型仍然依赖于外部区域提议算法。

直到Girshick等人的后续2015年论文,更快的R-CNN:用区域提议网络实现实时物体检测,R-CNN才成为真正的端到端深度学习物体探测器。删除选择性搜索要求,而是依赖于(1)完全卷积的区域提议网络(RPN)和(2)可以预测对象边界框和“对象”分数(即,量化它是一个区域的可能性的分数图像的图像可能包含图像)。然后将RPN的输出传递到R-CNN组件以进行最终分类和标记。

虽然R-CNN倾向于非常准确,但R-CNN系列网络的最大问题在于它们的速度 - 它们非常慢,在GPU上仅获得5 FPS。

为了提高基于深度学习的物体探测器的速度,单次探测器(SSD)和YOLO都使用单级探测器策略

这些算法将对象检测视为回归问题,采用给定的输入图像并同时学习边界框坐标和相应的类标签概率。

通常,单级检测器往往不如两级检测器准确,但明显更快。

YOLO是单级探测器的一个很好的例子。

Redmon等人于2015年首次推出了他们的论文“ You Only Look Once:Unified,Real-Time Object Detection”,详细介绍了一种能够进行超实时物体检测的物体探测器,在GPU上获得  45 FPS

注意:他们的模型的一个较小的变种称为“Fast YOLO”,声称在GPU上达到155 FPS。

YOLO经历了许多不同的迭代,包括YOLO9000:更好,更快,更强(即YOLOv2),能够检测超过9,000个物体探测器。

通过对对象检测和分类进行联合训练,Redmon和Farhadi能够实现如此大量的对象检测。通过联合训练,作者同时在ImageNet分类数据集和COCO检测数据集上训练了YOLO9000。结果是一个名为YOLO9000的YOLO模型,它可以预测没有标记检测数据的对象类的检测。

虽然有趣和新颖,但鉴于论文的标题和摘要,YOLOv2的表现有点令人沮丧。

在COCO的156级版本中,YOLO9000实现了16%的平均精度(mAP),是的,虽然YOLO可以检测9,000个单独的类,但准确性并不是我们想要的。

Redmon和Farhadi最近发表了一篇新的YOLO论文,YOLOv3:增量改进(2018)。YOLOv3比之前的型号大得多,但在我看来,它是YOLO系列物体探测器中最好的一款。

我们将在此博客文章中使用YOLOv3,特别是YOLO在COCO数据集上进行了培训。

COCO数据集由80个标签组成,包括但不限于:

  • 自行车
  • 汽车和卡车
  • 飞机
  • 停车标志和消防栓
  • 动物,包括猫,狗,鸟,马,牛和羊,仅举几例
  • 厨房和餐厅用品,如酒杯,杯子,叉子,刀子,勺子等。
  • …以及更多!

您可以使用此链接找到YOLO在COCO数据集上训练的内容的完整列表。

我将结束本节,说任何学术需要阅读Redmon的YOLO论文和技术报告 - 它们不仅具有新颖性和洞察力,而且还具有令人难以置信的娱乐性。

但严重的是,如果你今天什么都不做,请阅读YOLOv3技术报告

它只有6页,其中一页只是引用/引用。

此外,技术报告是诚实的,学术论文很少,如果有的话。

项目结构

我们来看看今天的项目布局。您可以使用操作系统的GUI(适用于OSX的Finder,适用于Ubuntu的Nautilus),但您可能会发现  在终端中使用tree命令更容易,更快捷 :

YOLO Object Detection with OpenCV

Shell

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

$ tree

.

├── images

│   ├── baggage_claim.jpg

│   ├── dining_table.jpg

│   ├── living_room.jpg

│   └── soccer.jpg

├── output

│   ├── airport_output.avi

│   ├── car_chase_01_output.avi

│   ├── car_chase_02_output.avi

│   └── overpass_output.avi

├── videos

│   ├── airport.mp4

│   ├── car_chase_01.mp4

│   ├── car_chase_02.mp4

│   └── overpass.mp4

├── yolo-coco

│   ├── coco.names

│   ├── yolov3.cfg

│   └── yolov3.weights

├── yolo.py

└── yolo_video.py

 

4 directories, 19 files

我们今天的项目包括4个目录和两个Python脚本。

目录(按重要性顺序)是:

  • yolo coco /  :YOLOv3对象检测器预先训练(在COCO数据集上)模型文件。这些都是由Darknet团队训练的。
  • images /  :此文件夹包含四个静态图像,我们将执行对象检测以进行测试和评估。
  • 视频/  :在使用YOLO对图像进行物体检测后,我们将实时处理视频。此目录包含四个示例视频供您测试。
  • 输出/  :输出已由YOLO处理并带有边界框和类名称注释的视频可以放在此文件夹中。

我们正在审查两个Python脚本 - yolo .py   和 yolo_video .py  。第一个脚本用于图像,然后我们将学习所学内容并将其应用于第二个脚本中的视频。

你准备好了吗?

图像中的YOLO对象检测

让我们开始将YOLO物体探测器应用于图像!

打开  项目中的 yolo .py文件并插入以下代码:

YOLO Object Detection with OpenCV

Python

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

# import the necessary packages

import numpy as np

import argparse

import time

import cv2

import os

 

# construct the argument parse and parse the arguments

ap = argparse.ArgumentParser()

ap.add_argument("-i", "--image", required=True,

help="path to input image")

ap.add_argument("-y", "--yolo", required=True,

help="base path to YOLO directory")

ap.add_argument("-c", "--confidence", type=float, default=0.5,

help="minimum probability to filter weak detections")

ap.add_argument("-t", "--threshold", type=float, default=0.3,

help="threshold when applying non-maxima suppression")

args = vars(ap.parse_args())

您需要为此脚本OpenCV 3.4.2+安装所有Python绑定。你可以在这里找到我的OpenCV安装教程,请记住OpenCV 4现在处于测试阶段 - 你可能会遇到安装或运行某些脚本的问题,因为它不是正式版本。暂时我建议去OpenCV 3.4.2+。实际上,你可以将起来,在不到5分钟运行与PIP为好。

首先,我们导入我们所需的包 - 只要安装了OpenCV和NumPy,您的解释器就会轻松过关。

现在让我们解析四个命令行参数。命令行参数在运行时处理,允许我们从终端更改脚本的输入。如果您不熟悉它们,我建议您在我之前的教程中阅读更多内容。我们的命令行参数包括:

  • image  :输入图像的路径。我们将使用YOLO检测此图像中的对象。
  • yolo  :YOLO目录的基本路径。然后,我们的脚本将加载所需的YOLO文件,以便对图像执行对象检测。
  • 置信度  :过滤弱检测的最小概率。我给它的默认值为50%( 0.5  ),但你可以随意尝试这个值。
  • threshold  :这是我们的非最大值抑制阈值,默认值为 0.3  。您可以在此处阅读有关非最大值抑制的更多信息。

解析之后, args   变量现在是一个包含命令行参数的键值对的字典。你会  在这个脚本的其余部分看到 args很多次。

让我们加载我们的类标签并为每个标签设置随机颜色:

YOLO Object Detection with OpenCV

Python

 

20

21

22

23

24

25

26

27

# load the COCO class labels our YOLO model was trained on

labelsPath = os.path.sep.join([args["yolo"], "coco.names"])

LABELS = open(labelsPath).read().strip().split("\n")

 

# initialize a list of colors to represent each possible class label

np.random.seed(42)

COLORS = np.random.randint(0, 255, size=(len(LABELS), 3),

dtype="uint8")

这里我们  在第21行和第22行加载所有类 LABELS   (注意第一个命令行参数 args “yolo”])  。  然后将随机 颜色分配给第25-27行的每个标签  。

让我们推导出YOLO权重和配置文件的路径,然后从磁盘加载YOLO:

YOLO Object Detection with OpenCV

Python

 

29

30

31

32

33

34

35

# derive the paths to the YOLO weights and model configuration

weightsPath = os.path.sep.join([args["yolo"], "yolov3.weights"])

configPath = os.path.sep.join([args["yolo"], "yolov3.cfg"])

 

# load our YOLO object detector trained on COCO dataset (80 classes)

print("[INFO] loading YOLO from disk...")

net = cv2.dnn.readNetFromDarknet(configPath, weightsPath)

要在第35行从磁盘加载YOLO  ,我们将利用OpenCV的名为cv2的DNN函数 dnn readNetFromDarknet  。此函数需要 configPath   和 weightsPath   ,它们是通过第30行和第31行上的命令行参数建立的  。

我不能强调这一点:至少需要OpenCV 3.4.2才能运行此代码,因为它具有  加载YOLO所需的更新的 dnn模块。

让我们加载图像并通过网络发送:

YOLO Object Detection with OpenCV

Python

 

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

# load our input image and grab its spatial dimensions

image = cv2.imread(args["image"])

(H, W) = image.shape[:2]

 

# determine only the *output* layer names that we need from YOLO

ln = net.getLayerNames()

ln = [ln[i[0] - 1] for i in net.getUnconnectedOutLayers()]

 

# construct a blob from the input image and then perform a forward

# pass of the YOLO object detector, giving us our bounding boxes and

# associated probabilities

blob = cv2.dnn.blobFromImage(image, 1 / 255.0, (416, 416),

swapRB=True, crop=False)

net.setInput(blob)

start = time.time()

layerOutputs = net.forward(ln)

end = time.time()

 

# show timing information on YOLO

print("[INFO] YOLO took {:.6f} seconds".format(end - start))

在这个块中我们:

  • 加载输入 图像   并提取其尺寸(第38和39行)。
  • 确定YOLO模型中的输出图层名称(第42和43行)。
  •   从图像构造一个 blob第48和49行)。您是否对blob是什么或cv2是什么感到困惑dnn blobFromImage   呢?给这篇博客文章一个阅读。

既然我们的blob准备好了,我们就会

  • 通过我们的YOLO网络进行正向传递(第50和52行
  • 显示YOLO的推理时间(第56行

除非我们想象我们的结果,否则物体检测有什么用?我们现在采取措施来过滤和可视化我们的结果。

但首先,让我们初步化一些我们在这样做过程中需要的列表:

YOLO Object Detection with OpenCV

Python

 

58

59

60

61

62

# initialize our lists of detected bounding boxes, confidences, and

# class IDs, respectively

boxes = []

confidences = []

classIDs = []

这些清单包括:

  • boxes  :我们围绕对象的边界框。
  • 置信度  :YOLO分配给对象的置信度值。较低置信度值表示该对象可能不是网络认为的对象。请记住,从上面的命令行参数中我们将过滤掉不符合 0.5   阈值的对象。
  • classIDs  :检测到的对象的类标签。

让我们开始用我们的YOLO layerOutputs中的数据填充这些列表  :

YOLO Object Detection with OpenCV

Python

 

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

# loop over each of the layer outputs

for output in layerOutputs:

# loop over each of the detections

for detection in output:

# extract the class ID and confidence (i.e., probability) of

# the current object detection

scores = detection[5:]

classID = np.argmax(scores)

confidence = scores[classID]

 

# filter out weak predictions by ensuring the detected

# probability is greater than the minimum probability

if confidence > args["confidence"]:

# scale the bounding box coordinates back relative to the

# size of the image, keeping in mind that YOLO actually

# returns the center (x, y)-coordinates of the bounding

# box followed by the boxes' width and height

box = detection[0:4] * np.array([W, H, W, H])

(centerX, centerY, width, height) = box.astype("int")

 

# use the center (x, y)-coordinates to derive the top and

# and left corner of the bounding box

x = int(centerX - (width / 2))

y = int(centerY - (height / 2))

 

# update our list of bounding box coordinates, confidences,

# and class IDs

boxes.append([x, y, int(width), int(height)])

confidences.append(float(confidence))

classIDs.append(classID)

在这个代码块中有很多 - 让我们分解它。

在这个块中,我们:

  • 遍历每个 layerOutputs   (从第65行开始  )。
  • 循环在每个 检测   中 输出   (嵌套循环开始于  第67行)。
  • 提取 classID   和 置信度   (第70-72行)。
  • 使用 置信度  滤除弱检测(第76行)。

现在我们已经过滤掉了不需要的检测,我们将:

  • 缩放边界框坐标,以便我们可以在原始图像上正确显示它们(第81行)。
  • 提取边界框的坐标和尺寸(第82行)。YOLO返回边界框坐标形式: 的centerX centerY 宽度高度  。
  • 使用此信息导出边界框的左上角(x,y) -坐标(第86和87行)。
  • 更新   , 置信度  和 classID   列表(第91-93行)。

有了这些数据,我们现在将应用所谓的“非最大值抑制”:

YOLO Object Detection with OpenCV

Python

 

95

96

97

98

# apply non-maxima suppression to suppress weak, overlapping bounding

# boxes

idxs = cv2.dnn.NMSBoxes(boxes, confidences, args["confidence"],

args["threshold"])

YOLO不对我们应用非最大值抑制  ,因此我们需要明确应用它。

应用非最大值抑制可以抑制明显重叠的边界框,只保留最自信的边界框。

NMS还确保我们没有任何冗余或无关的边界框。

利用OpenCV内置的NMS DNN模块实现,我们对第97和98行进行非最大值抑制  。所需要的只是我们提交边界   , 置信度  ,以及我们的置信度阈值和NMS阈值。

如果你一直在阅读这篇博客,你可能想知道为什么我们没有使用我的imutils实现NMS。主要原因是 NMSBoxes   函数现在在OpenCV中工作。以前它对某些输入失败并导致错误消息。现在NMSBoxes   函数正常工作,我们可以在自己的脚本中使用它。

让我们在图像上绘制框和类文本!

YOLO Object Detection with OpenCV

Python

 

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

# ensure at least one detection exists

if len(idxs) > 0:

# loop over the indexes we are keeping

for i in idxs.flatten():

# extract the bounding box coordinates

(x, y) = (boxes[i][0], boxes[i][1])

(w, h) = (boxes[i][2], boxes[i][3])

 

# draw a bounding box rectangle and label on the image

color = [int(c) for c in COLORS[classIDs[i]]]

cv2.rectangle(image, (x, y), (x + w, y + h), color, 2)

text = "{}: {:.4f}".format(LABELS[classIDs[i]], confidences[i])

cv2.putText(image, text, (x, y - 5), cv2.FONT_HERSHEY_SIMPLEX,

0.5, color, 2)

 

# show the output image

cv2.imshow("Image", image)

cv2.waitKey(0)

假设存在至少一个检测(线101),我们继续循环   由非最大值抑制确定的idx

然后,我们  使用随机类颜色(第105-113行)在图像上绘制边界框和文本 。

最后,我们显示结果图像,直到用户按下键盘上的任意键(确保选择并聚焦OpenCV打开的窗口)。


要遵循本指南,请确保使用本教程的“下载”部分下载源代码,YOLO模型和示例图像。

从那里,打开一个终端并执行以下命令:

YOLO Object Detection with OpenCV

Shell

 

1

2

3

$ python yolo.py --image images/baggage_claim.jpg --yolo yolo-coco

[INFO] loading YOLO from disk...

[INFO] YOLO took 0.347815 seconds

 

图2:带有OpenCV的YOLO用于检测机场中的人员和行李。

 

在这里你可以看到YOLO不仅检测到输入图像中的每个人,还检测了手提箱!

此外,如果您看一下图像的右上角,您会看到YOLO还检测到女士肩上的手提包。

我们试试另一个例子:

YOLO Object Detection with OpenCV

Shell

 

1

2

3

$ python yolo.py --image images/living_room.jpg --yolo yolo-coco

[INFO] loading YOLO from disk...

[INFO] YOLO took 0.340221 seconds

 

图3:  使用OpenCV进行YOLO对象检测用于检测人,狗,电视和椅子。遥控器是假阳性检测器,但是在查看ROI时,您可以想象该区域确实与遥控器有相似之处。

 

上面的图像包含一个人(我自己)和一只狗(Jemma,家庭比格犬)。

YOLO还可以检测电视显示器和椅子。尤其令我印象深刻的是YOLO能够检测到椅子,因为它是手工制作的老式“婴儿高脚椅”。

有趣的是,YOLO认为我手中有一个“遥远的”。它实际上不是遥控器 - 它是VHS录像带上玻璃的反射; 但是,如果你盯着这个地区,它实际上看起来可能是遥远的。

以下示例图像演示了YOLO对象检测器的局限性和弱点:

YOLO Object Detection with OpenCV

Shell

 

1

2

3

$ python yolo.py --image images/dining_table.jpg --yolo yolo-coco

[INFO] loading YOLO from disk...

[INFO] YOLO took 0.362369 seconds

 

图4: YOLO和OpenCV用于餐桌的物体检测。

 

虽然YOLO正确地检测到葡萄酒瓶,餐桌和花瓶,但只有两个酒杯中的一个被正确检测到。

我们讨论为什么YOLO在下面的“YOLO物体探测器的限制和缺点”部分中与物体紧密相连。

让我们尝试一个最终图像:

YOLO Object Detection with OpenCV

Shell

 

1

2

3

$ python yolo.py --image images/soccer.jpg --yolo yolo-coco

[INFO] loading YOLO from disk...

[INFO] YOLO took 0.345656 seconds

 

图5:使用YOLO物体探测器使用OpenCV检测足球运动员和足球。

 

YOLO能够正确地检测球场上的每个球员,包括足球本身。请注意尽管区域高度模糊且部分遮挡,但仍会检测到背景中的人。

视频流中的YOLO对象检测

既然我们已经学会了如何将YOLO对象检测器应用于单个图像,那么我们也可以利用YOLO在输入视频文件中执行对象检测。

打开 yolo_video .py   文件并插入以下代码:

YOLO Object Detection with OpenCV

Python

 

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

# import the necessary packages

import numpy as np

import argparse

import imutils

import time

import cv2

import os

 

# construct the argument parse and parse the arguments

ap = argparse.ArgumentParser()

ap.add_argument("-i", "--input", required=True,

help="path to input video")

ap.add_argument("-o", "--output", required=True,

help="path to output video")

ap.add_argument("-y", "--yolo", required=True,

help="base path to YOLO directory")

ap.add_argument("-c", "--confidence", type=float, default=0.5,

help="minimum probability to filter weak detections")

ap.add_argument("-t", "--threshold", type=float, default=0.3,

help="threshold when applyong non-maxima suppression")

args = vars(ap.parse_args())

我们从导入和命令行参数开始。

请注意,此脚本没有  像以前那样的 image参数。取而代之的是,我们现在有两个与视频相关的论点:

  • input  :输入视频文件的路径。
  • output  :输出视频文件的路径。

鉴于这些论点,您现在可以使用您使用智能手机拍摄场景的视频或在线查找的视频。然后,您可以处理视频文件,生成带注释的输出视频。当然,如果您想使用网络摄像头处理实时视频流,也可以。只需在PyImageSearch上找到  来自imutils的  VideoStream类的 示例视频   被利用并进行一些小的改动。

继续,下一个块   YOLO图像处理脚本中的块相同

YOLO Object Detection with OpenCV

Python

 

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

# load the COCO class labels our YOLO model was trained on

labelsPath = os.path.sep.join([args["yolo"], "coco.names"])

LABELS = open(labelsPath).read().strip().split("\n")

 

# initialize a list of colors to represent each possible class label

np.random.seed(42)

COLORS = np.random.randint(0, 255, size=(len(LABELS), 3),

dtype="uint8")

 

# derive the paths to the YOLO weights and model configuration

weightsPath = os.path.sep.join([args["yolo"], "yolov3.weights"])

configPath = os.path.sep.join([args["yolo"], "yolov3.cfg"])

 

# load our YOLO object detector trained on COCO dataset (80 classes)

# and determine only the *output* layer names that we need from YOLO

print("[INFO] loading YOLO from disk...")

net = cv2.dnn.readNetFromDarknet(configPath, weightsPath)

ln = net.getLayerNames()

ln = [ln[i[0] - 1] for i in net.getUnconnectedOutLayers()]

在这里,我们加载标签并生成颜色,然后加载我们的YOLO模型并确定输出层名称。

接下来,我们将处理一些特定于视频的任务:

YOLO Object Detection with OpenCV

Python

 

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

# initialize the video stream, pointer to output video file, and

# frame dimensions

vs = cv2.VideoCapture(args["input"])

writer = None

(W, H) = (None, None)

 

# try to determine the total number of frames in the video file

try:

prop = cv2.cv.CV_CAP_PROP_FRAME_COUNT if imutils.is_cv2() \

else cv2.CAP_PROP_FRAME_COUNT

total = int(vs.get(prop))

print("[INFO] {} total frames in video".format(total))

 

# an error occurred while trying to determine the total

# number of frames in the video file

except:

print("[INFO] could not determine # of frames in video")

print("[INFO] no approx. completion time can be provided")

total = -1

在这个块中,我们:

  • 打开一个指向视频文件的文件指针,以便在即将到来的循环中读取帧(第45行)。
  • 初始化我们的视频 编写器   和帧尺寸(第46和47行)。
  • 尝试确定  视频文件中的 帧数,以便我们估计整个视频的处理时间(第50-61行)。

现在我们准备开始逐个处理帧:

YOLO Object Detection with OpenCV

Python

 

63

64

65

66

67

68

69

70

71

72

73

74

75

# loop over frames from the video file stream

while True:

# read the next frame from the file

(grabbed, frame) = vs.read()

 

# if the frame was not grabbed, then we have reached the end

# of the stream

if not grabbed:

break

 

# if the frame dimensions are empty, grab them

if W is None or H is None:

(H, W) = frame.shape[:2]

我们定义一个 while   循环(第64行),然后我们抓住第一帧(第66行)。

我们会检查它是否是视频的最后一帧。如果是这样,我们需要   从 while   循环中断开第70和71行)。

接下来,如果尚未抓住框架尺寸,我们会抓住框架尺寸(第74和75行)。

接下来,让我们使用当前   作为输入执行YOLO的正向传递 :

YOLO Object Detection with OpenCV

Python

 

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

# construct a blob from the input frame and then perform a forward

# pass of the YOLO object detector, giving us our bounding boxes

# and associated probabilities

blob = cv2.dnn.blobFromImage(frame, 1 / 255.0, (416, 416),

swapRB=True, crop=False)

net.setInput(blob)

start = time.time()

layerOutputs = net.forward(ln)

end = time.time()

 

# initialize our lists of detected bounding boxes, confidences,

# and class IDs, respectively

boxes = []

confidences = []

classIDs = []

在这里,我们构建一个 blob   并将其传递通过网络,从而获得预测。我已经用时间戳包围了前向传递操作,因此我们可以计算在一帧上进行预测所用的时间 - 这将有助于我们估计处理整个视频所需的时间。

然后我们将继续初始化我们在前一个脚本中使用的三个列表: box  , confidences  和classIDs  。

下一个块再次  我们之前的脚本相同

YOLO Object Detection with OpenCV

Python

 

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

# loop over each of the layer outputs

for output in layerOutputs:

# loop over each of the detections

for detection in output:

# extract the class ID and confidence (i.e., probability)

# of the current object detection

scores = detection[5:]

classID = np.argmax(scores)

confidence = scores[classID]

 

# filter out weak predictions by ensuring the detected

# probability is greater than the minimum probability

if confidence > args["confidence"]:

# scale the bounding box coordinates back relative to

# the size of the image, keeping in mind that YOLO

# actually returns the center (x, y)-coordinates of

# the bounding box followed by the boxes' width and

# height

box = detection[0:4] * np.array([W, H, W, H])

(centerX, centerY, width, height) = box.astype("int")

 

# use the center (x, y)-coordinates to derive the top

# and and left corner of the bounding box

x = int(centerX - (width / 2))

y = int(centerY - (height / 2))

 

# update our list of bounding box coordinates,

# confidences, and class IDs

boxes.append([x, y, int(width), int(height)])

confidences.append(float(confidence))

classIDs.append(classID)

在这个代码块中,我们:

  • 循环输出层和检测(第94-96行)。
  • 提取 classID   并过滤掉弱预测(99-105)。
  • 计算边界框坐标(第111-117行)。
  • 更新我们各自的列表(第121-123行)。

接下来,我们将应用非最大值抑制并开始继续注释框架:

YOLO Object Detection with OpenCV

Python

 

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

# apply non-maxima suppression to suppress weak, overlapping

# bounding boxes

idxs = cv2.dnn.NMSBoxes(boxes, confidences, args["confidence"],

args["threshold"])

 

# ensure at least one detection exists

if len(idxs) > 0:

# loop over the indexes we are keeping

for i in idxs.flatten():

# extract the bounding box coordinates

(x, y) = (boxes[i][0], boxes[i][1])

(w, h) = (boxes[i][2], boxes[i][3])

 

# draw a bounding box rectangle and label on the frame

color = [int(c) for c in COLORS[classIDs[i]]]

cv2.rectangle(frame, (x, y), (x + w, y + h), color, 2)

text = "{}: {:.4f}".format(LABELS[classIDs[i]],

confidences[i])

cv2.putText(frame, text, (x, y - 5),

cv2.FONT_HERSHEY_SIMPLEX, 0.5, color, 2)

您也应该识别这些行。在这里,我们:

  • 使用cv2应用NMS dnn NMSBoxes   函数(第127和128行)用于抑制弱的重叠边界框。您可以在此处阅读有关非最大值抑制的更多信息。
  • 循环遍历   由NMS计算的 idx并绘制相应的边界框+标签(第131-144行)。

让我们完成脚本:

YOLO Object Detection with OpenCV

Python

 

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

# check if the video writer is None

if writer is None:

# initialize our video writer

fourcc = cv2.VideoWriter_fourcc(*"MJPG")

writer = cv2.VideoWriter(args["output"], fourcc, 30,

(frame.shape[1], frame.shape[0]), True)

 

# some information on processing single frame

if total > 0:

elap = (end - start)

print("[INFO] single frame took {:.4f} seconds".format(elap))

print("[INFO] estimated total time to finish: {:.4f}".format(

elap * total))

 

# write the output frame to disk

writer.write(frame)

 

# release the file pointers

print("[INFO] cleaning up...")

writer.release()

vs.release()

总结一下,我们简单地说:

  • 初始化我们的视频 作家   如果有必要(行147-151)。该 作家   将在循环的第一次迭代被初始化。
  • 打印出我们对处理视频所需时间的估计(第154-158行)。
  • 写入   输出视频文件(第161行)。
  • 清理和释放指针(第165和166行)。

要将YOLO对象检测应用于视频流,请确保使用此博客文章的“下载”部分下载源,YOLO对象检测器和示例视频。

从那里,打开一个终端并执行以下命令:

YOLO Object Detection with OpenCV

Shell

 

1

2

3

4

5

6

7

$ python yolo_video.py --input videos/car_chase_01.mp4 \

--output output/car_chase_01.avi --yolo yolo-coco

[INFO] loading YOLO from disk...

[INFO] 583 total frames in video

[INFO] single frame took 0.3500 seconds

[INFO] estimated total time to finish: 204.0238

[INFO] cleaning up...

 

图6:应用于车祸视频的YOLO深度学习对象检测。

 

上面你可以看到我在YouTube上找到的汽车追逐视频中的GIF摘录。

在视频/ GIF中,您不仅可以看到被检测到的车辆,还可以检测到人员以及交通信号灯!

YOLO物体探测器在这里表现相当不错。让我们尝试从同一车追逐视频中的不同视频剪辑:

YOLO Object Detection with OpenCV

Shell

 

1

2

3

4

5

6

7

$ python yolo_video.py --input videos/car_chase_02.mp4 \

--output output/car_chase_02.avi --yolo yolo-coco

[INFO] loading YOLO from disk...

[INFO] 3132 total frames in video

[INFO] single frame took 0.3455 seconds

[INFO] estimated total time to finish: 1082.0806

[INFO] cleaning up...

 

图7:在这个运行中的嫌疑人的视频中,我们使用OpenCV和YOLO对象检测来找到该人。

 

嫌疑人现在已经逃离汽车并正在停车场。

YOLO再一次能够发现人。

有一次,嫌疑人实际上能够回到他们的汽车并继续追逐 - 让我们看看YOLO在那里的表现如何:

YOLO Object Detection with OpenCV

Shell

 

1

2

3

4

5

6

7

$ python yolo_video.py --input videos/car_chase_03.mp4 \

--output output/car_chase_03.avi --yolo yolo-coco

[INFO] loading YOLO from disk...

[INFO] 749 total frames in video

[INFO] single frame took 0.3442 seconds

[INFO] estimated total time to finish: 257.8418

[INFO] cleaning up...

 

图8: YOLO是一种快速深度学习对象检测器,能够在使用GPU的情况下用于实时视频。

 

注意:此视频对我来说太大了,无法包含在“下载”中。您可以在此处从YouTube下载视频

作为最后一个例子,让我们看看我们如何使用YOLO作为构建流量计数器的起点:

YOLO Object Detection with OpenCV

Shell

 

1

2

3

4

5

6

7

$ python yolo_video.py --input videos/overpass.mp4 \

--output output/overpass.avi --yolo yolo-coco

[INFO] loading YOLO from disk...

[INFO] 812 total frames in video

[INFO] single frame took 0.3534 seconds

[INFO] estimated total time to finish: 286.9583

[INFO] cleaning up...

 

图9:在立交桥下的交通视频表明,YOLO和OpenCV可用于准确,快速地检测汽车。

 

我在下面汇总了YOLO对象检测示例的完整视频:

 

视频和音频的积分:

YOLO物体探测器的局限和缺点

可以说YOLO物体探测器的最大限制和缺点是:

  1. 它并不总能很好地处理小物体
  2. 尤其不处理靠近组合的对象

这种限制的原因是由于YOLO算法本身:

  • YOLO对象检测器将输入图像划分为SxS网格,其中网格中的每个单元格仅预测单个对象。
  • 如果单个单元格中存在多个小对象,则YOLO将无法检测到它们,最终导致错过对象检测。

因此,如果您知道您的数据集由许多靠近在一起的小对象组成,那么您不应该使用YOLO对象检测器。

就小物体而言,更快的R-CNN往往效果最好; 然而,它也是最慢的。

SSD也可以在这里使用; 但是,SSD也可能会遇到较小的对象(但不如YOLO那么多)。

固态硬盘通常在速度和准确性方面也有很好的权衡。

同样值得注意的是,在本教程中,YOLO比SSD运行速度慢。在我之前关于OpenCV对象检测的教程中,我们使用了SSD - SSD的单个正向传递耗时约0.03秒。

但是,从本教程中,我们知道YOLO物体探测器的前向传递需要约0.3秒,大约慢一个数量级!

如果您正在使用预先训练过的深度学习物体探测器OpenCV供应,您可能需要考虑使用SSD而不是YOLO。根据我的个人经验,我很少遇到需要在SSD上使用YOLO的情况:

  • 我发现SSD更容易训练,它们在准确性方面的表现几乎总是优于YOLO(至少对于我曾经使用过的数据集)。
  • YOLO在COCO数据集上可能会有很好的结果; 但是,我没有找到与我自己的任务相同的准确度。

因此,在针对给定问题选择对象检测器时,我倾向于使用以下准则:

  1. 如果我知道我需要检测小物体并且速度不是问题,我倾向于使用更快的R-CNN。
  2. 如果速度绝对是最重要的,我使用YOLO。
  3. 如果我需要一个中间立场,我倾向于使用SSD。

在我的大多数情况下,我最终使用SSD或RetinaNet - 两者都是YOLO / Faster R-CNN之间的良好平衡。

想要训练自己的深度学习物体探测器?

图10:在我的书“ 深度学习计算机视觉与Python”中,我介绍了多种对象检测算法,包括更快的R-CNN,SSD和RetinaNet。在里面我将教你如何创建对象检测图像数据集,训练对象检测器,并进行预测。更不用说我还涵盖深度学习基础,最佳实践和我个人的经验法则。现在抓住你的副本,这样你就可以开始学习新技能了。

我们在本教程中使用的YOLO模型是在COCO数据集上预先训练的......

...但是,如果您想在自己的数据集上训练深度学习对象检测器,该怎么办?

在我的书“ 深度学习计算机视觉与Python”中,我将教你如何训练更快的R-CNN,单发探测器(SSD)和RetinaNet:

  • 检测图像中的徽标
  • 检测交通标志(例如停车标志,产量标志等)
  • 检测车辆的前视图和后视图(用于构建自动驾驶汽车应用)
  • 检测图像和视频流中的武器

书中的所有对象检测章节都包含对算法和代码的详细说明,确保您能够成功训练自己的对象检测器。

要了解有关我的书的更多信息(并获取免费的示例章节和目录),请单击此处。

摘要

在本教程中,我们学习了如何使用Deep Learning,OpenCV和Python执行YOLO对象检测。

然后,我们简要讨论了YOLO架构,然后实现了Python代码:

  1. 将YOLO对象检测应用于单个图像
  2. 将YOLO对象检测器应用于视频流

在配备3GHz Intel Xeon W处理器的机器上,YOLO的单个前向传输耗时约0.3秒; 但是,使用前一个教程中的单次检测器(SSD),只能检测到0.03秒,速度提高了一个数量级!

对于使用OpenCV和Python在CPU上进行基于深度学习的实时对象检测,您可能需要考虑使用SSD。

如果您有兴趣在自己的自定义数据集上训练自己的深度学习对象探测器,请务必参阅我的书“使用Python进行计算机视觉深度学习”,其中提供了有关如何成功训练自己的探测器的详细指南。

我希望你喜欢今天的YOLO对象检测教程!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值