9

AI 在视频领域运用—弹幕穿人

 2 years ago
source link: https://my.oschina.net/u/4939618/blog/5282309
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

AI 在视频领域运用—弹幕穿人

图片

导读:如今,B 站已经成为了国内最大的视频弹幕网站,其他视频平台、漫画、阅 读等内容平台也都增加了弹幕功能。弹幕已经成为一种重要的内容互动的手段, 因此研发一套接入灵活、玩法丰富的弹幕组件就显得非常重要 。

全文3979字,预计阅读时间9分钟。

引言:

如今B 站已经成为了国内最大的视频弹幕网站,其他视频平台、漫画、阅读等内容平台也都增加了弹幕功能。弹幕已经成为一种重要的内容互动的手段。

厂内在短视频,长视频,直播等媒体类产品线较多,面临着同样的弹幕问题,诸如弹幕量大影响视频体验,弹幕互动(点赞),角色弹幕,彩色弹幕等诸多业务需求。

目前市面上开源的弹幕实现主要是基于DanmakuFlame, 该库代码已经停止维护,并且支持的功能比较单一,接入维护困难,扩展困难。基于以上原因因此研发一套接入灵活、玩法丰富的弹幕组件就显得非常重要。BDDMBarrage即是基于满足以上需求开发的弹幕sdk,该sdk支持自定义弹幕样式,支持弹幕数据源注入,弹幕穿人等功能。

该文会主旨讲述弹幕穿人的解决方案,为方便理解,我们会从宏观的弹幕架构出发,深入到人像分离技术,算法,服务端部署,弹幕遮罩管理,遮罩缓存以及开发中遇到的棘手问题包括解决该问题的技术策略,还有端侧的性能优化的诸多方面展开讨论,最后会分享一些对未来技术畅享和规划。

先体验一下最终的实现效果图:

图片


一、弹幕架构图

图片

  • 弹幕数据管理模块:其主要功能是为弹幕渲染模块提供数据。首先,会在弹幕缓存模块内查找是否有该时间点的弹幕数据,如果有数据,则直接提供给弹幕渲染模块;如果没有数据,则触发弹幕数据的网络请求,获得弹幕数据后再提供给弹幕渲染模块。因为弹幕对时效性要求比较高,所以该模块设计了一个预取策略,这样保证弹幕渲染模块在获取数据的时候,尽可能地命中缓存模块,减少由于网络请求而产生的时间延迟。

  • 弹幕渲染模块:其中弹幕时间引擎可以方便地统一调控弹幕整体速度,比如倍速、慢速、暂停等;弹幕调度模块提供一套严密的轨道算法:可以根据弹幕自身的长度设定合理的速度,并且能够保证同一轨道的任何两条弹幕不会碰撞。针对弹幕的样式以及弹幕自身交互,提供一套自定义方案。接入方可以按照自己的APP形态去任意设计弹幕的UI,也能够发掘出新的玩法从而提升整个APP的互动氛围,比如番乐APP设计了依据剧情的角色弹幕,运营弹幕,也可以增加VIP弹幕等。

  • 弹幕穿人模块:该模块是利用AI的图像分割技术产生一系列的蒙版文件,然后根据视频播放器对视频的裁剪方式,对蒙版进行处理生成合适的遮罩,最后按照视频的时间轴把相应的遮罩渲染到弹幕View上。具体方案会在后面介绍。

二、弹幕穿人

在几个产品线接入弹幕组件以后,发现大家都不约而同把弹幕轨道数设置为3,具体原因是担心弹幕过多而影响用户的视频消费体验。这样虽然保证了视频观看的体验,但是大大弱化了弹幕营造的氛围,为此我们弹幕组件的rd们开始暗戳戳地准备一个黑科技——弹幕穿人技术,希望以此能解决问题。下面一段视频给大家看下我们当前的进展。

弹幕穿人架构图:

图片

整个流程自下而上,分成算法侧、服务端、客户端三层:

首先,算法侧按每秒 32 帧的频率进行视频抽帧,对每一帧进行人脸识别,配合人脸跟踪和平滑处理,生成每一帧的人脸元数据;其次,服务端将多个帧的人脸元数据进行相似度滤重,然后根据每3分钟一个元数据包。在客户端sdk侧会根据播放进度预拉取服务侧的对应时间段的压缩包,播放到相应帧将弹幕试图与人脸元数据做一个混合渲染。

下面着重介绍下每个模块或子模块完成的任务

1、算法侧

1)视频抽帧模块:将视频流按每秒 32 帧(可配置)的频率抽帧。抽帧频率越高,遮罩越平滑,遮罩显示画质会更细腻,但后面人脸识别算法耗时也随之增加,手机的性能损耗也会随之增大,如内存耗电等。

2)模型训练模块:提供多张多角度剧中出现的人物图像,给模型训练模块来训练,生成对应人脸库,再配合已训练完成的明星库,这两个库可以大大提高人脸检测的准确度;

3)人脸检测:识别每一帧图像中的人脸,并给出人脸轮廓数据;

4)人脸相似度:为减少网络数据传输压力,会对相似度大于95%的两帧,丢弃一帧,或者数帧。

2、服务端

1)视频抽帧元数据管理:管理算法侧提供的帧数据,以视频维度,视频内时间段维度将大量的视频元数据进行分包,建立映射索引,提供到SDK的可以是某个时间段内视频的元数据组

2)合并:算法侧吐出的都是每一帧的元数据,但客户端关心的是一张人脸的变化过程,服务端会把元数据合并,去重组成人脸组数据;

