iOS视觉-- (06) OpenGL ES+GLSL实现灰度滤镜解析

114 阅读4分钟

在人生道路上,有时候我们怀揣着一个目标,但是走着走着,我们就会忘记了我们当时是为了什么而出发的。本来学习OpenGL ES是为了给图片、视频做滤镜,动效类似剪映一样的东西,前面写着写着。突然到了别的东西,这篇本来是计划写天空盒子,下一篇写粒子系统。但是好像滤镜和动效这些用不到这些东西,可能后面下雪,下雨,撒花会用到粒子系统。到时候再学。想了解的同学也可以自己去学习。技能多多益善。幸好自己及时反应过来,回归到自己的正途上来。

前面我们学习了,如何渲染一张图片了。接下来让我们学习如何给一张图片添加滤镜吧。

灰度滤镜

一张图片的显示是由三个颜色通道(RGB)来决定的,所以图片也称为三通道图。

三通道图:图片每个像素点都有三个值表示 ,所以就是三通道。也有四通道的图。例如RGB图片即为三通道图片,RGB色彩模式是工业界的一种颜色标准,是通过对红(R)、绿(G)、蓝(B)三个颜色通道的变化以及它们相互之间的叠加来得到各式各样的颜色的,RGB即是代表红、绿、蓝三个通道的颜色,这个标准几乎包括了人类视力所能感知的所有颜色,是目前运用最广的颜色系统之一。总之,每一个点由三个值表示。

理解了三通道图的概念,那么灰度滤镜其实就是:**只有一个通道有值,也就是只要得到图片的亮度即可,其实这也就是单通道图。**在人眼中,绿色的亮度是最显眼的,绿色值越深,在肉眼观察中图片越暗淡,这是眼睛的一种生理现象。

单通道图:俗称灰度图,每个像素点只能有有一个值表示颜色,它的像素值在0到255之间,0是黑色,255是白色,中间值是一些不同等级的灰色。(也有3通道的灰度图,3通道灰度图: R,G,B三个通道的亮度一致,即R=G=B,那么这样的图片就是灰度模式的图片)。

有5中方法来实现灰度滤镜的算法(前三种方法是利用权重来实现的):

  • 浮点算法: Gray = R * 0.3 + G * 0.59 + B * 0.11 (根据对应纹素的颜色值调整RGB的比例)
  • 整数算法: Gray = (R * 30 + G * 59 + B * 11) / 100 (同浮点算法)
  • 移位算法: Gray = (R * 76 + G * 151 + B * 28) >> 8
  • 平均值法: Gray = (R + G + B) / 3; (获取到对应纹素的RGB平均值,填充到三个通道上面)
  • 仅取绿色: Gray = G (一个颜色填充三个通道)

要获取亮度值,那么我们就去了解一下从RGB颜色空间转换成带有亮度值的颜色空间:

RGB颜色空间转YC颜色空间 常见的颜色空间有: RGB,YIQ,HSV,YCbCr YCbCr模型广泛用于数字视频,Y表示亮度,Cb、Cr分别为蓝色分量和红色分量相对于参考值的坐标。 公式:Y709 = 0.213R′ + 0.715G′ + 0.072B′

  • 片元着色器代码: 注意:在着色器的代码中,最好不要加中文注释,有可能无法编译程序,此处加注释只是为了便于理解
precision mediump float; //通过precision关键字来指定默认精度,这样就不用每一个变量前面都声明精度限定符了
// 灰度图像转换的709亮度值
const vec3 kRec709Luma = vec3(0.213, 0.715, 0.072);

varying lowp vec2 varyTextCoord; //顶点着色器传递过来的纹理坐标

uniform sampler2D colorMap; //纹理

void main()
{
    vec4 outColor = texture2D(colorMap, varyTextCoord);
    float grayColor = dot(outColor.rgb, kRec709Luma);
    gl_FragColor = vec4(vec3(grayColor), 1.0);
    
    //仅取绿色: 将RGB全部设置为G,即GRB全部取绿色值
//    gl_FragColor = vec4(outColor.g, outColor.g, outColor.g, 1.0);
}

这里面涉及到数学的知识点就是向量的点积向量点乘与叉乘的概念及几何意义 向量点乘和几何意义

那么:float grayColor = dot(outColor.rgb, kRec709Luma); 的意思就是:纹理的rgb颜色值在BT709亮度值方向上的投影。计算出亮度值,然后给rgb三通道赋值然后提交给OpenGL gl_FragColor = vec4(vec3(grayColor), 1.0);

效果图

到此灰色滤镜就结束了。下一篇我们会学习多滤镜怎么实现。 本文Demo 码云Github