在2D阵列上执行有效的局部平均

时间:2016-01-28 16:17:49

标签: c# arrays performance 2d average

我有一个2d数组自定义Vector类,大约250个,250个维度。 Vector类只存储向量的x和y float组件。我的项目要求我对数组执行平滑功能,以便通过获取数组中每个向量的i索引的局部平均值来创建新数组。我的问题是我当前的解决方案计算速度不够快,并且想知道是否有更好的计算方法。

我当前解决方案的伪代码如下所示。我在C#中实现这一点,任何帮助将不胜感激。我的实际解决方案使用1d数组来加速,但我没有在这里包含它。

function smoothVectorArray(Vector[,] myVectorArray, int averagingDistance) {

    newVectorArray = new Vector[250,250];

    for (x = 0; x < 250; x++)
    {
        for (y = 0; y < 250; y++)
        {
            vectorCount = 0;
            vectorXTotal = 0;
            vectorYTotal = 0;

            for (i = -averageDistance; i < averagingDistance+ 1; i++)
            {
                for (j = -averageDistance; j < averagingDistance+ 1; j++)
                {

                    tempX = x + i;
                    tempY = y + j;

                    if (inArrayBounds(tempX, tempY)) {
                        vectorCount++;
                        vectorXTotal += myVectorArray[tempX, tempY].x;
                        vectorYTotal += myVectorArray[tempX, tempY].y;
                    }

                }
            }

            newVectorArray[x, y] = new Vector(vectorXTotal / vectorCount, vectorYTotal / vectorCount);

        }
    }

    return newVectorArray;

}

2 个答案:

答案 0 :(得分:2)

你的内心循环所做的是计算矩形的总和:

blue

您可以在O(n ^ 2)中有效地预先计算它们。让我们介绍一个数组S [N] [N](在你的情况下N = 250)。

为了简单起见,我假设只有一个坐标。您可以通过构建2个数组轻松地将其调整为对(x,y)。

S [i,j] - 将是子矩形(0,0)的总和 - (i,j)

我们可以有效地构建这个数组:

for (i = -averageDistance; i < averagingDistance+ 1; i++)
   for (j = -averageDistance; j < averagingDistance+ 1; j++)

一旦我们计算了这个部分和数组,我们就可以得到O(1)中的子矩形和。让我们说我们想得到矩形(a,b) - (c,d)

的和

为了得到它,我们从大矩形(0,0) - (c,d)开始,我们需要从中减去(0,0) - (a-1,d-1)和(0,0) - (c-1,b-1)并添加后加矩形(0,0) - (a-1,b-1),因为它被减去了两次。

这样你就可以摆脱你的内心循环。

https://en.wikipedia.org/wiki/Summed_area_table

答案 1 :(得分:0)

您肯定希望利用CPU缓存来解决这个问题,听起来您的一维阵列解决方案就是这么想的。尝试安排算法一次处理连续内存块,而不是在数组周围跳跃。到目前为止,您应该使用Vector结构而不是类,或者使用两个浮点数组,一个用于x值,另一个用于y值。通过使用类,您的数组存储指向堆中各个点的指针。因此,即使按顺序迭代数组,当您跳转到Vector对象的位置时,仍然始终缺少缓存。每次缓存未命中都会浪费大约200个cpu周期。这将是首先解决的主要问题。

之后,您可以考虑进行一些微观优化

  • 在inArrayBounds方法中使用内联提示:[MethodImpl(MethodImplOptions.AggressiveInlining)]

  • 使用不安全模式并使用指针算法迭代以避免数组边界检查开销

最后两个想法可能会或可能不会产生任何重大影响,您应该进行测试。