在这篇文章中,我们将学习如何使用YOLOv3(一种最先进的物体探测器)与OpenCV。

YOLOv3是流行的物体检测算法YOLO的最新变种- 你只看一次。已发布的模型可识别图像和视频中的80个不同对象,但最重要的是它具有超快速且几乎与Single Shot MultiBox(SSD)一样准确。

从OpenCV 3.4.2开始,您可以在自己的OpenCV应用程序中轻松使用YOLOv3模型。

这篇文章主要关注推理,但是如果你想在你的数据集上训练你自己的YOLOv3模型,你会在后续帖子中找到相同的教程。

YOLO如何运作?

我们可以将对象检测器视为对象定位器和对象识别器的组合。

在传统的计算机视觉方法中,使用滑动窗口来寻找不同位置和尺度的物体。因为这是如此昂贵的操作,所以通常假设物体的纵横比是固定的。

基于早期深度学习的对象检测算法(如R-CNN和快速R-CNN)使用称为选择性搜索的方法来缩小算法必须测试的边界框的数量。

另一种称为Overfeat的方法涉及使用滑动窗口式机制以多个比例扫描图像。

紧随其后的是更快的R-CNN,它使用区域提议网络(RPN)来识别需要测试的边界框。通过巧妙的设计,提取用于识别对象的特征也被RPN用于提出潜在的边界框,从而节省了大量的计算。

另一方面,YOLO以完全不同的方式处理对象检测问题。它只通过网络转发整个图像一次。SSD是另一种物体检测算法,它通过深度学习网络将图像转发一次,但YOLOv3比SSD快得多,同时实现了非常可比的精度。YOLOv3在M40,TitanX或1080 Ti GPU上提供比实时结果更快的速度。

让我们看看YOLO如何检测给定图像中的对象。

首先,它将图像划分为13×13的单元格。这169个单元的大小取决于输入的大小。对于我们在实验中使用的416×416输入尺寸,单元尺寸为32×32。然后每个单元负责预测图像中的多个框。

对于每个边界框,网络还预测边界框实际包围对象的置信度,以及封闭对象是特定类的概率。

大多数这些边界框都被消除了,因为它们的置信度很低,或者因为它们与另一个具有非常高置信度得分的边界框包围相同的对象。该技术称为非最大抑制。

YOLOv3,Joseph Redmon和Ali Farhadi 的作者使YOLOv3比以前的作品YOLOv2更快,更准确。YOLOv3可以更好地处理多个秤。他们还通过增加网络来改进网络,并通过添加快捷连接将网络扩展到剩余网络。

在Darknet和OpenCV上对YOLOv3进行速度测试

下表显示了YOLOv3在Darknet与OpenCV上的性能。所有情况下的输入大小为416×416。毫无疑问,Darknet的GPU版本优于其他任何东西。使用OpenMP的Darknet比没有OpenMP的Darknet工作得更好也不足为奇,因为OpenMP允许使用多个处理器。

令人惊讶的是,OpenCV的DNN CPU实现速度比使用OpenML的Darknet快9倍。

OS

Framework

CPU/GPU

Time(ms)/Frame

Linux 16.04

Darknet

12x Intel Core i7-6850K CPU @ 3.60GHz

9370

Linux 16.04

Darknet + OpenMP

12x Intel Core i7-6850K CPU @ 3.60GHz

1942

Linux 16.04

OpenCV [CPU]

12x Intel Core i7-6850K CPU @ 3.60GHz

220

Linux 16.04

Darknet

NVIDIA GeForce 1080 Ti GPU

23

macOS

DarkNet

2.5 GHz Intel Core i7 CPU

7260

macOS

OpenCV [CPU]

2.5 GHz Intel Core i7 CPU

400

第1步:下载模型

我们将从命令行使用脚本文件getModels.sh下载模型开始。

sudo chmod a+x getModels.sh

./getModels.sh

1

2

sudo chmod a+x getModels.sh

./getModels.sh

