本文共 3401 字,大约阅读时间需要 11 分钟。
亮度调节有非线性、线性两种实现方式。非线性亮度调节的实现非常简单,伪代码如下:
byte* image = loadImage();byte* r, g, b = interlaceImage(image);int brightness = 3;r += brightness;g += brightness;b += brightness;
线性亮度调节基于 HSL 色彩模式,HSL 分别代表色相(Hue)、饱和度(Saturation)、明度(Lightness),每个通道都可以使用 0~255 的数值来表示,线性亮度调节就是通过调节 L 的值实现的:
L = (max(r, max(g, b)) + min(r, min(g, b))) / 2;if (L > 128) { rHS = (r * 128 - (L - 128) * 256) / (256 - L); gHS = (g * 128 - (L - 128) * 256) / (256 - L); bHS = (b * 128 - (L - 128) * 256) / (256 - L);} else { rHS = r * 128 / L; gHS = g * 128 / L; bHS = b * 128 / L;}int delta = 20; // [0 - 255]newL = L + delta - 128;if (newL > 0) { newR = rHS + (256 - rHS) * newL / 128; newG = gHS + (256 - gHS) * newL / 128; newB = bHS + (256 - bHS) * newL / 128;} else { newR = rHS + rHS * newL / 128; newG = gHS + gHS * newL / 128; newB = bHS + bHS * newL / 128;}
对比度要对 RGB 三个通道同时调整,不能分别调整,否则会造成色偏的问题。设置对比度的函数如下:
y = (x - 0.5) * contrast + 0.5;
假如图片原来的色彩范围为 0.25 ~ 0.75,那么当 contrast 取值为 1.2 时,新的图片的色彩范围会变成 0.29 ~ 0.89,相当于扩大了颜色的表示范围,相应了,如果 contrast 取值小于 1,则相当于缩小了颜色的表示范围。
饱和度调节最简单的方法是判断 R、G、B 值是否大于 128,大于则加上调节值,小于则减去调节值;也可以将 RGB 转换为 HSL,然后调节 S 值。
这里介绍第一种方法,首先需要通过 RGB 计算像素点的亮度值:
luminance = 0.2125 * R + 0.7154 * G + 0.0721 * B;
然后设计一个参数 saturation,取值范围为 [0.0, 2.0]:
output = (1.0 - saturation) * vec3(luminance) + saturation * vec3(R, G, B);
线性滤波是一种常用的图像处理方法,做法很简单,假设有一个二维的滤波器矩阵,称为卷积核,对于要处理的图像的每个像素点,先计算它的领域像素和滤波器矩阵的对应元素的乘积,然后加起来,以此作为该像素位置的值,即完成整个滤波过程。
对图像和滤波矩阵进行逐个元素相乘再求和的操作称为卷积,相当于将一个二维的函数移动到另一个二维函数的所有位置,对于平面图像的卷积,一般称为 2D 卷积。
通常选用为 3x3 或 5x5的卷积核,比如:
int matrix[3][3] = { 0, 0, 0, 0, 1, 0, 0, 0, 0}
滤波器矩阵一般有如下要求:
1) 元素数目为奇数,这样才会有一个中心 2) 所有元素之和应该等于 1,这是为了保持亮度不变 3) 为了防止过载,滤波后的像素点的值一定要维持在 0 ~ 255 之间图像的锐化就是补偿图像的轮廓,增强图像的边缘以及灰度跳变的部分,使图像变得更加清晰。锐化效果器也是通过图像卷积来完成的,定义卷积矩阵如下:
int matrix[3][3] = { 0, -k, 0, -k, 4k + 1, -k, 0, -k, 0}
这个卷积矩阵实际上就是计算当前点和领域像素点的 Diff 值,然后将素有的 Diff 值加到像素点上,因此,当前像素点和领域像素点相差不大时,卷积之后的结果不变;而当它是正好是一个边缘或者细节点的时候,就会更加突出。
边缘检测算法与锐化类似,检测横向边缘的的矩阵如下:
int matrix[3][3] = { -1, -1, -1, 0, 0, 0, 1, 1, 1}
检测竖向边缘的的矩阵如下:
int matrix[3][3] = { -1, 0, 1, -1, 0, 1, -1, 0, 1}
找到这两个边缘点之后,可以做一个平方和来代替当前点的亮度值,差别越大,亮度值越大。
模糊滤波器其实就是对周围像素进行加权平均处理,对于均值模糊算法来说,周围所有领域点的权值都相同,所以不是很平滑。高斯模糊就是用来解决这个问题的,它会把图像的模糊处理的很平滑,被广泛用于图像降噪上。
高斯模糊的的权重是正态分布的权重,正态分布在图形上表示为一种钟形曲线,越接近中心,取值越大,越远离中心,取值越小。在图像处理领域,需要使用二维的高斯分布函数来实现高斯模糊算法,二维高斯函数如下:
根据该函数,可以给出一个 5x5 的卷积矩阵:
int matrix[3][3] = { 1, 4, 7, 4, 1, 4, 16, 26, 16, 4, 7, 26, 41, 26, 7, 4, 16, 26, 16, 4, 1, 4, 7, 4, 1,}
双边滤波是一种可以降噪保边的滤波器,它由两个因素共同影响,一个是由几何空间距离;另一个是像素差值。几何空间距离类似高斯模糊,由距离中心像素点的远近来确定权重值,然后由像素差值来决定是否让这个权重值参与权重计算,如果差值过大,那么就有可能丢弃该权重值,以达到保边的效果;如果差值不大,那么就保留该权重值,以达到降噪的效果。
最终的权重 = 高斯权重 * 像素差值权重(差值越大,权重越小)
假设 A 代表上面的图层的色彩值,B 代表下面的图层的色彩值,C 代表混合之后的色彩值,取值范围为 [0.0, 1.0]
公式如下:
C = A * B
任何颜色与白色正片叠底之后仍保持原来的颜色不变,而与其它颜色执行正片叠底混合模式后,会产生暗室中以该颜色照明的效果。
C = 1 - (1 - A) * (1 - B)
任何颜色与黑色混合,原色不受影响;与白色混合,得到白色;与其它颜色混合,会产生漂白的效果。
if (B <= 0.5) { C = 2 * A * B} else { C = 1 - 2 * (1 - A) * (1 - B)}
可使底色的图像饱和度以及对比度得到相应提高,使图像看起来更加鲜亮。
if (A <= 0.5) { C = (2 * A - 1) * (B - B * B) + B} else { C = (2 * A - 1) * (sqrt(B) - B * B) + B}
根据绘图色的明暗程度来决定最终色是变亮还是变暗,与发散的聚光灯照再图像上的效果类似。
if (A <= 0.5) { C = 2 * A * B} else { C = 1 - 2 * (1 - A) * (1 - B);}
根据绘图色来决定正片叠底还是滤色混合模式,与耀眼的聚光灯照在图像上的效果相似。