高斯濾波器的原理和實現

2020-12-06 電子發燒友

高斯濾波器是一種線性濾波器,能夠有效的抑制噪聲,平滑圖像。其作用原理和均值濾波器類似,都是取濾波器窗口內的像素的均值作為輸出。其窗口模板的係數和均值濾波器不同,均值濾波器的模板係數都是相同的為1;而高斯濾波器的模板係數,則隨著距離模板中心的增大而係數減小。所以,高斯濾波器相比於均值濾波器對圖像個模糊程度較小。


什麼是高斯濾波器

既然名稱為高斯濾波器,那麼其和高斯分布(正態分布)是有一定的關係的。一個二維的高斯函數如下:


其中(x,y)(x,y)為點坐標,在圖像處理中可認為是整數;σσ是標準差。要想得到一個高斯濾波器的模板,可以對高斯函數進行離散化,得到的高斯函數值作為模板的係數。例如:要產生一個3×33×3的高斯濾波器模板,以模板的中心位置為坐標原點進行取樣。模板在各個位置的坐標,如下所示(x軸水平向右,y軸豎直向下)


這樣,將各個位置的坐標帶入到高斯函數中,得到的值就是模板的係數。

對於窗口模板的大小為(2k+1)×(2k+1),模板中各個元素值的計算公式如下:


這樣計算出來的模板有兩種形式:小數和整數。

小數形式的模板,就是直接計算得到的值,沒有經過任何的處理;

整數形式的,則需要進行歸一化處理,將模板左上角的值歸一化為1,下面會具體介紹。使用整數的模板時,需要在模板的前面加一個係數,係數為也就是模板係數和的倒數。


高斯模板的生成

知道模板生成的原理,實現起來也就不困難了

void generateGaussianTemplate(double window[][11], int ksize, double sigma)
{
static const double pi = 3.1415926;
int center = ksize / 2; // 模板的中心位置,也就是坐標的原點
double x2, y2;
for (int i = 0; i < ksize; i++)
{
x2 = pow(i - center, 2);
for (int j = 0; j < ksize; j++)
{
y2 = pow(j - center, 2);
double g = exp(-(x2 + y2) / (2 * sigma * sigma));
g /= 2 * pi * sigma;
window[i][j] = g;
}
}
double k = 1 / window[0][0]; // 將左上角的係數歸一化為1
for (int i = 0; i < ksize; i++)
{
for (int j = 0; j < ksize; j++)
{
window[i][j] *= k;
}
}
}
需要一個二維數組,存放生成的係數(這裡假設模板的最大尺寸不會超過11);第二個參數是模板的大小(不要超過11);第三個參數就比較重要了,是高斯分布的標準差。

生成的過程,首先根據模板的大小,找到模板的中心位置ksize/2。然後就是遍歷,根據高斯分布的函數,計算模板中每個係數的值。

需要注意的是,最後歸一化的過程,使用模板左上角的係數的倒數作為歸一化的係數(左上角的係數值被歸一化為1),模板中的每個係數都乘以該值(左上角係數的倒數),然後將得到的值取整,就得到了整數型的高斯濾波器模板。


下面截圖生成的是,大小為3×3,σ=0.83×3,σ=0.8的模板


對上述解結果取整後得到如下模板:

這個模板就比較熟悉了,其就是根據σ=0.8的高斯函數生成的模板。

至於小數形式的生成也比較簡單,去掉歸一化的過程,並且在求解過程後,模板的每個係數要除以所有係數的和。具體代碼如下:

void generateGaussianTemplate(double window[][11], int ksize, double sigma)
{
static const double pi = 3.1415926;
int center = ksize / 2; // 模板的中心位置,也就是坐標的原點
double x2, y2;
double sum = 0;
for (int i = 0; i < ksize; i++)
{
x2 = pow(i - center, 2);
for (int j = 0; j < ksize; j++)
{
y2 = pow(j - center, 2);
double g = exp(-(x2 + y2) / (2 * sigma * sigma));
g /= 2 * pi * sigma;
sum += g;
window[i][j] = g;
}
}
//double k = 1 / window[0][0]; // 將左上角的係數歸一化為1
for (int i = 0; i < ksize; i++)
{
for (int j = 0; j < ksize; j++)
{
window[i][j] /= sum;
}
}
}
3×3,σ=0.8的小數型模板。