这将下载yolov3.weights文件(包含预先训练的网络权重),yolov3.cfg文件(包含网络配置)和coco.names文件,其中包含COCO数据集中使用的80个不同的类名。

第2步:初始化参数

YOLOv3算法生成边界框作为预测的检测输出。每个预测的框都与置信度得分相关联。在第一阶段,忽略置信度阈值参数以下的所有框以进行进一步处理。

其余的盒子经历非最大限度的抑制,这消除了多余的重叠边界框。非最大抑制由参数nmsThreshold控制。您可以尝试更改这些值,并查看输出预测框的数量如何变化。

接下来,设置网络输入图像的输入宽度(inpWidth)和高度(inpHeight)的默认值。我们将它们中的每一个设置为416,以便我们可以将我们的运行与YOLOv3作者给出的Darknet的C代码进行比较。您也可以将它们更改为320以获得更快的结果,或者更改为608以获得更准确的结果。

# Initialize the parameters

confThreshold = 0.5  #Confidence threshold

nmsThreshold = 0.4   #Non-maximum suppression threshold

inpWidth = 416       #Width of network's input image

inpHeight = 416      #Height of network's input image

1

2

3

4

5

# Initialize the parameters

confThreshold = 0.5  #Confidence threshold

nmsThreshold = 0.4   #Non-maximum suppression threshold

inpWidth = 416       #Width of network's input image

inpHeight = 416      #Height of network's input image

第3步:加载模型和类

文件coco.names包含训练模型的所有对象。我们读了班级名字。

接下来,我们加载网络有两个部分 –

yolov3.weights:预训练的重量。

yolov3.cfg:配置文件。

我们在这里将DNN后端设置为OpenCV,将目标设置为CPU。您可以尝试将首选目标设置为cv.dnn.DNN_TARGET_OPENCL以在GPU上运行它。但请记住,目前的OpenCV版本仅使用英特尔的GPU进行测试,如果您没有英特尔GPU,它会自动切换到CPU。

# Load names of classes

classesFile = “coco.names”;

classes = None

with open(classesFile, ‘rt’) as f:

classes = f.read().rstrip(‘\n’).split(‘\n’)

# Give the configuration and weight files for the model and load the network using them.

modelConfiguration = “yolov3.cfg”;

modelWeights = “yolov3.weights”;

net = cv.dnn.readNetFromDarknet(modelConfiguration, modelWeights)

net.setPreferableBackend(cv.dnn.DNN_BACKEND_OPENCV)

net.setPreferableTarget(cv.dnn.DNN_TARGET_CPU)

第4步:阅读输入

在此步骤中,我们将读取图像,视频流或网络摄像头。此外,我们还打开视频编写器以保存具有检测到的输出边界框的帧。

outputFile = "yolo_out_py.avi"

if (args.image):

# Open the image file

if not os.path.isfile(args.image):

print("Input image file ", args.image, " doesn't exist")

sys.exit(1)

cap = cv.VideoCapture(args.image)

outputFile = args.image[:-4]+'_yolo_out_py.jpg'

elif (args.video):

# Open the video file

if not os.path.isfile(args.video):

print("Input video file ", args.video, " doesn't exist")

sys.exit(1)

cap = cv.VideoCapture(args.video)

outputFile = args.video[:-4]+'_yolo_out_py.avi'

else:

# Webcam input

cap = cv.VideoCapture(0)

# Get the video writer initialized to save the output video

if (not args.image):

vid_writer = cv.VideoWriter(outputFile, cv.VideoWriter_fourcc('M','J','P','G'), 30, (round(cap.get(cv.CAP_PROP_FRAME_WIDTH)),round(cap.get(cv.CAP_PROP_FRAME_HEIGHT))))

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

outputFile = "yolo_out_py.avi"

if (args.image):

# Open the image file

if not os.path.isfile(args.image):

print("Input image file ", args.image, " doesn't exist")

sys.exit(1)

cap = cv.VideoCapture(args.image)

