【问题标题】:OpenGL ES 2.0 shader examples for image processing?用于图像处理的 OpenGL ES 2.0 着色器示例?
【发布时间】:2011-06-02 15:31:18
【问题描述】:

我正在学习着色器编程并寻找示例,专门用于图像处理。我想对我的照片应用一些 Photoshop 效果,例如曲线、色阶、色相/饱和度调整等。

【问题讨论】:

    标签: iphone image-processing shader opengl-es-2.0


    【解决方案1】:

    我假设你有一个简单的无争议的顶点着色器,因为它与问题并不真正相关,例如:

    void main()
    {
        gl_Position = modelviewProjectionMatrix * position;
        texCoordVarying = vec2(textureMatrix * vec4(texCoord0, 0.0, 1.0));
    }
    

    因此,如果禁用照明,这与 ES 1.x 的作用大致相同,包括几乎没有人使用过的纹理矩阵。

    我不是 Photoshop 专家,所以请原谅我对各种工具的作用的陈述——尤其是如果我错了。

    我认为我说水平工具有效地拉伸(和剪辑)亮度直方图是对的?在这种情况下,示例着色器可能是:

    varying mediump vec2 texCoordVarying;
    uniform sampler2D tex2D;
    
    const mediump mat4 rgbToYuv = mat4( 0.257,  0.439,  -0.148, 0.06, 
                                        0.504, -0.368,  -0.291, 0.5,
                                        0.098, -0.071,   0.439, 0.5, 
                                         0.0,     0.0,     0.0, 1.0);
    
    const mediump mat4 yuvToRgb = mat4( 1.164,  1.164,  1.164,  -0.07884, 
                                        2.018, -0.391,    0.0,  1.153216,
                                          0.0, -0.813,  1.596,  0.53866, 
                                          0.0,    0.0,    0.0,  1.0);
    
    uniform mediump float centre, range;    
    
    void main()
    {
        lowp vec4 srcPixel = texture2D(tex2D, texCoordVarying);
        lowp vec4 yuvPixel = rgbToYuv * srcPixel;
    
        yuvPixel.r = ((yuvPixel.r - centre) * range) + 0.5;
    
        gl_FragColor = yuvToRgb * yuvPixel;
    }
    

    您可以通过设置要通过的范围的中心(将移动到输出范围的中心)和要通过的总范围(整个范围为 1.0,0.5范围的一半,等等)。

    有趣的是,我从 RGB 输入空间切换到 YUV 颜色空间以进行中间调整。我使用矩阵乘法来做到这一点。然后我调整亮度通道,并应用另一个从 YUV 转换回 RGB 的矩阵。对我来说,在 luma/chroma 颜色空间中工作是最有意义的,从那里我相当随意地选择了 YUV,尽管它对于 ES 而言具有很大的优势,即作为 RGB 空间的简单线性变换。

    我了解到曲线工具也会重新映射亮度,但根据某些函数 f(x) = y,它是单调递增的(因此,只会与任何水平或垂直相交一次)并设置为界面以某种方式从左下角到右上角的曲线。

    因为 GL ES 在数据结构方面并不出色,并且在可能的情况下要避免分支,所以我建议最好的实现方法是上传 256x1 亮度纹理,其中“x”处的值为 f(x )。然后你可以通过次要纹理映射,例如与:

    ... same as before down to ...
    lowp vec4 yuvPixel = rgbToYuv * srcPixel;
    
    yuvPixel.r = texture2D(lookupTexture, vec2(yuvPixel.r, 0.0));
    
    ... and as above to convert back to RGB, etc ...
    

    您正在使用备用纹理单元来有效地索引查找表。在支持 ES 2.0 的 iOS 设备上,您至少可以获得 8 个纹理单元,因此您希望有一个备用。

    色相/饱和度调整显示起来更痛苦,因为从 RGB 到 HSV 的映射涉及很多条件,但过程基本相同——从 RGB 映射到 HSV,在 H 和 S 上执行您想要的修改,映射返回 RGB 并输出。

    基于 Google 的快速搜索,this site 提供了一些可下载的代码,其中包括一些 Photoshop 函数(虽然不是我可以看到的曲线或级别),并且重要的是,提供了函数 RGBToHSLHSLToRGB 的示例实现.它适用于桌面 GLSL,它有更多预定义的变量、类型和函数,但你不应该遇到任何大问题。只需记住添加精度修饰符并为缺少的 minmax 函数提供您自己的替换。

    【讨论】:

      【解决方案2】:

      对于曲线,Photoshop 使用双三次样条插值。对于一组给定的控制点,您可以预先计算每个通道和主曲线的所有 256 个值。我发现将结果存储为 256x1 纹理并将其传递给着色器然后更改每个组件的值更容易:

      uniform sampler2D curvesTexture;
      
      vec3 RGBCurvesAdjustment(vec3 color)
      {
          return vec3(texture2D(curvesTexture, vec2(color.r, 1.0)).r,
                      texture2D(curvesTexture, vec2(color.g, 1.0)).g,
                      texture2D(curvesTexture, vec2(color.b, 1.0)).b);
      }
      

      【讨论】:

        猜你喜欢
        • 2023-03-13
        • 1970-01-01
        • 1970-01-01
        • 2011-08-15
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2012-02-21
        • 1970-01-01
        相关资源
        最近更新 更多