Opengl 如何从边缘去除色度蒙版

Opengl 如何从边缘去除色度蒙版,opengl,glsl,chromakey,Opengl,Glsl,Chromakey,这是我用来做色度关键点的着色器,该着色器运行良好,但我需要对色度遮罩的边缘进行羽化 我该怎么做 #version 430 core uniform sampler2D u_tex; vec4 keyRGBA = vec4(86.0 / 255.0 , 194.0 / 255.0, 46.0 / 255.0 , 1.0); // key color as rgba vec2 keyCC; // the CC part of YCC color model of key

这是我用来做色度关键点的着色器,该着色器运行良好,但我需要对色度遮罩的边缘进行羽化

我该怎么做

#version 430 core

uniform sampler2D u_tex;     
vec4 keyRGBA = vec4(86.0 / 255.0 , 194.0 / 255.0, 46.0 / 255.0 , 1.0);    // key color as rgba
vec2 keyCC;      // the CC part of YCC color model of key color
uniform vec2 rangeSpill = vec2(0.1, .52);      // the smoothstep range for spill detection
uniform vec2 range = vec2(0.05, 0.21);      // the smoothstep range for chroma detection
in vec2 texCoord;
out vec4 FragColor;

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);
}       

vec2 RGBAToCC (float r, float g, float b) {
    
    float y = 0.299 * r + 0.587 * g + 0.114 * b;    
    return vec2((b - y) * 0.565, (r - y) * 0.713);
}


vec3 RGBToYCC( vec3 col )
{
    float y = 0.299 * col.r + 0.587 * col.g + 0.114 * col.b;    
    return vec3( y ,(col.b - y) * 0.565, (col.r - y) * 0.713);

}


vec3 YCCToRGB( vec3 col )
{
   float R  = col.x + (col.z - 128) *  1.40200;
   float G  = col.x + (col.y - 128) * -0.34414 + (col.z - 128) * -0.71414;
   float B  = col.x + (col.y - 128) *  1.77200;
   return vec3( R , G , B);

}


vec3 hueShift( vec3 color, float hueAdjust ){ 
     vec3  kRGBToYPrime = vec3 (0.299, 0.587, 0.114);
     vec3  kRGBToI      = vec3 (0.596, -0.275, -0.321);
     vec3  kRGBToQ      = vec3 (0.212, -0.523, 0.311);
     vec3  kYIQToR     = vec3 (1.0, 0.956, 0.621);
     vec3  kYIQToG     = vec3 (1.0, -0.272, -0.647);
     vec3  kYIQToB     = vec3 (1.0, -1.107, 1.704);
     float   YPrime  = dot (color, kRGBToYPrime);
     float   I       = dot (color, kRGBToI);
     float   Q       = dot (color, kRGBToQ);
     float   hue     = atan (Q, I);
     float   chroma  = sqrt (I * I + Q * Q);
     hue += hueAdjust;
     Q = chroma * sin (hue);
     I = chroma * cos (hue);
     vec3    yIQ   = vec3 (YPrime, I, Q);
     return vec3( dot (yIQ, kYIQToR), dot (yIQ, kYIQToG), dot (yIQ, kYIQToB) );
}


