天天看點

圖像處理之了解卷積

圖像處理之了解卷積

一:什麼是卷積

離散卷積的數學公式可以表示為如下形式:

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的像素填充。