outputFile = args.image[:-4]+'_yolo_out_py.jpg'

elif (args.video):

# Open the video file

if not os.path.isfile(args.video):

print("Input video file ", args.video, " doesn't exist")

sys.exit(1)

cap = cv.VideoCapture(args.video)

outputFile = args.video[:-4]+'_yolo_out_py.avi'

else:

# Webcam input

cap = cv.VideoCapture(0)

# Get the video writer initialized to save the output video

if (not args.image):

vid_writer = cv.VideoWriter(outputFile, cv.VideoWriter_fourcc('M','J','P','G'), 30, (round(cap.get(cv.CAP_PROP_FRAME_WIDTH)),round(cap.get(cv.CAP_PROP_FRAME_HEIGHT))))

神经网络的输入图像需要采用称为blob的特定格式。

从输入图像或视频流中读取帧后,将通过blobFromImage函数将其转换为神经网络的输入blob。在此过程中,它使用比例因子1/255将图像像素值缩放到0到1的目标范围。它还将图像的大小调整为给定大小(416,416)而不进行裁剪。请注意,我们不在此处执行任何均值减法,因此将[0,0,0]传递给函数的mean参数,并将swapRB参数保持为其默认值1。

然后输出blob作为输入传递到网络,并运行正向传递以获得预测边界框列表作为网络输出。这些框经过后处理步骤,以滤除低置信度分数。我们将在下一节中更详细地介绍后处理步骤。我们打印出左上角每帧的推理时间。然后将具有最终边界框的图像保存到磁盘,作为图像输入的图像或使用输入视频流的视频写入器。

while cv.waitKey(1) < 0:

# get frame from the video

hasFrame, frame = cap.read()

# Stop the program if reached end of video

if not hasFrame:

print("Done processing !!!")

print("Output file is stored as ", outputFile)

cv.waitKey(3000)

break

# Create a 4D blob from a frame.

blob = cv.dnn.blobFromImage(frame, 1/255, (inpWidth, inpHeight), [0,0,0], 1, crop=False)

# Sets the input to the network

net.setInput(blob)

# Runs the forward pass to get output of the output layers

outs = net.forward(getOutputsNames(net))

# Remove the bounding boxes with low confidence

postprocess(frame, outs)

# Put efficiency information. The function getPerfProfile returns the

# overall time for inference(t) and the timings for each of the layers(in layersTimes)

t, _ = net.getPerfProfile()

label = 'Inference time: %.2f ms' % (t * 1000.0 / cv.getTickFrequency())

cv.putText(frame, label, (0, 15), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255))

# Write the frame with the detection boxes

if (args.image):

cv.imwrite(outputFile, frame.astype(np.uint8));

else:

vid_writer.write(frame.astype(np.uint8))

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

26

27

28

29

30

31

32

33

34

35

while cv.waitKey(1) < 0:

# get frame from the video

hasFrame, frame = cap.read()

# Stop the program if reached end of video

if not hasFrame:

print("Done processing !!!")

print("Output file is stored as ", outputFile)

cv.waitKey(3000)

break

# Create a 4D blob from a frame.

blob = cv.dnn.blobFromImage(frame, 1/255, (inpWidth, inpHeight), [0,0,0], 1, crop=False)

# Sets the input to the network

net.setInput(blob)

# Runs the forward pass to get output of the output layers

outs = net.forward(getOutputsNames(net))

# Remove the bounding boxes with low confidence

postprocess(frame, outs)

# Put efficiency information. The function getPerfProfile returns the

# overall time for inference(t) and the timings for each of the layers(in layersTimes)

t, _ = net.getPerfProfile()

label = 'Inference time: %.2f ms' % (t * 1000.0 / cv.getTickFrequency())

cv.putText(frame, label, (0, 15), cv.FONT_HERSHEY_SIMPLEX, 0.5, (0, 0, 255))

# Write the frame with the detection boxes

if (args.image):

cv.imwrite(outputFile, frame.astype(np.uint8));

