大家好,欢迎来到IT知识分享网。
先体验 DEMO,基于 WebAV 实现
- 移除图片背景
- 移除视频背景
背景
因为视频相关标准及浏览器的实现问题,很难在主流浏览器中顺利播放背景透明的视频。
有两种方法可以为最通用的视频格式(MP4,H264)移除背景,实现透明效果:
- 原视频配上绿幕,使用本文介绍方法移除背景绿幕
- 优点:制作使用简单
- 缺点:抠图可能不完美,导致偏色
- 将视频中的 alpha 通道与画面并排放置,在客户端混合
- 优点:精确还原
- 缺点:分辨率增加,视频变大;可能适应场景小,原视频制作需要精确的 alpha 通道
方法二参考:https://juejin.cn/post/
绿幕抠图原理
- 传入四个参数
- 目标颜色,期望抠除背景色,可以不是绿色
- 相似度阈值
- 平滑度敏感系数
- 颜色饱和度敏感系数
- 使用 WebGL(片元着色器) 逐个比对原像素与目标颜色
- 计算过程
- 将颜色转换到 UV 空间,计算出当前像素与目标颜色的距离
- 将
距离 - 相似度阈值
,小于 0 则判定为绿幕,将像素点设置为全透明(alpha=0) - 与平滑度参数计算,将相似度转换成 alpha 通道值,越大越不透明
- 计算出原像素点的灰度值
- 将相似度与饱和度参数计算,然后与原像素点的灰度值混合,越大越靠近原像素点,越小越就接近灰度
(后两步为了移除前景边缘与绿幕反光,导致的前景像素点混合了绿幕背景颜色)
实现
参考:Production-ready green screen in the browser
需要先了解一下 YUV 颜色编码
Shader 代码
#version 300 es precision mediump float; out vec4 FragColor; in vec2 v_texCoord; uniform sampler2D frameTexture; uniform vec3 keyColor; // 色度的相似度阈值 uniform float similarity; // 透明度的平滑度计算 uniform float smoothness; // 降低绿幕饱和度,提高抠图准确度 uniform float spill; vec2 RGBtoUV(vec3 rgb) { return vec2( rgb.r * -0.169 + rgb.g * -0.331 + rgb.b * 0.5 + 0.5, rgb.r * 0.5 + rgb.g * -0.419 + rgb.b * -0.081 + 0.5 ); } void main() { // 获取当前像素的rgba值 vec4 rgba = texture(frameTexture, v_texCoord); // 计算当前像素与绿幕像素的色度差值 vec2 chromaVec = RGBtoUV(rgba.rgb) - RGBtoUV(keyColor); // 计算当前像素与绿幕像素的色度距离(向量长度), 越相似则色度距离越小 float chromaDist = sqrt(dot(chromaVec, chromaVec)); // 设置了一个相似度阈值,baseMask < 0,则像素是绿幕,> 0 则像素点可能属于前景(比如人物) float baseMask = chromaDist - similarity; // 与平滑度参数计算,将 baseMask 转换成 alpha 通道值,越大越不透明 float fullMask = pow(clamp(baseMask / smoothness, 0., 1.), 1.5); rgba.a = fullMask; // 如果 baseMask < 0,spillVal 等于 0;baseMask 越小,像素点饱和度越低 float spillVal = pow(clamp(baseMask / spill, 0., 1.), 1.5); // 计算当前像素的灰度值 float desat = clamp(rgba.r * 0.2126 + rgba.g * 0.7152 + rgba.b * 0.0722, 0., 1.); rgba.rgb = mix(vec3(desat, desat, desat), rgba.rgb, spillVal); FragColor = rgba; }
上面算法使用 CPU(纯 js 代码)也能实现,但性能会差很多
除了上面分析的核心代码之外还有一些为了让 Shader 运行起来的辅助代码,属于 WebGL 的基础知识,查看完整代码
如何使用
1、静态图片抠图示例
import { createChromakey } from '@webav/av-cliper'; const cvs = document.querySelector('#canvas') as HTMLCanvasElement; const ctx = cvs.getContext('2d', { alpha: true })!; (async () => { const img = new Image(); img.src = './public/img/green-dog.jpeg'; await new Promise((resolve) => { img.onload = resolve; }); const chromakey = createChromakey({ // 目标颜色不传,则取第一个像素点当做背景色 similarity: 0.35, smoothness: 0.05, spill: 0.05, }); ctx.drawImage(await chromakey(img), 0, 0, cvs.width, cvs.height); })();
2、 使用 @webav/av-cliper
对 mp4 视频进行逐帧抠图,体验 DEMO:mp4(chromakey) 合成视频的效果
import { createChromakey, MP4Clip } from '@webav/av-cliper'; const chromakey = createChromakey({ similarity: 0.4, smoothness: 0.1, spill: 0.1, }); const clip = new MP4Clip((await fetch('<mp4 url>')).body!); clip.tickInterceptor = async (_, tickRet) => { if (tickRet.video == null) return tickRet; return { ...tickRet, video: await chromakey(tickRet.video) }; };
传入一张 720P 的图片给 chromakey
首次执行(包括初始化)大概耗时 20ms,后续每次执行基本在 1ms 之内;
所以性能方面实现视频实时抠图没有压力,将 Video 标签传给 chromakey 即可
async function render() { ctx.drawImage(await chromakey(videoElement), 0, 0, cvs.width, cvs.height); requestAnimationFrame(render); // 注意:后台页面 requestAnimationFrame 停止执行 } render();
其它实现
precision mediump float; uniform sampler2D u_texture; uniform vec4 keyRGBA; // key color as rgba uniform vec2 range; // the smoothstep range varying vec2 v_texCoord; vec2 RGBToCC(vec4 rgba) { float Y = 0.299 * rgba.r + 0.587 * rgba.g + 0.114 * rgba.b; return vec2((rgba.b - Y) * 0.565, (rgba.r - Y) * 0.713); } void main() { // 从贴图获取源像素 vec4 srcColor = texture2D(u_texture, v_texCoord); // 源像素 RGB 转换为 YUV vec2 srcCC = RGBToCC(srcColor); // 目标颜色转换为 YUV vec2 keyCC = RGBToCC(keyRGBA); // 计算距离 float mask = sqrt(pow(keyCC.x - srcCC.x, 2.0) + pow(keyCC.y - srcCC.y, 2.0)); // 对距离值在range中进行平滑映射取值 mask = smoothstep(range.x, range.y, mask); // 低于range下限 if (mask == 0.0) { discard; } // 超过range上限 else if (mask == 1.0) { gl_FragColor = srcColor; } // 处于range之中 else { // 某些源像素(如头发边缘)混合了绿幕颜色,需要减去绿幕颜色,否则边缘会有绿斑 gl_FragColor = max(srcColor - (1.0 - mask) * keyRGBA, 0.0); } }
关于优联前端
武汉优联前端科技有限公司由一批从事前端10余年的专业人才创办,是一家致力于H5前端技术研究的科技创新型公司,为合作伙伴提供专业高效的前端解决方案,合作伙伴遍布中国及东南亚地区,行业涵盖广告,教育, 医疗,餐饮等。有效的解决了合作伙伴的前端技术难题,节约了成本,实现合作共赢。承接Web前端,微信小程序、小游戏,2D/3D游戏,动画交互与UI广告设计等各种技术研发。
免责声明:本站所有文章内容,图片,视频等均是来源于用户投稿和互联网及文摘转载整编而成,不代表本站观点,不承担相关法律责任。其著作权各归其原作者或其出版社所有。如发现本站有涉嫌抄袭侵权/违法违规的内容,侵犯到您的权益,请在线联系站长,一经查实,本站将立刻删除。 本文来自网络,若有侵权,请联系删除,如若转载,请注明出处:https://haidsoft.com/127450.html