理解多點觸控/卷積和反捲積
數學上,卷積被描述為一個運算子,它接收兩個函式 f 和 g,並生成第三個函式,表示 f 和 g 之間的重疊量。卷積在訊號分析中被廣泛使用,因為卷積運算通常非常便宜,可以並行執行,並且易於調整以適應情況。
在我們的案例中,我們將討論二維意義上的卷積,其中影像和已知卷積函式(稱為 **濾波器**)將被組合以生成一個更好地表示我們正在尋找的資料的影像。由於您應該已經熟悉這些概念,因此這將是對卷積工作原理的簡要概述,以及我們感興趣的特定卷積濾波器。
如果您回憶一下,我們的理論感測器模型將資料作為 8x8 的 8 位資料矩陣輸入系統,類似於以下內容
Horizontal Address
0 1 2 3 4 5 6 7
V A 0 00 00 00 00 00 00 00 00
e d 1 00 00 00 00 00 00 00 00
r d 2 00 00 00 00 00 00 00 00
t r 3 00 00 00 00 00 00 00 00
i e 4 00 00 00 00 00 00 00 00
c s 5 00 00 00 00 00 00 00 00
a s 6 00 00 00 00 00 00 00 00
l 7 00 00 00 00 00 00 00 00
然而,我們的卷積核尺寸要小得多。對於我們將用於理論模型的演算法,3x3 卷積核就足夠了。
在實現卷積核時,重要的是要記住,我們正在接受兩個函式並生成第三個函式。原始函式可以被丟棄,或者可以返回到系統中用於其他目的,例如降噪。因此,當我們在軟體中實現我們的濾波器時,我們將希望生成一個函式,該函式將返回一個與輸入緩衝區大小相同的填充緩衝區給使用者。
卷積操作應該看起來非常類似於此虛擬碼
function Convolution ( in_buffer[8][8], out_buffer[8][8], divisor )
{
define kernel[3][3];
for (x from 0 to 7)
for (y from 0 to 7)
out_buffer[x][y] = 0; //make sure the buffer is zeroed
if (x-1 >= 0 && y-1 >= 0)
out_buffer[x][y] += in_buffer[x-1][y-1] * kernel[0][0];
if (x-1 >= 0)
out_buffer[x][y] += in_buffer[x-1][y] * kernel[0][1];
if (x-1 >= 0 && y+1 <= 7)
out_buffer[x][y] += in_buffer[x-1][y+1] * kernel[0][2];
if (y-1 >= 0)
out_buffer[x][y] += in_buffer[x][y-1] * kernel[1][0];
//this is our "free" operation, the only one that will always work.
out_buffer[x][y] += in_buffer[x][y] * kernel[1][1];
if (y+1 <= 7)
out_buffer[x][y] += in_buffer[x][y+1] * kernel[1][2];
if (x+1 <= 7 && y-1 >= 0)
out_buffer[x][y] += in_buffer[x+1][y-1] * kernel[2][0];
if (x+1 <= 7)
out_buffer[x][y] += in_buffer[x+1][y] * kernel[2][1];
if (x+1 <= 7 && y+1 <= 7)
out_buffer[x][y] += in_buffer[x+1][y+1] * kernel[2][2];
if (divisor && divisor > 0)
out_buffer[x][y] /= divisor;
else
out_buffer[x][y] /= 9;
end for
end for
}
上述內容可能在您的硬體上進行了最佳化,因為您通常可以透過確保您的緩衝區足夠大來避免分支語句,以捕獲可能發生的溢位,而無需進行邊界測試,以記憶體換分支操作。您的演算法通常不需要除了常數核心之外的任何臨時資料,如果您過去處理過訊號處理,您可能已經在工具包中擁有類似的功能。
人們經常問在濾波器邊緣(稱為 **邊緣條件**)應該怎麼做。有許多選擇,例如選擇已知的“背景強度”並將其應用於該元素(在本例中,資料為零,因此不會影響核心操作;這與在本例中截斷濾波器完全相同),但是還有許多其他方法來處理這種情況,包括擴充套件影像邊緣的資料,截斷核心並且不執行操作,或者根本不將核心應用於超出邊緣的點(通常稱為“就地複製”)。
您還會注意到,我們在畫素操作期間沒有指定任何 else 情況;在所有不進行操作的情況下,我們假設該操作的輸出將為零。例如,如果卷積核的中心項為零,就像通常情況下那樣,沒有必要進行乘法並得到零。只需跳過該計算並繼續下一個。
在某些情況下,例如如果我們的資料是整數格式,我們需要應用一個除數來滿足數字格式的約束(在本例中,我們的緩衝區由 8 位資料組成)。除數通常是核心寬度乘以核心高度(3x3 為 9,5x5 為 25 等等),但也有一些情況下可能需要其他除數。
我們將要看的第一個核心是 **索貝爾運算元**,也稱為 **邊緣檢測** 核心。索貝爾運算元透過降低低頻畫素的強度,同時提高高頻畫素的強度,來強調影像函式中的高頻變化。本質上,索貝爾運算元正在對影像的每個座標處的強度求二階導數,然而,對於那些對數學不太瞭解的人,以及我們中的一些人來說,將其理解為卷積濾波器更容易。
-1 0 1 -2 0 2 -1 0 1
我們可以透過檢視常數函式 f(x) 的一維二階導數來思考這一點:. 透過取常數並將它們儲存在一個矩陣中,我們構建了一維卷積核:. 我們透過將該矩陣與垂直矩陣 相乘,將其轉換為二維卷積核,該矩陣只是我們正在進行卷積的點的絕對差值。
這個相對簡單的濾波器有幾個變體。例如,一個常見的調整是強調的方向
1 0 -1 2 0 -2 1 0 -1
這種調整將濾波器的前沿改為右側,而不是像前一個例子中那樣強調左側。它與上面相同的濾波器“翻轉”了,方法是將函式乘以 -1。
1 2 1 -1 -2 -1 0 0 0 or 0 0 0 -1 -2 -1 1 2 1
這些是原始濾波器的旋轉,分別強調向上和向下。