前言

本文是nano自动驾驶小车开发系列中关于环境感知部分的分享,介绍目标检测中的yolo算法。

我分别使用了OAK-D-Lite和普通USB摄像头这两种硬件在windows10下实现了yolov

5的复现。如果使用OAK的话,需要首先配置好OAK-SDK再使用。

​​​​​​​


 

一、硬件配置

硬件:OAK-D-Lite、普通USB摄像头

软件:depthAI(是跨平台的,Windows,Linux均可部署,也有docker镜像)

一、YOLO简介

1.1 目标检测任务​​​​​​​

目标检测是模式识别问题的一种,是计算机视觉领域中的一个重要研究方向,也是其他复杂视觉任务的基础。 作为图像理解和计算机视觉的基石,目标检测是解决分割、场景理解、目标跟踪、图像描述和事件检测等更高层次 视觉任务的基础。其本质就是回归问题和聚类问题。

目标检测有两种实现,一种是one-stage,另一种是two-stage,它们的区别如名称所体现的,two-stage有一个region proposal过程,可以理解为网络会先生成目标候选区域,然后把所有的区域放进分类器分类,而one-stage会先把图片分割成一个个的image patch,然后每个image patch都有Manchor box,把所有的anchor送进分类器输出分类和检测位置。很明显可以看出,后一种方法的速度会比较快。

图1.1:两种实现的主要区别

YOLO算法是一种典型的one-stage方法,它是You Only Look Once 的缩写,意思是神经网络只需要看一次图片,就能输出结果。

1.2yolo发展历程

YOLO到目前为止总共发布了七个版本,其中YOLOv1奠定了整个YOLO系列的基础,后面的YOLO算法是对其的不断改进创新。前五代是已经较为成熟和广泛应用的,至于v6v7虽然已经发布,但其并未被大范围使用,还在测试阶段。

YOLOv1发布于2015年,是one-stage detection的开山之作,在此之前的目标检测都是采用two-stage的方法,虽然准确率较高,但是运行速度慢。

由于YOLOv1存在定位不准确以及与two-stage方法相比召回率低的缺点,作者于2017年提出了YOLOv2算法。在论文中作者提出了从更准确,更快,更多识别三个角度对YOLOv1算法进行了改进,其中识别更多对象也就是扩展到能检测9000种不同对象,被称为YOLO9000

2018YOLO的作者提出了YOLOv3,它是前作的改进,最大的改进特点包括使用了残差模型Darknet-53,以及为了实现多尺度检测采用了FPN架构。YOLOv3中只有卷积层,控制特征图的尺寸这一任务由调节卷积步长来实现,同时由于采用了FPN架构,因此总共会输出三个特征图,第一个下采样32倍,第二个下采样16倍,第三个下采样8倍,小尺寸的特征图检测大尺寸物体,大尺寸特征图检测小尺寸物体。类似于YOLOv2,每种特征图对应了多种特征框,这里作者为每种特征图定义了3个先验框,总共有9个先验框,每个框预测五元组(即坐标和置信度)以及80one-hot向量。这9个先验框同样是根据K-means算法求出来的。

YOLOv4在原来的YOLO目标检测架构的基础上,采用了很多优化策略,在数据处理,主干网络,网络训练,激活函数,损失函数等方面都有不同程度的优化。YOLOv4的网络结构如上所示,可以看出,他是在YOLOv3的主干网Darknet-53的基础上增加了backbone结构,其中包含了5CSP模块,可以有效增强网络的学习能力,降低成本。同时增加了Droblock,缓解过拟合现象。此外很重要的一点是,使用了Mish激活函数输入部分采用了Mosaic数据增强,随机采用四张图片随即缩放后随机凭借,丰富了数据集,增强了模型的鲁棒性。预测部份采用了CIOU_Loss替换IOU_Loss,DIOU_nms替换了nms,充分考虑了边框不重合,中心点距离,以及边框宽高比的问题。

YOLOv5实际上也是在YOLOv4的基础上进行了一定程度的优化。在YOLOv5中新加入了一个focus框架,其最大的特点是原始608×608×3的图像输入Focus结构,采用切片操作,先变成304×304×12的特征图,再经过一次32个卷积核的卷积操作,最终变成304×304×32的特征图,加速了训练速度。 另外在YOLOv4中使用的CSP模块现在在backoneneck中都有应用。输入部分依然采用了YOLOv4中采用的Mosaic数据增强技术,另外对于anchor box的设置采用了每次训练时自适应生成的方式,以及为了保持正常的长宽比,在填充增强环节自适应增添最少的黑边。预测部份同样采用了CIOU_Loss替换了IOU_Loss,DIOU_nms替换了nms.

二、原理介绍

2.1整体原理

Yolov5首先会将一幅图像分成S*S个网格,如果某个object的中心落在这个网格内,则这个网格就负责预测这个object

每个网格要预测Bbounding box,每个bounding box除了要回归自身的位置之外(x,y,w,h),还要附带预测一个confidence值,共5个值。

