⼀⽂带你学会使⽤YOLO及Opencv完成图像及视频流⽬标检测
(上)附源码
计算机视觉领域中,⽬标检测⼀直是⼯业应⽤上⽐较热门且成熟的应⽤领域,⽐如⼈脸识别、⾏⼈检测等,国内的旷视科技、商汤科技等公司在该领域占据⾏业领先地位。相对于图像分类任务⽽⾔,⽬标检测会更加复杂⼀些,不仅需要知道这是哪⼀类图像,⽽且要知道图像中所包含的内容有什么及其在图像中的位置,因此,其⼯业应⽤⽐较⼴泛。那么,今天将向读者介绍该领域中表现优异的⼀种算算法——“你只需要看⼀次”(you only look once,yolo),提出该算法的作者风趣幽默可爱,其及论⽂风格显⽰了其性情,⽬前该算法已是第三个版本,简称YoLo V3。闲话少叙,下⾯进⼊教程的主要内容。
在本教程中,将学习如何使⽤YOLO、OpenCV和Python检测图像和视频流中的对象。主要内容有:
简要讨论YOLO算法;
使⽤YOLO、OpenCV、Python进⾏图像检测;
使⽤YOLO、OpenCV、Python进⾏视频流检测;
讨论YOLO算法的优点和缺点;
什么是YOLO?
图1: YOLO⽬标检测器简化⽰意图
当涉及基于深度学习的对象检测时,常⽤的三类算法有:
R-CNN家族系列算法:R-CNN、fast R-CNN以及faster R-CNN;
单发检测器(SSD);
YOLO算法;
是最早的基于深度学习的⽬标检测器之⼀,其结构是两级⽹络:
⾸先需要诸如之类的算法来提出可能包含对象的候选边界框;
然后将这些区域传递到CNN算法进⾏分类;
R-CNN算法存在的问题在于其仿真很慢,并且不是完整的端到端的⽬标检测器。
对原始R-CNN进⾏了相当⼤的改进,即提⾼准确度并减少执⾏正向传递所花费的时间,但是,该模型仍然依赖于外部区域搜索算法。
直到2015年,[faster R-CNN]()才成为真正的端到端深度学习⽬标检测器,删除了选择性搜索的要求,⽽是依赖于(1)完全卷积的区域提议⽹络(RPN)和(2)可以预测对象边界框和“对象”分数(量化它是⼀个区域的可能性的分数)。然后将RPN的输出传递到R-CNN组件以进⾏最终分类和标记。
R-CNN系列算法的检测结果⼀般都⾮常准确,但R-CNN系列算法最⼤的问题在仿真速度——⾮常慢,即使是在GPU上也仅获得5 FPS。
为了提⾼基于深度学习的⽬标检测器的速度,单次检测器(SSD)和YOLO都使⽤单级检测器策略(one stage)。这类算法将对象检测视为回归问题,获取给定的输⼊图像并同时学习边界框坐标和相应的类标签概率。通常,单级检测器往往不如两级检测器准确,但其速度明显更快。YOLO是单级检测器中⼀个很好的算法。
,在GPU上获得了 45 FPS性能,此外,同时也提出了⼀个较⼩的变体称为“Fast YOLO”,在GPU上达到155 FPS的性能。
YOLO经历了许多次的迭代,包括,能够检测超过9,000个⽬标。直到最近提出的,YOLOv3模型⽐之前的版本要复杂得多,但它是YOLO系列⽬标检测器中最好的⼀款。
本⽂使⽤YOLOv3,并在COCO数据集上进⾏训练。
COCO数据集由80个标签组成,可以使⽤到YOLO在COCO数据集上训练的内容的完整列表。
rectangle函数opencv项⽬结构
在终端中使⽤tree命令,可以很⽅便快捷地⽣成⽬标树:
$ 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个⽂件夹和2个Python脚本。
⽬录(按重要性顺序)是:
yolo - coco /:YOLOv3对象检测器预先(在COCO数据集上)训练得到最终的权重⽂件,可以在主页到对应的⽂件;
images /:此⽂件夹包含四个静态图像,之后将执⾏对象检测以进⾏测试和评估;
videos/:使⽤YOLO对图像进⾏⽬标检测器后,将实时处理视频。该⽂件夹中包含四个⽰例视频可供测试;
输出/:输出已由YOLO处理并带有边界框和类名称注释的视频可以放在此⽂件夹中;
此外还有两个Python脚本——yolo .py和yolo_video.py,第⼀个脚本⽤于图像处理,第⼆个脚本⽤于视频处理。下⾯进⼊实战内容,你准备好了吗?
将YOLO应⽤于图像对象检测
⾸先将YOLO⽬标检测器应⽤于图像中,⾸先打开项⽬中的yolo .py并插⼊以下代码:
# 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())
在使⽤之前,需要为此脚本安装 3.4.2+版本以上的OpenCV,可以直接使⽤
pip install opencv-python==3.4.2安装,你也可以到OpenCV安装教程,这⾥注意⼀点,OpenCV 4⽬前处于测试阶段,这⾥建议去安装OpenCV 3.4.2+。
⾸先,导⼊所需的数据包——OpenCV和NumPy。现在解析四个命令⾏参数,命令⾏参数在运⾏时处理,允许我们从终端更改脚本的输⼊。如果你对其不熟悉,建议阅读。命令⾏参数包括:
-- image:输⼊图像的路径;
-- yolo:YOLO⽂件路径,脚本将加载所需的YOLO⽂件,以便在图像上执⾏对象检测;
-- confidence:过滤弱检测的最⼩概率,默认值设置为0.5,但该值也可以随意设置;
-- threshold:⾮最⼤值抑制阈值,默认值设置为0.3,可以在此处阅读有关的更多信息。
解析之后,args变量是⼀个包含命令⾏参数的键值对的字典。下⾯为每个标签设置随机颜⾊:
# 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")
上述加载所有类LABELS,其类型是列表,保存的是类别名称,然后将随机颜⾊分配给每个标签。下⾯设置YOLO权重和配置⽂件的路径,然后从磁盘加载YOLO⽂件:
# 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 ")
net = adNetFromDarknet(configPath, weightsPath)
从磁盘加载YOLO⽂件后,并利⽤OpenCV中的adNetFromDarknet函数从中读取⽹络⽂件及权重参数,此函数需要两个参
数configPath和 weightsPath,这⾥再次强调,:OpenCV 的版本⾄少是3.4.2及以上才能运⾏此代码,
因为它需要加载YOLO所需的更新
的 dnn模块。
下⾯加载图像并处理:
# 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 = LayerNames()
ln = [ln[i[0] - 1] for i UnconnectedOutLayers()]
# 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))
在该代码中:
加载输⼊图像并获得其尺⼨;
确定YOLO模型中的输出图层名称;
从图像构造⼀个 blob结构;
如果你对blob和cv2.dnn.blobFromImage有疑问,可以看这篇博客进⼀步的了解。
当blob准备好了后,我们就会
通过YOLO⽹络进⾏前向传递;
显⽰YOLO的推理时间;
现在采取措施来过滤和可视化最终的结果。⾸先,让我们初步化⼀些处理过程中需要的列表:
# initialize our lists of detected bounding boxes, confidences, and
# class IDs, respectively
boxes = []
confidences = []
classIDs = []
这些列表包括:
boxes:对象的边界框。
confidences:YOLO分配给对象的置信度值,较低的置信度值表⽰该对象可能不是⽹络认为的对象。上⾯的命令⾏参数中将过滤掉不⼤于 0.5阈值的对象。
classIDs:检测到的对象的类标签。
下⾯⽤YOLO layerOutput s中的数据填充这些列表:
# 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;
循环每个detection中output;
提取classID和confidence;
使⽤confidence滤除弱检测;
过滤掉了不需要的检测结果后,我们将:
缩放边界框坐标,以便我们可以在原始图像上正确显⽰它们;
提取边界框的坐标和尺⼨,YOLO返回边界框坐标形式:(centerX ,centerY ,width,height);
使⽤此信息导出边界框的左上⾓(x,y)坐标;
更新boxes,confidences,classIDs列表。
有了这些数据后,将应⽤“⾮最⼤值抑制”(non-maxima suppression,nms):
# 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模块实现即可实现⾮最⼤值抑制,所需要的参数是边界框、置信度、以及置信度阈值和NMS阈值。
最后在图像上绘制检测框和类⽂本:
# 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]]]
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)
假设存在⾄少⼀个检测结果,就循环⽤⾮最⼤值抑制确定idx 。然后,我们使⽤随机类颜⾊在图像上绘制边界框和⽂本。最后,显⽰结果图像,直到⽤户按下键盘上的任意键。
下⾯进⼊测试环节,打开⼀个终端并执⾏以下命令:
$ python yolo.py --image images/baggage_claim.jpg --yolo yolo-coco
[INFO] loading YOLO
[INFO] YOLO took 0.347815 seconds
图2:YOLO⽤于检测机场中的⼈员和⾏李
从上图可以看到,YOLO不仅检测了输⼊图像中的每个⼈,还检测了⼿提箱。此外,可以从图像的右上⾓看到,YOLO还检测到⼥⼠肩上的⼿提包。
我们试试另⼀个例⼦:
$ python yolo.py --image images/living_room.jpg --yolo yolo-coco
[INFO] loading YOLO
[INFO] YOLO took 0.340221 seconds
图3: YOLO⽤于检测⼈、狗、电视和椅⼦
YOLO还可以检测电视显⽰器和椅⼦,令我惊讶的是YOLO能够检测到椅⼦,因为它是⼿⼯制作的⽼式“婴⼉⾼脚椅”。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论