我们都知道,卷积是一种好玩的东西,通过卷积可以实现很多功能,例如photoshop中的各种滤镜也可以通过对一副图像进行卷积获得。而目前大火的机器学习中的CNN算法也是利用卷积来实现的,至于CNN的算法以后再讲,今天主要是介绍卷积的原理以及利用它来实现高斯模糊。
我们先来看下卷积是将两个矩阵相乘在求和,而具体原理可在这篇文章中看。而图像中高斯模糊则是根据二维的正态分布(高斯分布)来产生高斯模糊卷积子。
利用这个二维高斯模糊公式,我们可以产生N*N的卷积核,然后利用这个核与图片中的每个像素进行卷积便是高斯模糊。
这个过程可以通过以下几张图来理解,假如我产生一个3*3的卷积核,取1,因此我们就可以产生以下的矩阵:
我们取图像中的某个像素周围3*3的矩阵:
而矩阵中的78对应的是(0,0)坐标,而这个矩阵我们是围绕着这个像素点在半径为1的范围内取得矩阵,因此我们卷积获得的值也应替代该值。
通过卷积:(0.0585*0+0.0965*0+0.0585*7+0.0965*4+0.1592*78+0.0965*8+0.0585*69+0.0965*2+0.0585*4)=18.4486
因此78这个位置的值也就变为18.4486。高斯模糊便是通过对每个像素以半径r范围取一N*N矩阵与N*N卷积核进行卷积并改变改像素点的值以获得滤波效果。
以下便是灰度图的高斯模糊程序:
#include
#include
#include
#include
#include
#define sigma 1 //定义sigma的大小越大越模糊
#define PI 3.14159
#define N 5 //定义卷积核大小
int main()
{
float liv_conv[N][N] = {0}; //定义卷积核
cv::Mat lMv_src = cv::imread("E:\\temp\\3D\\pad.jpg");//打开图片
cv::resize(lMv_src,lMv_src,cv::Size(lMv_src.cols/4,lMv_src.rows/4),0,0,cv::INTER_LINEAR);//因为我的图片太大,不方便显示,我就利用这个函数缩小
cv::Mat lMv_gray, lMv_OutPut = cv::Mat::zeros(lMv_src.rows, lMv_src.cols, CV_8UC1); //定义灰度图,与输出图像
cv::cvtColor(lMv_src,lMv_gray,CV_BGR2GRAY);//将彩色图转换灰度图
int liv_n = N/2; //获取半径
float all = 0.0;
/**************
产生卷积核
***************/
for(int i = 0; i(i+y,j+x)*liv_conv[y][x];//相称求和
}
}
lMv_OutPut.at(i,j) = lfv_sum/all;
}
}
cv::imshow("Gaussian",lMv_OutPut);//显示高斯模糊后的图像
cv::imshow("Src",lMv_gray);//显示原图
cv::waitKey(0);
return 0;
}
原图:
sigma = 1:
sigma = 10:
sigma = 0.1:
其实彩色图片的高斯模糊的原理是一样,程序也是基本一样的:
#include
#include
#include
#include
#include
#define sigma 1 //定义sigma的大小越大越模糊
#define PI 3.14159
#define N 5 //定义卷积核大小
int main()
{
float liv_conv[N][N] = {0}; //定义卷积核
cv::Mat lMv_src = cv::imread("E:\\temp\\3D\\pad.jpg");//打开图片
cv::resize(lMv_src,lMv_src,cv::Size(lMv_src.cols/2,lMv_src.rows/2),0,0,cv::INTER_LINEAR);//因为我的图片太大,不方便显示,我就利用这个函数缩小
cv::Mat lMv_gray, lMv_OutPut = cv::Mat::zeros(lMv_src.rows, lMv_src.cols, CV_8UC3); //定义灰度图,与输出图像
cv::cvtColor(lMv_src,lMv_gray,CV_BGR2GRAY);//将彩色图转换灰度图
int liv_n = N/2; //获取半径
float all = 0.0;
/**************
产生卷积核
***************/
for(int i = 0; i(i+y,j+x)[0]*liv_conv[y][x];//相称求和
lfv_sum_g+=lMv_src.at(i+y,j+x)[1]*liv_conv[y][x];
lfv_sum_r+=lMv_src.at(i+y,j+x)[2]*liv_conv[y][x];
}
}
lMv_OutPut.at(i,j)[0] = lfv_sum_b/all;
lMv_OutPut.at(i,j)[1] = lfv_sum_g/all;
lMv_OutPut.at(i,j)[2] = lfv_sum_r/all;
}
}
cv::imshow("Gaussian",lMv_OutPut);//显示高斯模糊后的图像
cv::imshow("Src",lMv_src);//显示原图
cv::waitKey(0);
return 0;
}
结果:
然后我们加入椒盐噪声测试下性能:
#define sigma 3 //定义sigma的大小越大越模糊
#define PI 3.14159
#define N 8 //定义卷积核大小
#define NN 1600
/*************************
创建椒盐噪点
*************************/
for(int i = 0; i(y,x)[0] = 255;
lMv_src.at(y,x)[1] = 255;
lMv_src.at(y,x)[2] = 255;
}
由此看来效果还是可以的,接下来我会跟大家分享去模糊的算法。
欢迎喜欢图像处理或人工智能的朋友通过邮箱[email protected]来联系我,一起交流。