高斯濾波
高斯濾波(也可以說“高斯模糊”)其實就是一種線性平滑濾波,適用於消除高斯噪聲,廣泛應用於圖像處理的減噪過程。簡單來說就是整個圖像某個像素點的值與周圍像素點的值掛鈎,是原圖像某一像素點的值其實是其本省和周圍像素點值的加權平均過程。
處理結果上:整個圖像相較於原圖像會看起來較為模糊,原圖像上的某些噪聲點在經過周圍像素點加權求和后會被剔除掉。
下面這個是貼吧上看到很有意思的兩張圖:

圖1 高斯 圖2 高斯濾波
什么時候需要用到高斯濾波?
答:原圖像上存在很多和周圍像素差距過大的像素點,這種噪聲點可能會對之后搜索圖像關鍵因素產生干擾的情況。當然,也可以不用高斯濾波,可以采用其他處理,反正就是怎么處理合適怎么來就好。
實現
現在經過初步了解什么是高斯濾波之后,下面說說怎么實現高斯濾波。
1、初步計算
之所以被冠以“高斯”之名,是因為處理過程里面,運用了高斯函數,也就是:

其中:μ是x的均值,σ是x的標准差。μ決定了分布對稱中心,σ決定了分布的形狀(σ越小形狀越瘦)。

圖3 一維高斯分布圖像
高斯公式在圖像上,是一種鍾形圖像。也就是越接近像素點,對該像素點的影響越大。
而每次計算都是以當前像素點計算,因此周圍坐標的均值μ其實就是0。因此將公式簡化:

現在假定一組一維像素點,σ = 1.5:
| 相對像素點坐標 | -1 | 0(中心坐標點) | 1 |
| 像素值 | 126 | 230 | 124 |
我們將像素坐標帶入高斯公式中,將得到(高斯公式的值與像素點的值無關,因此先忽略):
| 相對像素點坐標 | -1 | 0 | 1 |
| 計算值 | 0.212965 | 0.265962 | 0.212965 |
你可以將計算出的值理解為該相對位置“權重”,而這個“權重”與像素點的值無關。因此我們可以以這個為模板,事先計算出我們定好σ以及半徑后的各位置對應的值作為模板。這樣我們就能大大節約運算時間,不必每次都重新計算。
2、歸一化
但為了接下來方便計算,我們還可以進行一個操作:歸一化。
為什么歸一化呢?在加權求和時,最終的結果我們還需要除以權重和。而我們將這計算的和先除掉,其實並不影響之后的結果。
接下來,將得到的計算值求和:0.691892。將個計算值除這個和,我們就將得到真正的權重。
| 相對像素點坐標 | -1 | 0 | 1 |
| 最終結果 | 0.307801 | 0.384398 | 0.307801 |
這個得到的結果也可以被稱為:高斯掩膜。
之后將像素點的值計算之后我們就能得到處理后的中心坐標像素點了:126*0.307801+230*0.384398+124*0.307801=165.36179。
根據結果看:中心像素點過高的值明顯被拉低了。
3、擴展二維
(1)運算
對一維處理我們知道是怎么回事了,但圖像並不是一維的,我門還需學習二維的處理。
下面是二維的高斯公式和分布圖像。

圖4 二維高斯分布圖像
其實二維只是將一維坐標換為了二維坐標。根據一維的結論,我們就知道只需要事先求一個二維的高斯掩碼就可以了,這里就不求了。
我們計算某像素點的值,其實就還需要將周圍點的值乘對應位置的高斯掩碼,最后求和就好。
(2)優化算法
這么看來二維和一維差不了多少,但是接下來才是二維需要關注的點:優化算法。
假設是一個7*7的一個高斯掩碼。那我們處理一張圖像,那最起碼要遍歷49次圖像(每個像素點都需要遍歷周圍48個像素點),這樣來看耗時就會多很多。對於一些需要及時處理的情況無疑是致命的。
那有什么好的方法能減少處理時長呢?有!將二維的處理轉換為一維的處理。這其實是一個很簡單的過程。
這是二維的公式:

那么我們經過簡單的數學變換:

我們就得到一個結論:可以將二維變換拆解為兩個一維變化。
也就是說我們將原圖像經過一次x方向,一次y方向的一維變化后的效果與一次二維變化后的效果是一樣的。而遍歷次數則變為了14次(x方向遍歷7次,y方向遍歷7次),極大縮減了處理時長。
程序
以下是一個使用C語言的簡單高斯圖像處理函數:
/** * @fileOverview 高斯模糊 * @prama sigma 標准差 * @prama radius 模糊半徑 * @author * @since */
void fileOverview(uint8 radius,float sigma) { float gaussMatrix[2*radius+1];//模板數組 float gaussSum=0;
//高斯公式中的兩部分 float a=1/(sqrt(2*3.14159)); float b=-1/(2*sigma*sigma);
uint8 image[MTV03X_H][MTV03X_W];//和原圖像相同的數組,MTV03X_H為圖像高,MTV03X_w為圖像寬 //計算高斯矩陣 float sum=0;//求和用於歸一化 for(int i=-radius;i<=radius;i++){ gaussMatrix[i+radius]=a*exp(b*i*i); sum +=gaussMatrix[i+radius]; } //歸一化 for(int i=-radius;i<=radius;i++) { gaussMatrix[i+radius]=gaussMatrix[i+radius]/sum; } //x方向一維運算 for(int y=0;y<MT9V03X_H;y++) for(int x=radius;x<MT9V03X_W-radius;x++)
{ gaussSum=0;
//加權求和 for(int j=-radius;j<=radius;j++){ if((x+j>=0)&&(x+j<MT9V03X_W)){ gaussSum += gaussMatrix[j+radius]*mt9v03x_image[y][x+j]; } }
//記錄X方向處理結果,基於該結果對y方向處理 image[y][x]=gaussSum; } //y方向一維運算 for(int x=0;x<MT9V03X_W;x++) for(int y=radius;y<MT9V03X_H-radius;y++)//遍歷圖像,無邊界
{ gaussSum=0;
//加權求和 for(int j=-radius;j<=radius;j++){ if((y+j>=0)&&(y+j<MT9V03X_H)){ gaussSum += gaussMatrix[j+radius]*image[y+j][x]; } }
//更改原圖像 mt9v03x_image[y][x]=gaussSum; } }
希望本篇文章能夠對你有所幫助,如有錯誤歡迎指正。
