圖像處理之了解卷積
一:什麼是卷積
離散卷積的數學公式可以表示為如下形式:
f(x) = - 其中C(k)代表卷積操作數,g(i)代表樣本資料, f(x)代表輸出結果。
舉例如下:
假設g(i)是一個一維的函數,而且代表的樣本數為G = [1,2,3,4,5,6,7,8,9]
假設C(k)是一個一維的卷積操作數, 操作數為C=[-1,0,1]
則輸出結果f(x)可以表示為 F=[1,2,2,2,2,2,2,2,1] //邊界資料未處理
以上隻是一維的情況下,當對一幅二維數字圖像加以卷積時,其數學意義可以解釋如下:
源圖像是作為輸入源資料,處理以後要的圖像是卷積輸出結果,卷積操作數作為Filter
在XY兩個方向上對源圖像的每個像素點實施卷積操作。如圖所示:
粉紅色的方格每次在X/Y前進一個像素方格,就會産生一個新的輸出像素,圖中深藍色的代
表要輸出的像素方格,走完全部的像素方格,就得到了所有輸出像素。
圖中,粉紅色的矩陣表示卷積操作數矩陣,黑色表示源圖像– 每個方格代表一個像素點。
二:卷積在數字圖像進行中應用
一副數字圖像可以看作一個二維空間的離散函數可以表示為f(x, y), 假設有對于二維卷積操
作函數C(u, v) ,則會産生輸出圖像g(x, y) = f(x, y) *C(u,v), 利用卷積可以實作對圖像模糊處理,邊緣檢測,産生軋花效果的圖像。

一個簡單的數字圖像卷積處理流程可以如下:
1. 讀取源圖像像素
2. 應用卷積操作數矩陣産生目标圖像
3. 對目标圖像進行歸一化處理
4. 處理邊界像素
三:一個純Java的卷積模糊圖像效果
四:關鍵代碼解釋
完成對像素點RGB顔色的卷積計算代碼如下:
// red color
out3DData[row][col][1] =in3DData[row][col][1] +
in3DData[row-1][col][1] +
in3DData[row+1][col][1] +
in3DData[row][col-1][1] +
in3DData[row-1][col-1][1] +
in3DData[row+1][col-1][1] +
in3DData[row][col+1][1] +
in3DData[row-1][col+1][1] +
in3DData[row+1][col+1][1];
// green color
out3DData[row][col][2] =in3DData[row][col][2] +
in3DData[row-1][col][2] +
in3DData[row+1][col][2] +
in3DData[row][col-1][2] +
in3DData[row-1][col-1][2] +
in3DData[row+1][col-1][2] +
in3DData[row][col+1][2] +
in3DData[row-1][col+1][2] +
in3DData[row+1][col+1][2];
// blue color
out3DData[row][col][3] =in3DData[row][col][3] +
in3DData[row-1][col][3] +
in3DData[row+1][col][3] +
in3DData[row][col-1][3] +
in3DData[row-1][col-1][3] +
in3DData[row+1][col-1][3] +
in3DData[row][col+1][3] +
in3DData[row-1][col+1][3] +
in3DData[row+1][col+1][3];
計算歸一化因子以及對卷積結果歸一化處理的代碼如下:
// find the peak data frominput and output pixel data.
int inpeak = 0;
int outPeak = 0;
for(int row=0; row<srcH; row++) {
for(int col=0; col<srcW; col++) {
if(inpeak < in3DData[row][col][1]) {
inpeak = in3DData[row][col][1];
}
if(inpeak < in3DData[row][col][2]) {
inpeak = in3DData[row][col][2];
if(inpeak < in3DData[row][col][3]) {
inpeak = in3DData[row][col][3];
if(outPeak < out3DData[row][col][1]) {
outPeak = out3DData[row][col][1];
if(outPeak < out3DData[row][col][2]) {
outPeak = out3DData[row][col][2];
if(outPeak < out3DData[row][col][3]) {
outPeak = out3DData[row][col][3];
}
}
// normalization
double outputScale = ((double) inpeak) / ((double)outPeak);
out3DData[row][col][1] = (int)(outputScale * out3DData[row][col][1]);
out3DData[row][col][2] = (int)(outputScale * out3DData[row][col][2]);
out3DData[row][col][3] = (int)(outputScale * out3DData[row][col][3]);
五:本文沒有提及的内容 –邊界像素處理
沒有處理邊緣像素,對邊緣像素的處理,有兩個可以參考的方法
其一是直接填充法– 超出邊界部分的以邊界像素填充。
其二是線性插值法– 超出邊界部分的以 i/row的像素填充。