3)弹幕服务:提供基础的弹幕数据

3、客户端sdk

1)渲染模块:渲染模块 有两套方案:

▌其一是直接通过Canvas的混合模式绘制setXfermode模式绘制。该模式会对canvas上的两个图层进行选择性叠加,这样在头像部分的图层上,我们选择只绘制遮罩层,而不绘制弹幕层即可实现遮罩效果;

▌其二使用OpenGL,根据传入的遮罩图,在Fragment Shader 处,输出对应的绘制颜色即可。最初使用的方案是OpenGL的绘制,通过源码阅读发现两种实现方案在底层实现上是一致的,Canvas也是Surface提供出来的可绘制api,选择第一种既可以,方便简洁;

2)人脸数据缓存:缓存整个视频的索引表,根据索引表定位到具体的遮罩包, 根据当前的播放进度在遮罩包内便宜取处对应的遮罩;

3)弹幕基础控制API,以及配置API。

三、服务部署

**1: 环境:**环境依赖:FFmpeg、Python2.7、OpenCV、numpy

  • 人脸检测服务2qps

  • 人像分割服务10qps

2:  离线数据存储结构

离线处理过程中的文件存放目录及文件后缀:
目录名:{vid}_{media_id}根据视频vid及media_id生成对应文件夹,包含如下子文件:

  1. frame(抽帧文件 .jpg)

  2. humanseg(人像分割处理后的base64图片信息 .json)

  3. contour_png(图像处理过程中生成的轮廓图 .png)

  4. contour_svg(转存为svg格式的图片 .svg)

  5. zip(最终打包文件 .zip)

  6. mapping(索引文件 .json)

  7. log(脚本日志)

3: 抽帧脚本:

抽帧使用的百度内部人像脚本:

图片


四、SDK内置人脸模型碰到的问题

厂内也尝试了使用端内置人脸模型的方案。碰到如下问题:

1、视频的播放每16s一帧,会产生大量的帧数据,模型识别速度在性能上碰到了瓶颈,会存在丢帧的情况,导致遮罩效果不够细腻。尤其头像边缘处理较为严重。

2、端侧识别时手机 cup 消耗增大,即耗电量会增大,同时可能也影响到播放器卡顿率,整个内存压力也很大。


五、棘手的问题

1:蒙版文件太大

一个2分钟视频按照每秒32帧进行抽针、图像分割的话,将会得到3840张蒙版文件,目前从图像分割算子获取的蒙版文件是一张二值图(PNG格式),大约在100多K,那么一个2分钟视频生成的蒙版文件总计375M。按照这样的规格去设计,弹幕蒙版文件有可能比视频本身还大,占用更多的带宽,这样肯定是不能落地的。另外,由于弹幕蒙版文件过大,下载也需要花费比较长的时间,势必会造成视频已经播放了很长一段时间,但弹幕蒙版还处于下载中,用户体验也会非常糟糕。

针对这个问题,我们主要从两方面入手:第一、把二值图转为svg文件,因为svg文件就是一个纯粹的XML,并且可压缩性非常强。只需要把二值图中人形轮廓记录到svg文件里面即可(也就是一些点的集合)。另外还可以灵活调整记录人形轮廓的粒度,从而进一步调整svg文件的大小。最终我们把一张二值图大小从100多K压缩为几百字节。第二、蒙版文件集合采用分段压缩存储,这样可以达到边播变下载的效果。而且,在第一段下载完成以后就可以渲染,提升用户体验;另外,视频播到哪里,弹幕蒙版文件下载到哪里,这样也节省了带宽。

Svg压缩包格式:

zip文件命名规则:

{vid}_{interval} _{index}.zip

示例:4752528107223374247_10_0.zip

svg文件命名规则:

{index}.svg 示例:0000001.svg

▎**索引文件结构:**index.json

图片

2: 手机端内存消耗过大

不同手机内存是有限制的,尤其一些低端机对内存的消耗更是捉襟见肘,而视频类app相对来说更耗内存,所以弹幕sdk的耗内存程度,直接决定了其可用程度。

由于每个遮罩文件大约在100~200kb, 我们的遮罩是1分钟会产生32帧,即使经过合并处理也还是很大。按照这个计算1分钟的内存占用:

Memory Total = 32 * 100kb = 3.125MB

在ios侧还算可以,在Android侧每一分钟产生3mb的内存占用即使进行内存回收也会产生很差的性能体验,平凡的内存回收会很耗性能,导致app卡顿明显。

解决思路:

根据视频时长分配固定的本地内存,该本地内存循环利用,这样减少了内存的频繁回收,限制了内存的无止尽使用。

六、未来展望

人脸数据的产生过程是很耗成本的,单服务跑一个脚本5分钟视频,大约需要2小时,但是产生的数据是复杂的,不仅可以产产生人脸二值图,还可以产生人体的其他数据, 如人的运动轨迹等,下一步我们准备把带有人脸数据和人体数据的脚本,人像运动轨迹做为基本脚本,基于这些基本脚本,可以做很多创新的案例,比人弹幕互动,弹幕跟随的玩法,也可以对视频中不同人物的头像进行变脸等等。

推荐阅读:

iOS签名校验那些事儿

信息流推荐系统智能交付解决方案探索

图谱相关技术在风控反作弊中的应用和探索

---------- END ----------

百度 Geek 说

百度官方技术公众号上线啦!

技术干货 · 行业资讯 · 线上沙龙 · 行业大会

招聘信息 · 内推信息 · 技术书籍 · 百度周边

欢迎各位同学关注


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK