OpenCV图像处理---模糊原理

模糊原理

  • Smooth/Blur(平滑和模糊) 是图像处理中最简单和常用的操作之一
  • 使用该操作的原因之一就是为了给图像预处理时候降低噪声把噪声与周围的数值平均一下就可以平滑噪声
  • 使用Smooth/Blur操作背后是数学的卷积计算
  • 卷积:通过两个函数f 和g 生成第三个函数的一种数学算子,表征函数f 与g经过翻转和平移的重叠部分的面积。
    在这里插入图片描述
    其中:f()表示一副图像,i、j表示图像的行和列,h(k,l)表示卷积算子(卷积核)(也可以叫掩膜),k l又可以叫窗口大小(掩膜的大小,比如3*3),g()表示输出的像素值;f()的第一行,第一列数据不要,边缘像素怎么处理后续会有介绍
    • 通常这些卷积算子计算都是线性操作,所以又叫线性滤波

OpenCV图像处理---模糊原理_第1张图片
假设有6x6的图像像素点矩阵(灰色) ,黄色3x3是卷积算子
卷积过程:6x6上面有个3x3的窗口,这个3x3的窗口从左向右,从上向下移动
黄色的卷积算子乘以图像对应的像素点后,将得到的像素点值加在一起,取平均值赋给中心红色像素,作为卷积处理后的新的像素值
OpenCV图像处理---模糊原理_第2张图片

1. 归一化盒子滤波(均值滤波)

@param src input image; it can have any number of channels, which are processed independently, but
the depth should be CV_8U, CV_16U, CV_16S, CV_32F or CV_64F.
@param dst output image of the same size and type as src.
@param ksize blurring kernel size.
@param anchor anchor point; default value Point(-1,-1) means that the anchor is at the kernel
center.
@param borderType border mode used to extrapolate pixels outside of the image, see #BorderTypes
@sa  boxFilter, bilateralFilter, GaussianBlur, medianBlur

void blur( InputArray src, OutputArray dst,Size ksize, Point anchor = Point(-1,-1),int borderType = BORDER_DEFAULT );

在这里插入图片描述
OpenCV图像处理---模糊原理_第3张图片

矩阵卷积运算的具体过程

假设有一个卷积核h,就一般为33的矩阵:
在这里插入图片描述
有一个待处理矩阵x:
OpenCV图像处理---模糊原理_第4张图片
h
x的计算过程分为三步

第一步,将卷积核翻转180°,也就是成为了

在这里插入图片描述
第二步,将卷积核h的中心对准x的第一个元素,然后对应元素相乘后相加,没有元素的地方补0。
OpenCV图像处理---模糊原理_第5张图片
这样结果Y中的第一个元素值Y11=10+20+10+00+01+02±10±25±1*6=-16

第三步每个元素都像这样计算出来就可以得到一个输出矩阵,就是卷积结果

OpenCV图像处理---模糊原理_第6张图片

……………………

像这样计算,其他过程略了。

最后结果

OpenCV图像处理---模糊原理_第7张图片

均值滤波参考代码

#include 
#include 

using namespace std;
using namespace cv;

