方法有两种
一、 使用透明背景的webm格式视频
具体方式可自行百度,跟代码关系不大,直接用就行,但是支持程度可能不太行
二、使用canvas进行抠图
mdn链接:https://developer.mozilla.org/zh-CN/docs/Web/API/Canvas_API/Manipulating_video_using_canvas
html部分
<!DOCTYPE html
PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<style>
body {
color: #CCCCCC;
}
#c2 {
/* background-image: url("/assets/images/blue.png"); */
background-size: cover;
background-repeat: no-repeat;
}
div {
float: left;
border: 1px solid #444444;
padding: 10px;
margin: 10px;
}
.d-flex {
display: flex;
}
.main {
width: 500px;
}
video {
width: 100%;
}
canvas {
margin-top: 20px;
width: 450px;
}
.right {
width: 450px;
position: relative;
overflow-x: hidden;
}
.center {
width: 100%;
position: absolute;
left: 50%;
transform: translateX(-50%);
object-fit: cover;
top: 0;
pointer-events: none;
z-index: -1;
}
.text-white {
color: #fff;
}
</style>
<script type="text/javascript;" src="main.js"></script>
</head>
<body class="d-flex">
<div class="main">
<!--需要抠图的视频-->
<video preload="auto" id="video" loop src="./assets/video/out.webm" controls="true" />
</div>
<canvas id="c1" width="1080" height="1920">
</canvas>
<div class="right">
<!--背景视频-->
<video preload="auto" class="center" id="personVideo" muted autoplay src="./assets/video/bg.WebM"></video>
<!--输出视频-->
<canvas id="c2" width="1080" height="1920" />
</div>
</body>
注意素材自己找一下
JS部分
/*
* @Description:
* @Date: 2021-08-19 14:49:56
* @LastEditTime: 2021-08-20 10:53:02
* @FilePath: \virtualGuide(6)\src\util\videoHandler.js
*/
export class VideoHandler {
// 源视频
video = null
width = 1080
height = 1920
// canvas1, 用于复制视频
c1 = null
ctx1 = null
// canvas2, 输出去除背景之后的视频
c2 = null
ctx2 = null
/**
* @description: 构造方法
* @param {HTMLVideoElement} source 原视频
* @param {HTMLCanvasElement} canvas 输出canvas
* @param {?HTMLCanvasElement} c1 绘制源视频的canvas,不穿默认创建
* @return {*}
*/
constructor(source, canvas, c1, width = 1080, height = 1920) {
try {
this.video = source
if (c1) {
this.c1 = c1
} else {
this.c1 = document.createElement("canvas")
this.c1.width = this.width
this.c1.height = this.height
}
this.ctx1 = this.c1.getContext('2d')
this.c2 = canvas
this.ctx2 = canvas.getContext('2d')
this.width = width;
this.height = height;
} catch (error) {
console.warn(error)
}
}
/**
* @description: 初始化dom,添加监听视频的事件
* @param {*}
* @return {*}
*/
doLoad() {
this.video?.addEventListener('play', () => {
this.timerCallback();
}, false);
}
/**
* @description: 当视频播放时,递归绘制视频,这里的延时可根据需求自行设置,16为每秒绘制60多次,基本满足视觉要求
* @param {*}
* @return {*}
*/
timerCallback() {
if (this.video.paused || this.video.ended) {
return;
}
this.computeFrame();
let self = this;
setTimeout(function () {
self.timerCallback();
}, 16);
}
/**
* @description: 绘制每一帧视频
* @param {*}
* @return {*}
*/
computeFrame() {
this.ctx1.clearRect(0, 0, this.width, this.height)
this.ctx1.drawImage(this.video, 0, 0, this.width, this.height);
let frame = this.ctx1.getImageData(0, 0, this.width, this.height);
// 每四个为一个像素点,分别为rgba
let step = 4
// 像素点个数
let l = frame.data.length / step;
for (let i = 0; i < l; i++) {
let r = frame.data[i * step + 0];
let g = frame.data[i * step + 1];
let b = frame.data[i * step + 2];
// rgba通道,当颜色为黑色时,a通道设置为0
if (g < 10 && r < 10 && b < 10)
frame.data[i * step + 3] = 0;
}
this.ctx2?.putImageData(frame, 0, 0);
return;
}
/**
* @description: 绘制第一帧,需要源视频设置preload:auto
* @param {*}
* @return {*}
*/
printFirstFrame() {
this.video.currentTime = 0
console.log(this.video.currentTime, "first");
setTimeout(() => {
this.ctx1.clearRect(0, 0, this.width, this.height)
this.ctx1.drawImage(this.video, 0, 0, this.width, this.height);
let frame = this.ctx1.getImageData(0, 0, this.width, this.height);
// 每四个为一个像素点,分别为rgba
let step = 4
// 像素点个数
let l = frame.data.length / step;
for (let i = 0; i < l; i++) {
let r = frame.data[i * step + 0];
let g = frame.data[i * step + 1];
let b = frame.data[i * step + 2];
// rgba通道,当颜色为黑色时,a通道设置为0
if (g < 10 && r < 10 && b < 10)
frame.data[i * step + 3] = 0;
}
// console.log(this, this.ctx2);
this.ctx2?.putImageData(frame, 0, 0);
}, 20);
}
}
使用
let video = document.querySelector("#personVideo");
let canvas = document.querySelector("#c2");
const videoHandler = new VideoHandler(video, canvas);
const videoHandler.doLoad();
视频不方便发布,可以看下mdn的效果图
总结
第一种方法方便快捷,就是webm格式的透明背景视频不好弄,可以让ui大哥帮忙。但是适配性可能也不太好
第二种方法基本上只要支持canvas的浏览器都能用,但是会把背景里所有目标颜色都设为透明,比如我背景色是黑色,我要扣的图里面如果有黑色也会被扣掉,例如头发眼睛。当然这种可以通过改背景色来解决;也可以优化处理像素的算法来解决