else:

vid_writer.write(frame.astype(np.uint8))

现在让我们详细了解上面使用的一些函数调用。

步骤4a:获取输出层的名称

OpenCV的Net类中的forward函数需要结束层,它应该在网络中运行。由于我们想要遍历整个网络,我们需要确定网络的最后一层。我们通过使用函数getUnconnectedOutLayers()来实现这一点,该函数给出了未连接的输出层的名称,这些输出层基本上是网络的最后一层。然后我们运行网络的正向传递以从输出层获得输出,如前面的代码片段(net.forward(getOutputsNames(net)))。

# Get the names of the output layers

def getOutputsNames(net):

# Get the names of all the layers in the network

layersNames = net.getLayerNames()

# Get the names of the output layers, i.e. the layers with unconnected outputs

return [layersNames[i[0] - 1] for i in net.getUnconnectedOutLayers()]

1

2

3

4

5

6

# Get the names of the output layers

def getOutputsNames(net):

# Get the names of all the layers in the network

layersNames = net.getLayerNames()

# Get the names of the output layers, i.e. the layers with unconnected outputs

return [layersNames[i[0] - 1] for i in net.getUnconnectedOutLayers()]

步骤4b:后处理网络的输出

网络输出边界框每个都由一组+5个元素的向量表示。

前4个元素代表center_x,center_y,width和height。第五个元素表示边界框包围对象的置信度。

其余元素是与每个类相关的置信度(即对象类型)。该框被分配到与该框的最高分相对应的类。

盒子的最高分也被称为信心。如果框的置信度小于给定阈值,则删除边界框并且不考虑进行进一步处理。

然后对其置信度等于或大于置信度阈值的框进行非最大抑制。这将减少重叠框的数量。

# Remove the bounding boxes with low confidence using non-maxima suppression

def postprocess(frame, outs):

frameHeight = frame.shape[0]

frameWidth = frame.shape[1]

classIds = []

confidences = []

boxes = []

# Scan through all the bounding boxes output from the network and keep only the

# ones with high confidence scores. Assign the box's class label as the class with the highest score.

classIds = []

confidences = []

boxes = []

for out in outs:

for detection in out:

scores = detection[5:]

classId = np.argmax(scores)

confidence = scores[classId]

if confidence > confThreshold:

center_x = int(detection[0] * frameWidth)

center_y = int(detection[1] * frameHeight)

width = int(detection[2] * frameWidth)

height = int(detection[3] * frameHeight)

left = int(center_x - width / 2)

top = int(center_y - height / 2)

classIds.append(classId)

confidences.append(float(confidence))

boxes.append([left, top, width, height])

# Perform non maximum suppression to eliminate redundant overlapping boxes with

# lower confidences.

indices = cv.dnn.NMSBoxes(boxes, confidences, confThreshold, nmsThreshold)

for i in indices:

i = i[0]

box = boxes[i]

left = box[0]

top = box[1]

width = box[2]

height = box[3]

drawPred(classIds[i], confidences[i], left, top, left + width, top + height)

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

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

# Remove the bounding boxes with low confidence using non-maxima suppression

def postprocess(frame, outs):

frameHeight = frame.shape[0]

frameWidth = frame.shape[1]

classIds = []

confidences = []

boxes = []

# Scan through all the bounding boxes output from the network and keep only the

# ones with high confidence scores. Assign the box's class label as the class with the highest score.

classIds = []

confidences = []

boxes = []

for out in outs:

for detection in out:

scores = detection[5:]

classId = np.argmax(scores)

confidence = scores[classId]

if confidence > confThreshold:

center_x = int(detection[0] * frameWidth)

center_y = int(detection[1] * frameHeight)

width = int(detection[2] * frameWidth)

height = int(detection[3] * frameHeight)

left = int(center_x - width / 2)

top = int(center_y - height / 2)

classIds.append(classId)

confidences.append(float(confidence))

boxes.append([left, top, width, height])

