OpenCV2:图像滤波基础
一:基本概念
濾波是數(shù)字圖像處理中的一個基本操作,在信號處理領域可以說無處不在。圖像濾波,即在盡量保留圖像細節(jié)特征的條件下對目標圖像的噪聲進行抑制,通常是數(shù)字圖像處理中不可缺少的操作,其處理效果的好壞將直接影響到后續(xù)運算和分析的效果。簡單來說,圖像濾波的根本目的是在圖像中提取出人類感興趣的特征。
當我們觀察一幅圖像時,有兩種處理方法:?
1. 觀察不同的灰度(或彩色值)在圖像中的分布情況,即空間分布。?
2. 觀察圖像中的灰度(或彩色值)的變化情況,這涉及到頻率方面的問題。
因此,圖像濾波分為頻域和空域濾波,簡單來說,空域指用圖像的灰度值來描述一幅圖像;而頻域指用圖像灰度值的變化來描述一幅圖像。而低通濾波器和高通濾波器的概念就是在頻域中產生的。低通濾波器旨在去除圖像中的高頻成分,而高通濾波器則是去除了圖像中的低頻成分。
這里簡單記錄以下低通濾波器中的均值和高斯濾波器(線性濾波器)、中值濾波器(非線性濾波器);高通濾波器中的sobel算子(方向濾波器)和拉普拉斯變換(二階導數(shù)),其中,sobel算子和拉普拉斯變換均可以對圖像的邊緣進行檢測。
二:低通濾波器
消除圖像中的噪聲成分叫作圖像的平滑化或低通濾波。信號或圖像的能量大部分集中在幅度譜的低頻和中頻段是很常見的,而在較高頻段,感興趣的信息經常被噪聲淹沒。因此一個能降低高頻成分幅度的濾波器就能夠減弱噪聲的影響。
圖像濾波的目的有兩個:一是抽出對象的特征作為圖像識別的特征模式;另一個是為適應圖像處理的要求,消除圖像數(shù)字化時所混入的噪聲。當然,在設計低通濾波器時,要考慮到濾波對圖像造成的細節(jié)丟失等問題。
平滑濾波是低頻增強的空間域濾波技術。它的目的有兩類:一類是圖像模糊;另一類是濾除圖像噪聲??臻g域的平滑濾波一般采用簡單平均法進行,就是求鄰近像元點的平均灰度值或亮度值。鄰域的大小與平滑的效果直接相關,鄰域越大平滑的效果越好,但鄰域過大,平滑會使邊緣信息損失的越大,從而使輸出的圖像變得模糊,因此需合理選擇鄰域的大小。
關于濾波器,一種形象的比喻法是:我們可以把濾波器想象成一個包含加權系數(shù)的窗口,當使用這個濾波器平滑處理圖像時,就把這個窗口放到圖像之上,透過這個窗口來看我們得到的圖像。
濾波器的種類有很多, 在OpenCV中,提供了如下幾種常用的圖像平滑處理操作方法及函數(shù):?
1. 領域均值濾波:blur函數(shù),將圖像的每個像素替換為相鄰矩形內像素的平均值(均值濾波)?
2. 高斯低通濾波:GaussianBlur函數(shù)?
3. 方框濾波:boxblur函數(shù)?
4. 中值濾波:medianBlur函數(shù)?
5. 雙邊濾波:bilateralFilter函數(shù)
以下是均值濾波和高斯低通濾波的簡單代碼,在Qt中新建控制臺項目,在.pro文件中添加以下內容:
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ù),這里設定卷積核的大小均為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);// 對圖像進行高斯低通濾波cv::Mat result;cv::GaussianBlur(image,result,cv::Size(5,5),1.5);cv::namedWindow("Gaussian filtered Image");cv::imshow("Gaussian filtered Image",result);// 對圖像進行均值濾波cv::blur(image,result,cv::Size(5,5));cv::namedWindow("Mean filtered Image");cv::imshow("Mean filtered Image",result);return a.exec(); }效果:
相比均值濾波,高斯低通濾波的主要不同是引入了加權方案,因為在通常情況下,對于圖像的一個像素,與越靠近的臨近像素有更高的關聯(lián)性,因此離中心像素近的像素系數(shù)應該比遠處的像素擁有更多的權重。在高斯濾波器中,像素的全重與它離開中心像素點的距離成正比,一維高斯函數(shù)可表示為以下形式:
其中,為歸一化系數(shù),作用是使不同權重之和為1;稱為西格瑪數(shù)值,它的主要作用是控制高斯函數(shù)的高度,數(shù)值越大則函數(shù)越平坦。若要查看高斯濾波器的核,只需選擇合適的西格瑪數(shù)值,然后調用函數(shù)cv::getGaussianKernel,返回一個ksize*1的數(shù)組,該數(shù)組的元素滿足高斯公式:
式中的參數(shù)分別對應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() << "]";
若要對一幅圖像使用二維高斯濾波器,根據(jù)二維高斯濾波器的可分離特性(即一個二維高斯濾波器可分解為兩個一維高斯濾波器),可以先對圖像的行使用一維高斯濾波器,再對圖像的列使用一維高斯濾波器。在OpenCV中,指定高斯濾波的方法是將系數(shù)個數(shù)(第三個參數(shù),必須是奇數(shù))以及西格瑪數(shù)值?(第四個參數(shù))提供給cv::GaussianBlur函數(shù)。
關于GaussianBlur函數(shù)的源碼解析可以參考:http://www.cnblogs.com/tornadomeet/archive/2012/03/10/2389617.html
以上的均值濾波和高斯低通濾波均屬于線性濾波,此外還存在非線性濾波器,中值濾波器就是最常用的其中一種。與均值濾波、高斯低通濾波相似,它是對一個像素的相鄰區(qū)域進行操作以確定像素的值,不同的是中值濾波器僅僅統(tǒng)計這組數(shù)組的中值,并用該中值替換中心像素點的值。中值濾波廣泛用于噪聲濾除,以下給出簡單的實現(xià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;}}} }驗證中值濾波法與之前的均值濾波法的效果,修改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);// 對圖像進行均值濾波cv::blur(image,result,cv::Size(5,5));cv::namedWindow("Mean filter");cv::imshow("Mean filter",result);// 對圖像進行中值濾波cv::medianBlur(image,result,5);cv::namedWindow("Median Filter");cv::imshow("Median Filter",result);return a.exec(); }效果如下:
可以看到,中值濾波器對于去除椒鹽噪點效果拔群,這是由于一個例外的黑點或白點像素出現(xiàn)在一個相鄰區(qū)域時,通常不會被選為中值,因為它們代表的是0或255兩個極端,因此這些噪聲點總會被替換為某個相鄰像素的值,而均值濾波和高斯濾波均會引入噪點信息,噪點處的像素值會極大地影響區(qū)域的結果,因此無法很好地濾除這一類噪聲。
由于中值濾波器是非線性的,因此它無法表示為一個核矩陣。此外,中值濾波器還有保留邊緣銳利度的優(yōu)點。但是缺點是相同區(qū)域中的紋理細節(jié)也被濾除,如下圖中的樹木部分。
三:高通濾波器
前面主要介紹了低通濾波器對圖像進行模糊處理,這里進行相反的變換,使用高通濾波器進行圖像銳化或邊緣檢測。Sobel算子就是通過卷積操作來計算圖像的一階導數(shù),由于邊緣處圖像灰度變化率較大,因此可以用sobel算子來進行邊緣檢測。提個簡單的3*3 Sobel算子的核定義為:
如果將圖像視為二維函數(shù),Sobel算子可被認為是在垂直和水平方向變化的測量。這種測量在數(shù)學中被成為梯度,通常它被定義為由函數(shù)在兩個正交方向上的一階導數(shù)組成的二維向量:
因此,Sobel算子通過在水平和垂直方向下進行像素差分給出圖像梯度的近似。它在感興趣像素的小窗口內運算,這樣可減少噪聲的影響。OpenCV中提供了函數(shù)cv::Sobel使用Sobel核計算圖像卷積的結果,其函數(shù)的主要參數(shù)如下:
cv::Sobel(image, // 輸入圖像sobel, // 輸出圖像image_depth, // 圖像類型xorder, yorder, // 核的階數(shù)kernel_size, // 核的大小alpha,beta); // 縮放值及偏移值現(xiàn)設計算法,使用Sobel方向濾波器。在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);// 水平濾波器設置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);// 垂直濾波器設置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);// 計算Sobel范式,濾波器結果保存在16位有符號整數(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);// 將圖像轉換為8位圖像cv::Mat sobelImage;sobel.convertTo(sobelImage, CV_8U, -255./sobmax, 255);// 輸出圖像cv::namedWindow("Sobel Image");cv::imshow("Sobel Image", sobelImage);// 將結果閾值化得到二值圖像cv::Mat ThresholdedImage;cv::threshold(sobelImage, ThresholdedImage, 225, 255, cv::THRESH_BINARY);cv::namedWindow("Binary Sobel Image");cv::imshow("Binary Sobel Image",ThresholdedImage);得出水平、垂直方向的邊緣檢測和融合了兩個方向的檢測結果:
Sobel算子是一種經典的邊緣檢測線性濾波器,其主要介紹參考:http://blog.csdn.net/liyuefeilong/article/details/43452711
拉普拉斯(Laplacian)是另一種基于圖像導數(shù)的高斯線性濾波器,它計算二階導數(shù)以衡量圖像的彎曲度。在OpenCV中,使用cv::Laplacian函數(shù)來計算,它與cv::Sobel函數(shù)相類似。事實上,拉普拉斯與Sobel法都使用同一個函數(shù)cv::getDerivkernels來獲取核矩陣。他們的唯一差別是不存在指定導數(shù)階數(shù)的參數(shù),因為它們都是二階導數(shù)。,2D函數(shù)的拉普拉斯變換定義如下:
可用一個最簡單的3*3核近似:
與Sobel算子相同,也能夠使用更大的核計算Laplacian,同時由于Laplacian運算對于噪聲十分敏感,我們傾向于這么做(除非計算效率更重要)。需要注意Laplacian核的總數(shù)為0,這保證了強度不變區(qū)域的Laplacian為0。事實上,由于Laplacian度量的是圖像函數(shù)的曲率,它在平坦區(qū)域應該等于0。
拉普拉斯算子的效果可能很難解釋。從核的定義來看,很明顯,任何孤立的像素值(它與相鄰像素值截然不同)將被算子放大。這源于算子對噪點的高靈敏度。但是拉普拉斯算子值在圖像邊緣處的表現(xiàn)更有趣。邊緣的存在是圖像中不同灰度區(qū)域間快速過渡的結果。沿著圖像在一條邊上的變化(例如,從暗處到亮處),可以觀察到灰度的提升意味著從正曲率(強度值開始上升)到負曲率(當強度即將達到最高至)的漸變。因此,正、負拉普拉斯算子值(或導數(shù))之間的過渡是存在邊緣的指示器。另一種表達這個事實的方法是說,邊緣
總結
以上是生活随笔為你收集整理的OpenCV2:图像滤波基础的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【OpenCV】5种图像滤波辨析:方框、
- 下一篇: 快速双边滤波在High-Dynamic