基于色键技术的纯客户端实时蒙版弹幕

2019 年 1 月 24 日 前端大全

(给前端大全加星标,提升前端技能


作者:parksben

https://segmentfault.com/a/1190000017954676


导读:本文内容是笔者最近实现的 web 端弹幕组件—— Barrage UI 的一个延伸。在阅读本文的实例和相关代码之前,不妨先浏览项目文档,对组件的使用方式和相关接口进行了解。

各位童鞋如果经常上 B 站(bilibili.com) ,应该对 蒙版弹幕 这个概念并不陌生。

蒙版弹幕 是由知名弹幕视频网站 bilibili 于 2018 年中推出的一种弹幕渲染效果,可以有效减少弹幕文字对视频主体信息的干扰。

关于 B 站蒙版弹幕的实现原理,其实网上已经有很多细致的讨论和研究。个人总结了一下,大致要点如下:

  1. 基于用户数据和一些机器学习的相关应用,可以提炼出视频的关键主体

  2. 服务端预先对视频进行处理,并生成相应的蒙版数据

  3. 客户端播放视频时,实时地加载对应资源

  4. 通过一些前端的技术手段,实现弹幕的蒙版处理

客户端方面,由于 B 站弹幕是基于 div+css 的实现,因而采用了 svg 格式来传输矢量蒙版(至少目前是这样),通过 CSS 遮罩的方式实现渲染。

逼乎上有一篇关于这个方案的讨论,感兴趣的童鞋可以移步 这里 进行了解。

Barrage UI

Barrage UI 是个人最近实现的一个前端弹幕组件,主要用于在前端页面中挂载弹幕动画。

组件提供了一系列的操作接口以方便用户对弹幕的相关特性进行定制。你也可以在渲染层面对动画中的每一帧图像进行处理,比如:

  1. 实时读取视频信息

  2. 对每一帧视频图像进行实时处理,计算出抠图蒙版

  3. 将计算出的蒙版传给弹幕组件,以实现实时的蒙版弹幕

下面是基于 Barrage UI 组件实现的蒙版弹幕效果:

由于文中不方便嵌入视频,Demo 的实际效果请移步到:https://parksben.github.io/masking-danmaku-demo 查看。

下面我们来介绍如何实现上图的动画效果。

色键(色度键控)

Demo 中使用了初音小姐姐跳舞的视频。最主要的特点是除了人物外,视频的背景是比较一致的纯色。对于这种类型的图像,我们可以使用 色键 的方式进行抠图(生成“蒙版”)。

色度键控,又称色彩嵌空,是一种去背合成技术。Chroma 为纯色之意,Key 则是抽离颜色之意。把被拍摄的人物或物体放置于绿幕的前面,并进行去背后,将其替换成其他的背景。此技术在电影、电视剧及游戏制作中被大量使用,色键也是虚拟摄影棚(Virtual studio)与视觉效果(Visual effects)当中的一个重要环节。

下图是色键技术的一个示例:在绿幕前穿着蓝色衣服的小姐姐,左图为去背前,右图为去背后的新背景。

如何扣取视频图像

在浏览器环境中,我们可以通过 canvas 画布实时地绘制视频的每一帧,并从画布中读取到图像中每个像素的 RGBA 信息,检测每个点的 R(red)、G(green)、B(blue) 值是否满足要求,最终将需要扣除的像素的 A(alpha) 值置为 0,即可得到用于合成蒙版弹幕的蒙版图像。

注意:

Barrage UI 组件的蒙版功能是基于 Canvas 2D API 的 CanvasRenderingContext2D.globalCompositeOperation 属性实现的(使用了 source-in 的混合模式),因而只需将不需要的像素设置为透明(alpha=0)即可,并不需要改变图像的 RGB 色值。

下面介绍此案例的代码实现。

具体实现

安装 Barrage UI 组件

直接使用 yarn 或 npm 安装此组件:

  
  
    
  1. yarn add barrage-ui

  
  
    
  1. npm install --save barrage-ui

HTML + CSS

准备一个 video 元素用于播放视频, video 的父级元素用于挂载弹幕:

  
  
    
  1. <div id="container">

  2.  <video id="video" src="videos/demo.mp4" controls></video>

  3. </div>

根据视频的实际尺寸(880×540)设置 #container#video 的样式:

  
  
    
  1. html,

  2. body {

  3.  font: 14px/18px Helvetica, Arial, 'Microsoft Yahei', Verdana, sans-serif;

  4.  width: 100%;

  5.  margin: 0;

  6.  padding: 0;

  7.  background: #eee;

  8.  overflow: hidden;

  9. }


  10. #container,

  11. #video {

  12.  width: 880px;

  13.  height: 540px;

  14. }


  15. #container {

  16.  margin: 0 auto;

  17.  margin-top: 50vh;

  18.  margin-left: 50vw;

  19.  transform: translate(-50%, -50%);

  20.  background-color: #ddd;

  21. }

