在openGL中比较两个纹理

时间:2016-01-11 13:57:19

标签: opengl opengl-es

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

问题是:在比较两个图像时,有没有办法比较两个纹理?比如逐个像素地比较两个图像?

3 个答案:

答案 0 :(得分:5)

实际上你似乎要求的是不可能的,或者至少不像在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周围找到答案)。这样,您可以在没有溢出的情况下计算值,并从算法中获得非常精确的结果。这意味着您可以将浮动值写为从第一个着色器输出开始的颜色,并继续执行每个其他绘制调用(获取纹理,将其转换为浮点数,求和,将其转换回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);

答案 1 :(得分:0)

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

// 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上测试着色器。

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

答案 2 :(得分:0)

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

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

检查GLSL语言规范