每个网格还要预测C个类别信息,记为C类。则S*S个网格,每个网格要预测Bbounding box还要预测Ccategories。输出就是S*S(5*B+C)的一个张量。

最后去除可能性较低的目标窗口,用NMS非极大值抑制去除冗余窗口。

 

图2.1:整体运行原理

2.2自适应锚框计算

锚框就是bounding box在进行非极大值抑制之前的名字,其本质上是同一个东西。

YOLOv5对于不同的数据集,都会计算先验框 anchor。然后在网络训练时,网络会在 anchor 的基础上进行预测,然后输出预测框,再和标签框进行对比,最后就进行梯度地反向传播。在YOLOv3YOLOv4中,训练不同的数据集时,是使用单独的脚本进行初始锚框的计算,在YOLOv5中,则是将此功能嵌入到整个训练代码里中。所以在每次训练开始之前,它都会根据不同的数据集来自适应计算 anchor

自适应锚框计算主要分为五步进行:

Step1:读取训练集中所有图片的wh以及检测框的wh

Step2:将读取的坐标修正为绝对坐标

Step3:使用Kmeans算法对训练集中所有的检测框进行聚类,得到kanchors

Step4:通过遗传算法对得到的anchors进行变异,如果变异后效果好将其保留,否则跳过

Step5:将最终得到的最优anchors按照面积返回

 

图2.2:自适应锚框计算

2.3自适应图片缩放

自适应图片缩放针对不同的目标检测算法而言,我们通常需要执行图片缩放操作,即将原始的输入图片缩放到一个固定的尺寸,再将其送入检测网络中。yolov5处理的图片的大小是640*640,如果输入的不是640*640的话,会按照比例进行缩放,将不够的部分用黑色来填充。因为网络里定义的步长是32,而图片的大小必须是32的整数倍,所以输入的图片大小是640*640

原始的缩放方法存在着一些问题,因为在实际的使用中的很多图片的长宽比不同,所以在进行缩放填充之后,两端的黑边大小都不相同,但是如果填充过多,则会存在大量的信息冗余,从而影响整体的推理速度。

为了进一步提升推理速度,YOLOv5 提出一种方法能够自适应的添加最少的黑边到缩放之后的图片中。也就是通过调用letterbox这个类实现自适应图片缩放。其核心思想是根据原始图片大小与输入到网络图片大小计算缩放比例,根据原始图片大小与缩放比例计算缩放后的图片大小,计算黑边填充数值。这样,图像高度上两端的黑边变少了,在推理时,计算量也会减少,目标检测速度得到提升。

三、原理解析

3.1 Yolov5-6.2的文件结构

Requeirements.txt运行yolov5所需要的配置。

Detect.py用来检测,直接运行默认是对date/images文件夹下的两张照片进行检测识别。

Train.py用来训练,直接执行默认下载coco128数据集,进行训练。

Val.py用来验证。

Yolov5s.pt官方提供的已经训练好的权重文件,后缀是pt说明是用pytorch框架训练的。

Date文件夹里存放的是数据集,也就是要进行识别的图片或是视频,也可以是自定义的数据集。

Models文件夹用来存放模型。里面主要是一些网络构建的配置文件和函数,其中包含了该项目的四个不同的版本,分别为是smlx。从名字就可以看出,这几个版本的大小。他们的检测测度分别都是从快到慢,但是精确度分别是从低到高。如果训练自己的数据集的话,就需要修改这里面相对应的yaml文件来训练自己模型。

Runs文件夹里存放的是运行结果。

Utila文件夹里是运行detect.py及其他py文件所依赖的一些模块。例如工具类的函数里面有loss函数,metrics函数,plots函数等等

图3.1:文件结构

3.2detect.py剖析

detec.py用来检测要是别的图片或视频或摄像头实时拍摄的图像。而detect.py中最主要的就是parse_opt()run()这两个子函数。

3.2.1 Parse_opt()

parse_opt()是用来设置输入参数的子函数。

weights: 训练的权重路径,可以使用自己训练的权重,也可以使用官网提供的权重默认官网的权yolov5s.pt

source: 测试数据,可以是图片/视频路径,也可以是'0'(电脑自带摄像头),也可以是rtsp等视频流, 默认data/images

data: 配置数据文件路径, 包括image/label/classes等信息, 训练自己的文件, 需要作相应更改

class:要检测的类别,如果设置了只显示个别类别即使用--classes = 0,数字和类别相对应才能只检测某一个类

imgsz: 网络输入图片大小, 默认的大小是640*640

conf-thres: 置信度阈值, 默认为0.25

iou-thres:  nmsiou阈值, 默认为0.45

max-det: 保留的最大检测框数量, 每张图片中检测目标的个数最多为1000  device: 设置设备CPU/CUDA, 如果有GPU的运行环境会默认使用GPU

view-img: 是否展示预测之后的图片/视频, 默认False, --view-img 电脑界面出现图片或者视频检测结果

