likes
comments
collection
share

利用 canvas 2D 把视频处理成透明背景

作者站长头像
站长
· 阅读数 32

背景

今天给大家分享一个如何使用 canvas 2D 将带有透明通道的视频处理成透明的背景。

如图所示的视频:

利用 canvas 2D 把视频处理成透明背景

这种视频的内容分为左右两部分,左边是黑白内容,右边是彩色内容。目的就是要将它处理成透明的背景。

最终结果:

利用 canvas 2D 把视频处理成透明背景

原理

读取视频数据

因为我们要使用 canvas 2d 来处理视频数据,所以只能是提取出视频里的每一帧的图片数据来进行处理。

万幸的是 canvas 原生就支持这种能力:

canvasContext.drawImage(videoElement, 0, 0)

你没看错,直接把 video 元素传进去就可以了。这样就把视频数据写入到了 canvas 里面。

写进去的数据就是一帧视频图片,因为视频是图片组合而成的,所以写进去的就是一帧图片数据。

解析图片数据

使用 getImageData 就能获取到写入到 canvas 中的图片数据,你将会看到里面存储的是图片的一组组 rgba 值:[0,0,0,255,123,134,23,255, ...]。它是每4 个数字组成为一个颜色值,每一组的最后一个值是 alpha 通道,255 表示不透明,0 表示透明。

因为它是一个一维数组,我们不太方便做逻辑上的处理,所以我这里会将它转换为二维数组来进行处理,如果不明白为啥能转,请查看我的上一篇文章。

处理透明度

接下来就是处理透明度了,因为这种视频的左右两部分是一样的,所以逻辑就是读取左边的像素来处理对应的右边的像素。如果左边是黑色,那就把右边的对应位置的像素设置成透明的。这样处理完毕后,就能得到最终的结果了。

代码示例

<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

转载自:https://juejin.cn/post/7343811905271840805
评论
请登录