是否可以使用着色器找到两个纹理之间的“差异”? (XNA / HLSL)

时间:2009-07-25 14:14:07

标签: c# xna webcam hlsl shader

我制作了一个简单的基于网络摄像头的应用程序来检测“运动边缘”,因此绘制一个纹理,显示当前帧的像素与前一帧的显着不同的位置。这是我的代码:

// LastTexture is a Texture2D of the previous frame.
// CurrentTexture is a Texture2D of the current frame.
// DifferenceTexture is another Texture2D.
// Variance is an int, default 100;

Color[] differenceData = new Color[CurrentTexture.Width * CurrentTexture.Height];
Color[] currentData = new Color[CurrentTexture.Width * CurrentTexture.Height];
Color[] lastData = new Color[LastTexture.Width * LastTexture.Height];

CurrentTexture.GetData<Color>(currentData);
LastTexture.GetData<Color>(lastData);

for (int i = 0; i < currentData.Length; i++)
{
    int sumCD = ColorSum(currentData[i]); // ColorSum is the same as c.R + c.B + c.G where c is a Color.
    int sumLD = ColorSum(lastData[i]);
    if ((sumCD > sumLD - Variance) && (sumCD < sumLD + Variance))
        differenceData[i] = new Color(0, 0, 0, 0); // If the current pixel is within the range of +/- the Variance (default: 100) variable, it has not significantly changes so is drawn black.
    else
        differenceData[i] = new Color(0, (byte)Math.Abs(sumCD - sumLD), 0); // This has changed significantly so is drawn a shade of green.
}

DifferenceTexture = new Texture2D(game1.GraphicsDevice, CurrentTexture.Width, CurrentTexture.Height);
DifferenceTexture.SetData<Color>(differenceData);

LastTexture = new Texture2D(game1.GraphicsDevice,CurrentTexture.Width, CurrentTexture.Height);
LastTexture.SetData<Color>(currentData);

有没有办法使用着色器将此计算卸载到GPU(使用上述方法可以达到约25/26 fps,但这有点慢)?我对HLSL着色器的工作原理有一个基本的了解,并且不希望有完整的解决方案,我只是想知道这是否可能以及如何从着色器中获取“差异”纹理数据,如果这实际上更快

提前致谢。

3 个答案:

答案 0 :(得分:3)

您可以在像素着色器中对两个纹理进行采样,然后将差异写为颜色值。如果设置Render Target,则从着色器输出的颜色信息将存储在此纹理中而不是帧缓冲区中。

我不知道你期望看到什么样的速度增益,但我就是这样做的。

*编辑 - 哦,我忘了说,请注意您使用的采样类型,因为它会影响结果。如果您希望算法直接转换为GPU,请使用点采样开始。

答案 1 :(得分:2)

关于您上面关于决定使用双线程方法解决问题的评论,请查看Microsoft的.Net Parallel Extensions CTP。 microsoft.com

如果您不打算部署到XBox360,这个库可以很好地使用XNA,并且我已经看到在某些循环和迭代中大幅提升了速度。

您基本上只需更改几行代码,例如:

for (int i = 0; i < currentData.Length; i++)
{
    // ...
}

将更改为:

Parallel.For(0, currentData.Length, delegate(int i)
{
   // ...
});

自动使处理器中的每个核心都有数字运算帮助。它快速而优秀。

祝你好运!

答案 2 :(得分:0)

Sobel operator或类似的东西在游戏引擎和其他实时应用程序中用于边缘检测。写为像素着色器是微不足道的。