save-txt: 是否将预测的框坐标以txt文件形式保存, 默认False, 使用--save-txt 在路径runs/detect/exp*/labels/*.txt下生成每张图片预测的txt文件

save-conf: 是否将置信度conf也保存到txt, 默认False

save-crop: 是否保存裁剪预测框图片, 默认为False, 使用--save-crop runs/detect/exp*/crop/剪切类别文件夹/ 路径下会保存每个接下来的目标

nosave: 不保存图片、视频, 要保存图片,不设置--nosave runs/detect/exp*/会出现预测的结果

classes: 设置只保留某一部分类别, 形如0或者0 2 3, 使用--classes = n, 则在路径runs/detect/exp*/下保存的图片为n所对应的类别, 此时需要设置data

agnostic-nms: 进行NMS去除不同类别之间的框, 默认False

augment: TTA测试时增强/多尺度预测

visualize: 是否可视化网络层输出特征

update: 如果为True,则对所有模型进行strip_optimizer操作,去除pt文件中的优化器等信息,默认为False

project:保存测试日志的文件夹路径

name:保存测试日志文件夹的名字, 所以最终是保存在project/name

exist_ok: 是否重新创建日志文件, False时重新创建文件

line-thickness: 画框的线条粗细

hide-labels: 可视化时隐藏预测类别

hide-conf: 可视化时隐藏置信度

half: 是否使用F16精度推理, 半进度提高检测速度

dnn: OpenCV DNN预测

图3.2:parse_opt()子函数

3.2.2Run()

run()子函数按照逻辑顺序可以分为处理输入来源、结果保存的设置、模型加载、数据加载、推理、打印运行结果,这六个主要部分。具体解释在代码中以注释的形式体现。

第一部分:处理输入来源。定义了一些布尔值区分输入是图片、视频、网络流还是摄像头。

图3.3:run()第一部分

第二部分:创建一个新的文件夹exp(在runs文件夹下)用于保存运行的结果。

图3.4:run()第二部分

第三部分:模型加载,调用Utila文件夹里其他py文件中定义的一些类,来搭建模型。

其中imgsz就是上文提到的640*640,自适应缩放图片大小

图3.5:run()第三部分

第四部分:数据加载,如果webcam的值是Ture就加载摄像头,如果值是False就加载图片(输入是视频是会一帧一帧地输入,其本质也是图片)

图3.6:run()第四部分

第五部分:推理部分。是整个算法的核心部分。通过for循环对加载的数据进行遍历,一帧一帧地推理,进行NMS非极大值抑制、绘制bounding box、预测类别。

图3.7:run()第五部分

图3.8:run()第五部分

第六部分:在终端里打印出运行的结果

图3.9:run()第六部分

四、复现步骤

4.1环境搭建

前提是要已经配置好python的运行环境以及pip下载工具。然后从官网克隆源代码到本地(GitHub - ultralytics/yolov5: YOLOv5 🚀 in PyTorch > ONNX > CoreML > TFLite)。

打开cmd,切换到源代码文件夹所在的地址,执行pip install -r requeirements.txt安装运行yolov5所需要的第三方库。如果想使用GPU运行的话,需要在另外安装GPU驱动和对应显卡版本的CUDA

4.2训练自己的数据集

首先我们要准备好数据集并将其划分为训练集、验证集、测试集。然后使用labelimg这个工具对数据打标签。

图4.1:labelimg标注工具

打好标签后,会生成一些txt文件。一张jpg照片对应一个txt文本文件,这两者命名完全一样。txt文本文件里包含的就是对应图片的标记数据,图片内有几个bounding box,文本文件就对应有几行,每一行的第一个数字就是预测的bounding box对应物体的类别,后四个数字就是bounding box的位置。

图4.2:coco128数据集0241

将我们自定义打标好签标签后的图片放到date/images文件夹下,并在date文件夹下新建一个yaml配置文件,可以参考coco128数据集的配置文件,配置以下内容:

path: 自定义打标好签标签后的图片放置的路径

train:训练集数据存放路径

val:验证集数据存放路径

nc:自定义的数据集所包含种类的数目

names:种类列表,其大小就是nc的值​​​​​​​

 图4.3:coco128数据集的配置文件

做完以上操作,就可以执行train.py来训练自己的数据集,训练结束后会生成一个权重文件,将这个权重文件作为detect.py的输入时,就可以用来检测我们标记的物体。

5成果展示

以下图片是我在windows10系统上部署yolov5运行的一些结果。

 

图5.1:yolov5-6.2运行结果


 

总结

        本文仅是简单介绍了yolov5原理和代码,对于API和类并未详细介绍,如果是想深究其源码,大家可以去官网查阅详细资料;如果是简单理解原理与运用,看本文足够了。本文同时作为笔者这学期修读的计算机视觉课程的期末作业,ddl才是最佳生产力。

        由于笔者水平有限,出现错误也是在所难免,随时欢迎各位的交流与批评指正。 

        本文为原创博客,如需转载,请联系本人,注明出处即可。

Logo

更多推荐