背景
看过我这篇文章: 《使用 div 能以像素级别绘制图片吗?》 的同学们应该都知道图片的存储结构是什么样的了。
今天给大家分享一个如何使用 canvas 2D 将带有透明通道的视频处理成透明的背景。
如图所示的视频:
这种视频的内容分为左右两部分,左边是黑白内容,右边是彩色内容。目的就是要将它处理成透明的背景。
最终结果:
对于这种视频的处理办法,有另外一种处理办法,就是使用 webgl 来实现,大家对 webgl 处理办法感兴趣的话,可以前往查看这篇文章:webgl 实现透明视频 动画。
原理
读取视频数据
因为我们要使用 canvas 2d 来处理视频数据,所以只能是提取出视频里的每一帧的图片数据来进行处理。
万幸的是 canvas 原生就支持这种能力:
js
canvasContext.drawImage(videoElement, 0, 0)
你没看错,直接把 video 元素传进去就可以了。这样就把视频数据写入到了 canvas 里面。
写进去的数据就是一帧视频图片,因为视频是图片组合而成的,所以写进去的就是一帧图片数据。
解析图片数据
使用 getImageData 就能获取到写入到 canvas 中的图片数据,你将会看到里面存储的是图片的一组组 rgba 值:[0,0,0,255,123,134,23,255, ...]
。它是每4 个数字组成为一个颜色值,每一组的最后一个值是 alpha 通道,255 表示不透明,0 表示透明。
因为它是一个一维数组,我们不太方便做逻辑上的处理,所以我这里会将它转换为二维数组来进行处理,如果不明白为啥能转,请查看我的上一篇文章。
处理透明度
接下来就是处理透明度了,因为这种视频的左右两部分是一样的,所以逻辑就是读取左边的像素来处理对应的右边的像素。如果左边是黑色,那就把右边的对应位置的像素设置成透明的。这样处理完毕后,就能得到最终的结果了。
代码示例
html
<template>
<div class="about">
<video
ref="video"
src="../assets/2868412.mp4"
autoplay="true"
width="420"
height="300"
controls
loop
muted
></video>
<hr />
<canvas
ref="canvas1"
width="1500"
height="1064"
style="width: 420px; height: 300px"
></canvas>
<canvas
ref="canvas2"
width="1500"
height="1064"
style="width: 420px; height: 300px"
></canvas>
</div>
</template>
<script>
export default {
data() {
return {
id: null,
canvas1: null,
ctx1: null,
canvas2: null,
ctx2: null,
};
},
mounted() {
const c = this.$refs.canvas1;
this.ctx1 = c.getContext("2d", { willReadFrequently: true });
const c2 = this.$refs.canvas2;
this.ctx2 = c2.getContext("2d", { willReadFrequently: true });
const video = this.$refs.video;
video.addEventListener(
"play",
() => {
let $this = this;
(function loop() {
if (!video.paused && !video.ended) {
$this.ctx2.drawImage(video, 0, 0);
let frameData = $this.ctx2.getImageData(0, 0, 1500, 1064);
let data = frameData.data;
for (let i = 0; i < 1064; i++) {
for (let j = 0; j < 1500; j++) {
if (j < 750) {
if (
data[i * 1500 * 4 + j * 4] === 0 &&
data[i * 1500 * 4 + j * 4 + 1] === 0 &&
data[i * 1500 * 4 + j * 4 + 2] === 0
) {
data[i * 1500 * 4 + (j + 750) * 4 + 3] = 0;
}
}
}
}
$this.ctx1.putImageData(frameData, -750, 0, 750, 0, 750, 1064);
setTimeout(loop, 1000 / 24);
}
})();
},
0
);
},
};
</script>
这个原视频的地址是 https://dlied5sdk.myapp.com/music/release/upload/t_mm_file_publish/2868412.mp4
对应作者的 webgl 处理方法是这个,感兴趣的可以学习: https://y.qq.com/m/act/demo/index.html