什么是LUT滤镜
LUT:Look Up Table,即颜色查找表。把要处理的颜色效果,以一张表提前存好,图片处理时查找提前准备好的LUT图,比如整体颜色调暗。
我们先看看主流app中LUT的使用情况
可见,涉及到照片处理时,LUT几乎是必选项
LUT原理
1D LUT
看上图,一个横条色,包含了[0, 255]的亮度,根据RGB各通道的值进行查找。1D LUT的处理能力很有限,只能处理明亮,是一种简单的线性处理.
2D LUT
从1D 到 2D原理相同,只是从一维的256各值拓展到 256 * 256个值,查找的逻辑有变:
从查找逻辑,可以想象到LUT 图的样子
LUT示意图
2D LUT正片叠底
3D LUT
顾名思义,3D可以表⽰出所有颜⾊(256×256×256种),⾮常适⽤于精确的颜⾊校准⼯作,⽽且能够处理从简单的 Gamma调整到⾼级的⾮线性属性、⾊相、饱和度等的调节。
3D LUT有许多种,常见的三种是 经典Lev Zelensky LUT、64 * 64 LUT 和 2048 * 64 LUT。这里介绍最经典的Lev Zelensky基准颜色查找表.
为了节省空间,3D LUT中,把256中颜色归化到64的范围内:
经典3D LUT示意图
Lev Zelensky查找表是8 * 8个小方格组成,每个方格有64 * 64个点,则LUT图宽度均为512。
3D LUT的映射计算: 根据待处理图片的p(x, y)对应的RGB -->求出LUT map映射的结果
x代表R值;y代表G值;B对应第几个小方格
直接读代码,很好理解,实际的算法中用位运算做了优化
static int f_Filter512(unsigned char* srcData, int width ,int height, int stride, unsigned char*Map)
{
int i, j, r, g, b, offset, pos, nx, ny, k;
unsigned char* pSrc = srcData;
offset = stride - (width * 4);
for(j = 0; j < height; j++)
{
for(i = 0; i < width; i++)
{
b = pSrc[0];
g = pSrc[1];
r = pSrc[2];
k = (b >> 2);
// 简化:nx = r >> 2 + (k - (k >> 3) << 3) << 6;
// k >> 3 << 3 对k按照8来取整
// k - (k >> 3) << 3,即 k%8,求余数,求x坐标不关注8的倍数,8个大方格成一行
// << 6即 * 64,一个大方格是64个点
// 最后 +r >> 2,即 x坐标,注意r >> 2 即256化成64
nx = (int)(r >> 2) + ((k - ((k >> 3) << 3)) << 6);
// b>>5:b/4/8,b/4 256归化到64范围, /8求得第几行,最后<<6即往下数几个大方格;
// + (g >> 2)即加上小方格的y轴偏移
ny = (int)(((b >> 5) << 6) + (g >> 2));
// nx 和 ny 求出 map映射文件的坐标
// ny * 512 * 4,一行512个点,一个点有4通道
// pSrc即根据Map映射的设计文件,查找到新的艳色值
pos = (nx * 4) + (ny * 512 * 4);
pSrc[0] = Map[pos];
pSrc[1] = Map[pos + 1];
pSrc[2] = Map[pos + 2];
pSrc += 4;
}
pSrc += offset;
}
return 0;
};
LUT优缺点
优点:
- 极大的简化了代码,将复杂的算法计算简化为一次LUT操作,有助于算法本身的保护。
- LUT更容易进行OpenGL渲染,可以轻松应用于Camera预览和视频的实时处理,速度快,效果稳定
- LUT的设计更容易进行热更新,设计师设计好效果可以动态发布
缺点:
- 增加软件包的体积(可以考虑后下发来优化)
- LUT资源容易被破解、泄密(得到LUT图,就相当于得到一个算子