简体   繁体   English

用于图像处理的 OpenGL ES 2.0 着色器示例?

[英]OpenGL ES 2.0 shader examples for image processing?

I am learning shader programming and looking for examples, specifically for image processing.我正在学习着色器编程并寻找示例,特别是图像处理。 I'd like to apply some Photoshop effect to my photos, eg Curves, Levels, Hue/Saturation adjustments, etc.我想对我的照片应用一些 Photoshop 效果,例如曲线、色阶、色相/饱和度调整等。

I'll assume you have a simple uncontroversial vertex shader, as it's not really relevant to the question, such as:我假设您有一个简单的、无争议的顶点着色器,因为它与问题并不真正相关,例如:

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

So that does much the same as ES 1.x would if lighting was disabled, including the texture matrix that hardly anyone ever uses.所以这和 ES 1.x 一样,如果光照被禁用,包括几乎没有人使用的纹理矩阵。

I'm not a Photoshop expert, so please forgive my statements of what I think the various tools do — especially if I'm wrong.我不是 Photoshop 专家,所以请原谅我对各种工具的作用的陈述——尤其是如果我错了。

I think I'm right to say that the levels tool effectively stretches (and clips) the brightness histogram?我想我说水平工具有效地拉伸(和剪辑)亮度直方图是对的吗? In that case an example shader could be:在这种情况下,示例着色器可能是:

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

You'd control that by setting the centre of the range you want to let through (which will be moved to the centre of the output range) and the total range you want to let through (1.0 for the entire range, 0.5 for half the range, etc).您可以通过设置要通过的范围的中心(将移动到 output 范围的中心)和要通过的总范围(整个范围为 1.0,一半为 0.5)来控制它范围等)。

One thing of interest is that I switch from the RGB input space to a YUV colour space for the intermediate adjustment.有趣的一件事是我从 RGB 输入空间切换到 YUV 颜色空间以进行中间调整。 I do that using a matrix multiplication.我使用矩阵乘法来做到这一点。 I then adjust the brightness channel, and apply another matrix that transforms back from YUV to RGB.然后我调整亮度通道,并应用另一个从 YUV 转换回 RGB 的矩阵。 To me it made most sense to work in a luma/chroma colour space and from there I picked YUV fairly arbitrarily, though it has the big advantage for ES purposes of being a simple linear transform of RGB space.对我来说,在亮度/色度颜色空间中工作是最有意义的,从那里我相当随意地选择了 YUV,尽管它对于 ES 而言具有很大的优势,即作为 RGB 空间的简单线性变换。

I am under the understanding that the curves tool also remaps the brightness, but according to some function f(x) = y, which is monotonically increasing (so, will intersect any horizontal or vertical only exactly once) and is set in the interface as a curve from bottom left to top right somehow.我的理解是曲线工具也会重新映射亮度,但根据一些 function f(x) = y,它是单调递增的(因此,只会与任何水平或垂直相交一次)并在界面中设置为不知何故从左下角到右上角的曲线。

Because GL ES isn't fantastic with data structures and branching is to be avoided where possible, I'd suggest the best way to implement that is to upload a 256x1 luminance texture where the value at 'x' is f(x).因为 GL ES 在数据结构方面并不出色,并且在可能的情况下要避免分支,所以我建议最好的实现方法是上传 256x1 亮度纹理,其中“x”处的值为 f(x)。 Then you can just map through the secondary texture, eg with:然后你可以通过二级纹理只 map ,例如:

... 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 ...

You're using a spare texture unit to index a lookup table, effectively.您正在使用备用纹理单元来有效地索引查找表。 On iOS devices that support ES 2.0 you get at least eight texture units so you'll hopefully have one spare.在支持 ES 2.0 的 iOS 设备上,您至少可以获得八个纹理单元,因此您希望有一个备用。

Hue/saturation adjustments are more painful to show because the mapping from RGB to HSV involves a lot of conditionals, but the process is basically the same — map from RGB to HSV, perform the modifications you want on H and S, map back to RGB and output.色相/饱和度调整显示起来更痛苦,因为从 RGB 到 HSV 的映射涉及很多条件,但过程基本相同 — map 从 RGB 到 HSV,在 H 和 S 上执行您想要的修改,map 回到 RGB和 output。

Based on a quick Google search, this site offers some downloadable code that includes some Photoshop functions (though not curves or levels such that I can see) and, significantly, supplies example implementations of functions RGBToHSL and HSLToRGB .根据 Google 的快速搜索, 该站点提供了一些可下载的代码,其中包括一些 Photoshop 函数(虽然不是我可以看到的曲线或级别),并且重要的是,提供了函数RGBToHSLHSLToRGB的示例实现。 It's for desktop GLSL, which has a more predefined variables, types and functions, but you shouldn't have any big problems working around that.它适用于桌面 GLSL,它具有更多预定义的变量、类型和函数,但您不应该遇到任何大问题。 Just remember to add precision modifiers and supply your own replacements for the absent min and max functions.只需记住添加精度修饰符并为缺少的minmax函数提供自己的替换。

For curves photoshop uses bicubic spline interpolation.对于曲线,Photoshop 使用双三次样条插值。 For a given set of control points you can precalculate all 256 values for each channel and for the master curve.对于一组给定的控制点,您可以预先计算每个通道和主曲线的所有 256 个值。 I found that it's easier to store the results as a 256x1 texture and pass it to the shader and then change values of each component:我发现将结果存储为 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);
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM