前言:
??????歡迎來到本博客??????
?????? 本專欄主要結(jié)合OpenCV和C++來實現(xiàn)一些基本的圖像處理算法并詳細解釋各參數(shù)含義,適用于平時學習、工作快速查詢等,隨時更新。
?????? 具體食用方式:可以點擊本專欄【OpenCV快速查找(更新中)】–>搜索你要查詢的算子名稱或相關(guān)知識點,或者通過這篇博客??通俗易懂OpenCV(C++版)詳細教程——OpenCV函數(shù)快速查找(不斷更新中)]查閱你想知道的知識,即可食用。
??????支持:如果覺得博主的文章還不錯或者您用得到的話,可以悄悄關(guān)注一下博主哈,如果三連收藏支持就更好啦!這就是給予我最大的支持!??????
學習目標
- 了解雙邊濾波含義及原理
- C++實現(xiàn)雙邊濾波案例
??每一張圖像都可能包含某種程度的噪聲,噪聲可以理解為由一種或者多種原因造成的灰度值的隨機變化。
??在大多數(shù)情況下,通過平滑技術(shù)(也常稱為濾波技術(shù))進行抑制或者去除,其中具備保持邊緣(Edge Preserving)作用的平滑技術(shù)得到了更多的關(guān)注。
??常用的平滑處理算法包括基于二維離散卷積的高斯平滑、均值平滑,基于統(tǒng)計學方法的中值平滑,具備保持邊緣作用的平滑算法的雙邊濾波、導向濾波等。
??下面幾節(jié)將詳細關(guān)于具備保持邊緣作用得相關(guān)方法,首先介紹雙邊濾波技術(shù)原理、常見應用及實現(xiàn)。
一、雙邊濾波原理
1.1 原理
??均值平滑和高斯平滑本質(zhì)上是計算每個位置的鄰域加權(quán)和作為該位置的輸出,只是這種運算可以用卷積實現(xiàn),加權(quán)系數(shù)模板是通過卷積核逆時針翻轉(zhuǎn)180°得到的。
??雙邊濾波(Bilateral filter)是一種非線性的濾波方法,是結(jié)合圖像的空間鄰近度和像素值相似度的一種折中濾波方法,根據(jù)每個位置的鄰域,對該位置構(gòu)建不同的權(quán)重模板,詳細過程如下:
??(1) 首先,構(gòu)建空間距離權(quán)重模板,與構(gòu)建高斯卷積核的過程類似。

??其中wd表示鄰域內(nèi)某點q(k,l)
與中心點p(i, j)
的歐氏距離。σd為高斯函數(shù)的標準差。使用該公式生成的濾波器模板和高斯濾波器使用的模板是沒有區(qū)別的,每個位置的空間距離權(quán)重模板是相同的。
??(2) 然后,構(gòu)建相似性權(quán)重模板,是通過(r,c)
處的值與其鄰域值的差值的指數(shù)衡量的。

??其中,f(i,j)
表示圖像在點(i,j)
處的像素值;f(k,l)
為模板窗口中心坐標點的像素值。σr為高斯函數(shù)?標準差,顯然每個位置的相似性權(quán)重模板是不一樣的。
??(3) 最后,將上述兩個模板相乘,然后進行歸一化,便可得到該位置的權(quán)重模板。

??濾波后的圖像的像素值為:

