在 WPF 中将视频中的纯绿色显示为透明

最近需要制作一个类似桌面宠物的东西,碰到了这样一个问题:受 MediaElement 支持的带 alpha 通道的视频格式有限,且后续还要接入相关的深度学习模型动态生成口型,大概率生成不了透明背景。这个该怎么办呢?一个思路是把视频抽帧抠图,然后依次显示透明背景的图片(或者再组合成视频播放)。另外一个想法是直接在 WPF 中把某种颜色显示为透明。

最终我们采用的是后一种办法,并使用 Pixel Shader 来解决这个问题。但是由于 CodePlex 已经关闭,甚至相关的工具都下载不到,最终找到了大佬的一篇文章:https://blog.walterlv.com/post/create-wpf-pixel-shader-effects-using-shazzam-shader-editor.html

这篇文章告诉我们该如何使用 Shazzam Shader Editor ,并在 WPF 项目中使用你所写的 Shader 。里面提供了一个镜像地址,可以下载到需要的 Shazzam Shader Editor 。不过好像只有代码,如果想直接下载编译好的工具可以看另外一个仓库:https://github.com/webmaster442/ShazzamTool/releases

但是这篇文章并不包括关于 HLSL 基本语法的介绍。所以我另外参考了 StackOverFlow 上的相关问题,以及 GitHub 上的相关代码(都放在文章最后),最终达到了把纯绿色显示为透明的效果:

sampler2D input : register(s0);

float4 main(float2 uv : TEXCOORD) : COLOR 
{
    float4 color = tex2D(input, uv);
    if (color.r == 0 && color.g == 1 && color.b == 0)
    {
        color.rgba = 0;
    }
    return color;
}

这里要注意 r 、 g 、 b 是 0 到 1 之间的浮点数,而不是 0 到 255 。此外,设置 alpha 是没有用的,出于性能考虑, WPF 默认透明度已预乘在 rgb 中。

另外,视频的背景可能不是完全的纯绿色,所以可能需要这样限制一个球体的范围,这里 0.6 可根据实际情况调节:

sampler2D input : register(s0);

float4 main(float2 uv : TEXCOORD) : COLOR 
{
    float4 color = tex2D(input, uv);
    if ((color.r * color.r + (color.g - 1) * (color.g - 1) + color.b * color.b) < 0.6)
    {
        color.rgba = 0;
    }
    return color;
}

参考资料:

posted @ 2024-12-29 22:12  yueyinqiu  阅读(38)  评论(0编辑  收藏  举报