【问题标题】:Comparing two textures in openGL比较openGL中的两个纹理
【发布时间】:2016-01-12 04:20:39
【问题描述】:

我是 OpenGL 的新手,我期待比较两个纹理以了解它们之间的相似程度。我知道如何使用两个位图图像来做到这一点,但我真的需要使用一种方法来比较两个纹理。

问题是:当我们比较两张图片时,有什么方法可以比较两张纹理?就像逐个像素地比较两个图像?

【问题讨论】:

  • 您预期的最终结果是什么?
  • “当我们比较两张图片时”比较两张图片?我不知道很多提供图像比较功能的语言。确实提供此类功能的库提供了许多方法来做到这一点,对于比较它们的含义有非常不同的想法。所以根本不清楚你要的是什么。
  • @Vertexwahn 告诉我百分比值或任何其他方式的相似性!我只需要知道有什么办法吗?如果有,那怎么办?
  • 您使用哪个版本的 OpenGL? GL4.x? 3.2?

标签: opengl opengl-es


【解决方案1】:

实际上,您似乎要求的东西是不可能的,或者至少不像在 GPU 上看起来那么容易。问题在于 GPU 旨在在最短的时间内完成尽可能多的小任务。不包括遍历像素等数据数组,因此获取整数或浮点值之类的数据可能有点困难。

您可以尝试一种非常有趣的程序,但我不能说结果适合您:

您可以首先创建一个新纹理,它是两个输入纹理之间的差异,然后继续对结果进行下采样直到 1x1 像素纹理,并获取该像素的值以查看它的差异。

要实现这一点,最好使用固定大小的目标缓冲区,即 POT(2 的幂),例如 256x256。如果您没有使用固定尺寸,则结果可能会因图像尺寸而有很大差异。

所以在第一遍中,您会将两个纹理重绘到第三个(使用 FBO - 帧缓冲区对象)。您将使用的着色器很简单:

vec4 a = texture2D(iChannel0,uv);
vec4 b = texture2D(iChannel1,uv);
fragColor = abs(a-b);

所以现在你有了一个纹理,它代表了两个图像每个像素、每个颜色分量之间的差异。如果两张图片相同,则结果将是全黑图片。

现在您需要创建一个新的 FBO,它在每个维度上都缩小一半,在本示例中为 128x128。要绘制到这个缓冲区,您需要使用GL_NEAREST 作为纹理参数,因此不会对纹理提取进行插值。然后对于每个新像素,将源图像的 4 个最近像素相加:

vec4 originalTextCoord = varyingTextCoord;
vec4 textCoordRight = vec2(varyingTextCoord.x+1.0/256, varyingTextCoord.y);
vec4 textCoordBottom = vec2(varyingTextCoord.x, varyingTextCoord.y+1.0/256);
vec4 textCoordBottomRight = vec2(varyingTextCoord.x+1.0/256, varyingTextCoord.y+1.0/256);

fragColor = texture2D(iChannel0, originalTextCoord) + 
texture2D(iChannel0, textCoordRight) + 
texture2D(iChannel0, textCoordBottom) + 
texture2D(iChannel0, textCoordBottomRight);

256 值来自源纹理,因此它应该是统一的,因此您可以重复使用相同的着色器。

绘制完成后,需要下拉到 64、32、16... 然后将像素读回 CPU 并查看结果。

现在不幸的是,此过程可能会产生非常不希望的结果。由于颜色只是简单地加在一起,这将对所有不够相似的图像产生溢出(导致白色像素或(1,1,1,0) 不透明)。这可以通过在第一个着色器通道上使用比例来克服,将输出除以足够大的值。但这可能还不够,可能需要在第二个着色器中进行平均(将所有texture2D 调用乘以.25)。

最终结果可能还是有点奇怪。您在 CPU 上获得 4 个颜色分量,它们代表图像差异的总和或平均值。我想您可以总结它们并选择您认为图像是否相似的内容。但是,如果您想更清楚地了解您得到的结果,您可能希望将整个像素视为单个 32 位浮点值(这些有点棘手,但您可能会在 SO 周围找到答案)。这样,您可以计算没有溢出的值,并从算法中获得非常准确的结果。这意味着您将写入浮动值,就好像它是一种颜色,从第一个着色器输出开始并在每个其他绘制调用中继续(获取 texel,将其转换为浮点数,求和,将其转换回 vec4 并分配为输出) , GL_NEAREST 在这里是必不可少的。

如果没有,那么您可以优化程序并使用GL_LINEAR 而不是GL_NEAREST,并简单地重新绘制差分纹理,直到它达到单个像素大小(不需要 4 个坐标)。这应该会产生一个很好的像素,它代表差分纹理中所有像素的平均值。所以这是两个图像中像素之间的平均差异。这个过程也应该很快。

然后,如果您想做一些更智能的算法,您可能会在创建差分纹理方面创造一些奇迹。简单地减去颜色可能不是最好的方法。模糊其中一张图像然后将其与另一张图像进行比较会更有意义。对于那些非常相似的图像,这将失去精度,但对于其他一切,它会给你一个更好的结果。例如,您可以说只有当像素与另一张图像(模糊的)的权重相差 30% 时您才感兴趣,因此您将丢弃并缩放每个组件的 30%,例如 result.r = clamp(abs(a.r-b.r)-30.0/100.0, .0, 1.0)/((100.0-30.0)/100.0);

【讨论】:

  • 另一个可能值得尝试的选项是在差异纹理上调用 glGenerateMipmap(),并从生成的 mipmap 链中读回 1x1 级别的值。
【解决方案2】:

您可以将这两个纹理绑定到一个着色器,并通过绘制一个四边形或类似的东西来访问每个像素。

// Equal pixels are marked green. Different pixels are shown in red color.
void mainImage( out vec4 fragColor, in vec2 fragCoord )
{
    vec2 uv = fragCoord.xy / iResolution.xy;

    vec4 a = texture2D(iChannel0,uv);
    vec4 b = texture2D(iChannel1,uv);

    if(a != b)
        fragColor = vec4(1,0,0,1);
    else
        fragColor = vec4(0,1,0,1);
}

您可以在Shadertoy 上测试着色器。

或者您也可以将两个纹理绑定到计算着色器并通过迭代访问每个像素。

【讨论】:

  • 谢谢。我要测试它;)
【解决方案3】:

你不能比较向量。你必须使用

if(any(notEqual(a,b)))

查看 GLSL 语言规范

【讨论】:

    猜你喜欢
    • 2013-07-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-04-20
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多