Unity 绿幕视频抠图算法&原理与实现 -- 效果极好
1 Unity播放视频1.1 把绿幕视频放到Assets中这个太简单了,直接视频拖到Assets下的某个目录,例如video目录1.2 创建播放视频的对象RawImageHierarchy面板,UI -> Raw Image。1.3 创建RenderTexture这个将为视频播放的输出,也是RawImage的输入。在Project面板,你要的目录下,邮件,创建Render Texture建立
码字不易,转载请注明出处喔
https://blog.csdn.net/newchenxf/article/details/119575690
分两件事来说,一个是Unity怎么播放视频,二是播放了,怎么把绿色的抠掉!
1 Unity播放视频
1.1 把绿幕视频放到Assets中
这个太简单了,直接视频拖到Assets下的某个目录,例如video目录
1.2 创建播放视频的对象RawImage
Hierarchy面板,UI -> Raw Image。
1.3 创建RawImage输入源即纹理Render Texture
这个将为视频播放的输出,也是RawImage的输入。
在Project面板,你要的目录下,右键,创建Render Texture
建立好了,在Inspector面板,改一下纹理size,最好和视频源一样的宽高。
1.4 Raw Image的纹理设置
把它的Texture设置为第三步新建的texture。(直接把Project面板的texture文件,拖到箭头区域即可)。Texture可以认为是Raw Image的输入源。
1.5 给RawImage加视频组件
即选中Raw Image,在Inspector面板中,给他添加VideoPlayer组件。
即Add Component,选择VideoPlayer。
1.6 配置Video Player
视频来源,即Video Clip,选择为前面导入的绿幕视频
Render Mode选择为Render Texture,然后,目标Target Texture选择为前面第三步新建的texture。
流程搭建完成了。
视频的输出到一个texture,这个texture又是Raw Image的输入。 Raw Image最终被显示到屏幕上。
完成到6,已经可以播放视频了。只不过,出来的是原始数据,带绿幕的!
1.7 补充:调整输出宽高
如果你想调试的时候,显示窗口是1080P,然后画面也铺满,怎么办?
一方面,调整显示窗口宽高:
即Game窗口做如下修改:
当然了,如果你默认Game窗口没出来,则手动打开一下:
别问我这个窗口干嘛的,这个是调试窗口。模拟真实输出的画面。点击这个:
就会自己出来了。这够基础了,跑偏了。。囧
好了,输出窗口改好了,接下来,就是把Raw Image的宽高,也设置为1080P,即Inspector做如下修改。然后挪一下Raw Image位置,屏幕居中显示,就妥了。
2 视频处理,即抠图
再次回到Raw Image的Inspector面板。
发现我们的Material是没有做任何设置的。
Material是干嘛的?下文做个介绍
2.1 Material材质简介
材质
,又称物体质地,表示一个物体的色彩、纹理、光滑度、透明度、反射率、折射率、发光度等属性。
在Unity层面来说,材质的本质是一个Shader实例。
Shader又是什么?它是渲染管线中的GPU图像算法程序。可以理解为,一个对象 渲染的方式
。
所以,我们如果添加一个材质,就代表要怎么渲染这个对象。
2.2 添加shader
这是一个大神贡献的shader算法(源码见附录),专业抠绿幕!把这个文件,放到Assets下的Material目录中:
// Created by Oliver Davies. Enjoy.
// oliver@psyfer.io
Shader "Unlit/ChromaKey"
{
Properties
{
_MainTex ("Texture", 2D) = "white" {}
_KeyColor("KeyColor", Color) = (0,1,0,0)
_TintColor("TintColor", Color) = (1,1,1,1)
_ColorCutoff("Cutoff", Range(0, 1)) = 0.2
_ColorFeathering("ColorFeathering", Range(0, 1)) = 0.33
_MaskFeathering("MaskFeathering", Range(0, 1)) = 1
_Sharpening("Sharpening", Range(0, 1)) = 0.5
_Despill("DespillStrength", Range(0, 1)) = 1
_DespillLuminanceAdd("DespillLuminanceAdd", Range(0, 1)) = 0.2
}
SubShader
{
Tags
{
"RenderPipeline"="HDRenderPipeline"
"RenderType"="HDUnlitShader"
"Queue" = "Transparent+1"
}
Blend SrcAlpha OneMinusSrcAlpha
ZWrite Off
cull off
Pass
{
CGPROGRAM
#pragma vertex vert
#pragma fragment frag
#include "UnityCG.cginc"
struct appdata
{
float4 vertex : POSITION;
float2 uv : TEXCOORD0;
};
struct v2f
{
float2 uv : TEXCOORD0;
float4 vertex : SV_POSITION;
//float4 uvgrab : TEXCOORD1;
};
sampler2D _MainTex;
float4 _MainTex_TexelSize;
float4 _MainTex_ST;
float4 _KeyColor;
float4 _TintColor;
float _ColorCutoff;
float _ColorFeathering;
float _MaskFeathering;
float _Sharpening;
float _Despill;
float _DespillLuminanceAdd;
//sampler2D _GrabTexture;
//float4 _GrabTexture_TexelSize;
#define GRABXYPIXEL(kernelx, kernely) tex2Dproj( _GrabTexture, UNITY_PROJ_COORD(float4(i.uvgrab.x + _GrabTexture_TexelSize.x * kernelx, i.uvgrab.y + _GrabTexture_TexelSize.y * kernely, i.uvgrab.z, i.uvgrab.w)))
// Utility functions -----------
float rgb2y(float3 c)
{
return (0.299*c.r + 0.587*c.g + 0.114*c.b);
}
float rgb2cb(float3 c)
{
return (0.5 + -0.168736*c.r - 0.331264*c.g + 0.5*c.b);
}
float rgb2cr(float3 c)
{
return (0.5 + 0.5*c.r - 0.418688*c.g - 0.081312*c.b);
}
float colorclose(float Cb_p, float Cr_p, float Cb_key, float Cr_key, float tola, float tolb)
{
float temp = (Cb_key-Cb_p)*(Cb_key-Cb_p)+(Cr_key-Cr_p)*(Cr_key-Cr_p);
float tola2 = tola*tola;
float tolb2 = tolb*tolb;
if (temp < tola2) return (0);
if (temp < tolb2) return (temp-tola2)/(tolb2-tola2);
return (1);
}
float maskedTex2D(sampler2D tex, float2 uv)
{
float4 color = tex2D(tex, uv);
// Chroma key to CYK conversion
float key_cb = rgb2cb(_KeyColor.rgb);
float key_cr = rgb2cr(_KeyColor.rgb);
float pix_cb = rgb2cb(color.rgb);
float pix_cr = rgb2cr(color.rgb);
return colorclose(pix_cb, pix_cr, key_cb, key_cr, _ColorCutoff, _ColorFeathering);
}
//-------------------------
v2f vert (appdata v)
{
v2f o;
o.vertex = UnityObjectToClipPos(v.vertex);
//o.uvgrab.xy = (float2(o.vertex.x, o.vertex.y) + o.vertex.w) * 0.5;
//o.uvgrab.zw = o.vertex.zw;
o.uv = TRANSFORM_TEX(v.uv, _MainTex);
return o;
}
float4 frag (v2f i) : SV_Target
{
// Get pixel width
float2 pixelWidth = float2(1.0 / _MainTex_TexelSize.z, 0);
float2 pixelHeight = float2(0, 1.0 / _MainTex_TexelSize.w);
//float2 uv = i.uv.xy;
//half4 grab = GRABXYPIXEL(0,0);
// Unmodified MainTex
float4 color = tex2D(_MainTex, i.uv);
// Unfeathered mask
float mask = maskedTex2D(_MainTex, i.uv);
// Feathering & smoothing
float c = mask;
float r = maskedTex2D(_MainTex, i.uv + pixelWidth);
float l = maskedTex2D(_MainTex, i.uv - pixelWidth);
float d = maskedTex2D(_MainTex, i.uv + pixelHeight);
float u = maskedTex2D(_MainTex, i.uv - pixelHeight);
float rd = maskedTex2D(_MainTex, i.uv + pixelWidth + pixelHeight) * .707;
float dl = maskedTex2D(_MainTex, i.uv - pixelWidth + pixelHeight) * .707;
float lu = maskedTex2D(_MainTex, i.uv - pixelHeight - pixelWidth) * .707;
float ur = maskedTex2D(_MainTex, i.uv + pixelWidth - pixelHeight) * .707;
float blurContribution = (r + l + d + u + rd + dl + lu + ur + c) * 0.12774655;
float smoothedMask = smoothstep(_Sharpening, 1, lerp(c, blurContribution, _MaskFeathering));
float4 result = color * smoothedMask;
// Despill
float v = (2*result.b+result.r)/4;
if(result.g > v) result.g = lerp(result.g, v, _Despill);
float4 dif = (color - result);
float desaturatedDif = rgb2y(dif.xyz);
result += lerp(0, desaturatedDif, _DespillLuminanceAdd);
return float4(result.xyz, smoothedMask);
}
ENDCG
}
}
}
接着,还是Assets/Materail目录下,自定义一个Material:
然后,改个名字,然后,选中这个Material,Inspector面板显示其具体参数。它的Shader默认配置了Standard。咱们改成Unlit -> ChromaKey
。
这个Unlit-> ChromaKey哪里来的?
就是在上面的shader脚本,第一句话定义的:
Shader "Unlit/ChromaKey"
当你导入这个shader,则菜单上就会显示这个选项了!
选好以后,面板的各种可选项,和代码是息息相关的:
你可以就着代码仔细研究一下哈。
2.3 RawImage的Material定制
上面自己加了Material,现在就可以拖到Raw Image的Materail选项了。
2.4 播放效果
这是我这里的播放效果,你需要调整箭头的一些参数,才能保证抠图效果完美。默认参数可能不会抠对,可能又蒙层啥的。
附录
Unity 工程源码
https://github.com/newchenxf/UnityCutGreenVideo
其他参考资料
- https://blog.csdn.net/qq_42672770/article/details/108068718
- https://blog.csdn.net/cs874300/article/details/89294433
- shader算法源码
- https://www.reddit.com/r/vfx/comments/ikfcrv/created_a_free_chromakey_green_screen_shader_for/
开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!
更多推荐
所有评论(0)