前言
在上一章中描述了绘制图形与文字,详细描述可点击查看(https://www.jianshu.com/writer#/notebooks/47386368/notes/77130883)
目标
本章中,将学习如何:
- 模糊图像的意义和作用
- 模糊原理
- 模糊方法
- 代码演示
模糊图像的意义和作用
图像的模糊处理就是将图像处理的更加模糊,如下图,左侧是原图,右侧是经过处理后的图像。
正常情况下,我们希望看到清晰的图像,而不是模糊的图像。所以很多时候我们听说还有一种专门进行模糊图像的操作时,对于初学者来说有些不可思议,这有什么用呢。要知道模糊图像只是处理图像噪声带来的副作用,并不是我们的目的。图像没有噪声的时候,我们用平滑滤波器去模糊图像干什么呢?还真有一个重要的应用。把上面的图像使用变得更加模糊。效果如下:
我们可以看到,相对原始图像,一些娇小的物体已经融入背景,看不到了,有些物体即使能看到,亮度也明显降低。这样,我们用图像模糊将图像中较大的物体保留下来,而其他的物体则消除掉。我们再进一步通过二值化处理对模糊后的图像进行操作,将最高亮度的25%作为阈值,低于此阈值的赋为0,高于此阈值的赋为255。经过处理后图像如下:
像这样利用阈值函数处理并基于物体亮度来消除某些物体的操作时很典型。当我们只想得到感兴趣的物体时,通过图像模糊,可以将那尺寸和亮度较小的物体过滤掉,较大的物体则易于检测。除了降低噪声,这就是图像平滑(模糊)的另一个重要应用:目标提取。
模糊原理
模糊操作时图像处理中最简单和常用的操作之一,使用该操作的原因之一就为了给图像预处理时减低噪声。
使用模糊操作的背后是数学的卷积计算:
其中权重核h(k,l)h(k,l)为“滤波系数”。上面的式子可以简记为:
通常这些卷积算子计算都是线性操作,所以又叫线性滤波。示例:假设有6x6的图像像素点矩阵,进行均值滤波。
卷积过程:6x6上面是个3x3的窗口,从左向右,从上向下移动,黄色的每个像素点值之和取平均值赋给中心红色像素作为它卷积处理之后新的像素值。每次移动一个像素格。
模糊方法
均值滤波(归一化滤波)
均值滤波是典型的线性滤波算法,它是指在图像上对目标像素给一个模板,改模板包括了其周围的临近像素(以目标像素为中心的周围8个像素,构成一个绿波模板,即去掉目标像素本身),再用模板中的全体像素的平均值来代替原来像素值。
再用3x3大小模板进行均值滤波。
上图中由于图像边框上的像素无法被模板覆盖,所以不做处理。这会造成图像边缘的缺失。以(2,2)坐标的像素点为例:
则滤波后的结果为:
滤波后(2,2)像素点的值由10变为3,其他像素点也使用相同的处理方式,最终结果如下:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
Mat srcImage;
srcImage = imread("//lena512color.png");
imshow("均值滤波【原图】", srcImage);
Mat dst; // 构造目标类
medianBlur(srcImage, dst, 3);
//blur(srcImage, dst, Size(5, 5)); // 进行均值滤波操作
imshow("均值滤波【处理后】", dst);
waitKey();
return 0;
}
函数原型: void blur( InputArray src, OutputArray dst, Size ksize, Point anchor = Point(-1,-1), int borderType = BORDER_DEFAULT );
函数说明:
1.第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。该函数对通道是独立处理的,且可以处理任意通道数的图像,但需要注意,待处理的图像深度应该为CV_8U,CV_16U,CV_16S,CV_32F以及CV_64F之一。
2.第二个参数,OutputArray类型的dst,即目标图像,需要和源图像有一样的尺寸和类型。比如可以用Mat::Clone,以源图像为模板,来初始化得到相同尺寸和类型的目标图。
3.第三个参数,Size类型,内核的大小。一般这样写Size(w,h)来表示内核的大小(其中,w为像素宽度,h为像素高度)。
4.第四个参数,Point类型的anchor,表示锚点(即被平滑的那个点),注意他有默认值Point(-1,-1)。如果这个点坐标是负值的话,就表示取核的中心为锚点,所以默认值Point(-1,-1)表示这个锚点在核的中心。
5.第五个参数,int类型的borderType,用于推断图像外部像素的某种边界模式。默认值为BORDER_DEFAULT,一般不修改。
中值滤波
中值,中间值,将数据从小到大排序后的中间值。用3x3大小模板进行中值滤波。
还是以(2,2)坐标的像素点为例:
对模板中的9个数进行从小到大排序:1,1,1,2,2,5,6,6,10。中间值为2。中值滤波后(2,2)坐标的像素值变为2。同理对其他像素点进行处理。结果如下:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
Mat srcImage;
srcImage = imread("d://1.png");
imshow("均值滤波【原图】", srcImage);
Mat dst; // 构造目标类
medianBlur(srcImage, dst, 3);
//blur(srcImage, dst, Size(5, 5)); // 进行均值滤波操作
imshow("高斯滤波【处理后】", dst);
waitKey();
return 0;
}
函数原型:void medianBlur( InputArray src, OutputArray dst, int ksize );
函数说明:
1.第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。该函数对通道是独立处理的,且可以处理任意通道数的图像,但需要注意,待处理的图像深度应该为CV_8U,CV_16U,CV_16S,CV_32F以及CV_64F之一。
2.第二个参数,OutputArray类型的dst,即目标图像,需要和源图像有一样的尺寸和类型。比如可以用Mat::Clone,以源图像为模板,来初始化得到相同尺寸和类型的目标图。
3.第三个参数,int类型,内核的大小。
双边滤波
双边滤波是一种非线性的滤波方法,是结合图像的空间临近度和像素值相似度的一种折中处理,同时考虑空间与信息和灰度相似性,达到保边去噪的目的,具有简单、非迭代、局部处理的特点。之所以能够达到保边去噪的滤波效果是因为滤波器由两个函数构成:一个函数是由几何空间距离决定滤波器系数,另一个是由像素差值决定滤波器系数。双边滤波器中,输出像素的值依赖于领域像素的值的加权组合。其公式如下:
权重系数w(i,j,k,l)取决于定义域核
和值域核
的乘积,也就是
通俗来讲就是双边滤波模板主要有两个模板生成,第一个是高斯模板,第二个是以灰度级的差值作为函数系数生产的模板,然后这两个模板点乘就得到了最终的双边滤波模板,第一个模板是全局模板,所以只需要一次,第二个模板需要对每个像素都计算一次。双边滤波器比高斯滤波器多了一个高斯方差sigma-d,它是基于空间分布的高斯滤波函数,所以在边缘附近,离的较远的像素不会太多影响到边缘上的像素,这样就能对边缘附近的像素值予以保存,但是由于保存过多的高频信息,对于彩色图像里的高频噪声,双边滤波器不能够干净的滤掉,只能够对于低频信息进行较好的滤除。
双边滤波器可以很好的保存图像边缘细节而滤除掉低频分量的噪音,但是双边滤波器的效率不是太高,花费的时间相较于其他滤波器而言也比较长。对于简单的滤波而言,可以将两个sigma值设置成相同的值,如果值<10,则对滤波器影响很小,如果值>150则会对滤波器产生较大的影响,会使图片看起来像卡通。
特点:
均值模糊无法克服边缘像素信息丢失缺陷,原因是均值模糊是基于平均权重。
高斯模糊部分克服了该缺陷,但是无法完全避免,因为没考虑到像素值的不同。
双边滤波是保留边缘的滤波方法,避免了边缘信息的丢失,保留了图像轮廓不变。
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
/*
d:计算的半径
sigmaColor:多少差值之内的像素会被计算
sigmaSpace:如果d>0,那么声明无效,否则根据它来计算d值
*/
Mat srcImage;
srcImage = imread("d://1.png");
imshow("双边滤波【原图】", srcImage);
Mat dst; // 构造目标类
bilateralFilter(srcImage, dst, 15, 150, 3);
//medianBlur(srcImage, dst, 3);
//blur(srcImage, dst, Size(5, 5)); // 进行均值滤波操作
imshow("双边滤波【处理后】", dst);
waitKey();
return 0;
}
函数原型:void bilateralFilter( InputArray src, OutputArray dst, int d, double sigmaColor, double sigmaSpace, int borderType = BORDER_DEFAULT );
函数说明:
1.第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可。该函数对通道是独立处理的,且可以处理任意通道数的图像,但需要注意,待处理的图像深度应该为CV_8U,CV_16U,CV_16S,CV_32F以及CV_64F之一。
2.第二个参数,OutputArray类型的dst,即目标图像,需要和源图像有一样的尺寸和类型。比如可以用Mat::Clone,以源图像为模板,来初始化得到相同尺寸和类型的目标图。
3.第三个参数,表示在过滤过程中每个像素邻域的直径范围。如果这个值是非正数,则函数会从第五个参数sigmaSpace计算该值。
4.第四个参数,颜色空间过滤器的sigma值,这个参数的值月大,表明该像素邻域内有月宽广的颜色会被混合到一起,产生较大的半相等颜色区域。
5第四个参数,.坐标空间中滤波器的sigma值,如果该值较大,则意味着颜色相近的较远的像素将相互影响,从而使更大的区域中足够相似的颜色获取相同的颜色。当d>0时,d指定了邻域大小且与sigmaSpace五官,否则d正比于sigmaSpace.
6.第六个参数,用于推断图像外部像素的某种边界模式,有默认值BORDER_DEFAULT.