OpenCV2:图像滤波基础
一:基本概念
濾波是數(shù)字圖像處理中的一個(gè)基本操作,在信號(hào)處理領(lǐng)域可以說(shuō)無(wú)處不在。圖像濾波,即在盡量保留圖像細(xì)節(jié)特征的條件下對(duì)目標(biāo)圖像的噪聲進(jìn)行抑制,通常是數(shù)字圖像處理中不可缺少的操作,其處理效果的好壞將直接影響到后續(xù)運(yùn)算和分析的效果。簡(jiǎn)單來(lái)說(shuō),圖像濾波的根本目的是在圖像中提取出人類(lèi)感興趣的特征。
當(dāng)我們觀察一幅圖像時(shí),有兩種處理方法:?
1. 觀察不同的灰度(或彩色值)在圖像中的分布情況,即空間分布。?
2. 觀察圖像中的灰度(或彩色值)的變化情況,這涉及到頻率方面的問(wèn)題。
因此,圖像濾波分為頻域和空域?yàn)V波,簡(jiǎn)單來(lái)說(shuō),空域指用圖像的灰度值來(lái)描述一幅圖像;而頻域指用圖像灰度值的變化來(lái)描述一幅圖像。而低通濾波器和高通濾波器的概念就是在頻域中產(chǎn)生的。低通濾波器旨在去除圖像中的高頻成分,而高通濾波器則是去除了圖像中的低頻成分。
這里簡(jiǎn)單記錄以下低通濾波器中的均值和高斯濾波器(線性濾波器)、中值濾波器(非線性濾波器);高通濾波器中的sobel算子(方向?yàn)V波器)和拉普拉斯變換(二階導(dǎo)數(shù)),其中,sobel算子和拉普拉斯變換均可以對(duì)圖像的邊緣進(jìn)行檢測(cè)。
二:低通濾波器
消除圖像中的噪聲成分叫作圖像的平滑化或低通濾波。信號(hào)或圖像的能量大部分集中在幅度譜的低頻和中頻段是很常見(jiàn)的,而在較高頻段,感興趣的信息經(jīng)常被噪聲淹沒(méi)。因此一個(gè)能降低高頻成分幅度的濾波器就能夠減弱噪聲的影響。
圖像濾波的目的有兩個(gè):一是抽出對(duì)象的特征作為圖像識(shí)別的特征模式;另一個(gè)是為適應(yīng)圖像處理的要求,消除圖像數(shù)字化時(shí)所混入的噪聲。當(dāng)然,在設(shè)計(jì)低通濾波器時(shí),要考慮到濾波對(duì)圖像造成的細(xì)節(jié)丟失等問(wèn)題。
平滑濾波是低頻增強(qiáng)的空間域?yàn)V波技術(shù)。它的目的有兩類(lèi):一類(lèi)是圖像模糊;另一類(lèi)是濾除圖像噪聲。空間域的平滑濾波一般采用簡(jiǎn)單平均法進(jìn)行,就是求鄰近像元點(diǎn)的平均灰度值或亮度值。鄰域的大小與平滑的效果直接相關(guān),鄰域越大平滑的效果越好,但鄰域過(guò)大,平滑會(huì)使邊緣信息損失的越大,從而使輸出的圖像變得模糊,因此需合理選擇鄰域的大小。
關(guān)于濾波器,一種形象的比喻法是:我們可以把濾波器想象成一個(gè)包含加權(quán)系數(shù)的窗口,當(dāng)使用這個(gè)濾波器平滑處理圖像時(shí),就把這個(gè)窗口放到圖像之上,透過(guò)這個(gè)窗口來(lái)看我們得到的圖像。
濾波器的種類(lèi)有很多, 在OpenCV中,提供了如下幾種常用的圖像平滑處理操作方法及函數(shù):?
1. 領(lǐng)域均值濾波:blur函數(shù),將圖像的每個(gè)像素替換為相鄰矩形內(nèi)像素的平均值(均值濾波)?
2. 高斯低通濾波:GaussianBlur函數(shù)?
3. 方框?yàn)V波:boxblur函數(shù)?
4. 中值濾波:medianBlur函數(shù)?
5. 雙邊濾波:bilateralFilter函數(shù)
以下是均值濾波和高斯低通濾波的簡(jiǎn)單代碼,在Qt中新建控制臺(tái)項(xiàng)目,在.pro文件中添加以下內(nèi)容:
INCLUDEPATH+=C:\OpenCV\install\include\opencv\ C:\OpenCV\install\include\opencv2\ C:\OpenCV\install\includeLIBS+=C:\OpenCV\lib\libopencv_calib3d249.dll.a\ C:\OpenCV\lib\libopencv_contrib249.dll.a\ C:\OpenCV\lib\libopencv_core249.dll.a\ C:\OpenCV\lib\libopencv_features2d249.dll.a\ C:\OpenCV\lib\libopencv_flann249.dll.a\ C:\OpenCV\lib\libopencv_gpu249.dll.a\ C:\OpenCV\lib\libopencv_highgui249.dll.a\ C:\OpenCV\lib\libopencv_imgproc249.dll.a\ C:\OpenCV\lib\libopencv_legacy249.dll.a\ C:\OpenCV\lib\libopencv_ml249.dll.a\ C:\OpenCV\lib\libopencv_nonfree249.dll.a\ C:\OpenCV\lib\libopencv_objdetect249.dll.a\ C:\OpenCV\lib\libopencv_ocl249.dll.a\ C:\OpenCV\lib\libopencv_video249.dll.a\ C:\OpenCV\lib\libopencv_photo249.dll.a\ C:\OpenCV\lib\libopencv_stitching249.dll.a\ C:\OpenCV\lib\libopencv_superres249.dll.a\ C:\OpenCV\lib\libopencv_ts249.a\ C:\OpenCV\lib\libopencv_videostab249.dll.a然后修改main函數(shù),這里設(shè)定卷積核的大小均為5*5:
#include <QCoreApplication> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <QDebug>int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);// 輸入圖像cv::Mat image= cv::imread("c:/peng.jpg",0);if (!image.data)return 0;cv::namedWindow("Original Image");cv::imshow("Original Image",image);// 對(duì)圖像進(jìn)行高斯低通濾波cv::Mat result;cv::GaussianBlur(image,result,cv::Size(5,5),1.5);cv::namedWindow("Gaussian filtered Image");cv::imshow("Gaussian filtered Image",result);// 對(duì)圖像進(jìn)行均值濾波cv::blur(image,result,cv::Size(5,5));cv::namedWindow("Mean filtered Image");cv::imshow("Mean filtered Image",result);return a.exec(); }效果:
相比均值濾波,高斯低通濾波的主要不同是引入了加權(quán)方案,因?yàn)樵谕ǔG闆r下,對(duì)于圖像的一個(gè)像素,與越靠近的臨近像素有更高的關(guān)聯(lián)性,因此離中心像素近的像素系數(shù)應(yīng)該比遠(yuǎn)處的像素?fù)碛懈嗟臋?quán)重。在高斯濾波器中,像素的全重與它離開(kāi)中心像素點(diǎn)的距離成正比,一維高斯函數(shù)可表示為以下形式:
其中,為歸一化系數(shù),作用是使不同權(quán)重之和為1;稱(chēng)為西格瑪數(shù)值,它的主要作用是控制高斯函數(shù)的高度,數(shù)值越大則函數(shù)越平坦。若要查看高斯濾波器的核,只需選擇合適的西格瑪數(shù)值,然后調(diào)用函數(shù)cv::getGaussianKernel,返回一個(gè)ksize*1的數(shù)組,該數(shù)組的元素滿(mǎn)足高斯公式:
式中的參數(shù)分別對(duì)應(yīng)cv::GaussianBlur函數(shù)中的參數(shù)。以下代碼顯示出核的值,在main函數(shù)中添加:
// 得到高斯核 (西格瑪數(shù)值=1.5)cv::Mat gauss= cv::getGaussianKernel(9,1.5,CV_32F);// 顯示高斯核的值cv::Mat_<float>::const_iterator it= gauss.begin<float>();cv::Mat_<float>::const_iterator itend= gauss.end<float>();qDebug() << "[";for ( ; it!= itend; ++it){qDebug() << *it << " ";}qDebug() << "]";
若要對(duì)一幅圖像使用二維高斯濾波器,根據(jù)二維高斯濾波器的可分離特性(即一個(gè)二維高斯濾波器可分解為兩個(gè)一維高斯濾波器),可以先對(duì)圖像的行使用一維高斯濾波器,再對(duì)圖像的列使用一維高斯濾波器。在OpenCV中,指定高斯濾波的方法是將系數(shù)個(gè)數(shù)(第三個(gè)參數(shù),必須是奇數(shù))以及西格瑪數(shù)值?(第四個(gè)參數(shù))提供給cv::GaussianBlur函數(shù)。
關(guān)于GaussianBlur函數(shù)的源碼解析可以參考:http://www.cnblogs.com/tornadomeet/archive/2012/03/10/2389617.html
以上的均值濾波和高斯低通濾波均屬于線性濾波,此外還存在非線性濾波器,中值濾波器就是最常用的其中一種。與均值濾波、高斯低通濾波相似,它是對(duì)一個(gè)像素的相鄰區(qū)域進(jìn)行操作以確定像素的值,不同的是中值濾波器僅僅統(tǒng)計(jì)這組數(shù)組的中值,并用該中值替換中心像素點(diǎn)的值。中值濾波廣泛用于噪聲濾除,以下給出簡(jiǎn)單的實(shí)現(xiàn)和效果。
首先需要編寫(xiě)一個(gè)簡(jiǎn)單的圖像加噪函數(shù),作用是生成若干椒鹽噪聲:
void salt(cv::Mat& image, int n) // 添加椒鹽噪聲 {for(int k=0; k<n; k++){int i = rand()%image.cols;int j = rand()%image.rows;if(image.channels() == 1){if(rand() % 2 == 0)image.at<uchar>(j,i) = 0;elseimage.at<uchar>(j,i) = 255;}else{if(rand() % 2 == 0){image.at<cv::Vec3b>(j,i)[0] = 0;image.at<cv::Vec3b>(j,i)[1] = 0;image.at<cv::Vec3b>(j,i)[2] = 0;}else{image.at<cv::Vec3b>(j,i)[0] = 255;image.at<cv::Vec3b>(j,i)[1] = 255;image.at<cv::Vec3b>(j,i)[2] = 255;}}} }驗(yàn)證中值濾波法與之前的均值濾波法的效果,修改main函數(shù):
#include <QCoreApplication> #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <QDebug>int main(int argc, char *argv[]) {QCoreApplication a(argc, argv);// 輸入圖像image = cv::imread("c:/peng.jpg",0);if (!image.data)return 0;// 給圖像添加椒鹽噪聲salt(image, 3000);// 顯示加噪圖圖cv::namedWindow("Salt&Pepper Image");cv::imshow("Salt&Pepper Image",image);// 對(duì)圖像進(jìn)行均值濾波cv::blur(image,result,cv::Size(5,5));cv::namedWindow("Mean filter");cv::imshow("Mean filter",result);// 對(duì)圖像進(jìn)行中值濾波cv::medianBlur(image,result,5);cv::namedWindow("Median Filter");cv::imshow("Median Filter",result);return a.exec(); }效果如下:
可以看到,中值濾波器對(duì)于去除椒鹽噪點(diǎn)效果拔群,這是由于一個(gè)例外的黑點(diǎn)或白點(diǎn)像素出現(xiàn)在一個(gè)相鄰區(qū)域時(shí),通常不會(huì)被選為中值,因?yàn)樗鼈兇淼氖?或255兩個(gè)極端,因此這些噪聲點(diǎn)總會(huì)被替換為某個(gè)相鄰像素的值,而均值濾波和高斯濾波均會(huì)引入噪點(diǎn)信息,噪點(diǎn)處的像素值會(huì)極大地影響區(qū)域的結(jié)果,因此無(wú)法很好地濾除這一類(lèi)噪聲。
由于中值濾波器是非線性的,因此它無(wú)法表示為一個(gè)核矩陣。此外,中值濾波器還有保留邊緣銳利度的優(yōu)點(diǎn)。但是缺點(diǎn)是相同區(qū)域中的紋理細(xì)節(jié)也被濾除,如下圖中的樹(shù)木部分。
三:高通濾波器
前面主要介紹了低通濾波器對(duì)圖像進(jìn)行模糊處理,這里進(jìn)行相反的變換,使用高通濾波器進(jìn)行圖像銳化或邊緣檢測(cè)。Sobel算子就是通過(guò)卷積操作來(lái)計(jì)算圖像的一階導(dǎo)數(shù),由于邊緣處圖像灰度變化率較大,因此可以用sobel算子來(lái)進(jìn)行邊緣檢測(cè)。提個(gè)簡(jiǎn)單的3*3 Sobel算子的核定義為:
如果將圖像視為二維函數(shù),Sobel算子可被認(rèn)為是在垂直和水平方向變化的測(cè)量。這種測(cè)量在數(shù)學(xué)中被成為梯度,通常它被定義為由函數(shù)在兩個(gè)正交方向上的一階導(dǎo)數(shù)組成的二維向量:
因此,Sobel算子通過(guò)在水平和垂直方向下進(jìn)行像素差分給出圖像梯度的近似。它在感興趣像素的小窗口內(nèi)運(yùn)算,這樣可減少噪聲的影響。OpenCV中提供了函數(shù)cv::Sobel使用Sobel核計(jì)算圖像卷積的結(jié)果,其函數(shù)的主要參數(shù)如下:
cv::Sobel(image, // 輸入圖像sobel, // 輸出圖像image_depth, // 圖像類(lèi)型xorder, yorder, // 核的階數(shù)kernel_size, // 核的大小alpha,beta); // 縮放值及偏移值現(xiàn)設(shè)計(jì)算法,使用Sobel方向?yàn)V波器。在main函數(shù)中添加:
cv::Mat image= cv::imread("c:/075.png",0); // 輸入圖像if (!image.data)return 0;cv::namedWindow("Original Image");cv::imshow("Original Image",image);// 水平濾波器設(shè)置cv::Mat sobelX;cv::Sobel(image, sobelX, CV_8U, 1, 0, 3, 0.4, 128);cv::namedWindow("Sobel X Image");cv::imshow("Sobel X Image", sobelX);// 垂直濾波器設(shè)置cv::Mat sobelY;cv::Sobel(image, sobelY, CV_8U, 0, 1, 3, 0.4, 128);cv::namedWindow("Sobel Y Image");cv::imshow("Sobel Y Image", sobelY);// 計(jì)算Sobel范式,濾波器結(jié)果保存在16位有符號(hào)整數(shù)圖像中cv::Sobel(image, sobelX, CV_16S, 1, 0);cv::Sobel(image, sobelY, CV_16S, 0, 1);cv::Mat sobel;// 將水平和垂直方向相加sobel = abs(sobelX) + abs(sobelY);// 搜索Sobel的極大值double sobmin, sobmax;cv::minMaxLoc(sobel, &sobmin, &sobmax);// 將圖像轉(zhuǎn)換為8位圖像cv::Mat sobelImage;sobel.convertTo(sobelImage, CV_8U, -255./sobmax, 255);// 輸出圖像cv::namedWindow("Sobel Image");cv::imshow("Sobel Image", sobelImage);// 將結(jié)果閾值化得到二值圖像cv::Mat ThresholdedImage;cv::threshold(sobelImage, ThresholdedImage, 225, 255, cv::THRESH_BINARY);cv::namedWindow("Binary Sobel Image");cv::imshow("Binary Sobel Image",ThresholdedImage);得出水平、垂直方向的邊緣檢測(cè)和融合了兩個(gè)方向的檢測(cè)結(jié)果:
Sobel算子是一種經(jīng)典的邊緣檢測(cè)線性濾波器,其主要介紹參考:http://blog.csdn.net/liyuefeilong/article/details/43452711
拉普拉斯(Laplacian)是另一種基于圖像導(dǎo)數(shù)的高斯線性濾波器,它計(jì)算二階導(dǎo)數(shù)以衡量圖像的彎曲度。在OpenCV中,使用cv::Laplacian函數(shù)來(lái)計(jì)算,它與cv::Sobel函數(shù)相類(lèi)似。事實(shí)上,拉普拉斯與Sobel法都使用同一個(gè)函數(shù)cv::getDerivkernels來(lái)獲取核矩陣。他們的唯一差別是不存在指定導(dǎo)數(shù)階數(shù)的參數(shù),因?yàn)樗鼈兌际嵌A導(dǎo)數(shù)。,2D函數(shù)的拉普拉斯變換定義如下:
可用一個(gè)最簡(jiǎn)單的3*3核近似:
與Sobel算子相同,也能夠使用更大的核計(jì)算Laplacian,同時(shí)由于Laplacian運(yùn)算對(duì)于噪聲十分敏感,我們傾向于這么做(除非計(jì)算效率更重要)。需要注意Laplacian核的總數(shù)為0,這保證了強(qiáng)度不變區(qū)域的Laplacian為0。事實(shí)上,由于Laplacian度量的是圖像函數(shù)的曲率,它在平坦區(qū)域應(yīng)該等于0。
拉普拉斯算子的效果可能很難解釋。從核的定義來(lái)看,很明顯,任何孤立的像素值(它與相鄰像素值截然不同)將被算子放大。這源于算子對(duì)噪點(diǎn)的高靈敏度。但是拉普拉斯算子值在圖像邊緣處的表現(xiàn)更有趣。邊緣的存在是圖像中不同灰度區(qū)域間快速過(guò)渡的結(jié)果。沿著圖像在一條邊上的變化(例如,從暗處到亮處),可以觀察到灰度的提升意味著從正曲率(強(qiáng)度值開(kāi)始上升)到負(fù)曲率(當(dāng)強(qiáng)度即將達(dá)到最高至)的漸變。因此,正、負(fù)拉普拉斯算子值(或?qū)?shù))之間的過(guò)渡是存在邊緣的指示器。另一種表達(dá)這個(gè)事實(shí)的方法是說(shuō),邊緣
總結(jié)
以上是生活随笔為你收集整理的OpenCV2:图像滤波基础的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 【OpenCV】5种图像滤波辨析:方框、
- 下一篇: 快速双边滤波在High-Dynamic