【從零學習OpenCV 4】高斯濾波
- 2019 年 12 月 30 日
- 筆記
高斯雜訊是一種常見的雜訊,影像採集的眾多過程中都容易引入高斯雜訊,因此針對高斯雜訊的高斯濾波也廣泛應用於影像去噪領域。高斯濾波器考慮了像素離濾波器中心距離的影響,以濾波器中心位置為高斯分布的均值,根據高斯分布公式和每個像素離中心位置的距離計算出濾波器內每個位置的數值,從而形成一個形如圖5-15所示的高斯濾波器。之後將高斯濾波器與影像之間進行濾波操作,進而實現對影像的高斯濾波。

圖5-15 高斯濾波器空間構型
OpenCV 4提供了對影像進行高斯濾波操作的GaussianBlur()函數,該函數的函數原型在程式碼清單5-13中給出。
程式碼清單5-13 GaussianBlur()函數原型 void cv::GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY = 0, int borderType = BORDER_DEFAULT )
- src:待高斯濾波影像,影像可以具有任意的通道數目,但是數據類型必須為CV_8U,CV_16U,CV_16S,CV_32F或CV_64F。
- dst:輸出影像,與輸入影像src具有相同的尺寸、通道數和數據類型。
- ksize:高斯濾波器的尺寸,濾波器可以不為正方形,但是必須是正奇數。如果尺寸為0,則由標準偏差計算尺寸。
- sigmaX:X方向的高斯濾波器標準偏差。
- sigmaY:Y方向的高斯濾波器標準偏差; 如果輸入量為0,則將其設置為等於sigmaX,如果兩個軸的標準差均為0,則根據輸入的高斯濾波器尺寸計算標準偏差。
- borderType:像素外推法選擇標誌,取值範圍在表3-5中給出,默認參數為BORDER_DEFAULT,表示不包含邊界值倒序填充。
該函數能夠根據輸入參數自動生成高斯濾波器,實現對影像的高斯濾波,函數的前兩個參數與前面介紹的濾波函數的參數含義相同。該函數第三個參數是高斯濾波器的尺寸,與前面函數不同的是,該函數除了必須是正奇數以外,還允許輸入尺寸為0,當輸入的尺寸為0時,會根據輸入的標準偏差計算濾波器的尺寸。函數第四個和第五個參數為X方向和Y方向的標準偏差,當Y方向參數為0時表示Y方向的標準偏差與X方向相同,當兩個參數都為0時,則根據輸入的濾波器尺寸計算兩個方向的標準偏差數值。但是為了能夠使計算結果符合自己的預期,建議將第三個參數、第四個參數和第五個參數都明確的給出。
高斯濾波器的尺寸和標準偏差存在著一定的互相轉換關係,OpenCV 4提供了輸入濾波器單一方向尺寸和標準偏差生成單一方向高斯濾波器的getGaussianKernel()函數,在函數的定義中給出了濾波器尺寸和標準偏差存在的關係,這個關係不是數學中存在的關係,而是OpenCV 4為了方便而自己設定的關係。在了解這個關係之前,我們首先了解以下getGaussianKernel()函數,該函數的函數原型在程式碼清單5-14中給出。
程式碼清單5-14 getGaussianKernel()函數原型 Mat cv::getGaussianKernel(int ksize, double sigma, int ktype = CV_64F )
- ksize:高斯濾波器的尺寸。
- sigma:高斯濾波的標測差。
- ktype:濾波器係數的數據類型,可以是CV_32F或者CV_64F,默認數據類型為CV_64F。
該函數用於生成指定尺寸的高斯濾波器,需要注意的是該函數生成的是一個ksize×1的Mat類矩陣。函數第一個參數是高斯濾波器的尺寸,這個參數必須是一個正奇數。第二個參數表示高斯濾波的標準差,這個參數如果是一個負數,則調用程式中默認的高斯濾波器尺寸與標準差的公式,其計算公式如式(5.4)所示。

生成一個二維的高斯濾波器需要調用兩次getGaussianKernel()函數,將X方向的一維高斯濾波器和Y方向的一維高斯濾波器相乘,得到最終的二維高斯濾波器。例如計算的X方向的一維濾波器和Y方向的一維濾波器均如式(5.5)所示。

最終二維高斯濾波器計算過程和結果如式(5.6)所示。

為了了解高斯濾波對不同雜訊的去除效果,在程式碼清單5-15中利用高斯濾波分別處理不含有雜訊的影像、含有椒鹽雜訊的影像和含有高斯雜訊的影像,處理結果在圖5-16、圖5-17、圖5-18中給出。通過結果可以發現,高斯濾波對高斯雜訊去除效果較好,但是同樣會對影像造成模糊,並且濾波器的尺寸越大,濾波後影像變得越模糊。
程式碼清單5-15 myGaussianBlur.cpp影像高斯濾波 #include <opencv2opencv.hpp> #include <iostream> using namespace cv; using namespace std; int main() { Mat equalLena = imread("equalLena.png", IMREAD_ANYDEPTH); Mat equalLena_gauss = imread("equalLena_gauss.png", IMREAD_ANYDEPTH); Mat equalLena_salt = imread("equalLena_salt.png", IMREAD_ANYDEPTH); if (equalLena.empty()||equalLena_gauss.empty()||equalLena_salt.empty()) { cout << "請確認影像文件名稱是否正確" << endl; return -1; } Mat result_5, result_9; //存放不含雜訊濾波結果,後面數字代表濾波器尺寸 Mat result_5gauss, result_9gauss; //存放含有高斯雜訊濾波結果,後面數字代表濾波器尺寸 Mat result_5salt, result_9salt; ////存放含有椒鹽雜訊濾波結果,後面數字代表濾波器尺寸 //調用均值濾波函數blur()進行濾波 GaussianBlur(equalLena, result_5, Size(5, 5), 10, 20); GaussianBlur(equalLena, result_9, Size(9, 9), 10, 20); GaussianBlur(equalLena_gauss, result_5gauss, Size(5, 5), 10, 20); GaussianBlur(equalLena_gauss, result_9gauss, Size(9, 9), 10, 20); GaussianBlur(equalLena_salt, result_5salt, Size(5, 5), 10, 20); GaussianBlur(equalLena_salt, result_9salt, Size(9, 9), 10, 20); //顯示不含雜訊影像 imshow("equalLena ", equalLena); imshow("result_5", result_5); imshow("result_9", result_9); //顯示含有高斯雜訊影像 imshow("equalLena_gauss", equalLena_gauss); imshow("result_5gauss", result_5gauss); imshow("result_9gauss", result_9gauss); //顯示含有椒鹽雜訊影像 imshow("equalLena_salt", equalLena_salt); imshow("result_5salt", result_5salt); imshow("result_9salt", result_9salt); waitKey(0); return 0; }

圖5-16 myGaussianBlur.cpp程式中不含雜訊影像高斯濾波結果

圖5-17 myGaussianBlur.cpp程式中含椒鹽雜訊影像高斯濾波結果

圖5-18 myGaussianBlur.cpp程式中含高斯雜訊影像高斯濾波結果