σσ值的意義及選取

通過上述的實現過程,不難發現,高斯濾波器模板的生成最重要的參數就是高斯分布的標準差σσ。標準差代表著數據的離散程度,如果σσ較小,那麼生成的模板的中心係數較大,而周圍的係數較小,這樣對圖像的平滑效果就不是很明顯;反之,σσ較大,則生成的模板的各個係數相差就不是很大,比較類似均值模板,對圖像的平滑效果比較明顯。

來看下一維高斯分布的概率分布密度圖:

橫軸表示可能得取值x,豎軸表示概率分布密度F(x),那麼不難理解這樣一個曲線與x軸圍成的圖形面積為1。σσ(標準差)決定了這個圖形的寬度,可以得出這樣的結論:σσ越大,則圖形越寬,尖峰越小,圖形較為平緩;σσ越小,則圖形越窄,越集中,中間部分也就越尖,圖形變化比較劇烈。這其實很好理解,如果sigma也就是標準差越大,則表示該密度分布一定比較分散,由於面積為1,於是尖峰部分減小,寬度越寬(分布越分散);同理,當σσ越小時,說明密度分布較為集中,於是尖峰越尖,寬度越窄!

於是可以得到如下結論:

σσ越大,分布越分散,各部分比重差別不大,於是生成的模板各元素值差別不大,類似於平均模板;

σσ越小,分布越集中,中間部分所佔比重遠遠高於其他部分,反映到高斯模板上就是中心元素值遠遠大於其他元素值,於是自然而然就相當於中間值得點運算。

基於OpenCV的實現

在生成高斯模板好,其簡單的實現和其他的空間濾波器沒有區別,具體代碼如下:

void GaussianFilter(const Mat &src, Mat &dst, int ksize, double sigma)
{
CV_Assert(src.channels() || src.channels() == 3); // 只處理單通道或者三通道圖像
const static double pi = 3.1415926;
// 根據窗口大小和sigma生成高斯濾波器模板
// 申請一個二維數組,存放生成的高斯模板矩陣
double **templatematrix = new double*[ksize];
for (int i = 0; i < ksize; i++)
templateMatrix[i] = new double[ksize];
int origin = ksize / 2; // 以模板的中心為原點
double x2, y2;
double sum = 0;
for (int i = 0; i < ksize; i++)
{
x2 = pow(i - origin, 2);
for (int j = 0; j < ksize; j++)
{
y2 = pow(j - origin, 2);
// 高斯函數前的常數可以不用計算,會在歸一化的過程中給消去
double g = exp(-(x2 + y2) / (2 * sigma * sigma));
sum += g;
templateMatrix[i][j] = g;
}
}
for (int i = 0; i < ksize; i++)
{
for (int j = 0; j < ksize; j++)
{
templateMatrix[i][j] /= sum;
cout << templateMatrix[i][j] << " ";
}
cout << endl;
}
// 將模板應用到圖像中
int border = ksize / 2;
copyMakeBorder(src, dst, border, border, border, border, BorderTypes::BORDER_REFLECT);
int channels = dst.channels();
int rows = dst.rows - border;
int cols = dst.cols - border;
for (int i = border; i < rows; i++)
{
for (int j = border; j < cols; j++)
{
double sum[3] = { 0 };
for (int a = -border; a <= border; a++)
{
for (int b = -border; b <= border; b++)
{
if (channels == 1)
{
sum[0] += templateMatrix[border + a][border + b] * dst.at(i + a, j + b);
}
else if (channels == 3)
{
Vec3b rgb = dst.at(i + a, j + b);
auto k = templateMatrix[border + a][border + b];
sum[0] += k * rgb[0];
sum[1] += k * rgb[1];
sum[2] += k * rgb[2];
}
}
}
for (int k = 0; k < channels; k++)
{
if (sum[k] < 0)
sum[k] = 0;
else if (sum[k] > 255)
sum[k] = 255;
}
if (channels == 1)
dst.at(i, j) = static_cast(sum[0]);
else if (channels == 3)
{
Vec3b rgb = { static_cast(sum[0]), static_cast(sum[1]), static_cast(sum[2]) };
dst.at(i, j) = rgb;
}
}
}
// 釋放模板數組
for (int i = 0; i < ksize; i++)
delete[] templateMatrix[i];
delete[] templateMatrix;
}
只處理單通道或者三通道圖像,模板生成後,其濾波(卷積過程)就比較簡單了。不過,這樣的高斯濾波過程,其循環運算次數為m×n×ksize2,其中m,n為圖像的尺寸;ksize為高斯濾波器的尺寸。這樣其時間複雜度為O(ksize2),隨濾波器的模板的尺寸呈平方增長,當高斯濾波器的尺寸較大時,其運算效率是極低的。為了,提高濾波的運算速度,可以將二維的高斯濾波過程分解開來。

