1.9【OpenCV圖像處理】平滑模糊濾波
平滑去噪、均值濾波blur()、高斯濾波GaussianBlur()、中值濾波medianBlur()、雙邊濾波bilateralFilter()
1.9.1 平滑模糊原理1 - 卷積
平滑/模糊(Smooth/Blur)是圖像處理中最簡單和常用的操作之一,使用該操作的原因之一就為了給圖像預處理時候降低雜訊。圖像平滑處理往往使圖像中的邊界、輪廓變得模糊,原因是因為圖像受到了平均或積分運算,從頻率域來考慮,圖像模糊的實質是因為其高頻分量被衰減。
(比如邊緣提取演算法canny通過高斯來給圖像降噪以獲得更好的圖像效果、OCR識別等圖像識別中在圖像特徵提取之前經常通過smooth來使圖像雜訊降低、在二值化之前通過smooth把不必要的雜訊去掉,以免影響對準確的對象的提取)
卷積(convolution):使用卷積核對圖像每一個像素進行操作。它具有增強原信號特徵、降低噪音的作用。
通常這些卷積運算元計算都是線性操作,所以又叫線性濾波。
使用Smooth/Blur操作其背後原理就是數學的卷積計算:
對圖像來說卷積計算可以看成離散的求和操作,f(i,j)表示一幅圖像,第i行j列的像素,h(k,l)是卷積核(kernel)、卷積運算元(又叫掩膜),k l 大小又叫窗口大小,在k l範圍內f(i,j)與h(k,l)乘積,各值相加得到一新像素值,輸出圖像g(i,j)。
卷積核(卷積運算元): 四方形網格結構,每個方格都有一個權重值,也稱邊緣檢測運算元。卷積核大小又叫窗口大小。
卷積過程: 假設有6x6的圖像像素點矩陣,3x3窗口是他的卷積運算元,從左向右從上向下每次移動一個像素格, 黃色覆蓋下的灰色區域與黃色的係數(權值)每一個對應想乘(包括紅色),各值相加再取平均值(周圍差值減小,變模糊了),賦給中心的像素。
邊緣效應:邊緣像素沒被處理,如果卷積運算元變成5*5大小,邊緣就會有2個像素沒被處理。opencv的API(Application Programming Interface,應用程序編程介面,是一些預先定義的函數)中也提供了邊緣像素處理方法(如常數填充、向外擴張(臨近點插值、雙線性插值))。
1.9.2 平滑模糊原理2 - 濾波4種
(1)均值濾波(mean filter) (歸一化盒子濾波):
均值濾波是典型的線性濾波演算法,它是指在圖像上對目標像素給一個濾波模板f(x,y),該模板包括了其周圍的鄰近像素(以目標像素為中心的周圍8個像素,即去掉目標像素本身)和中心像素,再用模板中的全體像素的平均值來代替原來像素值。
作用:平滑圖像, 可以把銳度降低;模糊圖像,降低雜訊;演算法簡單,計算速度快,效果較差。
g(x,y)=1/m ∑f(x,y),m為該模板中包含當前像素在內的像素總個數。
k =所有的和/(核的寬度*高度),卷積核所有的係數都是1,不分權重,權重都是1,取平均值。
K = (f(x-1,y-1) + f(x,y-1)+ f(x+1,y-1) + f(x-1,y) + f(x,y) + f(x+1,y) + f(x-1,y+1) + f(x,y+1) + f(x+1,y+1))/9
(2)高斯濾波(Gauss filter):
高斯濾波是一種線性平滑濾波,適用於消除高斯雜訊,高斯濾波就是對整幅圖像進行加權平均的過程,每一個像素點的值,都由其本身和鄰域內的其他像素值經過加權平均後得到。
操作:用一個模板(或稱卷積、掩模)掃描圖像中的每一個像素,用模板中像素的加權平均值去替代模板中心像素點的值。
作用:相對於均值濾波它的平滑效果更柔和,而且邊緣保留的也更好。
σ越大,高斯濾波器的頻帶就越寬,平滑程度就越好,低通(高阻)濾波的效果越明顯。高斯濾波被用作為平滑濾波器的本質原因是因為它是一個低通濾波器。要對數字圖像做高斯模糊,就是用一個符合高斯函數分布的卷積核對數字圖像做卷積運算。
如下圖為一個標準差為1.0的整數值高斯核,高斯濾波後圖像被平滑的程度取決於標準差。它的輸出是領域像素的加權平均,同時離中心越近的像素權重越高。
高斯分布(正態分布)曲線:鐘擺型,若隨機變數X服從一個數學期望為μ、方差為σ^2的正態分布,記為N(μ,σ^2)。其概率密度函數為正態分布的期望值μ決定了其位置,其標準差 σ 決定了分布的幅度。當μ = 0,σ = 1時的正態分布是標準正態分布。數字圖像是離散的,總概率之和為1,中心化對稱,注意要中心化
四個不同參數集的概率密度函數(紅色線代表標準正態分布)
A是歸一化係數,數學期望為μ、方差為σ^2 。
(3)中值濾波
中值濾波法是一種非線性平滑技術,它將每一像素點的像素值設置為該點某鄰域窗口內的所有像素點像素值的中值。統計排序濾波器,中值對椒鹽雜訊(有最大小值特性)有很好的抑制作用,效果是圖像中瑕疵更光滑。(沒用卷積)
操作:窗口內的像素從小到大排序取中值賦給中間像素。
椒鹽雜訊也稱為脈衝雜訊,是圖像中經常見到的一種雜訊,它是一種隨機出現的白點或者黑點,可能是亮的區域有黑色像素或是在暗的區域有白色像素(或是兩者皆有)。成因可能是影像訊號受到突如其來的強烈干擾而產生、類比數位轉換器或位元傳輸錯誤等。例如失效的感應器導致像素值為最小值,飽和的感應器導致像素值為最大值。
高斯雜訊是一種具有正態分布(也稱作高斯分布)概率密度函數的雜訊。換句話說,高斯雜訊的值遵循高斯分布或者它在各個頻率分量上的能量具有高斯分布。如果一個雜訊幅度分布服從高斯分布,而它的功率譜密度又是均勻分布的,則稱它為高斯白雜訊。高斯雜訊的主要來源出現在採集期間,由於不良照明和/或高溫引起的感測器雜訊。可以使用空間濾波器來降低高斯雜訊。
(4)雙邊濾波
高斯雙邊模糊是既考慮空間位置(空域核)不同也考慮像素值(值域核)的不同的邊緣保留濾波方法,避免了邊緣信息丟失,保留了圖像輪廓不變。(也是用於美容演算法的處理步驟之一)效果比高斯濾波好,磨皮效果,差值設置越大越模糊。
均值模糊無法克服邊緣像素信息丟失缺陷,原因是均值濾波是基於平均權重。
高斯模糊部分克服了該缺陷,但是無法完全避免,因為只考慮了空間位置的不同,距離越近權值越大,但沒有考慮像素值的不同,像素值差值的閾值,大於這個閾值的才考慮進去。
雙邊濾波的卷積核分為空域核和值域核:
空域核:在窗口內每個位置都有權重(即每個位置的像素都考慮)。
值域核:是指像素值落差在一定範圍之內才把它輸出去模糊,像素值高的在高的部分模糊,低的在低的那部分模糊,他們的之間差值太大不應被模去,邊緣的保留了,圖像的兩個之間的差異還存在,整體特徵還存在。
1.9.3 模糊相關API
(1)均值模糊:(平均權重,都是1)
blur(Mat src, Mat dst, Size(xradius, yradius), Point(-1,-1), int borderType );
// 原圖像,目標圖像,窗口大小x y坐標,中心坐標默認(-1,-1),borderType邊界處理類型默認
Size(x, y) 卷積核的大小,當x>y時著重在x軸方向模糊,當x<y時著重在y軸方向模糊,x, y 必須是正數而且是奇數。
blur(InputArray src, OutputArray dst, Size ksize, Point anchor=Point(-1,-1), int borderType=BORDER_DEFAULT );
blur(src, dst, Size(3, 3), Point(-1, -1)); //均值濾波,窗口大小,中心點,borderType默認為4不用管
filter2D(src, dst, src.depth(), kernel); 也可以做模糊,但要自己做核Mat kernel = (Mat_<char>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0);
(2)高斯模糊:(有權重)
GaussianBlur(Mat src, Mat dst, Size(11, 11), sigmaX, sigmaY, int borderType);
// 原圖像,目標圖像,高斯窗口大小x y坐標, σx σy正態分布情況
其中Size(x, y), x, y 必須是正數而且是奇數。
GaussianBlur(InputArray src, OutputArray dst, Size ksize, double sigmaX, double sigmaY=0,int borderType=BORDER_DEFAULT );
GaussianBlur(src, dst2, Size(11, 11), 11, 11); //高斯模糊,高斯窗口大小x y坐標,σx σy正態分布情況
(3)中值模糊:(取中間值)
medianBlur( Mat src, Mat dest, ksize );
- ksize - 窗口大小ksize * ksize, ksize必須是大於1而且必須是奇數。(因為偶數不容易找中心像素,高斯也要中心化等)
medianBlur(InputArray src, OutputArray dst, int ksize);
medianBlur(src2, dst3, 3); //中值濾波,窗口大小3*3
(4)雙邊模糊:(有權重、考慮像素值範圍)
bilateralFilter(src, dest, d=15, 150, 3);
- 15 –計算的半徑,半徑之內的像數都會被納入計算,如果提供-1 則根據sigma space參數取值
- 150 – sigma color像素差值,決定多少差值之內的像素會被計算,值域
- 3 – sigma space空間大小,如果d的值大於0則此聲明無效,否則根據它來計算d值
bilateralFilter(InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType=BORDER_DEFAULT );
bilateralFilter(src, dst4, 15, 100, 3); //雙邊濾波,半徑,像素差值,空間大小
可以結合filter2D提高一下對比度,效果可能更好。
完整程序:
/*1.9 平滑模糊濾波*/#include <opencv2/opencv.hpp>#include <iostream> using namespace cv; //使用cv命名空間int main(int argc, char** argv) { //argc 表示命令行輸入參數的個數(以空白符分隔),argv中存儲了所有的命令行參數Mat src, src2, dst1, dst2, dst3, dst4, maskResult; src = imread("E:/OpenCV/testimage/test6.jpg"); src2 = imread("E:/OpenCV/testimage/椒鹽雜訊.png");if (src.empty()) { printf("could not load image...
");return -1; }char input_title[] = "input image";char output_title[] = "blur image"; namedWindow(input_title, CV_WINDOW_AUTOSIZE); namedWindow(output_title, CV_WINDOW_AUTOSIZE); imshow(input_title, src); imshow("input image2", src2); blur(src, dst1, Size(5, 5), Point(-1, -1)); //均值濾波,窗口大小,中心點,borderType默認為4不用管 imshow(output_title, dst1); GaussianBlur(src, dst2, Size(5, 5), 3, 3); //高斯模糊,高斯窗口大小x y坐標,σx σy正態分布情況 imshow("GaussianBlur", dst2); medianBlur(src, dst3, 3); //中值濾波,窗口大小3*3 imshow("medianBlur", dst3); bilateralFilter(src, dst4, 15, 100, 3); //高斯雙邊濾波,半徑,像素差值,空間大小 imshow("bilateralFilter", dst4);Mat kernel = (Mat_<int>(3, 3) << 0, -1, 0, -1, 5, -1, 0, -1, 0); //定義掩膜 filter2D(dst4, maskResult, -1, kernel, Point(-1, -1), 0); //矩陣掩膜,提高對比度 imshow("bilateralFilter and maskResult", maskResult); waitKey(0);return 0;}
運行結果:
推薦閱讀:
※最近在搞Kinect的指尖識別,手指都可以畫出來了,有什麼方法可以將每隻手指對應的名稱識別出來啊?
※[171103] 基於縮略圖哈希值比較的圖像相似性檢索
※元旦贈書 | 18本紙質書:OpenCV、Python和機器學習,總有一本適合你
※【小林的OpenCV基礎課 0】一切為了學習!
TAG:OpenCV | 图像处理 | 学习OpenCV书籍 |