作者:位元組流動
來源:
https://blog.csdn.net/Kennethdroid/article/details/103355129OpenGLES 相機 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 圖(模闆圖)。
LUT 圖在橫豎方向上被分成了 8 X 8 一共 64 個小方格,每一個小方格内的 B(Blue)分量為一個定值,64 個小方格一共表示了 B 分量的 64 種取值。
對于每一個小方格,橫豎方向又各自分為 64 個小格,以左下角為原點,橫向小格的 R(Red)分量依次增加,縱向小格的 G(Green)分量依次增加。
至此,我們可以根據原始采樣像素 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 濾鏡對比圖
聯系與交流
技術交流/擷取源碼可以添加我的微信:Byte-Flow
「視訊雲技術」你最值得關注的音視訊技術公衆号,每周推送來自阿裡雲一線的實踐技術文章,在這裡與音視訊領域一流工程師交流切磋。