分離實現高斯濾波

由於高斯函數的可分離性,尺寸較大的高斯濾波器可以分成兩步進行:首先將圖像在水平(豎直)方向與一維高斯函數進行卷積;然後將卷積後的結果在豎直(水平)方向使用相同的一維高斯函數得到的模板進行卷積運算。具體實現代碼如下:

// 分離的計算
void separateGaussianFilter(const Mat &src, Mat &dst, int ksize, double sigma)
{
CV_Assert(src.channels()==1 || src.channels() == 3); // 只處理單通道或者三通道圖像
// 生成一維的高斯濾波模板
double *matrix = new double[ksize];
double sum = 0;
int origin = ksize / 2;
for (int i = 0; i < ksize; i++)
{
// 高斯函數前的常數可以不用計算,會在歸一化的過程中給消去
double g = exp(-(i - origin) * (i - origin) / (2 * sigma * sigma));
sum += g;
matrix[i] = g;
}
// 歸一化
for (int i = 0; i < ksize; i++)
matrix[i] /= sum;
// 將模板應用到圖像中
int border = ksize / 2;
copyMakeBorder(src, dst, border, border, border, border, BorderTypes::BORDER_REFLECT);
int channels = dst.channels();
int rows = dst.rows - border;
int cols = dst.cols - border;
// 水平方向
for (int i = border; i < rows; i++)
{
for (int j = border; j < cols; j++)
{
double sum[3] = { 0 };
for (int k = -border; k <= border; k++)
{
if (channels == 1)
{
sum[0] += matrix[border + k] * dst.at(i, j + k); // 行不變,列變化;先做水平方向的卷積
}
else if (channels == 3)
{
Vec3b rgb = dst.at(i, j + k);
sum[0] += matrix[border + k] * rgb[0];
sum[1] += matrix[border + k] * rgb[1];
sum[2] += matrix[border + k] * rgb[2];
}
}
for (int k = 0; k < channels; k++)
{
if (sum[k] < 0)
sum[k] = 0;
else if (sum[k] > 255)
sum[k] = 255;
}
if (channels == 1)
dst.at(i, j) = static_cast(sum[0]);
else if (channels == 3)
{
Vec3b rgb = { static_cast(sum[0]), static_cast(sum[1]), static_cast(sum[2]) };
dst.at(i, j) = rgb;
}
}
}
// 豎直方向
for (int i = border; i < rows; i++)
{
for (int j = border; j < cols; j++)
{
double sum[3] = { 0 };
for (int k = -border; k <= border; k++)
{
if (channels == 1)
{
sum[0] += matrix[border + k] * dst.at(i + k, j); // 列不變,行變化;豎直方向的卷積
}
else if (channels == 3)
{
Vec3b rgb = dst.at(i + k, j);
sum[0] += matrix[border + k] * rgb[0];
sum[1] += matrix[border + k] * rgb[1];
sum[2] += matrix[border + k] * rgb[2];
}
}
for (int k = 0; k < channels; k++)
{
if (sum[k] < 0)
sum[k] = 0;
else if (sum[k] > 255)
sum[k] = 255;
}
if (channels == 1)
dst.at(i, j) = static_cast(sum[0]);
else if (channels == 3)
{
Vec3b rgb = { static_cast(sum[0]), static_cast(sum[1]), static_cast(sum[2]) };
dst.at(i, j) = rgb;
}
}
}
delete[] matrix;
}
代碼沒有重構較長,不過其實現原理是比較簡單的。首先得到一維高斯函數的模板,在卷積(濾波)的過程中,保持行不變,列變化,在水平方向上做卷積運算;接著在上述得到的結果上,保持列不邊,行變化,在豎直方向上做卷積運算。這樣分解開來,算法的時間複雜度為O(ksize)O(ksize),運算量和濾波器的模板尺寸呈線性增長。

