前言

其实年初的时候,我也跟着别人的源码,用 Tensoflow 实现过扑克牌的目标检测。虽然也通过博文的方式记录了,但是那个项目使用的 TF 版本比较旧,自身对 TF 并不熟。后期如果说要升级或修改估计够呛,知道最近看到 YOLO 对目标检测的实现方法,发现这个更方便快捷。

于是决定用 YOLOv5.6 来重新实现一下扑克牌的点数识别,本文章主要是个人记录,也面向刚刚接触 YOLO 的同学阅读。所以以下会从数据标注,归一化处理到模型训练的实战内容,也包括各种踩坑经历和处理方法,最后对 detect.py 的重写,完成目标对象的坐标和识别标记输出。

打开网易新闻 查看更多图片

YOLO 简介

YOLO(You Only Look Once)是一种基于深度神经网络的对象识别和定位算法,其最大的特点是运行速度很快,可以用于实时系统。现在 YOLO 已经发展到 v8 版本,每个版本都在原有基础上改进演化的。选择 V5 是因为后面几个新版发行并不久,v5 相关资料和文章较多,踩坑起来也好搜索。其中每个版本里又有按场景划分几个特定场景版本,比如:

  • YOLOv5s:最小版本,速度最快,但检测性能最低。
  • YOLOv5m:中等版本,速度比 s 慢一些,但检测性能更好。
  • YOLOv5l:大型版本,速度比 m 慢,但检测性能更好。
  • YOLOv5x:最大版本,速度最慢,但是检测性能最好。
  • YOLOv5n6:中等版本,速度比 m 快一些,但检测性能更好。

总之,根据具体需求和应用场景,可以选择合适的 YOLOv5 版本以满足性能、速度和准确性的要求,我这里以 YOLOv5s 为例。然后在项目开始前呢,我们可以先去github下载 demo 代码和权重文件,比如 yolov5s.pt,下载完后就要准备数据集,也就是标记的图片。

数据集

图片的话,看你要识别的目标是啥,可以拍摄整理或去网上下载。为了让训练的模型稍微有点准确,最好准备一两百张,我这里就直接从原来 TF 项目那里拿过来。一共有 363 张扑克牌图片并且都已经用 VOC 格式标注好了,不过为了大家了解,这里还是会介绍如何标注,以及标注工具 labelImg 的基本使用。

LabelImg 使用

  • 操作界面

打开网易新闻 查看更多图片

  • 快捷使用

1、W 是进行标注

2、A 是切换到上一张图片

3、D 是切换到下一张图片

  • LabelImg 保存格式

1. PascalVOC 默认,xml格式

2. YOLO text可以直接拿来训练不用转换

实战

创建目录

在根目录下新建 datasets 用于放置训练的数据集,由于用同一 yolo 可以创建多个检测目标,所以在 datasets 先创建一个项目名目录。然后再在项目名下可创建 VOC 和 YOLO 两种格式的目录,虽然 labelImg 标注后可以直接保存 YOLO 格式也就是归一化后的 text,但是毕竟三百多张图的标注,我这里依然使用以前 TF 的 VOC 的标注数据。如果需要这些数据集的,可以留言,到时我再放在评论区。

打开网易新闻 查看更多图片

依赖安装

依赖直接安装项目根目录下的 requirements.txt 就可以,但是要严格按照里面的版本。因为我用的是以前 conda 创建的环境,可以包都装过,所以一开始就看到已经有的就没装,导致后面运行的时候很多问题都是包的版本问题。所以最好的方法就是用 conda 创建一个新环境,然后直接pip install -r requirements.txt 是最好的。

归一化和数据集划分

如果 LabelImg 标注后保存的是 YOLO 格式,归一化过程就可以略过了。前面我也说了是用的以前扑克牌的 VOC 格式,所以需要对 xml 里节点数据抽取坐标和标记然后转换成 yolo 的 txt 格式。以下代码是我从其他博主那薅过来的,主要就是归一化和划分训练数据集和校验数据集。特别主要是 classes 部分要修改成自己的目标分类,其他的可以不用改动,当然只是划分的话可以适当删减。

