使用 JavaScript 进行实时视频色度抠图绿幕抠像处理(无需插件实现)

使用 JavaScript 进行实时视频色度抠图绿幕抠像处理(无需插件实现)

在本教程中,我们将向您展示使用 JavaScript 进行实时视频处理的基础知识。您将学习如何从视频中删除绿屏背景并将另一个视频合并为背景。准备?一起来看看吧!

使用 JavaScript 进行实时视频色度抠图绿幕抠像处理(无需插件实现)

一、基本设置

首先,搞一个绿幕视频文件素材,下载地址://repo.bfw.wiki/bfwrepo/video/63e1dd7ddd2b0.mp4

二、JavaScript视频处理

然后使用视频标签将视频放在我们的页面上。我将属性设置为自动播放静音和循环。至于输出,我们将使用与视频大小相同的画布。
<video id="video" width="800" src="video2.mp4" autoplay muted loop></video>
<canvas id="output-canvas" width="800" height="450" ></canvas>

然后,我将创建一个初始化函数。让我们从获取视频和画布上下文开始。(使用画布时,我们需要使用它的上下文而不是画布元素本身)我还将创建另一个画布作为临时工作空间。我们将使用此画布提取每个视频帧并对其进行处理,然后再将其放入输出画布。在初始化结束时,我们将添加事件侦听器,以便在视频开始播放时开始处理。
let video,c1,ctx1,c_tmp,ctx_tmp; 
function init() {
  video = document.getElementById('video');

  c1 = document.getElementById('output-canvas');
  ctx1 = c1.getContext('2d');

  c_tmp = document.createElement('canvas');
  c_tmp.setAttribute('width', 800);
  c_tmp.setAttribute('height', 450);
  ctx_tmp = c_tmp.getContext('2d');

  video.addEventListener('play', computeFrame );
}

我们将处理代码放在另一个调用 computeFrame 的函数中。然后使用临时画布使用 drawImage 方法将当前视频帧作为 Image 获取,并传递我们的视频元素和视频大小。在临时画布上绘制视频帧后,我们将使用 getImageData 方法获取图像数据。我们暂时跳过处理逻辑,将图像数据直接放入输出画布。然后使用 setTimeout 递归调用自身并创建渲染循环。
function computeFrame() {

    ctx_tmp.drawImage(video, 0, 0, video.videoWidth , video.videoHeight );
    let frame = ctx_tmp.getImageData(0, 0, video.videoWidth , video.videoHeight );

    ctx1.putImageData(frame, 0, 0);
    setTimeout(computeFrame, 0);
}

最后,我们将在加载页面内容时调用 init 函数。
document.addEventListener("DOMContentLoaded", () => {
  init();
});

我们的基本设置已经完成。您应该看到左侧播放的原始视频和右侧的输出画布具有相同的图像。

三、删除绿屏背景

接下来,我们将开始删除绿屏背景。我们目前在画布上拥有的图像数据是一维数组格式。它从第一行的第一个像素开始,然后是同一行中的下一个像素。然后重复从下一行重新开始,直到我们覆盖整个图像。使用 JavaScript 进行实时视频色度抠图绿幕抠像处理(无需插件实现)现在每个像素有 4 个数据。前三个是 RGB 值,最后一个是 alpha 或透明度。因此,每个像素需要 4 个数组空间,最终数组大小将是实际像素数的 4 倍。使用 JavaScript 进行实时视频色度抠图绿幕抠像处理(无需插件实现)现在要删除绿屏,我们需要创建循环来检查所有像素 RGB 值(请注意,我已经将数组大小除以 4)然后我们可以通过将索引乘以 4 并添加偏移量来获取每个像素的 RGB 值。R 是每个像素的第一个值,因此偏移量为零。G 和 B 将分别需要 1 和 2 偏移。
for (let i = 0; i < frame.data.length /4; i++) {
  let r = frame.data[i * 4 + 0];
  let g = frame.data[i * 4 + 1];
  let b = frame.data[i * 4 + 2];

然后添加 if 语句以检查每个像素的 RGB 值是否接近绿屏颜色。您可以根据需要调整条件。太宽,您将删除非背景像素。太窄,您仍然会有绿色背景。然后将 alpha 值设置为零以删除绿屏。
if (r > 70 && r < 160 && g > 95 && g < 220 && b > 25 && b < 150) 
   frame.data[i * 4 + 3] = 0;

使用 JavaScript 进行实时视频色度抠图绿幕抠像处理(无需插件实现)由于这是一个基本的 RGB 检查。您将看到仍然剩下绿色像素。我们需要更先进的算法来检查颜色。但对于本教程,这应该足够了。

四、合并视频

接下来,我们将添加另一个视频作为背景。所以我要下载这个火焰效果视频。首先,我将为背景视频动态创建一个视频元素,并设置源和其他属性。
video2 = document.createElement('video');
video2.src = "fire.mp4"
video2.muted = true;
video2.autoplay = true;

然后使用临时画布提取每一帧,就像我们对第一个视频所做的那样。我们不会从第一个视频中删除绿屏,而是将 RGB 值替换为第二个视频。
    ctx_tmp.drawImage(video2, 0, 0, video2.videoWidth , video2.videoHeight );
    let frame2 = ctx_tmp.getImageData(0, 0, video2.videoWidth , video2.videoHeight );


      if (r > 70 && r < 160 && g > 95 && g < 220 && b > 25 && b < 150) 
      {  
          frame.data[i * 4 + 0] = frame2.data[i * 4 + 0];
          frame.data[i * 4 + 1] = frame2.data[i * 4 + 1];
          frame.data[i * 4 + 2] = frame2.data[i * 4 + 2];
      }

使用 JavaScript 进行实时视频色度抠图绿幕抠像处理(无需插件实现)

您可以在此处下载本教程的源代码,源代码下载地址:https://project.bfw.wiki/project/16757380202788680065.html

{{collectdata}}

网友评论0