在OpenCV也有對高斯濾波器的封裝GaussianBlur,其聲明如下:

CV_EXPORTS_W void GaussianBlur( InputArray src, OutputArray dst, Size ksize,
double sigmaX, double sigmaY = 0,
int borderType = BORDER_DEFAULT );

二維高斯函數的標準差在x和y方向上應該分別有一個標準差,在上面的代碼中一直設其在x和y方向的標準是相等的,在OpenCV中的高斯濾波器中,可以在x和y方向上設置不同的標準差。

下圖是自己實現的高斯濾波器和OpenCV中的GaussianBlur的結果對比

上圖是5×5,σ=0.8的高斯濾波器,可以看出兩個實現得到的結果沒有很大的區別。

總結

高斯濾波器是一種線性平滑濾波器,其濾波器的模板是對二維高斯函數離散得到。由於高斯模板的中心值最大,四周逐漸減小,其濾波後的結果相對於均值濾波器來說更好。

高斯濾波器最重要的參數就是高斯分布的標準差σσ,標準差和高斯濾波器的平滑能力有很大的能力,σσ越大,高斯濾波器的頻帶就較寬,對圖像的平滑程度就越好。通過調節σσ參數,可以平衡對圖像的噪聲的抑制和對圖像的模糊。

打開APP閱讀更多精彩內容

聲明:本文內容及配圖由入駐作者撰寫或者入駐合作網站授權轉載。文章觀點僅代表作者本人,不代表電子發燒友網立場。文章及其配圖僅供工程師學習之用,如有內容圖片侵權或者其他問題,請聯繫本站作侵刪。 侵權投訴