# Perform non maximum suppression to eliminate redundant overlapping boxes with

# lower confidences.

indices = cv.dnn.NMSBoxes(boxes, confidences, confThreshold, nmsThreshold)

for i in indices:

i = i[0]

box = boxes[i]

left = box[0]

top = box[1]

width = box[2]

height = box[3]

drawPred(classIds[i], confidences[i], left, top, left + width, top + height)

非最大抑制由nmsThreshold参数控制。如果nmsThreshold设置得太低,例如0.1,我们可能无法检测到相同或不同类的重叠对象。但如果设置得太高,例如1,那么我们会为同一个对象获得多个框。所以我们在上面的代码中使用了0.4的中间值。下面的gif显示了改变NMS阈值的效果。

步骤4c:绘制预测的框

最后,我们在输入框架上绘制通过非最大抑制过滤的框,其中包含指定的类标签和置信度分数。

# Draw the predicted bounding box

def drawPred(classId, conf, left, top, right, bottom):

# Draw a bounding box.

cv.rectangle(frame, (left, top), (right, bottom), (0, 0, 255))

label = '%.2f' % conf

# Get the label for the class name and its confidence

if classes:

assert(classId < len(classes))

label = '%s:%s' % (classes[classId], label)

#Display the label at the top of the bounding box

labelSize, baseLine = cv.getTextSize(label, cv.FONT_HERSHEY_SIMPLEX, 0.5, 1)

top = max(top, labelSize[1])

cv.putText(frame, label, (left, top), cv.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,255))

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

# Draw the predicted bounding box

def drawPred(classId, conf, left, top, right, bottom):

# Draw a bounding box.

cv.rectangle(frame, (left, top), (right, bottom), (0, 0, 255))

label = '%.2f' % conf

# Get the label for the class name and its confidence

if classes:

assert(classId < len(classes))

label = '%s:%s' % (classes[classId], label)

#Display the label at the top of the bounding box

labelSize, baseLine = cv.getTextSize(label, cv.FONT_HERSHEY_SIMPLEX, 0.5, 1)

top = max(top, labelSize[1])

cv.putText(frame, label, (left, top), cv.FONT_HERSHEY_SIMPLEX, 0.5, (255,255,255))

源码下载地址:

温馨提示: 此处内容需要 评论本文 后 刷新本页 才能查看!

本文最后更新于2019年6月13日,已超过 1 年没有更新,如果文章内容或图片资源失效,请留言反馈,我们会及时处理,谢谢!

