【问题标题】:iOS GLSL. Is There A Way To Create An Image Histogram Using a GLSL Shader?iOS GLSL。有没有办法使用 GLSL 着色器创建图像直方图?
【发布时间】:2012-05-06 04:46:59
【问题描述】:

在 StackOverflow 的其他地方,有人询问了有关深度缓冲区直方图的问题 - Create depth buffer histogram texture with GLSL

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

【问题讨论】:

    标签: ios image-processing glsl histogram


    【解决方案1】:

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

    Tommy's suggestion 在您链接的问题中是一个很好的起点,this paper by Scheuermann and Hensley 也是如此。建议使用散射为图像中的颜色通道建立直方图。散射是一个过程,您将点网格传递给顶点着色器,然后让该着色器读取该点的颜色。然后将该点所需颜色通道的值写为 X 坐标(Y 和 Z 坐标为 0)。然后,您的片段着色器在目标中的该坐标处绘制一个半透明的 1 像素宽的点。

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

    在 iOS 的着色器中执行此操作的主要问题是,尽管 reports to the contrary,Apple 明确表示在顶点着色器中读取纹理在 iOS 上不起作用。我在我所有的 iOS 5.0 设备上都试过这个,但没有一个能够在顶点着色器中执行纹理读取(屏幕只是变黑,没有抛出 GL 错误)。

    为了解决这个问题,我发现我可以读取输入图像的原始像素(通过glReadPixels()faster texture caches)并将这些字节作为顶点数据以 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);
    

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

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

     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 框架中找到它的工作实现。抓取并运行 FilterShowcase 示例,您可以自己查看直方图分析和绘图。

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

    【讨论】:

    • 非常酷。只是一个小小的挑剔:值0.0078125 将值箱偏移了一个灰度值。使用 (2.0/255.0 = 0.00784313725) 将 255 映射到 2(在减去 1 之前)。
    【解决方案2】:

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

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

    【讨论】:

    • 感谢您的快速响应。干杯。
    • 你确定那篇文章是相关的吗?他们在哪里使用着色器计算直方图?
    • 我只是指出,因为它涉及到这两个主题,并用粗体表示了同样的东西,说这只是为了让他开始。也许这是一个坏主意,即使在陈述之后也是如此。我应该删除它吗?
    • 我只是想确保我在那篇文章中没有遗漏任何东西。我自己一直在研究基于 OpenGL ES 着色器的直方图实现,但那篇文章中没有任何内容接近我一直在做的事情,所以我想我可能错过了一些细节。如果它只是对 GLSL 用于某事的广泛引用,那么在这种情况下可能根本无济于事。汤米在上述问题中的回答是一个更好的起点。当我自己的实现正常工作时,我会回答。
    • 我正在尝试准备一个简单的示例。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-01-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-01-05
    相关资源
    最近更新 更多