iOS GLSL.有没有办法使用GLSL着色器创建图像直方图?

dug*_*gla 13 image-processing glsl histogram ios

在StackOverflow的其他地方,有人询问深度缓冲直方图 - 使用GLSL创建深度缓冲直方图纹理.

我正在编写一个iOS图像处理应用程序,并对此问题很感兴趣,但对提供的答案不清楚.那么,是否可以通过GLSL使用GPU创建图像直方图?

Bra*_*son 34

是的,虽然它在iOS上比你想象的更具挑战性.这是一个红色直方图,完全在GPU上生成并绘制,针对实时视频源运行:

GPU红色直方图

在你提出的问题中,汤米的建议是一个很好的起点,Scheuermann和Hensley的这篇论文也是如此.建议使用散射来为图像中的颜色通道建立直方图.散射是一个将点网格传递到顶点着色器的过程,然后让该着色器读取该点的颜色.然后将该点处所需颜色通道的值写为X坐标(Y和Z坐标为0).然后,片段着色器会在目标中的该坐标处绘制一个半透明的1像素宽点.

该目标是1像素高,256像素宽的图像,每个宽度位置代表一个颜色区域.通过写出具有低Alpha通道(或低RGB值)的点,然后使用加法混合,您可以根据图像中特定颜色值出现的次数为每个bin累积更高的值.然后可以读取这些直方图像素以供稍后处理.

在iOS上的着色器中执行此操作的主要问题是,尽管有相反的报告,Apple明确指出顶点着色器中的纹理读取在iOS上不起作用.我尝试使用我的所有iOS 5.0设备,并且没有一个能够在顶点着色器中执行纹理读取(屏幕变黑,没有抛出GL错误).

为了解决这个问题,我发现我可以读取输入图像的原始像素(通过glReadPixels()更快的纹理缓存)并将这些字节作为顶点数据传递给GL_UNSIGNED_BYTE类型.以下代码完成此操作:

glReadPixels(0, 0, inputTextureSize.width, inputTextureSize.height, GL_RGBA, GL_UNSIGNED_BYTE, vertexSamplingCoordinates);

[self setFilterFBO];

[filterProgram use];

glClearColor(0.0, 0.0, 0.0, 1.0);
glClear(GL_COLOR_BUFFER_BIT);

glBlendEquation(GL_FUNC_ADD);
glBlendFunc(GL_ONE, GL_ONE);
glEnable(GL_BLEND);

glVertexAttribPointer(filterPositionAttribute, 4, GL_UNSIGNED_BYTE, 0, (_downsamplingFactor - 1) * 4, vertexSamplingCoordinates);
glDrawArrays(GL_POINTS, 0, inputTextureSize.width * inputTextureSize.height / (CGFloat)_downsamplingFactor);

glDisable(GL_BLEND);
Run Code Online (Sandbox Code Playgroud)

在上面的代码中,您会注意到我使用一个步幅来仅对一小部分图像像素进行采样.这是因为您可以写出的最低不透明度或灰度级别是1/256,这意味着每个bin在该图像中具有该颜色值超过255个像素时最大化.因此,我不得不减少处理的像素数量,以使直方图的范围在这个有限的窗口内.我正在寻找一种方法来扩展这个动态范围.

用于执行此操作的着色器如下所示,从顶点着色器开始:

 attribute vec4 position;

 void main()
 {
     gl_Position = vec4(-1.0 + (position.x * 0.0078125), 0.0, 0.0, 1.0);
     gl_PointSize = 1.0;
 }
Run Code Online (Sandbox Code Playgroud)

并使用片段着色器完成:

 uniform highp float scalingFactor;

 void main()
 {
     gl_FragColor = vec4(scalingFactor);
 }
Run Code Online (Sandbox Code Playgroud)

可以在我的开源GPUImage框架中找到这方面的工作实现.抓取并运行FilterShowcase示例以查看直方图分析并为自己绘图.

这个实现存在一些性能问题,但这是我想到在iOS上在GPU上执行此操作的唯一方法.我愿意接受其他建议.


小智 0

是的。这显然不是最好的方法,但它确实是 iOS 中可用的最好方法,因为不支持 OpenCL。您将失去优雅,并且您的代码可能不会那么简单,但几乎所有 OpenCL 功能都可以通过着色器实现。

如果有帮助的话,DirectX11 附带了一个用于计算着色器的 FFT 示例。请参阅 DX11 8 月 SDK 发行说明。

  • 我只是想确保那篇文章中没有遗漏任何内容。我自己一直致力于基于 OpenGL ES 着色器的直方图实现,但那篇文章中没有任何内容与我一直在做的事情相近,所以我想我可能错过了一些细节。如果只是广泛引用 GLSL 的用途,那么在这种情况下可能根本没有帮助。汤米在上述问题中的回答是一个更好的起点。当我自己的实施工作正常时我会回答。 (2认同)