1.什么是 LUT

LUT 是 Look Up Table 的简称,称作颜色查找表,是一种针对色彩空间的管理和转换技术。它可以分为一维 LUT(1D LUT) 和 三维 LUT(3D LUT),其中三维 LUT 比较常用。简单来讲,LUT 就是一个 RGB 组合到另一个 RGB 组合的映射关系表。

LUT 滤镜是一种比较经典的滤镜,本质上属于独立像素点替换,即根据 OpenGL 采样器对纹理进行采样得到的像素点,再基于像素点的(R,G,B)分量查表,获得 LUT 映射的(R1,G1,B1),替换原来的输出。

2.LUT图

一般 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 组合。

3.LUTl滤镜实现

3.1顶点着色器
#version 300 es
layout(location = 0) in vec3 attr_position;
layout(location = 1) in vec2 attr_uv;uniform mat4   uni_mat;
out vec2   v_texcoord;void main(void)
{v_texcoord = attr_uv;gl_Position = uni_mat* vec4(attr_position,1.0);
}

mvp矩阵和材质顶点

3.2 片元着色器
#version 300 es
precision mediump float;
//precision highp float;//Lut 采样器
uniform sampler2D s_LutTexture;uniform sampler2D uni_textureY;
uniform sampler2D uni_textureU;
uniform sampler2D uni_textureV;in vec2 v_texcoord;
out vec4 fragColor;uniform float u_offset;//偏移量
uniform vec2 texSize;//纹理尺寸vec4 YuvToRgb(vec2 uv){vec3 yuv;vec3 rgb;yuv.x = texture(uni_textureY, uv).r;yuv.y = texture(uni_textureU, uv).r - 0.5;yuv.z = texture(uni_textureV, uv).r - 0.5;rgb = mat3( 1,1,1, 0,-0.39465,2.03211,1.13983,-0.58060,0) * yuv;return vec4(rgb, 1);
}vec4 LutFilter(vec2 texCoord)
{//原始采样像素的 RGBA 值vec4 textureColor = YuvToRgb(texCoord);//获取 B 分量值,确定 LUT 小方格的 index, 取值范围转为 0~63float 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 = texture(s_LutTexture, texPos1);vec4 newColor2 = texture(s_LutTexture, texPos2);//使用 Mix 方法对 2 个边界像素值进行混合vec4 newColor = mix(newColor1, newColor2, fract(blueColor));return mix(textureColor, vec4(newColor.rgb, textureColor.w), 1.0);
}void main(void)
{//为了方便查看效果,做了分屏处理if(v_texcoord.x > 0.5){fragColor = LutFilter(v_texcoord);}else{fragColor = YuvToRgb(v_texcoord);}}

拿到原始的RGB颜色值,然后获取B分量,对B分量的RG分量进行处理,重新采样得到新的颜色,然后生成新的RGB颜色进行返回。

为了查看效果,做了左右分屏处理。

3.3 渲染部分
void MSDynamicGridLine::Render(MSGLCamera *pCamera) {glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);if(m_bUpdateData == false){return;}static MSVertex triangleVert[] = {{-1, 1,  1,     0,0},{-1, -1,  1,    0,1},{1,  1,  1,     1,0},{1,  -1,  1,    1,1},};glm::mat4x4  objectMat = glm::mat4x4(1.0);glm::mat4x4  objectTransMat = glm::translate(glm::mat4(1.0f), glm::vec3(0.0f, 0.0f, -5));objectMat = objectMat * objectTransMat;objectMat = pCamera->projectionMatrix * pCamera->viewMatrix * objectMat ;m_pOpenGLShader->Bind();m_pOpenGLShader->SetUniformValue("uni_mat",objectMat);m_pOpenGLShader->EnableAttributeArray("attr_position");m_pOpenGLShader->SetAttributeBuffer("attr_position",GL_FLOAT,triangleVert,3,sizeof(MSVertex));m_pOpenGLShader->EnableAttributeArray("attr_uv");m_pOpenGLShader->SetAttributeBuffer("attr_uv",GL_FLOAT,&triangleVert[0].u,2,sizeof(MSVertex));m_PeriodicFrameIndex++;float progress = GetFrameProgress();m_pOpenGLShader->SetUniformValue("u_offset",0.2f * progress);//    LOGD("m_nVideoW is %d,progress is %f",m_nVideoW,progress);if (m_nVideoW>0){m_pOpenGLShader->SetUniformValue("texSize",glm::vec2(m_nVideoW,m_nVideoH));}else{m_pOpenGLShader->SetUniformValue("texSize",glm::vec2(720,1280));}m_pOpenGLShader->SetUniformValue("uni_textureY",0);glActiveTexture(GL_TEXTURE0);glBindTexture(GL_TEXTURE_2D, m_textures[0]);glPixelStorei(GL_UNPACK_ALIGNMENT, 1);glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_nVideoW, m_nVideoH, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, m_pBufYuv420p);glPixelStorei(GL_UNPACK_ALIGNMENT, 4);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);m_pOpenGLShader->SetUniformValue("uni_textureU",1);glActiveTexture(GL_TEXTURE1);glBindTexture(GL_TEXTURE_2D, m_textures[1]);glPixelStorei(GL_UNPACK_ALIGNMENT, 1);glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE,m_nVideoW/2, m_nVideoH/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, (char*)(m_pBufYuv420p+m_yFrameLength));glPixelStorei(GL_UNPACK_ALIGNMENT, 4);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);m_pOpenGLShader->SetUniformValue("uni_textureV",2);glActiveTexture(GL_TEXTURE2);glBindTexture(GL_TEXTURE_2D, m_textures[2]);glPixelStorei(GL_UNPACK_ALIGNMENT, 1);glTexImage2D(GL_TEXTURE_2D, 0, GL_LUMINANCE, m_nVideoW/2, m_nVideoH/2, 0, GL_LUMINANCE, GL_UNSIGNED_BYTE, (char*)(m_pBufYuv420p+m_yFrameLength+m_uFrameLength));glPixelStorei(GL_UNPACK_ALIGNMENT, 4);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);//增加 Lut滤镜采样器m_pOpenGLShader->SetUniformValue("s_LutTexture",3);glActiveTexture(GL_TEXTURE3);glBindTexture(GL_TEXTURE_2D,m_texID);glDrawArrays(GL_TRIANGLE_STRIP, 0, 4);glBindTexture(GL_TEXTURE_2D, 0);m_pOpenGLShader->DisableAttributeArray("attr_position");m_pOpenGLShader->DisableAttributeArray("attr_uv");m_pOpenGLShader->Release();return;
}