??將所得到的權(quán)重模板和該位置鄰域的對應位置相乘,然后求和就得到該位置的輸出值,和卷積運算的第二步操作類似。
1.2 作用
??中值濾波、高斯濾波、維納濾波等濾波方法容易模糊圖片的邊緣細節(jié),對高頻細節(jié)的保護效果并不明顯。相較而言,雙邊濾波器可以很好的在降噪的同時保護邊緣。但是,雙邊濾波的卷積核是非線性的,因此計算復雜度高。
二、C++實現(xiàn)
2.1 原理實現(xiàn)
??首先,通過定義函數(shù)getClosenessWeight
實現(xiàn)空間距離權(quán)重模板,代碼如下:
#include <iostream>
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include<opencv2/highgui/highgui.hpp>
#include <cmath>
#include <opencv2/imgproc.hpp>
using namespace std;
using namespace cv;
cv::Mat getClosenessWeight(double Sigma_g,Size size) {
//獲取模板大小
int H = size.height;
int W = size.width;
//獲取模板中心點
int H_center = (H - 1) / 2;
int W_center = (W - 1) / 2;
//設(shè)置 空間距離權(quán)重模板
Mat ClosenessWeight = Mat::zeros(size, CV_64FC1);
for (int r = 0; r < H; r++){
for (int c = 0; c <W; c++){
double norm2 = pow(double(r- HH_center),2.0)+ pow(double(c - W_center), 2.0);
double Sigma_g2 =2 * pow(Sigma_g, 2.0);
//模板賦值
ClosenessWeight.at<double>(r, c) = exp(-norm2 / Sigma_g2);
}
}
return ClosenessWeight;
}
??通過定義函數(shù)bfltGray
實現(xiàn)圖像的雙邊濾波:
????其中參數(shù)image
代表圖像矩陣且灰度值,范圍是[0,1];
????參H
和W
分別代表權(quán)重模板的高和寬且均為奇數(shù);
????sigma_g
代表空間距離,權(quán)重模板的標準差;
????sigma_d
代表相似性權(quán)重模板的標準差,1效果會比較好,返回值是浮點型矩陣。
??具體代碼如下:
Mat bfltGray(const Mat& image, Size winSize, float sigma_g, float sigma_d){
int winH = winSize.height;
int winW = winSize.width;
//平滑窗口得高、寬為奇數(shù)
CV_Assert(winH > 0 && winW > 0);
CV_Assert(winH%2==1&& winW%2==1);
if (winH==1 && winW==1){
return image;
}
//中心點
int half_winW = (winW - 1) / 2;
int half_winH = (winH - 1) / 2;
//空間距離得權(quán)重因子
Mat closenessWeight = getClosenessWeight(sigma_g, winSize);
//圖像得寬高
int rows = image.rows;
int cols = image.cols;
//雙邊濾波后得輸出圖
Mat blfImage =Mat::zeros(image.size(), CV_32FC1);
//對每個像素得領(lǐng)域進行核卷積
for (int r = 0; r < rows; r++){
for (int c = 0; c < cols; c++){
double pixel = image.at<double>(r, c);
//判斷邊界
int rTop= (r - half_winH) < 0 ? 0 : r - half_winH;
int rBottom = (r + half_winH) > rows - 1 ? rows - 1 : r + half_winH;
int cLeft = (c - half_winW) <0 ? 0 : c - half_winW;
int cRight = (c + half_winW) > cols - 1 ? cols - 1 : c + half_winW;
//核作用區(qū)域
Mat region = image(Rect(Point(cLeft, rTop),Point(cRight+1, rBottom+1))).clone();
//相似性權(quán)重模板
Mat similaritWeight;
pow(region-pixel,2.0,similaritWeight);
exp(-0.5 * similaritWeight / pow(sigma_d, 2), similaritWeight);
similaritWeight /= pow(sigma_d, 2);
//空間距離權(quán)重
Rect regionRect = Rect(Point(cLeft - c + half_winW,rTop - r + half_winH),Point(cRight - c + half_winW,rBottom - r + half_winH + 1));
Mat closenessWeightTemp = closenessWeight(regionRect).clone();
//兩個權(quán)重模板點乘并歸一化
Mat weightTemp =closenessWeightTemp.mul(similaritWeight);
weightTemp = weightTemp /sum(weightTemp)[0];
//權(quán)重模板與當前領(lǐng)域?qū)恢孟喑耍蠛?/span>
Mat result = weightTemp.mul(region);
blfImage.at<double>(r, c)= sum(result)[0];
}
}
return blfImage;
}
??使用bfltGray
實現(xiàn)圖像的雙濾濾波,需要注意bfltGray
返回的是灰度值在范圍[0,1]之間的浮點型圖像矩陣,如果使用函數(shù)imwrite
直接保存的話,則顯示為一張黑色的圖片,所以要先乘以255并轉(zhuǎn)換為8位圖進行保存。主函數(shù)如下:
int main() {
//輸入圖像
Mat I = imread("D:/VSCodeFile/OpenCV_CSDN/image/logo_gray.jpeg");
if (!I.data)
{
return -1;
}
//灰度值歸一化
Mat FI;
I.convertTo(FI, CV_64FC1, 1.0 / 255, 0);
//雙邊濾波
Mat blfI = bflfGray(FI,Size(7,7),19,0.5);
//顯示原圖與結(jié)果圖
imshow("原圖",I);
imshow("雙邊濾波", blfI);
//若保存為8位圖,則需要乘255,并轉(zhuǎn)換為CV_8U
blfI.convertTo(blfI, CV_8U, 255, 0);
imshow("blf", blfI);
waitKey(0);
return 0;
}
2.2 OpenCV函數(shù)
??在OpenCV中通過定義函數(shù)bilateralFilter
實現(xiàn)了雙邊濾波的功能。文章來源:http://www.zghlxwxcb.cn/news/detail-543906.html
cv::bilateralFilter(InputArray src,
OutputArray dst,
int d,
double sigmaColor,
double sigmaSpace,
int borderType = BORDER_DEFAULT
)
參數(shù) | 解釋 |
---|---|
src | 輸入矩陣,Mat類型,8位或者浮點型單通道、三通道的圖像 |
dst | 輸出矩陣,其大小與數(shù)據(jù)類型和src一致 |
d | 表示在過濾過程中每個像素鄰域的直徑。如果這個值設(shè)其為非正數(shù),那么會從第五個參數(shù)sigmaSpace 來計算出它來,在使用過程中類似于模糊力度。 |
sigmaColor | 顏色空間濾波器的sigma值。這個參數(shù)的值越大,就表明該像素鄰域內(nèi)有更寬廣的顏色會被混合到一起,產(chǎn)生較大的半相等顏色區(qū)域。類似模糊范圍的意思,范圍越大看著越模糊 |
sigmaSpace | 坐標空間中濾波器的sigma值,坐標空間的標注方差。數(shù)值越大,意味著越遠的像素會相互影響,從而使更大的區(qū)域足夠相似的顏色獲取相同的顏色。當d>0,d指定了鄰域大小且與sigmaSpace無關(guān)。否則,d正比于sigmaSpace。值越大,圖像的過渡效果越好。 |
borderType | 推斷圖像邊緣像素的邊界模式,默認 |
三、 總結(jié)
??最后,長話短說,大家看完就好好動手實踐一下,切記不能三分鐘熱度、三天打魚,兩天曬網(wǎng)。OpenCV是學習圖像處理理論知識比較好的一個途徑,大家也可以自己嘗試寫寫博客,來記錄大家平時學習的進度,可以和網(wǎng)上眾多學者一起交流、探討,有什么問題希望大家可以積極評論交流,我也會及時更新,來督促自己學習進度。希望大家覺得不錯的可以點贊、關(guān)注、收藏。文章來源地址http://www.zghlxwxcb.cn/news/detail-543906.html

到了這里,關(guān)于【圖像處理OpenCV(C++版)】——5.5 圖像平滑之雙邊濾波的文章就介紹完了。如果您還想了解更多內(nèi)容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!