OpenGL Shader-卷积基础在特效中的应用

632 阅读3分钟

「这是我参与2022首次更文挑战的第25天,活动详情查看:2022首次更文挑战

卷积基础

数字图像处理中许多滤镜效果是基于卷积计算开发出来的。卷积作为常见数字图像处理操作,我可以来处理过滤一副图像。其实现过滤方法是计算图像与卷积内核之间的积。其卷积内核是一个NxN的矩阵,n一般为奇数,在进行卷积计算处理的过程就是将卷积内核对处理图像中每个像素都应用一次。

image.png

  1. 卷积内核中心值对准当前像素,卷积内核其他值各自对准一个像素。
  2. 卷积内核中每个值与其对准像素的颜色值相乘。
  3. 最后将乘积加权求和得到处理后的图片中该位置像素颜色值。

卷积应用

卷积算法可以应用于许多场景,轻松实现模糊、边缘检测、浮雕等一些特殊滤镜特效效果。

平滑过渡

平滑过渡效果和之前实现高斯模糊方法类似,采用3x3的平滑过滤卷积内核实现了一定的模糊效果。卷积内核中各个值对应像素相对于待处理像素纹理坐标偏移做处理,然后获取到卷积内核各个值对应的像素颜色值,最后将每个纹理的颜色求和获取到最终纹理结果。

111
111
111
void main() {
    vec2 uv = gl_FragCoord.xy / iResolution.xy;
    
    vec2 offset0 = vec2(-1.,-1.);
    vec2 offset1 = vec2(0.,-1.);
    vec2 offset2 = vec2(1.,-1.);
    vec2 offset3 = vec2(-1.,0.);
    vec2 offset4 = vec2(0.,0.);
    vec2 offset5 = vec2(1.,0.);
    vec2 offset6 = vec2(-1.,1.);
    vec2 offset7 = vec2(0.,1.);
    vec2 offset8 = vec2(1.,1.);

    float scaleFactor = 1./ 8.;

    float size = 512.;

    float kernelValue0 = 1.;
    float kernelValue1 = 1.;
    float kernelValue2 = 1.;
    float kernelValue3 = 1.;
    float kernelValue4 = 1.;
    float kernelValue5 = 1.;
    float kernelValue6 = 1.;
    float kernelValue7 = 1.;
    float kernelValue8 = 1.;

    vec4 sum;
    vec4 cTemp0,cTemp1,cTemp2,cTemp3,cTemp4,cTemp5,cTemp6,cTemp7,cTemp8;
    cTemp0 = texture(iChannel2,uv + offset0.xy / size);
    cTemp1 = texture(iChannel2,uv + offset1.xy / size);
    cTemp2 = texture(iChannel2,uv + offset2.xy / size);
    cTemp3 = texture(iChannel2,uv + offset3.xy / size);
    cTemp4 = texture(iChannel2,uv + offset4.xy / size);
    cTemp5 = texture(iChannel2,uv + offset5.xy / size);
    cTemp6 = texture(iChannel2,uv + offset6.xy / size);
    cTemp7 = texture(iChannel2,uv + offset7.xy / size);
    cTemp8 = texture(iChannel2,uv + offset8.xy / size);

    sum = kernelValue0 * cTemp0 + 
    kernelValue1 * cTemp1 +
    kernelValue2 * cTemp2 +
    kernelValue3 * cTemp3 +
    kernelValue4 * cTemp4 +
    kernelValue5 * cTemp5 +
    kernelValue6 * cTemp6 +
    kernelValue7 * cTemp7 +
    kernelValue8 * cTemp8;


    gl_FragColor = sum * scaleFactor; 

}
原图平滑过渡
image.pngimage.png

边缘检测

卷积除了能对图片进行平滑处理外还能实现边缘检测功能。不同点在于实现边缘检测的卷积内核各个值和平滑过渡的值有所不同。另外边缘检测还需要将图片进行灰度化处理凸显边缘效果。

010
1-41
010
    
    float scaleFactor = 1./ 0.8;
    
    float kernelValue0 = 0.;
    float kernelValue1 = 1.;
    float kernelValue2 = 0.;
    float kernelValue3 = 1.;
    float kernelValue4 = -4.;
    float kernelValue5 = 1.;
    float kernelValue6 = 0.;
    float kernelValue7 = 1.;
    float kernelValue8 = 0.;
    ..... 
    float hd = (sum.r + sum.g + sum.b) / 3.;
    gl_FragColor = vec4(hd) * scaleFactor; 
原图边缘检测效果
image.pngimage.png

总结

卷积应用还有其他特效实现,这里只是举例了两种效果。之后继续分享分析其他卷积应用特效实现过程和原理。

参考

  • 《OpenGL ES 2.0游戏开发》