目录
3.1 经典 Lev Zelensky LUT原始 MAP 生成原理
3.2 经典 Lev Zelensky LUT的查找代码实现
1 概述
所谓滤镜,最初是指安装在相机镜头前用来过滤自然光的附加镜头,以此来实现调色和添加效果,也就是硬件滤镜。
随着软件技术与数字图像技术的发展,现在的滤镜主要指软件滤镜。软件滤镜又叫作滤镜算法,是用图像算法对大部分硬件镜头滤镜的效果进行模拟,以达到两者效果上的逼近。当然, 由于只是算法的逼近,误差在所难免,再加上不同硬件滤镜自身材质的影响,我们无法再现真实的拍摄场景,无法复原照片中未包含的信息,因而,对于某些硬件滤镜,诸如偏光镜和紫外线(UV)滤色镜等,是无法通过软件滤镜来模拟的。
近些年来,软件滤镜有了广泛的定义与应用,各种图像处理软件(诸如PC端Adobe系 列、手机端美图系列、腾讯天天P图系列及Instagram、“无他相机”、 Faceu、B612等App)向用户展现了各种各样的图像/视频特效,这些特效算法也统称为滤镜,也就是软件滤镜。
对于这些滤镜特效,根据功能与实现,将其归纳为四类:颜色(LUT)滤镜、几何滤镜、 混合滤镜与智能滤镜。
(1)颜色(LUT)滤镜
颜色滤镜即调色滤镜,是最常见的滤镜。任何通过调节图像像素值的亮度、对比度、饱和 度、色相等而得到的不同于原始图像颜色的效果,统称为颜色滤镜。
颜色滤镜特效,如果不是使用纯粹的算法编程得到的,而是通过LUT(Look Up Table, 颜色查找表)来记录并映射调色算法得到的,就称为LUT颜色滤镜,LUT颜色滤镜是颜色滤 镜的优化升级版,可减少滤镜耗时开销。
(2)几何滤镜
几何滤镜是指通过改变图像像素的几何位置来达到某种效果。这个定义可以这样理解,比 如哈哈镜效果,跟颜色无关,是通过改变像素的几何信息得到的特效。目前在Faceu、B612、 “无他相机”等流行的App中,各种人脸变形特效都属于几何滤镜。
(3)混合滤镜
混合滤镜即综合LUT滤镜和几何滤镜得到的复杂滤镜特效,比如“美颜相机”中的美颜滤镜,既有美白调色这种颜色滤镜,也有基于像素位置关系的磨皮滤波、大眼、瘦脸滤镜。
(4)智能滤镜
智能滤镜是指一些基于深度学习等算法实现的依据不同的场景做出不同变化的自动滤镜 效,比如风格化滤镜(Prisma)、谷歌的 HDRNet 学到的高级智能调色滤镜及“美图秀秀”的 A I 人像滤镜等。
本文接下来重点介绍颜色滤镜,颜色滤镜按照实现方式不同又可以分为算法颜色滤镜和LUT颜色滤镜。
2 算法颜色滤镜
算法颜色滤镜是指完全通过算法编程来实现滤镜算法,进而得到滤镜效果。我们以对一张照片进行饱和度调整(饱和度值为+41)的颜色增强滤镜为例进行介绍。
2.1 图像饱和度调整计算公式
假设在RGB颜色空间中,图像像素P(i,j)的颜色值为RGB,饱和度调整后的颜色值为RGBnew,饱和度S的取值范围为[-100,100]。
(1)计算颜色R、G、B分量的最大值和最小值,分别记作 rgbMax 和 rgbMin
rgbMax = max(R,G,B)
rgbMin = min(R,G,B)
若 rgbMax 与 rgbMin 大小相等,则 RGBnew = RGB
(2)HSL中的L分量值计算
L = (rgbMax + rgbMin)/ 2
(3)计算饱和度 S
(4)计算RGBnew(以下是伪代码)
k = saturation * 128 / 100
if (k ≥ 0)
{
alpha = (k + S ≥ 128) ? S : (128 - k)
alpha - 128 * 128 / alpha - 128
}
else
{
alpha = k
}
RGBnew = RGB + (RGB - L) * alpha / 128
2.2 图像饱和度调整代码实现
/*************************************************
功 能:图像饱和度调整
参 数:srcData - [输入/输出] 原始图像,格式为32位BGRA格式,执行后修为结果图像
width - [输入] 原始图像宽度
height - [输入] 原始图像高度
stride - [输入] 原始图像的Stride(也就是行字节数width*4)
saturation - [输入] 饱和度程度(-100~100)
返 回: 0-成功,其他-失败.
*************************************************/
int saturationAdjust(unsigned char *srcData, int width, int height, int stride, int saturation)
{
int ret = 0;
if (saturation == 0)
return ret;
unsigned char* pSrc = srcData;
int r, g, b, rgbMin, rgbMax;
saturation = CLIP3(saturation, -100, 100);
int k = saturation / 100.0f * 128;
int alpha = 0;
int offset = stride - width * 4;
for (int j = 0; j < height; j++)
{
for (int i = 0; i < width; i++)
{
r = pSrc[2];
g = pSrc[1];
b = pSrc[0];
rgbMin = MIN2(MIN2(r, g), b);
rgbMax = MAX2(MAX2(r, g), b);
int delta = (rgbMax - rgbMin);
int value = (rgbMax + rgbMin);
if (delta == 0)
{
pSrc += 4;
continue;
}
int L = value >> 1;
int S = L < 128 ? (delta << 7) / value : (delta << 7) / (510 - value);
if (k >= 0)
{
alpha = k + S >= 128 ? S : 128 - k;
alpha = 128 * 128 / alpha - 128;
}
else
alpha = k;
r = r + ((r - L) * alpha >> 7);
g = g + ((g - L) * alpha >> 7);
b = b + ((b - L) * alpha >> 7);
pSrc[0] = CLIP3(b, 0, 255);
pSrc[1] = CLIP3(g, 0, 255);
pSrc[2] = CLIP3(r, 0, 255);
pSrc += 4;
}
pSrc += offset;
}
return ret;
};
2.3 颜色增强滤镜的定义
/*************************************************
功 能:图像饱和度颜色滤镜
参 数:srcData - [输入/输出] 原始图像,格式为32位BGRA格式,执行后修为结果图像
width - [输入] 原始图像宽度
height - [输入] 原始图像高度
stride - [输入] 原始图像的Stride(也就是行字节数width*4)
返回: 0-成功,其他-失败.
*************************************************/
int ColorFilter(unsigned char *srcData, int width, int height, int stride)
{
return saturationAdjust(srcData, width, height, stride, 41);
};
3 LUT颜色滤镜
LUT颜色滤镜是指通过 LUT(Look Up Table,查找表)的方式来实现的颜色滤镜。
3.1 经典 Lev Zelensky LUT原始 MAP 生成原理
Lev Zelensky 查找表是一个宽度和高度均为512的正方形,该正方形由8×8个宽度和高度均为64的正方形组成,查找表与像素 RGB 值的关系如下所述。
(1)对于每一个64×64大小的小正方形而言,它的x坐标代表的是像素的R值,R计算如下:
width = height = 64
for x in width:
R(x) = x * 4
(2)对于每一个64×64大小的小正方形而言,它的y坐标代表的是像素的G值,G计算如下 :
width = height = 64
for y in height:
G(y) = y * 4
(3)对于8×8个小正方形,从左上角到右下角顺序排列标号0~63,小正方形所在位置的标号代表的是像素的B值,B计算如下:
label = 63
for i in label:
B(i) = i * 4
根据上述步骤(1)~(3),我们就可以编程自动生成一张 Lev Zelensky 基准颜色查找表了。
3.2 经典 Lev Zelensky LUT的查找代码实现
关于Lev Zelensky LUT的查找原理,在理解了它的生成原理之后,就可以逆向操作进行查找了。下面给出代码(此代码进行了移位优化):
static int 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 = (int)(r >> 2) + ((k - ((k >> 3) << 3)) << 6);
ny = (int)(((b >> 5) << 6) + (g >> 2));
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;
};
/*************************************************
功 能:图像3D LUT颜色滤镜
参 数:srcData - [输入/输出] 原始图像,格式为32位BGRA格式,执行后修为结果图像
width - [输入] 原始图像宽度
height - [输入] 原始图像高度
stride - [输入] 原始图像的Stride(也就是行字节数width*4)
Map - [输入] 3D Map图像数据
返回: 0-成功,其他-失败.
*************************************************/
int LUTFilter(unsigned char *srcData, int width, int height, int stride, unsigned char* Map)
{
return filter512(srcData, width, height, stride, Map);
};
3.3 经典 Lev Zelensky LUT优缺点
对于 Lev Ze lensky LUT 的应用,就目前而言,几乎所有的图像/摄像类App、PC图像处理软件都在使用。从滤镜到美颜美妆,但凡涉及像素调色内容,都是可以使用Lev Zelensky LUT的。
使用 Lev Zelensky LUT 的优缺点如下所述。
-
优点:
-
极大地简化了代码,将复杂的算法计算简化为一次 LUT 操作,有助于算法本身的代码保护 。
-
LUT 更容易进行 OpenGL 渲染,可以轻松应用于 Camera 实时预览和视频实时处理,速度快,效果稳定。
-
LUT的设计更容易进行资源配置化,从设计师到效果上线不需要过多的人力、物力和时间 。
-
-
缺点:
-
由于LUT以图像资源的方式存在,而且必须是BMP和PNG等无压缩损失格式,因而占用空间较大,随着LUT数量的增多,会增加软件包的大小。
-
LUT资源容易被破解、泄密。
-
在一些嵌入式开发中,对内存要求苛刻,因而应用受限。
-
4 演示Demo
4.1 开发环境
-
Windows 10 Pro x64
-
Visual Studio 2015
4.2 功能介绍
演示程序主界面如下图所示,具有图像读取、显示、保存、显示RGBA值、HSV调整、提取YUV分量、灰度化、二值化、直方图、亮度/对比度调整、饱和度调整、均值滤波、高斯滤波、拉普拉斯锐化、USM锐化、Sobel边缘检测、Canny边缘检测、算法颜色滤镜、LUT颜色滤镜等功能。
原图
算法颜色滤镜 效果图
LUT颜色滤镜 效果图
4.3 下载地址
开发环境:
-
Windows 10 pro x64
-
Visual Studio 2015
下载地址:图像处理之图像滤镜简介Demo
参考
1 图像视频滤镜与人像美颜美妆算法详解. 胡耀武、谭娟、李云夕. 电子工业出版社、2020-07