OpenGL ES 如何实现图像锐化?

图像锐化是一种图像处理技术,其目的是增强图像中的细节和边缘,使图像看起来更加清晰。这一过程通常涉及到突出图像中的高频信息,特别是强调像素之间的灰度变化。

什么是图像锐化?

图像锐化是一种图像处理技术,其目的是增强图像中的细节和边缘,使图像看起来更加清晰。这一过程通常涉及到突出图像中的高频信息,特别是强调像素之间的灰度变化。

通过增强图像的高频细节,图像锐化可以改善图像在人类视觉系统和计算机视觉系统中的感知效果。

图像锐化处理的目的是为了使图像的边缘、轮廓线以及图像的细节变得清晰,经过平滑的图像变得模糊的根本原因是因为图像受到了平均或积分运算,因此可以对其进行逆运算(如微分运算,其实这里用的是差分)就可以使图像变得清晰。

图像锐化原理?

图像锐化通过突出图像中的边缘和细节,增强图像的高频信息,以提高图像的清晰度和视觉质量。不同的锐化方法可能使用不同的滤波器或卷积核,但它们的基本原理是在图像中寻找和增强灰度变化较大的区域。

图像中边缘的定义是什么?在图像处理中认为,灰度值变化剧烈的地方就是边缘。

变化剧烈程度,数学上就是函数的一阶导数。假设下图是图像的灰度函数,可以看出,中间变化较快的地方应该是图像的边缘。第二张图是图一的一阶导数,由数学知识可知,一阶导数的极值就是那个变化最快的点(边缘)。

对于连续的函数来说,一阶导数就是直接求导,二阶同理。但是,图像本质是一个二维矩阵,离散型的,是无法求导的。

这时候,就需要用到差分这个概念了,由泰勒公式可以推导出。实在理解不到的话,可以认为:连续型函数是求导(求微分),离散型函数则是求差分。

OpenGL ES 如何实现图像锐化?

OpenGL ES 实现图像锐化可以使用卷积运算实现,通过应用特定的卷积核(也称为滤波器),可以突出图像中不同方向的高频细节。

使用 5x5 的卷积核:

precision highp float;
varying highp vec2 vTextureCoord;
uniform lowp sampler2D sTexture;
uniform highp vec2 inputSize;

void main() {
    vec2 uv = vTextureCoord;

    float step = 1.0;
    vec2  uvOffsets[25];
    float dx = step / inputSize.x;
    float dy = step / inputSize.y;

    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 5; j++)
        {
            uvOffsets[((i*5)+j)].x = (-2.0 * dx) + (float(i) * dx);
            uvOffsets[((i*5)+j)].y = (-2.0 * dy) + (float(j) * dy);
        }
    }

    vec4 sampleCols[25];
    for (int i = 0; i < 25; i++)
    {
        // 采样邻域的网格
        sampleCols[i] = texture2D(sTexture, uv + uvOffsets[i]);
    }

    // 锐化权重:
    // -1 -1 -1 -1 -1
    // -1 -1 -1 -1 -1
    // -1 -1 25 -1 -1
    // -1 -1 -1 -1 -1
    // -1 -1 -1 -1 -1

    vec4 result = 25.0 * sampleCols[12];
    for (int i = 0; i < 25; i++)
    {
        if (i != 12)
        result -= sampleCols[i];
    }

    vec4 orgResult = texture2D(sTexture, uv);

    result = mix(orgResult, result, smoothstep(0.40, 0.6, uv.x));

    gl_FragColor = result;
}

效果如下

使用 3x3 的卷积核:

precision highp float;
varying highp vec2 vTextureCoord;
uniform lowp sampler2D sTexture;
uniform highp vec2 inputSize;

void main() {
    vec2 uv = vTextureCoord;

    float step = 5.0;
    vec2  uvOffsets[9];
    float dx = step / inputSize.x;
    float dy = step / inputSize.y;

    for (int i = 0; i < 3; i++)
    {
        for (int j = 0; j < 3; j++)
        {
            uvOffsets[((i*5)+j)].x = (-1.0 * dx) + (float(i) * dx);
            uvOffsets[((i*5)+j)].y = (-1.0 * dy) + (float(j) * dy);
        }
    }

    vec4 sampleCols[9];

    for (int i = 0; i < 9; i++)
    {
        // 采样邻域的网格
        sampleCols[i] = texture2D(sTexture, uv + uvOffsets[i]);
    }

    // 锐化卷积核 3x3
    // -1 -1 -1
    // -1  9 -1
    // -1 -1 -1

    vec4 result = 9.0 * sampleCols[4];
    for (int i = 0; i < 9; i++)
    {
        if (i != 4)
        result -= sampleCols[i];
    }

    vec4 orgResult = texture2D(sTexture, uv);

    result = mix(orgResult, result, smoothstep(0.40, 0.6, uv.x));

    gl_FragColor = result;
}

结果图如下,你可以对比下使用 3x3 和 5x5 的卷积核效果差异。

参考文章:

  • https://blog.csdn.net/weixin_44225182/article/details/101310131
  • https://blog.csdn.net/panda1234lee/article/details/52320832

手机扫码阅读