天天看點

NDK OpenGL ES 3.0 開發(十八):相機 LUT 濾鏡OpenGLES 相機 LUT 濾鏡聯系與交流

作者:位元組流動

來源:

https://blog.csdn.net/Kennethdroid/article/details/103355129

OpenGLES 相機 LUT 濾鏡

NDK OpenGL ES 3.0 開發(十八):相機 LUT 濾鏡OpenGLES 相機 LUT 濾鏡聯系與交流

什麼是 LUT ? LUT 是 Look Up Table 的簡稱,稱作顔色查找表,是一種針對色彩空間的管理和轉換技術。它可以分為一維 LUT(1D LUT) 和 三維 LUT(3D LUT),其中三維 LUT 比較常用。簡單來講,LUT 就是一個 RGB 組合到另一個 RGB 組合的映射關系表。

LUT(R, G, B) = (R1, G1, B1)      

LUT 濾鏡是一種比較經典的濾鏡,本質上屬于獨立像素點替換,即根據 OpenGL 采樣器對紋理進行采樣得到的像素點,再基于像素點的(R,G,B)分量查表,獲得 LUT 映射的(R1,G1,B1),替換原來的輸出。

一般 RGB 像素占用 3 個位元組,包含 3 個分量,每個分量有 256 種取值,那麼三維 LUT 模闆就可以包含 256 X 256 X 256 種情況,占用 48MB 記憶體空間。這樣一個 LUT 模闆記憶體占用過大同時也降低了查找的效率,通常會采取下采樣方式來降低資料量。

例如可以對三維 LUT 模闆每個分量分别進行 64 次采樣,這樣就獲得一個 64 X 64 X 64 大小的映射關系表,對于不在表内的顔色值可以進行插值獲得其相似結果。

三維 LUT 模闆,即 64 X 64 X 64 大小的映射關系表,通常是用一張分辨率為 512 X 512 的二維圖檔表示,稱為 LUT 圖(模闆圖)。

NDK OpenGL ES 3.0 開發(十八):相機 LUT 濾鏡OpenGLES 相機 LUT 濾鏡聯系與交流

LUT 圖在橫豎方向上被分成了 8 X 8 一共 64 個小方格,每一個小方格内的 B(Blue)分量為一個定值,64 個小方格一共表示了 B 分量的 64 種取值。

對于每一個小方格,橫豎方向又各自分為 64 個小格,以左下角為原點,橫向小格的 R(Red)分量依次增加,縱向小格的 G(Green)分量依次增加。

NDK OpenGL ES 3.0 開發(十八):相機 LUT 濾鏡OpenGLES 相機 LUT 濾鏡聯系與交流

至此,我們可以根據原始采樣像素 RGB 中的 B 分量值,确定我們要選用 LUT 圖中的第幾個小格,然後再根據(R,G)分量值為縱橫坐标,确定映射的 RGB 組合。

OpenGLES 實作 LUT 濾鏡的 GLSL 腳本。

// Lut 濾鏡
#version 100
precision highp float;
varying vec2 v_texcoord;

//Lut 紋理
uniform sampler2D s_LutTexture;
uniform lowp sampler2D s_textureY;
uniform lowp sampler2D s_textureU;
uniform lowp sampler2D s_textureV;

vec4 YuvToRgb(vec2 uv) {
    float y, u, v, r, g, b;
    y = texture2D(s_textureY, uv).r;
    u = texture2D(s_textureU, uv).r;
    v = texture2D(s_textureV, uv).r;
    u = u - 0.5;
    v = v - 0.5;
    r = y + 1.403 * v;
    g = y - 0.344 * u - 0.714 * v;
    b = y + 1.770 * u;
    return vec4(r, g, b, 1.0);
}

void main()
{
    //原始采樣像素的 RGBA 值
    vec4 textureColor = YuvToRgb(v_texcoord);

    //擷取 B 分量值,确定 LUT 小方格的 index, 取值範圍轉為 0~63
    float blueColor = textureColor.b * 63.0;

    //取與 B 分量值最接近的 2 個小方格的坐标
    vec2 quad1;
    quad1.y = floor(floor(blueColor) / 8.0);
    quad1.x = floor(blueColor) - (quad1.y * 8.0);

    vec2 quad2;
    quad2.y = floor(ceil(blueColor) / 7.9999);
    quad2.x = ceil(blueColor) - (quad2.y * 8.0);

    //通過 R 和 G 分量的值确定小方格内目标映射的 RGB 組合的坐标,然後歸一化,轉化為紋理坐标。
    vec2 texPos1;
    texPos1.x = (quad1.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);
    texPos1.y = (quad1.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);

    vec2 texPos2;
    texPos2.x = (quad2.x * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.r);
    texPos2.y = (quad2.y * 0.125) + 0.5/512.0 + ((0.125 - 1.0/512.0) * textureColor.g);

    //取目标映射對應的像素值
    vec4 newColor1 = texture2D(s_LutTexture, texPos1);
    vec4 newColor2 = texture2D(s_LutTexture, texPos2);

    //使用 Mix 方法對 2 個邊界像素值進行混合
    vec4 newColor = mix(newColor1, newColor2, fract(blueColor));
    gl_FragColor = mix(textureColor, vec4(newColor.rgb, textureColor.w), 1.0);
}
      

LUT 濾鏡對比圖

NDK OpenGL ES 3.0 開發(十八):相機 LUT 濾鏡OpenGLES 相機 LUT 濾鏡聯系與交流

聯系與交流

技術交流/擷取源碼可以添加我的微信:Byte-Flow

「視訊雲技術」你最值得關注的音視訊技術公衆号,每周推送來自阿裡雲一線的實踐技術文章,在這裡與音視訊領域一流工程師交流切磋。
NDK OpenGL ES 3.0 開發(十八):相機 LUT 濾鏡OpenGLES 相機 LUT 濾鏡聯系與交流

繼續閱讀