使用 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(); });我们的基本设置已经完成。您应该看到左侧播放的原始视频和右侧的输出画布具有相同的图像。
三、删除绿屏背景
接下来,我们将开始删除绿屏背景。我们目前在画布上拥有的图像数据是一维数组格式。它从第一行的第一个像素开始,然后是同一行中的下一个像素。然后重复从下一行重新开始,直到我们覆盖整个图像。现在每个像素有 4 个数据。前三个是 RGB 值,最后一个是 alpha 或透明度。因此,每个像素需要 4 个数组空间,最终数组大小将是实际像素数的 4 倍。现在要删除绿屏,我们需要创建循环来检查所有像素 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;由于这是一个基本的 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]; }
您可以在此处下载本教程的源代码,源代码下载地址:https://project.bfw.wiki/project/16757380202788680065.html
网友评论0