写点什么

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

2019 年 8 月 23 日

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

一、需求背景

企鹅电竞是一款游戏直播产品,其中游戏短视频社区是其重要组成部分。


为了丰富游戏短视频内容,针对王者荣耀,需要一套自动化剪辑精彩时刻的系统,以能够快速根据主播直播内容生成精彩时刻反馈到游戏短视频社区。


二、问题思考

我们准备使用深度学习去探索这个问题。


该问题在计算机视觉中属于时序行为定位(Temportal Action Localization)问题,即,要在源视频中识别出包含某些行为的一段视频,包括该行为的起始帧和结束帧。


起初,我们尝试了 CDC(Convolutional-De-Convolutional)这种端到端的解决方案,实验结果表明,通过标注的精彩时刻和非精彩时刻片段训练出来的模型并不能满足我们的要求,主要有以下不足:


一、识别率低


原因为王者荣耀的精彩时刻与非精彩时刻画面差别并不大。


相比其他行为,比如游泳场景和打篮球场景等的画面差别就比较大,因此 CDC 网络在这种行为检测上可以表现良好,但是并不适合王者荣耀精彩时刻。


二、CDC 模型过大


CDC 涉及到 3D 卷积所以比较大,不适合生产环境。


重新分析精彩时刻视频,我们发现其具有明显特征:起始点为双方英雄接触的时刻,结束点为击败敌方英雄的时刻。所以,只要我们可以识别出画面中我方和敌方英雄的特征以及击败敌方英雄时的特征就可以定位精彩时刻,也就是将时序行为定位问题转化为了图像检测的问题。


由于队友或者敌方英雄在击败对手时也会出现击败的特征,所以需要通过击败者的头像和技能区域识别是否为当前英雄的击败。


综上所述,问题可以转化为:


一、击败特征检测;


二、敌方和我方英雄检测;


三、分类击败者英雄和当前英雄。


三、模型训练

图像检测常用的模型有 R-CNN、Fast R-CNN、Faster R-CNN、SSD、YOLO 等,综合考虑运行速度与识别率,我们选取了 YOLOv2 来检测敌我英雄和击败时刻的特征;图像分类的模型就更多了,主要有 AlexNet、VGGNet、GoogLeNet、ResNet、SqueezeNet 等,考虑到 SqueezeNet 模型较小,准确率也不错,这里选择其作为英雄分类的模型。


1.数据准备

1.1 王者荣耀视频准备

通常情况下,一局王者荣耀的大部分画面是在清兵或者打野,画面中出现多个英雄或者出现击败时刻的情况比较少,但是通过王者荣耀的王者时刻功能录制的视频基本都是存在多个英雄或者有较多的击败时刻,因此我们可以选择使用王者时刻的视频来产生训练所需要的图片。


具体操作上,我们可以自己打游戏录制或者从 YouTube 上下载王者时刻视频,但是这两种方法都需要耗费较多时间。之后我们发现网站游戏时刻中存在大量优质的精彩视频,我们通过脚本将其批量下载下来使用。


1.2 标记精彩时刻特征

我们基于之前所做的采用传统图像识别算法识别精彩时刻特征的项目来确定当前画面中是否存在精彩时刻特征。


图像识别使用 ORB(Oriented FAST and Rotated BRIEF)算法快速提取和描述特征点,使用 GMS(Grid-based Motion Statistics for Fast, Ultra-robust Feature Correspondence)算法将测试特征点与标准集的特征点进行比较。具体的实现步骤如下:


1.利用 FAST 特征点检测来检测特征点


2.利用 Harris 进行角点度量(Opencv 还提供了 FAST 角点度量),然后从特征点 3.中挑选出角点响应值最大的 N 个特征点


4.在特征点邻域利用 BRIEF 算法建立特征描述符(矩阵)


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 YOLOv2 模型训练

(1) Darknet 编译


首先从 Github 上下载源码:


git clone https://github.com/pjreddie/darknetcd darknet
复制代码


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


GPU=1
CUDNN=1
OPENCV=1
复制代码


然后执行 make 等待编译完成


make
复制代码


(2) 生成数据集


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


mkdir glorycd glorymkdir JPEGImages //需要用此文件名mkdir labels     //需要用此文件名
复制代码


JPEGImages 文件夹中为训练需要的图片,labels 文件夹中为 JPEGImages 中图片对应的标注。


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



第一列为对应的类别,后面分别为归一化的标注中心点坐标以及宽高。


