OpenGL ES 3.0(七)图像处理概述

图像处理的基本原理

亮度调节

亮度调节有非线性、线性两种实现方式。非线性亮度调节的实现非常简单,伪代码如下:

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);
}

根据绘图色来决定正片叠底还是滤色混合模式,与耀眼的聚光灯照在图像上的效果相似。

你可能感兴趣的:(OpenGL ES 3.0(七)图像处理概述)