相關焦點

  • 一文了解高斯濾波器,附原理及實現過程
    高斯濾波器是一種線性濾波器,能夠有效的抑制噪聲,平滑圖像。其作用原理和均值濾波器類似,都是取濾波器窗口內的像素的均值作為輸出。其窗口模板的係數和均值濾波器不同,均值濾波器的模板係數都是相同的為1;而高斯濾波器的模板係數,則隨著距離模板中心的增大而係數減小。所以,高斯濾波器相比於均值濾波器對圖像個模糊程度較小。
  • 高斯濾波器詳解
    本文主要介紹了高斯濾波器的原理及其實現過程高斯濾波器是一種線性濾波器,能夠有效的抑制噪聲,平滑圖像。
  • 時域測量的高斯響應低通濾波器
    近年來,移動通信和光纖網絡使用高速脈衝調製的射頻/微波和光波,要求從元件、部件至子系統、系統保持良好的頻率響應,以免對傳輸鏈路上的脈衝流引入瞬變過程失真、多次反射和高頻噪聲等雜散幹擾,更力求接近高斯響應。  時域法測量電子設備的幅度―頻率特性的關鍵是,保持測量用的標準階躍脈衝源具有高斯響應。對低速脈衝來說,高斯響應比較容易實現,而對高速脈衝來說,高斯響應往往不能達到。
  • 雙邊濾波器的原理及實現
    雙邊濾波器之所以能夠做到在平滑去噪的同時還能夠很好的保存邊緣(Edge Preserve),是由於其濾波器的核由兩個函數生成:一個函數由像素歐式距離決定濾波器模板的係數另一個函數由像素的灰度差值決定濾波器的係數其綜合了高斯濾波器(Gaussian Filter)和αα-截尾均值濾波器
  • 高斯類小波變換的開關電流頻域法實現
    Morlet小波、Marr小波及DOG小波同屬於高斯類小波,且從最大成度上解決了時寬和帶寬不相容的矛盾,因而很多工程領域將高斯類小波函數作為母小波函數進行小波分析。開關電流電路是電流模信號處理技術,它用離散時間的取樣數據系統處理連續時間的模擬信號。
  • 使用卡爾曼濾波器和路標實現機器人定位
    Robby(紅色大圓圈)和2個地標(紅色小圓圈) 這個文章的目的是教你用地標檢測和擴展卡爾曼濾波器一步一步實現機器人定位。這就是卡爾曼濾波器發揮作用的場合。 卡爾曼濾波器允許我們結合當前狀態的不確定和它的傳感器測量的不確定來理想地降低機器人的總體不確定程度。這兩類不確定通常用高斯概率分布或正態分布來描述。高斯分布有2個參數:均值和方差。均值表示最高概率的值,方差表示我們認為這個均值有多大的不確定性。 卡爾曼濾波器運行2個步驟。在預測步驟,卡爾曼濾波器以當前狀態變量值生成預測和不確定度。
  • 均值濾波器(平滑空間濾波器)基本原理及Python實現
    基本原理使用元素的領域內像素的平均值代替該元素,可明顯的降低圖像灰度的尖銳變換。它的一種重要應用是模糊處理:得到感興趣的區域的粗略表示,將次要的/小的元素與背景融合,使得主要的/較大的元素變得易於檢測$$ R=\frac{1}{m} \sum_{i=1}^{m} z_{i} $$ 2.
  • FIR濾波器原理
    如果超出1/2採樣頻率的頻率分量不佔主要地位,通常的解決辦法是在模數轉換電路之前放置一個低通濾波器(即抗混疊濾波器)將超過的高頻成分濾除。否則就必須用模擬濾波器實現要求的功能。  數字濾波器具有比模擬濾波器更高的精度,甚至能夠實現後者在理論上也無法達到的性能。
  • IIR數字濾波器的Matlab和FPGA實現
    關鍵詞:無限長單位脈衝響應濾波器;Matlab;FPGA;VHDL0 引言 數字濾波器具有比模擬濾波器精度高、穩定、體積小、重量輕、靈活、不要求阻抗匹配,以及能夠實現模擬濾波器無法實現的特殊濾波功能等特點,因此數字濾波器被廣泛應用於圖像處理和識別、語音處理和識別、通信、雷達、人工智慧、核技術等多個領域。
  • 高手講解濾波器原理(一),腔體濾波器原理解析
    越來越多的朋友想要了解濾波器原理,但對於不同的濾波器,其濾波器原理總是存在一定差異。而本文主要講解腔體濾波器原理,並於闡述濾波器原理後,向大家介紹腔體濾波器的應用。如果你對本文的內容存在一定興趣,那便耐心往下看吧。近年來,伴隨著科學技術的飛速發展,無線通信系統也在微波、毫米波技術的迅猛發展中得到了長足的進步。
  • 電源濾波器原理
    接地、屏蔽和濾波是抑制電磁幹擾最常見的三大措施,今天我們介紹其中一種方法:濾波。本文主要介紹電源濾波器的典型結構、基本原理和應用,感興趣的同學請多多關注。。。  電源濾波器是針對電源埠電磁騷擾的特點而設計的,一般是由電感、電容、電阻或鐵氧體器件構成的頻率選擇性二埠網絡,實際上是濾波器的一種,按照工作原理稱之為反射式濾波器。它可以在濾波器阻帶內提供了高的串聯阻抗和低的並聯阻抗,使它和噪聲源的阻抗和負載阻抗嚴重不匹配,從而把不希望的頻率分量發射回噪聲源。
  • 高手講解濾波器原理(四),巴特沃斯濾波器原理全知曉
    濾波器在生活中應用很多,因此很多朋友想一窺濾波器原理。通常,對於濾波器原理的理解往往基於一定技術基礎,所以學習濾波器原理需要耐心、堅持。本文中,將為大家詳細講解巴特沃斯濾波器原理,並向大家介紹巴特沃斯濾波器的一些相關知識,一起來看看吧。一、什麼是巴特沃斯濾波器巴特沃斯濾波器是電子濾波器的一種。巴特沃斯濾波器的特點是通頻帶的頻率響應曲線最平滑。
  • 濾波器原理
    導讀:濾波器是一種選頻裝置,本文主要介紹的是濾波器的原理,下面我們就一起來學習一下吧~~~本文引用地址:http://www.eepw.com.cn/article/272535.htm1.濾波器原理--簡介  濾波器是一種選頻裝置,可以使信號中特定的頻率成分通過
  • 卡爾曼濾波器的工作原理(一)
    卡爾曼濾波器是連續變化系統的理想選擇。卡爾曼濾波器具有佔用存儲小(不需要保留除先前狀態之外的任何歷史記錄),運算速度快,適合實時處理和嵌入式系統的優點。利用谷歌搜索到的對實現卡爾曼濾波器的數學描述普遍非常模糊。這其實很糟心,因為如果你以正確的方式看待它,卡爾曼濾波器實際上是超簡單易懂的。
  • 正弦波濾波器原理_正弦波濾波器的作用
    打開APP 正弦波濾波器原理_正弦波濾波器的作用 發表於 2019-08-30 14:55:52   正弦波濾波器原理   正弦波濾波器
  • 梳狀濾波器以及積分梳狀濾波器的FPGA實現
    梳狀濾波器以及積分梳狀濾波器的FPGA實現 lee 發表於 2020-11-21 09:57:00 作者:lee
  • EMI濾波器設計原理
    除此之外,可以利用EMI濾波器衰減電網與開關電源對彼此的噪聲幹擾。EMI騷擾通常難以精確描述,濾波器的設計通常是通過反覆迭代,計算製作以求逐步逼近設計要求。本文從EMI濾波原理入手,分別通過對其共模和差模噪聲模型的分析,給出實際工作中設計濾波器的方法,並分步驟給出設計實例。
  • 高手講解濾波器原理(二),輕鬆搞定LC濾波器原理
    很多朋友看來,濾波器原理屬於難以掌控的內容。但事實上,只要耐心學習,濾波器原理可被輕鬆掌握。本文中,將為大家講解LC濾波器原理,並附帶LC濾波電路實例。希望通過本文,大家能對LC濾波器原理有更深的理解。
  • 面向軟體工程師的卡爾曼濾波器
    這意味著,如果你了解當時的狀態向量k和提供給系統的輸入,則可以了解當時的k+1的系統狀態(與此同時使用系統工作原理的一些知識)。例如,假設我們有一個移動的機器人,並且我們關心其在空間中的位置(並且不在乎其方向)。
  • 巴特沃斯濾波器的原理_巴特沃斯濾波器優點介紹
    巴特沃斯濾波器原理   巴特沃斯型濾波器在現代設計方法設計的濾波器中,是最為有名的濾波器,由於它設計簡單,性能方面又沒有明顯的缺點,又因它對構成濾波器的元件Q值較低,因而易於製作且達到設計性能,因而得到了廣泛應用。其中,巴特沃斯濾波器的特點是通頻帶的頻率響應曲線最平滑。