前言:
😊😊😊欢迎来到本博客😊😊😊
🌟🌟🌟 本专栏主要结合OpenCV和C++来实现一些基本的图像处理算法并详细解释各参数含义,适用于平时学习、工作快速查询等,随时更新。
😊😊😊 具体食用方式:可以点击本专栏【OpenCV快速查找(更新中)】–>搜索你要查询的算子名称或相关知识点,或者通过这篇博客👉通俗易懂OpenCV(C++版)详细教程——OpenCV函数快速查找(不断更新中)]查阅你想知道的知识,即可食用。
🎁🎁🎁支持:如果觉得博主的文章还不错或者您用得到的话,可以悄悄关注一下博主哈,如果三连收藏支持就更好啦!这就是给予我最大的支持!😙😙😙
文章目录
- 学习目标
- 一、联合双边滤波原理
- 二、C++实现
- 2.1 原理实现
- 2.2 OpenCV函数
- 三、 总结
学习目标
- 了解联合双边滤波含义及原理
- C++实现联合双边滤波案例
每一张图像都可能包含某种程度的噪声,噪声可以理解为由一种或者多种原因造成的灰度值的随机变化。
在大多数情况下,通过平滑技术(也常称为滤波技术)进行抑制或者去除,其中具备保持边缘(Edge Preserving)作用的平滑技术得到了更多的关注。
常用的平滑处理算法包括基于二维离散卷积的高斯平滑、均值平滑,基于统计学方法的中值平滑,具备保持边缘作用的平滑算法的双边滤波、导向滤波等。
一、联合双边滤波原理
联合双边滤波(Joint bilaterral Filter或称Cross Bilater Filter)与双边滤波类似,原理具体过程如下:
(1) 首先,对每个位置的邻域构建空间距离权重模板。与双边滤波构建空间距离权重模
板一样。
(2) 然后,构建相似性权重模板。这是与双边滤波唯一的不同之处,双边滤波是根据原图,对于每一个位置,通过该位置和其邻域的灰度值的差的指数来估计相似性;而联合双边滤波是首先对原图进行高斯平滑,根据平滑的结果,用当前位置及其邻域的值的差来估计相似性权重模板。
(3) 接着,空间距离权重模板和相似性权重模板点乘,然后归一化,作为最后的权重模板。最后将权重模板与原图(注意不是高斯平滑的结果)在该位置的邻域对应位置积的和作为输出值。整个过程只在第二步计算相似性权重模板时和双边滤波不同,但是对图像平滑的效果,特别是对纹理图像来说,却有很大的不同。
二、C++实现
2.1 原理实现
通过定义函数jointBLF()
实现联合双边滤波,其中参数size
代表权重模板的尺寸,Size类的第一个参数是宽,第二个参数是高,即Size(W,H)
。具体实现代码如下:
#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 getClosenessWeight1(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;
//设置 空间距离权重模板
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;
}
}
Mat jointBLF(Mat I, Size size,float sigma_g,float sigma_d,int borterType=BORDER_DEFAULT){
//构建空间距离得权重模板
Mat closenessWeight = getClosenessWeight1(sigma_g, size);
//对图片I进行高斯平滑
Mat Ig;
GaussianBlur(I, Ig, size,sigma_g);
int winH = size.height;
int winW = size.width;
//平滑窗口得高、宽为奇数
CV_Assert(winH > 0 && winW > 0);
CV_Assert(winH%2==1&& winW%2==1);
//中心点
int half_winW = (winW - 1) / 2;
int half_winH = (winH - 1) / 2;
//对原图和高斯平滑后的结果进行边界扩充
Mat Ip, Igp;
copyMakeBorder(I,Ip, half_winW,half_winW, half_winH, half_winH,borterType);
copyMakeBorder(Ig,Igp, half_winW, half_winW,half_winH, half_winH, borterType);
//图像得宽高
int rows = I.rows;
int cols = I.cols;
int i=0, j=0;
//联合双边滤波后得输出图
Mat jblf = Mat::zeros(I.size(), CV_64FC1);
for (int r = half_winH; r < half_winH+ rows; r++)
{
for (int c = half_winW; c < half_winW+ cols; c++)
{
//当前位置的像素值
double pixel = I.at<double>(r, c);
//获取当前位置的作用区域(领域)
Mat region = Igp(Rect(c- half_winW,r- half_winH,size.width,size.height));
//设置当前位置相似性权重模板
Mat similaritWeight;
pow(region - pixel, 2.0, similaritWeight);
exp(-0.5 * similaritWeight /pow(sigma_d, 2), similaritWeight);
//空间距离权重模板与相似性权重模板点乘 并归一化
Mat weight = closenessWeight.mul(similaritWeight);
weight = weight /sum(weight)[0];
//权重模板与当前领域对应位置相乘,求和
Mat Iregion = Ip(Rect(c - half_winW,r - half_winH, size.width, size.height));
jblf.at<double>(i, j)= sum(Iregion.mul(weight))[0];
j += 1;
}
j = 0;
i+=1;
}
return jblf;
}
主函数:
int main() {
//输入图像
cv::Mat I = imread("D:/VSCodeFile/OpenCV_CSDN/image/img4.jpg", CV_LOAD_IMAGE_GRAYSCALE);
if (!I.data)
{
return -1;
}
Mat fI;
I.convertTo(fI,CV_64F,1.0,0);
//联合双边滤波
Mat jblf = jointBLF(fI, Size(33, 33), 7, 2);
Mat jblf8U;
jblf.convertTo(jblf8U, CV_8U, 1, 0);
//显示
imshow("联合双边滤波", jblf);
imshow("原图", I);
waitKey(0);
return 0;
}
2.2 OpenCV函数
在OpenCV中通过定义函数jointBilateralFilter
实现了联合双边滤波的功能:
jointBilateralFilter(InputArray joint,
InputArray src,
OutputArray dst,
int d,
double sigmaColor,
double sigmaSpace,
int borderType = BORDER_DEFAULT
)
参数 | 解释 |
---|---|
joint | 进行联合滤波的导向图像,8位或浮点、1通道或3通道图像 |
src | 输入图像,可以为单通道或多通道,与joint图像一致 |
dst | 输出矩阵,其大小与数据类型和src一致 |
d | 表示在过滤过程中每个像素邻域的直径。如果这个值设其为非正数,那么会从第五个参数sigmaSpace 来计算出它来,在使用过程中类似于模糊力度。 |
sigmaColor | 颜色空间滤波器的sigma值。这个参数的值越大,就表明该像素邻域内有更宽广的颜色会被混合到一起,产生较大的半相等颜色区域。类似模糊范围的意思,范围越大看着越模糊 |
sigmaSpace | 坐标空间中滤波器的sigma值,坐标空间的标注方差。数值越大,意味着越远的像素会相互影响,从而使更大的区域足够相似的颜色获取相同的颜色。当d>0,d指定了邻域大小且与sigmaSpace无关。否则,d正比于sigmaSpace。值越大,图像的过渡效果越好。 |
borderType | 推断图像边缘像素的边界模式,默认 |
三、 总结
最后,长话短说,大家看完就好好动手实践一下,切记不能三分钟热度、三天打鱼,两天晒网。OpenCV是学习图像处理理论知识比较好的一个途径,大家也可以自己尝试写写博客,来记录大家平时学习的进度,可以和网上众多学者一起交流、探讨,有什么问题希望大家可以积极评论交流,我也会及时更新,来督促自己学习进度。希望大家觉得不错的可以点赞、关注、收藏。