创建弹幕
  
  
    
  1. import Barrage from 'barrage-ui';

  2. import data from 'utils/mockData';


  3. // 获取父级容器

  4. const container = document.getElementById('container');


  5. // 创建弹幕实例

  6. const barrage = new Barrage({

  7.  container: container,

  8. });


  9. // 重置画布高度,避免弹幕遮挡视频播放控件

  10. barrage.canvas.height = container.clientHeight - 80;


  11. // 装填弹幕数据

  12. barrage.setData(data);

其中,mockData 是用于生成随机弹幕数据的方法。

关于弹幕数据的内容与格式,详见 Barrage UI 项目文档

实时获取视频图像
  
  
    
  1. // 获取 video 元素

  2. const video = document.getElementById('video');


  3. // 新建一个画布来实时绘制视频(纯绘图,不用添加进页面)

  4. const vCanvas = document.createElement('canvas');

  5. vCanvas.width = video.clientWidth;

  6. vCanvas.height = video.clientHeight;

  7. const vContext = vCanvas.getContext('2d');


  8. // 实时绘制视频到画布

  9. barrage.afterRender = () => {

  10.  vContext.drawImage(video, 0, 0, vCanvas.width, vCanvas.height);

  11. };

使用组件提供的渲染周期钩子 .afterRender() 可以在弹幕动画的每一帧图像渲染后,将视频图像绘制到中间画布 vCanvas 上。注意这里的 vCanvas 画布主要用于实时地获取视频图像,并不需要添加到页面中。

实时计算蒙版信息
  
  
    
  1. // 渲染前读取画布 vCanvas 的数据,并处理为蒙版图像

  2. barrage.beforeRender = () => {

  3.  // 读取图像

  4.  const frame = vContext.getImageData(0, 0, vCanvas.width, vCanvas.height);


  5.  // 图像总像素个数

  6.  const pxCount = frame.data.length / 4;


  7.  // 将 frame 构造成我们需要的蒙版图像

  8.  for (let i = 0; i < pxCount; i++) {

  9.    // 这里不用 ES6 解构赋值的写法,主要为了保证性能

  10.    // PS: 这里如果用解构赋值语法将导致大量新对象的创建,是个很耗时的过程

  11.    const r = frame.data[i * 4 + 0];

  12.    const g = frame.data[i * 4 + 1];

  13.    const b = frame.data[i * 4 + 2];


  14.    // 将黑色区域以外的内容设为透明

  15.    if (r > 15 || g > 15 || b > 15) {

  16.      frame.data[4 * i + 3] = 0;

  17.    }

  18.  }


  19.  // 设置蒙版

  20.  barrage.setMask(frame);

  21. };

使用组件提供的渲染周期钩子 .beforeRender() 可以在弹幕动画的每一帧图像渲染前计算出蒙版图像。其中,用于更新蒙版的接口为 .setMask()

视频、弹幕的操作绑定

最后,为了让弹幕的行为与视频播放的操作协同,还需要进行一些绑定的操作:

  
  
    
  1. // 绑定播放事件

  2. video.addEventListener(

  3.  'play',

  4.  () => {

  5.    barrage.play();

  6.  },

  7.  false

  8. );


  9. // 绑定暂停事件

  10. video.addEventListener(

  11.  'pause',

  12.  () => {

  13.    barrage.pause();

  14.  },

  15.  false

  16. );


  17. // 切换播放进度

  18. video.addEventListener(

  19.  'seeked',

  20.  () => {

  21.    barrage.goto(video.currentTime * 1000);

  22.  },

  23.  false

  24. );