cv dnn识别动作规范 open_[mcj]基于Opencv-DNN模块的YOLOv3目标检测并保存视频(C++)|YOLOV3修改检测物体为特定类别如飞机行人...相关推荐

  1. cv dnn识别动作规范 open_OpenCV开发笔记(七十三):红胖子8分钟带你使用opencv+dnn+yolov3识别物体...

    前言 级联分类器的效果并不是很好,准确度相对深度学习较低,上一章节使用了dnn中的tensorflow,本章使用yolov3模型,识别出具体的分类. Demo 320x320,置信度0.6 608x6 ...

  2. mask rcnn属于dnn么_基于OpenCV DNN的 MaskRCNN 目标检测与实例分割

    这里主要记录基于 OpenCV 4.x DNN 模块和 TensorFlow MaskRCNN 开源模型的目标检测与实例分割 的实现. MaskRCNN 不仅可以检测图片或视频帧中的物体边界框,还可以 ...

  3. 基于激光雷达点云的3D目标检测算法论文总结

    作者丨eyesighting@知乎 来源丨https://zhuanlan.zhihu.com/p/508859024 编辑丨3D视觉工坊 前言  过去很多年激光雷达的车规标准和高昂价格是阻碍其量产落 ...

  4. 值得收藏!基于激光雷达数据的深度学习目标检测方法大合集(下)

    作者 | 黄浴 来源 | 转载自知乎专栏自动驾驶的挑战和发展 [导读]在近日发布的<值得收藏!基于激光雷达数据的深度学习目标检测方法大合集(上)>一文中,作者介绍了一部分各大公司和机构基于 ...

  5. 用opencv的dnn模块做yolov5目标检测

    最近在微信公众号里看到多篇讲解yolov5在openvino部署做目标检测文章,但是没看到过用opencv的dnn模块做yolov5目标检测的.于是,我就想着编写一套用opencv的dnn模块做yol ...

  6. 笔记《基于无人驾驶方程式赛车的传感器融合目标检测算法研究及实现》

    论文结构 关键字:无人驾驶方程式赛车,相机,激光雷达,目标检测,传感器融合 一.绪论 1. 感知技术研究现状 1.1.1 基于相机的目标检测技术研究现状 1.1.2 基于激光雷达的目标检测技术研究现状 ...

  7. 基于深度学习的2D图像目标检测

    参见第一部分网址1,第二部分网址2 目前学术和工业界出现的目标检测算法分成3类:(参见一文读懂目标检测:R-CNN.Fast R-CNN.Faster R-CNN.YOLO.SSD) 1. 传统的目标 ...

  8. 基于opencv实现人脸猫脸图像检测(python)

    基于opencv实现人脸猫脸图像检测(python) 目录 基于opencv实现人脸猫脸图像检测(python) 1.方法流程如下 2 .导入相关库 3. 导入级联分类器 4.调整图像大小 5.彩色图 ...

  9. 基于轻量级卷积网络的小目标检测--轻量级骨干网络部分

    基于thundernet框架+dlanet网络+shufflenetv2卷积模块的小目标检测--轻量级骨干网络 前言 1 骨干网络框架DSNet(dlanet网络+shufflenetv2) 1.1 ...

最新文章

  1. php 限制刷新,PHP禁止频繁刷新方法
  2. Windows Azure Platform Introduction (2) 云计算的分类和服务层次
  3. 设置tomcat使用指定的jdk版本
  4. A Class For Executing MSSql Store Procedure
  5. textrank4zh是_GitHub - renxiaowei941015/TextRank4ZH: 从中文文本中自动提取关键词和摘要...
  6. 构建Java Web应用程序时遵循MVC的三个步骤
  7. mysql 触发器 for each row 理解_“for each row”如何在mysql中的触发器中工作?
  8. 权威!盘点 100 个最受欢迎的 Java 库!绝对经典
  9. Java生成png文件字体不清晰_java 文本图片字体模糊优化处理
  10. TD通过artnet控制电脑灯的操作
  11. 智能合约安全陷阱和开发建议
  12. html缩小照片尺寸像素不变,怎么修改照片像素,但又不改变照片大小呢?——解决照片因大小无法上传的方案...
  13. Codeforces D. Berserk And Fireball(贪心)
  14. 分析家数据格式、结构
  15. 原始套接字编程——Teardrop
  16. sklearn库:分类、回归、聚类、降维、模型优化、文本预处理实现用例(赶紧收藏)
  17. Flutter Container去掉边框
  18. External Storage
  19. ODOO11报价单确认订单创建入库单(_run_move)
  20. 数据分析师招聘岗位分析

热门文章

  1. python输入两个整数a和b、比较两者的大小、使得a大于b_面试题解:输入一个数A,找到大于A的一个最小数B,且B中不存在连续相等的两个数字...
  2. 巨型计算机辐射,事实:让我们看看各种计算机的辐射量有多大。您使用辐射多的计算机吗?...
  3. 微信什么情况下才会看到“对方正在输入……”
  4. ffmpeg android 编译
  5. JAVASE 面向对象
  6. 润乾键盘控制填报光标移动
  7. 谷歌浏览器(google)设置翻译中文,翻译选项不生效或没有弹出翻译选项
  8. 二层环路详解:交换机环路产生的过程和原因
  9. YUYV 转 RGB 24
  10. paypal tp 对接_Thinkphp5.1贝宝(Paypal)支付接入