float GetYComponent( vec3 color){ 
     vec3  kRGBToYPrime = vec3 (0.299, 0.587, 0.114);
     vec3  kRGBToI      = vec3 (0.596, -0.275, -0.321);
     vec3  kRGBToQ      = vec3 (0.212, -0.523, 0.311);
     vec3  kYIQToR     = vec3 (1.0, 0.956, 0.621);
     vec3  kYIQToG     = vec3 (1.0, -0.272, -0.647);
     vec3  kYIQToB     = vec3 (1.0, -1.107, 1.704);
     float   YPrime  = dot (color, kRGBToYPrime);
     return YPrime;
}

        
void main() {
    vec4 src1Color = texture2D(u_tex,  texCoord);   
    keyCC = RGBAToCC( keyRGBA.r , keyRGBA.g , keyRGBA.b  );
    vec2 CC = RGBToCC(src1Color);   
    float mask = sqrt(pow(keyCC.x - CC.x, 2.0) + pow(keyCC.y - CC.y, 2.0));     
    mask = smoothstep(rangeSpill.x + 0.5, rangeSpill.y, mask);
    if (mask > 0.0 && mask < .8)
    {
      src1Color = vec4( hueShift(src1Color.rgb , 1.8 ) , src1Color.a );  // spill remover           
    }   
    
    // Now the spill is removed do the chroma
     vec2 CC2 = RGBToCC(src1Color);
     float mask2 = sqrt(pow(keyCC.x - CC2.x, 2.0) + pow(keyCC.y - CC2.y, 2.0));
     mask2 = smoothstep(range.x, range.y, mask2);       
    if (mask2 == 0.0) { discard; }
            else if (mask2 == 1.0)
        {   
        FragColor = vec4(src1Color.rgb ,  mask2);
        }
        else 
        {
            vec4 col = max(src1Color - (1.0 - mask2) * keyRGBA, 0.0);               
            FragColor = vec4(hueShift(col.rgb , 0.3 ) , col.a); // do color correction      
        }
        
}
#版本430核心
均匀取样器2D u_tex;
vec4-keyRGBA=vec4(86.0/255.0194.0/255.0,46.0/255.0,1.0);//关键颜色为rgba
vec2-keyCC;//关键色YCC颜色模型的CC部分
均匀vec2 rangeSpill=vec2(0.1.52);//泄漏检测的平滑步长范围
均匀vec2范围=vec2(0.05,0.21);//色度检测的平滑步长范围
在vec2 texCoord;
out vec4 FragColor;
vec2 RGBToCC(vec4 rgba){
浮动Y=0.299*rgba.r+0.587*rgba.g+0.114*rgba.b;
返回向量2((rgba.b-Y)*0.565,(rgba.r-Y)*0.713);
}       
vec2 RGBAToCC(浮子r、浮子g、浮子b){
浮动y=0.299*r+0.587*g+0.114*b;
返回向量2((b-y)*0.565,(r-y)*0.713);
}
vec3 RGBToYCC(vec3列)
{
浮动y=0.299*col.r+0.587*col.g+0.114*col.b;
返回向量3(y,(列b-y)*0.565,(列r-y)*0.713);
}
vec3 YCTORGB(vec3列)
{
浮点数R=x列+(z列-128)*1.40200;
浮点数G=x列+(y列-128)*-0.34414+(z列-128)*-0.71414;
浮点数B=x列+(y列-128)*1.77200;
返回向量3(R,G,B);
}
vec3色调(vec3颜色,浮动色调){
vec3-kRGBToYPrime=vec3(0.299,0.587,0.114);
vec3-kRGBToI=vec3(0.596,-0.275,-0.321);
vec3-kRGBToQ=vec3(0.212,-0.523,0.311);
vec3-kYIQToR=vec3(1.0,0.956,0.621);
vec3-kYIQToG=vec3(1.0,-0.272,-0.647);
vec3-kYIQToB=vec3(1.0,-1.107,1.704);
浮点数=点(颜色,kRGBToYPrime);
浮点数I=点(颜色,kRGBToI);
浮点Q=点(颜色,kRGBToQ);
浮动色调=atan(Q,I);
浮动色度=sqrt(I*I+Q*Q);
色调+=hueAdjust;
Q=色度*正弦(色调);
I=色度*cos(色调);
vec3 yIQ=vec3(YPrime,I,Q);
返回vec3(dot(yIQ,kYIQToR)、dot(yIQ,kYIQToG)、dot(yIQ,kYIQToB));
}
浮点GetYComponent(vec3颜色){
vec3-kRGBToYPrime=vec3(0.299,0.587,0.114);
vec3-kRGBToI=vec3(0.596,-0.275,-0.321);
vec3-kRGBToQ=vec3(0.212,-0.523,0.311);
vec3-kYIQToR=vec3(1.0,0.956,0.621);
vec3-kYIQToG=vec3(1.0,-0.272,-0.647);
vec3-kYIQToB=vec3(1.0,-1.107,1.704);
浮点数=点(颜色,kRGBToYPrime);
返还优先权;
}
void main(){
vec4 src1Color=纹理2D(u_tex,texCoord);
keyCC=RGBAToCC(keyRGBA.r、keyRGBA.g、keyRGBA.b);
vec2 CC=RGBToCC(src1Color);
浮动掩码=sqrt(功率(keyCC.x-CC.x,2.0)+功率(keyCC.y-CC.y,2.0));
掩码=平滑步长(rangeSpill.x+0.5,rangeSpill.y,掩码);
如果(掩码>0.0&&掩码<.8)
{
src1Color=vec4(hueShift(src1Color.rgb,1.8),src1Color.a);//溢出清除器
}   
//现在溢出物已被清除,请执行色度
vec2 CC2=RGBToCC(src1Color);
float mask2=sqrt(功率(keyCC.x-CC2.x,2.0)+功率(keyCC.y-CC2.y,2.0));
mask2=平滑步长(范围.x,范围.y,mask2);
如果(mask2==0.0){discard;}
否则如果(mask2==1.0)
{   
FragColor=vec4(src1Color.rgb,mask2);
}
其他的
{
vec4 col=最大值(src1Color-(1.0-mask2)*keyRGBA,0.0);
FragColor=vec4(hueShift(col.rgb,0.3),col.a);//进行颜色校正
}
}
这是基本图像

这是色度键控后的结果。


此外,如果有人还可以提供一些有关在着色器中添加更多细节的信息,则色度键控也没有太多可用信息。

有效地说,您需要挤出色度键匹配的区域。虽然您可以在单个渲染过程中仅在模式(而不是单个点)中采样,但这不是很有效

相反,您应该首先将遮罩写入1比特(或尽可能多的透明度)遮罩纹理。然后可以在该遮罩上沿X和Y方向运行一个简单的1D着色器,以按固定量挤出已排除的区域。无论哪种方式,你都需要一个临时的纹理来打乒乓球,而分割X和Y维度所需的样本总数要少得多

例如,在5px范围内的最小不透明度,或使用定标器/钳形的高斯模糊,以保持已经完全透明的像素仍然透明

最后,像往常一样将最终遮罩与源图像结合起来