这里分别用到 Brrage UI 组件的 .play() .pause .goto() 三个接口,分别用于播放暂停切换弹幕动画的进度。需要注意的是,通过 video.currentTime 属性获取到的视频播放进度是一个单位为 的浮点数,需要转换为 毫秒数 再传给弹幕组件。

源码奉上

本文的案例已上传 github,感兴趣的童鞋可以点击 https://github.com/parksben/masking-danmaku-demo 查看源码细节。

关于 Barrage UI 组件如果有什么建议和疑问,欢迎大家在项目中提 issue 给我,帮助我持续改进和迭代,更欢迎 star 和 PR。


推荐阅读

(点击标题可跳转阅读)

Node 程序 debug 小记

探究 CSS 混合模式\滤镜导致 CSS 3D 失效问题

CSS 与网络性能



觉得本文对你有帮助?请分享给更多人

关注「前端大全」加星标,提升前端技能

喜欢就点一下「好看」呗~

登录查看更多
0

相关内容

层叠样式表(Cascading Style Sheet)是一种用来为结构化文档(如 HTML 文档或 XML 应用)添加样式(字体、间距和颜色等)的计算机语言。
【SIGIR2020】用于冷启动推荐的内容感知神经哈希
专知会员服务
22+阅读 · 2020年6月2日
【芝加哥大学】可变形的风格转移,Deformable Style Transfer
专知会员服务
30+阅读 · 2020年3月26日
必读的10篇 CVPR 2019【生成对抗网络】相关论文和代码
专知会员服务
31+阅读 · 2020年1月10日
已删除
将门创投
7+阅读 · 2019年10月10日
爱奇艺蒙版AI:弹幕穿人过,爱豆心中坐
机器之心
5+阅读 · 2018年11月12日
数字图像处理中的噪声过滤
AI研习社
8+阅读 · 2018年9月12日
基于 Storm 的实时数据处理方案
开源中国
4+阅读 · 2018年3月15日
深度解密换脸应用 Deepfake
AI研习社
8+阅读 · 2018年3月11日
Neo4j 和图数据库起步
Linux中国
8+阅读 · 2017年12月20日
图像算法在电商大促中的应用浅析
AI前线
4+阅读 · 2017年11月14日
Arxiv
4+阅读 · 2019年8月7日
Mesh R-CNN
Arxiv
4+阅读 · 2019年6月6日
Music Transformer
Arxiv
5+阅读 · 2018年12月12日
Arxiv
11+阅读 · 2018年4月8日
Arxiv
6+阅读 · 2018年4月4日
Arxiv
3+阅读 · 2018年3月21日
Arxiv
6+阅读 · 2018年1月14日
VIP会员
相关资讯
已删除
将门创投
7+阅读 · 2019年10月10日
爱奇艺蒙版AI:弹幕穿人过,爱豆心中坐
机器之心
5+阅读 · 2018年11月12日
数字图像处理中的噪声过滤
AI研习社
8+阅读 · 2018年9月12日
基于 Storm 的实时数据处理方案
开源中国
4+阅读 · 2018年3月15日
深度解密换脸应用 Deepfake
AI研习社
8+阅读 · 2018年3月11日
Neo4j 和图数据库起步
Linux中国
8+阅读 · 2017年12月20日
图像算法在电商大促中的应用浅析
AI前线
4+阅读 · 2017年11月14日
相关论文
Arxiv
4+阅读 · 2019年8月7日
Mesh R-CNN
Arxiv
4+阅读 · 2019年6月6日
Music Transformer
Arxiv
5+阅读 · 2018年12月12日
Arxiv
11+阅读 · 2018年4月8日
Arxiv
6+阅读 · 2018年4月4日
Arxiv
3+阅读 · 2018年3月21日
Arxiv
6+阅读 · 2018年1月14日
Top
微信扫码咨询专知VIP会员