Vertin_Slixey
2025-05-05
点 赞
1
热 度
205
评 论
0

基于YOLO的王者荣耀精彩时刻自动剪辑

  1. 首页
  2. 转载
  3. 基于YOLO的王者荣耀精彩时刻自动剪辑

一、需求背景

企鹅电竞是一款游戏直播的产品,游戏短视频社区是其重要组成部分。为了丰富游戏短视频内容,需要一套针对王者荣耀的自动化剪辑精彩时刻的系统,能够快速根据主播直播的内容生成精彩时刻反馈游戏短视频社区。

二、问题思考

我们准备使用深度学习去探索这个问题。这个问题在计算机视觉中属于时序行为定位 (Temportal Action Localization),即在源视频中可以识别出某段视频包含行为,以及行为的起始帧和结束帧。经过调研,我们使用 CDC(Convolutional-De-Convolutional) 网络训练模型,这是一种端到端的解决方案。但是通过标注的精彩时刻和非精彩时刻片段训练出来的模型并不能满足我们的要求。一是识别率并不高,原因可能是王者荣耀的精彩时刻与非精彩时刻的画面差别并不大,主要依据是最后能否击败敌方,而其他行为,比如:游泳和篮球的画面差别就比较大,所以 CDC 网络在其他行为检测可以表现良好,但是并不适合王者荣耀精彩时刻。二是 CDC 模型因为涉及到 3D 卷积所以比较大,不适合生产环境。

经过分析,我们发现精彩时刻的起始点为双方英雄接触的时刻,结束点为击败敌方英雄的时刻。所以只要我们可以识别出画面中击败敌方英雄的特征以及画面中我方和敌方英雄特征就可以定位精彩时刻,将问题转化为图像检测的问题。队友或者敌方英雄在击败时也会出现击败的特征,所以需要通过击败者的头像和技能区域识别是否为当前英雄的击败。所以问题可以转化为:一、检测击败特征;二、检测画面中是否存在敌方和我方英雄;三、分类击败者英雄和当前英雄。

三、模型训练

图像检测常用的模型有 R-CNN,Fast R-CNN,Faster R-CNN,SSD,YOLO 等,这里我们选取 YOLOv3 作为检测击败时刻和敌我英雄的特征,YOLOv3 对比其他几个模型,运行速度较快,识别率也在顶尖水平。模型运行时间和准确率如图所示:

图像分类的模型就更多了,主要有 AlexNet,VGGNet,GoogLeNet,ResNet,SqueezeNet 等,我们这里选择 SqueezeNet 作为英雄分类的模型,主要是因为其模型较小,准确率也很不错。模型大小如图所示:

1. 数据准备

1.1 王者荣耀视频准备

正常的一局王者荣耀大部分画面是在清兵或者在打野,画面中出现多个英雄以及击败时刻特征的画面比较少,但是通过王者荣耀的王者时刻功能录制的视频基本都是存在多个英雄以及有较多地击败时刻特征。所以我们选择使用王者时刻的视频来产生训练所需要的图片。我们可以通过自己打游戏录制或者 YouTube 下载王者时刻视频,但是其中两种方法都需要耗费较多地时间。后来发现网站游戏时刻中存在大量优质的精彩视频,我们可以通过脚本批量下载。

1.2 标记精彩时刻特征

团队中之前有使用传统的图像识别算法识别精彩时刻特征的项目,我们这里用来确定当前画面中是否存在精彩时刻特征。图像识别使用 ORB(Oriented FAST and Rotated BRIEF) 算法快速提取和描述特征点,使用 GMS 算法将测试特征点与标准集的特征点进行比较。具体的实现步骤如下:

(1)利用 FAST 特征点检测来检测特征点 (2)然后利用 Harris 进行角点度量(Opencv 还提供了 FAST 角点度量),然后从特征点从挑选出角点响应值最大的 N 个特征点 (3)在特征点邻域利用 BRIEF 算法建立特征描述符(矩阵)

(4)首先初始化将测试图的特征点和标准图的特征点映射到相同的矩阵内,建立若干个窗口网格
(5)统计每个测试网格与标准网格的匹配数,选择其中匹配数最大的作为匹配
(6)验证素有网格是否有效,即该网格的所有匹配是否大于阈值,若大于,则为正确匹配,否则作为错误匹配。
(7)统计所有正确匹配,得出相似度

