高斯濾波器詳解

2021-01-21 芯視tof

本文主要介紹了高斯濾波器的原理及其實現過程

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

什麼是高斯濾波器

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

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

這樣,將各個位置的坐標帶入到高斯函數中,得到的值就是模板的係數。
對於窗口模板的大小為 (2k+1)×(2k+1)(2k+1)×(2k+1),模板中各個元素值的計算公式如下:

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

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

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

高斯模板的生成

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

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];     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σ=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;        }    }        for (int i = 0; i < ksize; i++)    {        for (int j = 0; j < ksize; j++)        {            window[i][j] /= sum;        }    }}

3×3,σ=0.83×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;            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<uchar>(i + a, j + b);                    }                    else if (channels == 3)                    {                        Vec3b rgb = dst.at<Vec3b>(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<uchar>(i, j) = static_cast<uchar>(sum[0]);            else if (channels == 3)            {                Vec3b rgb = { static_cast<uchar>(sum[0]), static_cast<uchar>(sum[1]), static_cast<uchar>(sum[2]) };                dst.at<Vec3b>(i, j) = rgb;            }        }    }        for (int i = 0; i < ksize; i++)        delete[] templateMatrix[i];    delete[] templateMatrix;}

只處理單通道或者三通道圖像,模板生成後,其濾波(卷積過程)就比較簡單了。不過,這樣的高斯濾波過程,其循環運算次數為m×n×ksize2m×n×ksize2,其中m,n為圖像的尺寸;ksize為高斯濾波器的尺寸。這樣其時間複雜度為O(ksize2)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<uchar>(i, j + k); } else if (channels == 3) { Vec3b rgb = dst.at<Vec3b>(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<uchar>(i, j) = static_cast<uchar>(sum[0]); else if (channels == 3) { Vec3b rgb = { static_cast<uchar>(sum[0]), static_cast<uchar>(sum[1]), static_cast<uchar>(sum[2]) }; dst.at<Vec3b>(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<uchar>(i + k, j); } else if (channels == 3) { Vec3b rgb = dst.at<Vec3b>(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<uchar>(i, j) = static_cast<uchar>(sum[0]); else if (channels == 3) { Vec3b rgb = { static_cast<uchar>(sum[0]), static_cast<uchar>(sum[1]), static_cast<uchar>(sum[2]) }; dst.at<Vec3b>(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.85×5,σ=0.8的高斯濾波器,可以看出兩個實現得到的結果沒有很大的區別。

總結

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


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


相關焦點

  • 高斯濾波器的原理和實現
    高斯濾波器是一種線性濾波器,能夠有效的抑制噪聲,平滑圖像。其作用原理和均值濾波器類似,都是取濾波器窗口內的像素的均值作為輸出。其窗口模板的係數和均值濾波器不同,均值濾波器的模板係數都是相同的為1;而高斯濾波器的模板係數,則隨著距離模板中心的增大而係數減小。所以,高斯濾波器相比於均值濾波器對圖像個模糊程度較小。
  • 時域測量的高斯響應低通濾波器
    這種低通的脈衝上升時間濾波器,亦稱瞬變時間轉換器或高斯低通濾波器。  根據信號處理原理,高斯低通濾波器的插入相當在數學上執行輸入信號與高斯函數的卷積,使輸入信號變換成沒有過衝、上升時間快速、群延遲最小的近高斯響應的階躍脈衝。高斯濾波器的基本原理和設計已有大量專著和文獻可供參考,本文限於篇幅只引用頻率響應的重要結果。
  • 一文了解高斯濾波器,附原理及實現過程
    高斯濾波器是一種線性濾波器,能夠有效的抑制噪聲,平滑圖像。其作用原理和均值濾波器類似,都是取濾波器窗口內的像素的均值作為輸出。其窗口模板的係數和均值濾波器不同,均值濾波器的模板係數都是相同的為1;而高斯濾波器的模板係數,則隨著距離模板中心的增大而係數減小。所以,高斯濾波器相比於均值濾波器對圖像個模糊程度較小。
  • 射頻系統中的濾波器基礎知識詳解
    打開APP 射頻系統中的濾波器基礎知識詳解 發表於 2017-12-04 19:07:45 雖然對這數位技術的發展,採用數字濾波器有取代基帶部分甚至中頻部分的模擬濾波器,但射頻部分的濾波器任然不可替代。因此,濾波器是射頻系統中必不可少的關鍵性部件之一。濾波器的分類有很多種方法。例如:按頻率選擇的特性可以分為:低通、高通、帶通、帶阻濾波器等; 按實現方式可以分為:LC濾波器、聲表面波/體聲波濾波器、螺旋濾波器、介質濾波器、腔體濾波器、高溫超導濾波器、平面結構濾波器。
  • 卡爾曼濾波器詳解——從零開始(3) Kalman Filter from Zero
    前兩篇文章傳送門:卡爾曼濾波器詳解——從零開始(1) Kalman Filter from Zero卡爾曼濾波器詳解——從零開始(2) Kalman Filter from Zero學完這篇我們就不會因理論基礎不夠再徘徊在Kalman Filter的大門之外了
  • 濾波器有幾種?四種濾波器之間對比詳解
    四種濾波器之間對比詳解 發表於 2017-11-13 14:42:07   如今的濾波器已經廣泛的滲透到來日常的生活中。那麼最常用的四種濾波器是那種呢?它主要分為哪四類?
  • 詳解低通濾波器的設計
    詳解低通濾波器的設計 李倩 發表於 2018-03-29 08:58:32 1.兩種濾波器都是數字濾波器。根據衝激響應的不同,將數字濾波器分為有限衝激響應(FIR)濾波器和無限衝激響應(IIR)濾波器。
  • 濾波器的截止頻率和品質因數詳解
    打開APP 濾波器的截止頻率和品質因數詳解 佚名 發表於 2016-10-12 10:16:38 對於切比雪夫濾波器, 有時可以定義為幅度響應降至通帶以外時的頻率。例如, 一個0.1 dB切比雪夫濾波器的F0 可以定義為響應下降》 0.1 dB 時的頻率。 如果考察的是實際頻率與截止頻率之比,而不是實際頻率 本身,則衰減曲線的形狀(以及相位和延遲曲線,它們定 義著濾波器的時域響應)將是相同的。將濾波器歸一化至 1 rad/s,則可開發出一種簡單的濾波器設計和比較系統。
  • 巴特沃斯、切比雪夫、貝塞爾濾波器詳解:(區別,特點,電路圖)
    打開APP 巴特沃斯、切比雪夫、貝塞爾濾波器詳解:(區別,特點,電路圖) 發表於 2017-05-04 10:04:53 巴特沃斯濾波器的頻率特性曲線,無論在通帶內還是阻帶內都是頻率的單調函數。因此,當通帶的邊界處滿足指標要求時,通帶內肯定會有裕量。所以,更有效的設計方法應該是將精確度均勻的分布在整個通帶或阻帶內,或者同時分布在兩者之內。這樣就可用較低階數的系統滿足要求。這可通過選擇具有等波紋特性的逼近函數來達到。   巴特沃斯濾波器、切比雪夫濾波器、貝塞爾濾波器均包括模擬濾波器和數字濾波器兩種形式。
  • 雙邊濾波器的原理及實現
    雙邊濾波器之所以能夠做到在平滑去噪的同時還能夠很好的保存邊緣(Edge Preserve),是由於其濾波器的核由兩個函數生成:一個函數由像素歐式距離決定濾波器模板的係數另一個函數由像素的灰度差值決定濾波器的係數其綜合了高斯濾波器(Gaussian Filter)和αα-截尾均值濾波器
  • 高斯類小波變換的開關電流頻域法實現
    本文提出了一個以頻域中的高斯函數單元為核心的共享結構系統實現3種高斯類小波變換。在此頻域共享結構實現方案中,復用頻域高斯函數單元採用開關電流電路實現頻域高斯類小波變換系統,不同尺度上的高斯類小波變換可通過調節開關電流電路的時鐘頻率獲得,所提出的頻域共享結構高斯類小波變換系統適合於製成通用型小波變換晶片。
  • 【強基固本】卡爾曼濾波器
    目前,卡爾曼濾波已經有很多不同的實現,有施密特擴展濾波器、信息濾波器以及一系列的Bierman和Thornton發明的平方根濾波器等,而卡爾曼最初提出的形式現在稱為簡單卡爾曼濾波器。也許最常見的卡爾曼濾波器應用是鎖相環,它在收音機、計算機和幾乎全部視頻或通訊設備中廣泛存在。一個簡單的應用是估計物體的位置和速度。
  • 【深度】基於多解析度高斯濾波器組的 時頻分析方法
    通過對人耳聽覺系統非線性特性,設計高斯濾波器組對數變化中心頻率,同時基於小波變換思想擴展了濾波器組的多解析度特性。詳細討論了基於多解析度高斯濾波器組功率響應及臨界帶寬選取的濾波器參數設計方法。分析了多解析度高斯濾波器組相比等帶寬高斯濾波器組的多解析度特性及濾波器組倒譜係數特徵識別性能。
  • 詳解帶通濾波器的電路分析—電路圖天天讀(271)
    打開APP 詳解帶通濾波器的電路分析—電路圖天天讀(271) Ida 發表於 2015-10-29 17:05:23   傳統的帶通濾波器設計方法中涉及了很多複雜的理論分析和計算
  • 高斯過程回歸詳解
    本文介紹了高斯回歸的基本概念,並在 R 中利用高斯回歸實現對時間序列的預測。
  • 面向軟體工程師的卡爾曼濾波器
    與我的朋友交談時,我經常聽到:「哦,卡爾曼(Kalman)濾波器……我經常學它,然後我什麼都忘了」。好吧,考慮到卡爾曼濾波器(KF)是世界上應用最廣泛的算法之一(如果環顧四周,你80%的技術可能已經在內部運行某種KF),讓我們嘗試將其弄清楚。
  • 無線射頻技術基本概念詳解
    無線射頻技術基本概念詳解 工程師曾玲 發表於 2018-10-27 09:27:03 射頻、中頻、基帶 射頻信號指無調製發射發射載波信號;中頻信號指射頻信號經外差變換後的較低的中頻信號
  • 電容濾波器和電感濾波器詳解(工作原理,設計詳解,典型電路圖)
    有源濾波的主要形式是有源RC濾波,也被稱作電子濾波器。直流電中的脈動成分的大小用脈動係數來表示,此值越大,則濾波器的濾波效果越差。   脈動係數(S)=輸出電壓交流分量的基波最大值/輸出電壓的直流分量   半波整流輸出電壓的脈動係數為S=1.57,全波整流和橋式整流的輸出電壓的脈動係數S≈O.67。
  • 開發者說 | 手把手教你寫卡爾曼濾波器
    這兩步完成後,我們就會獲得某一時刻,自車坐標系下的各種傳感器數據。這些數據包括障礙物的位置、速度;車道線的曲線方程、車道線的類型和有效長度;自車的GPS坐標等等。在介紹卡爾曼濾波器數學原理之前,先從感性上看一下它的工作原理。
  • 卡爾曼濾波器的工作原理(一)
    視頻演示了一個卡爾曼濾波器通過測量一個自由浮動物體的速度計算出它的方向。1.卡爾曼濾波器是什麼?可以在任何有關某些動態系統的不確定信息的地方使用卡爾曼濾波器,並且可以對有關系統下一步做什麼進行有根據的預測。