int main (int argc,char **argv)
{
	Mat src = imread("/home/shining/工作/Opencv-test/picture/girl.jpg",1);
	if(src.empty())
	{
		cout << "Could not load image.."<

2. 高斯滤波
高斯滤波:正态分布
其中Size(x, y), x, y 必须是正数而且是奇数

在这里插入图片描述

@param src input image; the image can have any number of channels, which are processed
independently, but the depth should be CV_8U, CV_16U, CV_16S, CV_32F or CV_64F.
@param dst output image of the same size and type as src.
@param ksize Gaussian kernel size. ksize.width and ksize.height can differ but they both must be
positive and odd. Or, they can be zero's and then they are computed from sigma.
@param sigmaX Gaussian kernel standard deviation in X direction.
@param sigmaY Gaussian kernel standard deviation in Y direction; if sigmaY is zero, it is set to be
equal to sigmaX, if both sigmas are zeros, they are computed from ksize.width and ksize.height,
respectively (see #getGaussianKernel for details); to fully control the result regardless of
possible future modifications of all this semantics, it is recommended to specify all of ksize,
sigmaX, and sigmaY.
@param borderType pixel extrapolation method, see #BorderTypes

void GaussianBlur( InputArray src, OutputArray dst, Size ksize,double sigmaX, double sigmaY = 0,int borderType = BORDER_DEFAULT );

高斯滤波参考代码

#include 
#include 

using namespace std;
using namespace cv;

int main (int argc,char **argv)
{
	Mat src = imread("/home/shining/工作/Opencv-test/picture/girl.jpg",1);
	if(src.empty())
	{
		cout << "Could not load image.."<

说明1
模糊原理: 同样的卷积因子,均值模糊会比高斯模糊更模糊些。 不管对于哪种模糊,卷积核(比如3*3)的大小最好是奇数

  1. 归一化盒子滤波(均值滤波): 就是上面的卷积计算,卷积算子(掩膜)中的格子权重都是1,所以卷积和之后还要除以卷积因子的大小取均值
  2. 高斯滤波: 相比于均值滤波,权重是不一样,但是权重和为1,所以计算卷积和之后不用取均值了

说明2
在模糊处理方面,filter2D() 也可以自己定义卷积核;
参考代码:

#include
#include

using namespace cv;

int main(int argc,char** argv){
	Mat src=imread("E:/Experiment/OpenCV/Pictures/test.jpg");

	if(src.empty()){
		printf("Could not load Image ...");
		return -1;
	}
		
	char input_windows[]="Input Image";
	char blur_windows[]="blur Image";
	char gblur_windows[]="GBlur Image";
	namedWindow(input_windows,CV_WINDOW_AUTOSIZE);
	namedWindow(blur_windows,CV_WINDOW_AUTOSIZE);
	namedWindow(gblur_windows,CV_WINDOW_AUTOSIZE);

	imshow(input_windows,src);
	//模糊处理
	Mat blur_dst,gblur_dst;
	
	//均值模糊
	blur(src, blur_dst, Size(5, 5), Point(-1, -1));
	imshow(blur_windows,blur_dst);

	//高斯模糊
	GaussianBlur(src, gblur_dst, Size(5, 5), 11, 11);
	imshow(gblur_windows,gblur_dst);

	waitKey(0);
	return 0;
}

模糊是基本的图像处理方法。
在介绍中值滤波和双边滤波之前先来介绍两种常见的噪声:
椒盐噪声
椒盐噪声是由图像传感器,传输信道,解码处理等产生的黑白相间的亮暗点噪声。椒盐噪声分为两种即胡椒噪声和盐噪声,胡椒噪声是黑色的,属于低灰度噪声,盐噪声是白色的,属于高灰度噪声,一般两种噪声同时出现,呈现在图像上就是黑白杂点。去除椒盐噪声最常用的算法是中值滤波。

高斯噪声
高斯噪声是一种随机噪声,其幅度的统计规律服从高斯分布(正态分布),去高斯噪声最常用的算法是高斯滤波。

这些噪声出现在图片上某一点时都是比较突兀的,如出现椒盐噪声时,图片中突然某一点突然变成0或255,一般与噪声周围的灰度值有较大的差值,所以图像在去噪时一般都是用周围像素的灰度值经过一定的算子来改变这点像素上较为突兀的灰度值,但缺陷是对原来正常的像素点的灰度值也会产生影响使图片变得模糊;

在图像处理时,灰度图片一般会被视为一个矩阵,而图像上的每一像素所代表的灰度值被视为矩阵中相应位置中的元素,如一幅100×100像素的黑色灰度图片就可以视为100×100的一个矩阵,矩阵中的每一个元素都为0;
对图像进行处理也可以视为对这个矩阵进行处理。

在锐化和模糊时,会用到一些模板,这些模板是一个小如3×3,5×5的矩阵,用来与原图像进行处理产生新的图像,如在均值滤波时常用的模板
OpenCV图像处理---模糊原理_第8张图片
用上图所示的模板对图片的每一像素和其相邻像素组成的邻域进行卷积处理卷积的结果进行归一处理,结果为这一区域灰度值的平均值,用灰度值的平均值替代这一点像素的原灰度值。

均值滤波计算速度快,但会使图像变得较为模糊。
OpenCV图像处理---模糊原理_第9张图片
OpenCV图像处理---模糊原理_第10张图片
利用均值滤波处理后,椒盐噪声被处理成了小的气泡,与此同时图像开始变得模糊,均值滤波不适合椒盐噪声

  1. 中值滤波
void medianBlur( InputArray src, OutputArray dst, int ksize );
  • 统计排序滤波器
  • 中值对椒盐噪声有很好的抑制作用(处理黑白点)。 图像噪声就是硬件处理图像时受干扰产生了极大或极小的像素值,转换成颜色数据就是255或0,这就是椒盐噪声(黑白)。
    OpenCV图像处理---模糊原理_第11张图片
    中值,中间值,将数据从小到大排序后的中间值
    用 3×3 大小模板进行中值滤波。
    OpenCV图像处理---模糊原理_第12张图片
    以(2,2)像素点为例。
    OpenCV图像处理---模糊原理_第13张图片
    对模板中的 9 个数进行从小到大排序:1,1,1,2,2,5,6,6,10。中间值为 2.所有,中值滤波后(2,2)位置的值变为 2. 同理对其他像素点。
    处理结果:
    OpenCV图像处理---模糊原理_第14张图片
    参考代码:
#include 
#include 

using namespace std;
using namespace cv;

int main (int argc,char **argv)
{
	Mat src = imread("/home/shining/工作/Opencv-test/picture/girl_ZY.jpg",1);
	if(src.empty())
	{
		cout << "Could not load image.."<

中值滤波是基于排序统计理论的一种能有效抑制噪声的非线性信号处理技术,中值滤波的基本原理是把数字图像或数字序列中一点的值用该点的一个邻域中各点值的中值代替,让周围的像素值接近的真实值,从而消除孤立的噪声点。方法是用某种结构的二维滑动模板,将板内像素按照像素值的大小进行排序,生成单调上升(或下降)的为二维数据序列。二维中值滤波输出为g(x,y)=med{f(x-k,y-l),(k,l∈W)} ,其中,f(x,y),g(x,y)分别为原始图像和处理后图像。W为二维模板,通常为33,55区域,也可以是不同的的形状,如线状,圆形,十字形,圆环形等。

均值滤波也称为线性滤波,其采用的主要方法为邻域平均法。线性滤波的基本原理是用均值代替原图像中的各个像素值,即对待处理的当前像素点(x,y),选择一个模板,该模板由其近邻的若干像素组成,求模板中所有像素的均值,再把该均值赋予当前像素点(x,y),作为处理后图像在该点上的灰度g(x,y),即g(x,y)=1/m ∑f(x,y) m为该模板中包含当前像素在内的像素总个数。

2. 双边滤波

void bilateralFilter( InputArray src, OutputArray dst, int d,double sigmaColor, double sigmaSpace,int borderType = BORDER_DEFAULT );

双边模糊 bilateralFilter(src, dest, d=15, 150, 3);

  15 –计算的半径,半径之内的像数都会被纳入计算,如果提供-1 则根据sigma space参数取值
  150 – sigma color 决定多少差值之内的像素会被计算
  3 – sigma space 如果d的值大于0则声明无效,否则根据它来计算d值
  中值模糊的ksize大小必须是大于1而且必须是奇数。
  • 常说的双边滤波就是指高斯双边滤波(用于美颜)。两像素差值太大的不予考虑,像素差值有一个阈值范围,在这个范围的才考虑,其他原样输出,这个叫双边滤波。
    在双边滤波的基础加上高斯权重,就叫高斯双边滤波。

  • 均值模糊无法克服边缘像素信息丢失缺陷。原因是均值滤波是基于平均权重 权重都一样

  • 高斯模糊部分克服了该缺陷,但是无法完全避免,因为没有考虑像素值的不同 高斯滤波考虑到了空间位置不一样,权重就不一样,越靠近中心权重越大

  • 上面两种滤波所有的像素点都进行处理

  • 高斯双边模糊 – 是边缘保留的滤波方法,避免了边缘信息丢失,保留了图像轮廓不变 考虑到了像素值的问题,只有像素值在阈值范围内,才进行处理

  • 空域核 空间上考虑,每个点的权重不一样

  • 值域核 像素值,像素值在阈值范围内

OpenCV图像处理---模糊原理_第15张图片
参考代码:

#include 
#include 

using namespace std;
using namespace cv;

int main(int argc,char *argv[])
{
	Mat src = imread("/home/shining/工作/Opencv-test/picture/girl_ZY.jpg",IMREAD_COLOR);
	if(src.empty())
	{
		cout <<"Could not load image..."<(3,3) <<0,-1,0,-1,5,-1,0,-1,0);
	filter2D(image5,image8,image5.depth(),kernel,Point(-1,-1));//调用OpenCV函数进行掩膜操作,src.depth表示位图深度,有32、24、8等,如果不知道也可以传-1,表示跟输入图像一样
	imshow("outputlast",image8);

	waitKey(0);
	return 0;
}

推荐阅读: https://blog.csdn.net/qq_25819827/article/details/52050647

你可能感兴趣的:(OpenCV图像处理---模糊原理)