假设图片的宽高为 w、h,标注的坐标为




则第二到第五列对应的为:



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



(3) 模型配置


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



并在文件的最后修改 classes 的值为分类的个数,以及 fliters 的值为 num * (classes + 5):



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




(4) 开始训练


./darknet detector train qgame.data qgame.cfg darknet19_448.conv.23
复制代码


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


2.2 SqueezeNet 模型训练

这里使用 caffe 来训练 SqueezeNet,训练方法会在后续的文章中进行介绍,这里就不做过多展开。


四、系统构建

模型训练完成后,我们使用 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


系统运行效果如下所示:


me 代表当前英雄,friends 代表友方英雄,enemies 代表敌方英雄,winner 代表我方英雄头像,loser 代表敌方英雄头像,achievement 代表当前成就,skills 代表当前英雄技能。


原视频标记结果&剪辑处理结果


五、未来工作

继续优化性能,尝试 YOLOv3,减少 YOLO 网络运行以及 FFMepg 裁剪耗时,以及保证系统的完整可用。


本文转载自公众号小时光茶舍(ID:gh_7322a0f167b5)。


原文链接:


https://mp.weixin.qq.com/s/d7ISpQ0NOaNw3KEJ4g8scw


2019 年 8 月 23 日 18:274048

评论

发布
暂无评论
发现更多内容

区块链应用场景有哪些?区块链应用开发

t13823115967

区块链应用场景有哪些 区块链应用开发

市值管理机器人、自动跑k线机器人开发

t13823115967

市值管理机器人 自动跑k线机器人开发

面试JVM一问三不知??来看看这个

程序员的时光

JVM Java虚拟机

在线K歌的发展和优势

anyRTC开发者

音视频 WebRTC RTC sdk

我是面试官,我来分享一波面经!看看我的内心OS

比伯

Java 编程 架构 面试 技术宅

【薪火计划】05 - 坦诚是领导力的根基

brave heart

管理

彻底搞懂 IO 底层原理

vivo互联网技术

Java Netty 服务器 语法

30分钟开发一款抓取网站图片资源的浏览器插件

徐小夕

Java chrome 前端 前端进阶 chrome扩展

视频作品播放量低:自媒体作者如何走出新手村

石头IT视角

云原生应用Go语言:你还在考虑的时候,别人已经应用实践

华为云开发者社区

go 微服务 云技术

英特尔与南京溧水经济技术开发区共同成立智能交通研究院

新闻科技资讯

双指针算法和位运算&离散化和区间合并

落曦

基于DAYU的实时作业开发,分分钟搭建企业个性化推荐平台

华为云开发者社区

华为 算法 数据 dayu

Appium上下文和H5测试(一)

清菡

App

【JAVA】List转换为array

莫问

moon不讲武德!!!一个类加载机制给面试官说蒙了!!

moon聊技术

Java JVM 类加载 类加载器

如何基于App SDK快速地开发一个IoT App?

IoT云工坊

App 物联网 sdk 智能家居

Web前端如何实现断点续传

QiyihaoLabs

Web 断点续传 upload pl

甲方日常 56

句子

工作 随笔杂谈 日常

大厂经验:埋点数据质量之埋点验证

阿亮

埋点 数据验证

什么是堡垒机?为什么需要堡垒机?

xcbeyond

运维

程序员面试的时候突然遇到答不上的问题怎么办?

Java架构师迁哥

架构师训练营第 1 期 - 第 9 周 - 学习总结

wgl

极客大学架构师训练营

LeetCode题解:169. 多数元素,分治,JavaScript,详细注释

Lee Chen

算法 LeetCode 前端进阶训练营

马士兵最新2020涵盖P5—P8Java全栈架构师学习路线,跟着老师学我已拿P7Offer!

Java架构追梦

Java 学习 架构 面试 马士兵

申通快递 双11 云原生应用实践

阿里巴巴云原生

阿里云 Kubernetes 运维 云原生 监控

有奖话题 | 如果程序员和产品经理都会凡尔赛文学,将如何对话?

YourBatman

话题讨论 凡尔赛文学

MySQL如何实现万亿级数据存储?

冰河

MySQL 分布式 微服务 高可用 mycat

Python进阶——什么是元类?

Kaito

Python

About Me

翎君

android

如何用CSS实现图像替换链接文本显示并保证链接可点击

陈北

CSS小技巧

低代码的认知误区与落地实践

低代码的认知误区与落地实践

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