如下图为抠取预定位置图片以及标准图片的特征值:

经过 GMS 匹配后的图片为:

确定存在精彩时刻的图片,我们截取包含特征的区域,然后使用特征匹配算法确定英雄头像的位置。在 opencv 中我们使用我方英雄头像,敌方英雄头像,以及掩码图片进行匹配,如下图所示:

python 实现代码如下:

res = cv2.matchTemplate(img_rect, template1, cv2.TM_CCORR_NORMED, mask=mask)

通过处理之后我们可以得到如下图片的标记:

取的成就特征比如:击败、五连绝世等位置和尺寸都是固定的,所以标记起来很简单。

1.3 标记英雄位置

检测英雄的位置,我们可以通过检测英雄血条的位置实现,这里仍然使用模版匹配的方法标记英雄的位置。血条的模版和掩码图片如下图所示:

但是在使用模版匹配存在许多问题,首先我们不知道画面中具体存在几个英雄,所以不能只取匹配值最大的点,如果将大于某个阈值的点都算为英雄的话也是不行的,大部分匹配值都很接近,所以阈值很难选择,而且每个图片的阈值选择可能不同。如下图分别为阈值 0.76 和阈值 0.78,虽然很接近,但是结果去差别很大。

或者我们可以取前十个最大值进行筛选,实践下来也是比较困难的,如下图为前十个值的图框:

我们通过观察图片的匹配值生成的灰度图,可以看出匹配的血条会出现中心亮点,周围较黑的形状,如下图所示:

所以我们可以通过在匹配值灰度图上寻找局部极大值点去匹配血条位置,使用 scipy 的 ndimage 最大滤波器代码如下:

result = ndimage.maximum_filter(res, size=20)

获得的图片如下图所示:

然后我们获得局部极大值点的匹配值为 res,然后计算 20*20 的像素框内所有点与极值点之间的曼哈顿距离之和 distance,然后根据这连个变量计算出最终的值:

取出前 value 前 10 个值,并计算血条位置的像素值,用以确定是否是真实的血条以及其是自己、队友或者敌人,识别的图片结果如下:

血条的标注存在错误,针对一些标注错误的图片我们可以人工去除。

1.4 标记技能区域

这个区域基本是固定的,就在右下角,在标记中输入固定的数值即可。

1.5 获取英雄头像和技能区域分类数据

在 1.2 章节中同样可以获得英雄头像,并且可以通过与标准头像的特征匹配进行分类。技能区域我们截取英雄的第一个技能键,通过此技能键对当前英雄进行分类。这里因为技能键的位置是固定的,所以我们可以获得每个英雄的视频,然后通过 FFMpeg 截取对应位置即可。

2. 训练模型

2.1 YOLOv3 模型训练

(1) Darknet 编译

首先从 Github 上下载源码:

git clone https://github.com/pjreddie/darknet
cd darknet

如果环境中安装了 CUDA、cnDNN 或者 Opencv,可以将 Makefile 中如下的变量设置为 1:

GPU=1 
CUDNN=1 
OPENCV=1

然后执行 make 等待编译完成

make

(2) 生成数据集

这里我们使用和 VOC 数据集一样的数据组织格式,在 darknet 目录下执行如下命令:

mkdir glory
cd glory
mkdir JPEGImages //需要用此文件名
mkdir labels     //需要用此文件名

JPEGImages 文件夹中为训练需要的图片,labels 文件夹中为 JPEGImages 中图片对应的标注。假设 JPEGImages 中存在 000001.jpg 文件则 labels 中对应存在 000001.txt 文件,内容为图片中包含的物体类别及其归一化坐标,形式如下图:

第一列为对应的类别,后面分别为归一化的标注中心点坐标以及宽高。假设图片的宽高为 w,h,标注的坐标为 (xleft,ytop)(x_{left},y_{top})(x_{left},y_{top}) , (xright,ybottom)(x_{right},y_{bottom})(x_{right},y_{bottom}) , 则第二到第五列对应的为:

