簡體   English   中英

在2D數組上執行有效的局部平均

[英]Performing efficient local average over a 2D array

我有一個二維數組自定義Vector類,其尺寸約為250、250。 Vector類僅存儲向量的x和y浮點分量。 我的項目要求我對數組執行平滑功能,以便通過對數組中每個向量周圍的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;

}

您的內部循環所做的是計算矩形面積的總和:

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

您可以在O(n ^ 2)中有效地進行預先計算。 讓我們介紹一下數組S [N] [N](這里N = 250)。

為了簡化起見,我假設只有一個坐標。 您可以通過構建2個數組輕松將其調整為對(x,y)。

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

我們可以有效地構建此數組:

S[0, 0] = myVectorArray[0, 0]; //rectangle (0, 0)-(0,0) has only one cell (0, 0)
for (int i = 1; i < N; ++i){
  S[0, i] = S[0, i-1] + myVectorArray[0, i];  //rectangle (0, 0)-(0, i) is calculated based on previous rectangle (0,0)-(0,i-1) and new cell (0, i)
  S[i, 0] = S[i - 1, 0] + myVectorArray[i, 0]; //same for (0, 0)-(i, 0)
}

for (int i = 1; i < N; ++i){
  var currentRowSum = myVectorArray[i, 0];
  for (int j = 1; j < N; ++j){
     currentRowSum += myVectorArray[i, j]; //keep track of sum in current row
     S[i, j] = S[i - 1, j] + currentRowSum; //rectangle (0,0)-(i,j) sum constrcuted as //rectanle (0, 0) - (i-1, j) which is current rectagnle without current row which is already calculated + current row sum
  }
 }

一旦我們有了這個部分和數組,我們就可以得到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

您肯定會想利用CPU緩存作為解決方案,這聽起來像是您對一維陣列解決方案的考慮。 嘗試安排算法一次處理連續內存塊,而不是在數組中跳來跳去。 至此,您應該使用Vector結構而不是類,或者使用兩個浮點數組,一個數組用於x值,一個數組用於y值。 通過使用一個類,您的數組將存儲指向堆中各個位置的指針。 因此,即使您按順序遍歷數組,當您跳到Vector對象的位置時,仍然始終缺少緩存。 每個高速緩存未命中會浪費約200個cpu周期。 這是首先要解決的主要問題。

之后,您可以考慮進行一些微優化:

  • 在inArrayBounds方法上使用內聯提示: [MethodImpl(MethodImplOptions.AggressiveInlining)]

  • 使用不安全模式並使用指針算法進行迭代以避免數組邊界檢查開銷

您應該測試一下這最后兩個想法是否會產生重大影響。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM