iOS GLSL。 有没有办法使用GLSL着色器创build图像直方图?
在StackOverflow的其他地方,有人问到一个关于深度缓冲区直方图的问题 – 用GLSL创build深度缓冲区直方图纹理 。
我正在写一个iOSimage processing应用程序,并对这个问题感兴趣,但不清楚答案。 那么,是否可以通过GLSL使用GPU创build图像直方图?
是的。 这不是最好的方法,但它确实是iOS中最好的一个,因为不支持OpenCL。 你将失去优雅,你的代码可能不那么简单,但几乎所有的OpenCLfunction都可以通过着色器来实现。
如果有帮助的话,DirectX11会为计算着色器提供一个FFT示例。 请参阅DX11八月SDK发行说明。
是的,尽pipe在iOS上比在你想象的更具挑战性。 这是一个红色直方图,完全在GPU上生成并绘制,与实况videoFeed相对照:
汤米在你提到的问题上的build议是一个很好的起点,正如Scheuermann和Hensley的论文 。 build议使用散射build立图像中颜色通道的直方图。 散射是一个过程,将点网格传递给顶点着色器,然后让着色器读取该点的颜色。 然后将该点处的所需颜色通道的值写为X坐标(对于Y和Z坐标为0)。 您的片段着色器然后在目标中的该坐标处绘制一个半透明的1像素宽点。
该目标是1像素高,256像素宽的图像,每个宽度位置表示一个颜色区域。 通过写出低alpha通道(或低RGB值)的点,然后使用叠加混合,可以根据图像中出现特定颜色值的次数为每个bin累积更高的值。 然后可以读取这些直方图像素以供稍后处理。
在iOS着色器中这样做的主要问题是,尽pipe有相反的报告 ,但苹果明确指出顶点着色器中的纹理读取在iOS上不起作用。 我用我所有的iOS 5.0设备都尝试过,没有一个能够在顶点着色器中执行纹理读取(屏幕只是变黑,没有引发GL错误)。
要解决这个问题,我发现我可以读取input图像的原始像素(通过glReadPixels()
或更快的纹理caching ),并将这些字节作为GL_UNSIGNED_BYTEtypes的顶点数据传递。 下面的代码完成了这个:
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);
在上面的代码中,您会注意到我使用了一个步幅来仅对图像像素的一部分进行采样。 这是因为您可以写出的最低不透明度或灰度级别是1/256,这意味着每当图像中具有该颜色值的像素超过255个像素时,每个像素就会变为最大。 因此,我必须减less处理的像素数量,以便使直方图的范围在有限的窗口内。 我正在寻找扩大这个dynamic范围的方法。
用来做这件事的着色器如下,从顶点着色器开始:
attribute vec4 position; void main() { gl_Position = vec4(-1.0 + (position.x * 0.0078125), 0.0, 0.0, 1.0); gl_PointSize = 1.0; }
并完成片段着色器:
uniform highp float scalingFactor; void main() { gl_FragColor = vec4(scalingFactor); }
这个工作的实现可以在我的开源GPUImage框架中find。 抓取并运行FilterShowcase示例查看直方图分析和绘图。
这个实现有一些性能问题,但这是我能想到在iOS上完成这个GPU的唯一方法。 我接受其他build议。