根据之前 1.2,1.3,1.4 小节说明的标注方法为每张图片生成相对应的标注数据,然后分别将图片和标注文件放入 JPEGImages 和 labels 文件夹。之后将图片分为训练集和测试集,并将路径分别写入 train.txt 和 val.txt 文件,格式类似如下图:

(3) 模型配置

darknet 文件夹下的 cfg 文件为网络的配置文件,其描述了网络的结构,我们这里使用 yolov3-tiny.cfg,并做如下修改,在训练的时候使用 Training 的 batch 和 subdivisions,在测试的时候使用 Testing 的 batch 和 subdivisions:

并在文件的最后修改 classes 的值为分类的个数,以及 fliters 的个数。

新建文件 qgame.names,里面内容为分类的名称。新建 qgame.data,里面内容为训练数据路径,模型保存路径等配置。

(4) 开始训练

./darknet detector train qgame.data yolov3-tiny.cfg

可以观察 loss 的下降趋势,这里在训练到大概 20000 轮的时候,loss 大概下降到 0.5 左右,保持稳定。

(5) 模型裁剪

YOLOv3-tiny 还是不能满足我们的需求,这里需要对模型进行简化,在不降低性能的情况下尽可能的简化模型,这里简化四个模型,通过图表可以看出,YOLOv3-tiny-6 在准确率和性能方面表现最好。

(6) 模型优化

  • 使用聚类算法生成适用于精彩时刻检测 anchor,分别为 (25, 19), (24, 43), (53, 22), (124,196)

  • 使用不同的分辨率训练 YOLO

  • 检查训练集标注数据

  • 为训练数据添加不同的尺寸,旋转

  • 优化后的模型结构如图所示:

2.2 SqueezeNet 模型训练

这里使用 caffe 来训练 SqueezeNet,可以参考之前的文章王者荣耀英雄图片识别,训练方法与文章中的方法类似。训练后的模型准确率如图所示:

2.3 模型性能实测

在 iMac 上 CPU 4.2GHz Intel Core i7 实测,运行一次检测需要 10ms,运行一次分类需要 5ms。

四、系统构建

模型训练完成后,我们使用 Python 构建自动剪辑程序,此程序需要依赖 OpenCV 和 FFMpeg。在 darknet/python 文件中有调用 darknet 框架的 python 接口,可能需要做些修改。如果不是在 darknet 目录下运行 python 的话,需要修改 libdarknet.so 的路径,如下图所示:

如果是 python3,需要做如下修改:

首先我们利用 opencv 每秒钟读取一帧数据,然后运行 yolo 网络检测是否存在击败者,被击败者,获得成就,以及地方英雄特征。如果存在击败者,被击败者,以及获得成就,则将击败者头像和技能头像送入 SqueezeNet 网络识别英雄,并判断两者是否相等。如果相等则此时刻为精彩时刻的结束点,然后向前追溯直到连续三秒没有出现敌方英雄,此时为精彩时刻的起点。

然后使用 FFMepg 命令裁剪合并视频,其中 list.txt 中为分段的视频,格式为 file moments_i.mp4:

ffmpeg -y -i video -ss start -t duration moments_i.mp4
ffmpeg -y -f concat -i list.txt -c copy moments.mp4

将视频通过 YOLO 标注如下所示,me 代表当前英雄,friends 代表友方英雄,enemies 代表敌方英雄,winner 代表我方英雄头像,loser 代表敌方英雄头像,achievement 代表当前成就,skills 代表当前英雄技能。

通过系统剪辑出来的精彩时刻视频如下所示:

本文转自 https://zhuanlan.zhihu.com/p/35852544,如有侵权,请联系删除。


用键盘敲击出的不只是字符,更是一段段生活的剪影、一个个心底的梦想。希望我的文字能像一束光,在您阅读的瞬间,照亮某个角落,带来一丝温暖与共鸣。

Vertin_Slixey

intj 建筑师

站长

不具版权性
不具时效性

文章内容不具时效性。若文章内容有错误之处,请您批评指正。

目录

欢迎来到AliceBlog,为您导航全站动态

54 文章数
18 分类数
3 评论数
102标签数