渲染部分,除了增加了Lut采样器之外其他的都是常规操作。

Android OpenGL ES 3.0 LUT 滤镜相关推荐

  1. Android OpenGL ES 2.0 屏幕坐标和3D世界坐标转换

    Android OpenGL ES 2.0 屏幕坐标和3D世界坐标转换 查看全文 http://www.taodudu.cc/news/show-6705596.html 相关文章: word中如何加 ...

  2. 使用Android OpenGL ES 2.0绘图之五:添加运动

    传送门☞Android兵器谱☞转载请注明☞http://blog.csdn.net/leverage_1229 传送门☞系统架构设计☞转载请注明☞http://blog.csdn.net/levera ...

  3. 使用Android OpenGL ES 2.0绘图之一:搭建一个OpenGL ES环境

    传送门☞Android兵器谱☞转载请注明☞http://blog.csdn.net/leverage_1229 传送门☞系统架构设计☞转载请注明☞http://blog.csdn.net/levera ...

  4. Android opengl es 3.0 + ndk 绘画涂鸦项目

    前言 写一个opengl es 3.0 + ndk 的绘画涂鸦项目,命名为白板哈哈哈,记录自己遇到的问题,顺便学到的知识整合一遍,算是对自己一段时间的总结. 项目地址:Whiteboard 如果对你有 ...

  5. android opengl es 纹理 不同设备 白色,android – OpenGL ES 2.0纹理没有在某些设备上显示...

    早上好,这是2个纹理非幂的典型例子. 由于多种原因,纹理在分辨率上需要2的幂,这是一个非常常见的错误,每个人都碰巧陷入这个陷阱:)我也是. 2个纹理的非功率在某些设备/ GPU上运行平稳的事实,仅仅取 ...

  6. 使用Android OpenGL ES 2.0绘图之三:绘制形状

    传送门 ☞ 轮子的专栏 ☞ 转载请注明 ☞ http://blog.csdn.net/leverage_1229 在定义好待绘制的形状之后,就要开始绘制它们了.使用OpenGL ES 2.0绘制形状可 ...

  7. 使用Android OpenGL ES 2.0绘图之四:应用投影和相机视图

    传送门☞Android兵器谱☞转载请注明☞http://blog.csdn.net/leverage_1229 传送门☞系统架构设计☞转载请注明☞http://blog.csdn.net/levera ...

  8. 使用Android OpenGL ES 2.0绘图之二:定义形状

    传送门☞Android兵器谱☞转载请注明☞http://blog.csdn.net/leverage_1229 传送门☞系统架构设计☞转载请注明☞http://blog.csdn.net/levera ...

  9. android opengl es 2.0 编程指南,Android OpenGL ES 2.0 初次体验

    本文目录 一. OpenGL ES是什么? 二. OpenGL ES的版本 三. EGL是什么? 四. 需要知道的两个方法 五. 在Android中使用OpenGL ES的步骤 六. 例子1:简单的程 ...

最新文章

  1. Spring中的循环依赖及解决,2021Java精选面试实战总结整理
  2. How does UDO tool resolve objects
  3. 网址的bibtex格式
  4. 平台用户实名认证设计流程
  5. express捕获全局异常的三种方法
  6. 小程序是否转发群还是个人(转发功能)
  7. ecshop 支持 php,ecshop支持PHP7的修改方法
  8. 【李宏毅2020 ML/DL】P62-65 More about Auto-encoder
  9. 生产者消费者线程在QueueT中实现多线程同步
  10. Mysql 驱动包mysql-connector-java-8.0.25.jar下载
  11. NH2-UiO-66|CAS号1260119-00-3金属有机骨架
  12. 日赚1.7亿!华为发布2020年度财报!附华为十大5G应用场景
  13. 饿了么App,网易云音乐,虎牙直播
  14. springboot传图片到前端之有手就行
  15. luffy-(12)
  16. 无刷直流道闸控制器使用说明
  17. 【文献翻译】Concealed Object Detection(伪装目标检测)
  18. IBM MQ向MQ发送消息
  19. 网络协议(十四):WebSocket、WebService、RESTful、IPv6、网络爬虫、HTTP缓存
  20. 一键非自锁开关电路设计

热门文章

  1. 百度杯大学生计算机比赛,百度携手安全专家 打造网络安全顶级赛事
  2. java根据下载地址下载文件到本地
  3. 在iOS工程中用Cordova加载远程网页
  4. Quaternion.LookRotation作用
  5. 概率分布、概率分布函数
  6. 《视觉SLAM十四讲 第二版》笔记及课后习题(第七讲)
  7. JS 59 筋斗云案例
  8. html table表头说明,HTML table表头固定
  9. MFC 自定义CListCtrl
  10. A feature selection method via analysis of relevance, redundancy, and interaction