上面代码放在哪个位置看你自己,由于有些目录是相对位置,所以如果不想改也跟我一样放在 datasets 中。执行完上面代码后会在 datasets 下生成 images 和 labels 两个目录,而且特别注意的是这两个目录名最好就是也是这样,比如在上面代码改了生成名,在后面训练的时候,会提示找不到 labels 目录。当然也可以修改 YOLO 提供源码的 dataset.py,看个人选择,而且 images 里的 train 和 val 需要配置到 data 的 yaml 中,这个马上就会说。

配置

  • 数据集配置

该默认文件位于项目的 data/coco128.yaml,现在我们进行划分了数据集和自己的目标种类,当然要对其进行重新配置。最好的方法就是复制一份 coco128 然后修改名称,如下面 coco128_pocker.yaml 是我的配置示例。

  • 模型配置

该默认文件位于项目的 model 下,然后选择自己的场景,如我用的是 v5s 同样就复制一份重命名。这个文件主要是定义模型的基本机构和参数,比如分类数目 nc,模型深度倍数 depth_multiple,每层通道数倍数 width_multiple,以及目标框的大小和比例的 anchors。在刚使用 YOLO 的话,我们就改个 nc 就可以,后面再研究这些参数的用法,下面是 yolov5s_pocker.yaml 的示例。

  • 权重文件

这个就是我们从 yolo 开源那里下载的 yolov5s.pt,这里面有 80 个类目的检测,在基础识别时候可以直接用它。而训练自己的目标也需要基于他的权重再进行训练,所以可以在项目中创建一个 weights,然后再将 yolov5s.pt 放到其中。

训练

  • 基础预测

在训练目标模型前,可以先试试以前的基础检测,这里我们可以随便拿一张图放到 data/images 下,然后执行下面命令,根目录下会生成 runs,而 runs 下的 detect 会根据每次执行的次数生成不同次的标注结果。

python detect.py --weights weights/yolov5s.pt --source data/images/zidane.jpg

打开网易新闻 查看更多图片

  • 指令介绍

  • 开始训练

以下是我踩过坑后执行的命令,因为当时我用 CPU 训练一轮要 7 分钟就改成了 GPU,加了 --device 0 后速度快了 4 倍。batch-size 为 2,这么小是因为我的显卡 750Ti 显存只有 2G,就暂时用了这个数值。而加了 --workers 0,也是因为有坑,这个后面再说。训练完成后,会在根目录的 runs/train 下生成每次运行的权重文件和损失准确示例图等,其中 weights 下的 best.pt 和 last.pt,分别表示本轮训练最好的权重和最新的权重。

python train.py --weights weights/yolov5s.pt --cfg models/yolov5s_pocker.yaml --data data/coco128_pocker.yaml --epochs 1 --batch-size 2 --multi-scale --device 0 --workers 0

开始检测

训练完成后,我们可以把本轮的 best.pt 放到根目录的 weights 下,以下是不同检测方式的命令,可以分别都试一下。

1. 图片

python detect.py --weights weights/best.pt --data data/coco128_pocker.yaml --source data/images/cam_image16.jpg

2. 视频

python detect.py --weights weights/best.pt --data data/coco128_pocker.yaml --source data/images/test.mov

3. 使用cuda测试

python detect.py --device 0 --weights weights/best.pt --data data/coco128_pocker.yaml --source data/images/IMG_2681.JPG

detect.py 重写

因为在实际项目中,我们对图片和视频的目标检测,更多的可能是通过前端传递过来的图片或视频,模型给出的是预测的类目名称和目标的位置,而不是直接生成标注的图片和视频。所以我对 demo 提供的 detect 进行了简单的修改,修改结果就是前面放出的图片,不过还是采用命令方式,当然也可以直接改成接口,最后就是如果需要代码的可以评论区留言哈。