目录
什么是图片平滑?
目前,大多数数字图像系统中,输入光图像都是通过扫描方式将多维图像变成一维电信号,再对其进行存储、处理和传输等,最后形成多维图像信号。在这一系列复杂过程中,图像数字化设备、电气系统和外界影响将使得图像噪声的产生。——《数字图像处理》陈天华编著
所以图像平滑一般指消除图像中的噪音的过程。图像平滑也称图像模糊、图像去噪、机器去噪等。
怎么做到图像平滑?
回顾上节的图像增强概念思维导图,图像平滑采用空域滤波中的平滑滤波,也即是频域中的低通滤波。那么平滑滤波(即低通滤波)的几种方法如下:
1.邻域平均法(又名均值滤波法)
①逻辑层面:对某一像素值及其邻域的所有像素值取平均值然后赋值给该像素值。
②实现层面:将图像与模板进行卷积运算。
- 模板:模板又称卷积核,是一个行和列都为奇数的矩阵,有3*3模板、5*5模板、7*7模板等。
- 卷积:对于不专业数学人员来说,卷积就是加权和。
④数学演示:
如第二行第二列计算过程:(6*1+1*1+9*1+1*1+5*1+8*1+9*1+8*1+0*1)/9=5.22,取整为5。
⑤程序演示,基于Python Opencv:
1.cv::blur():dst = cv.blur(src, ksize[, dst[, anchor[, borderType]]])
- src:源图像,可以有任意通道数,每条通道都是单独卷积计算的。注意要有同样的图像深度。
- ksize:内核大小。
- dst:与源图像大小和类型相同的输出图像。
- anchor:锚点;默认值点(-1,-1)表示锚点位于内核中心。
- borderType:用于在图像外部外推像素的边框模式。
- 一般只需要用到前两个参数。
2.cv::boxFilter():dst = cv.boxFilter(src, ddepth, ksize[, dst[, anchor[, normalize[, borderType]]]])
- src:源图像。
- ddepth输出图像深度,若设置-1则使用src.depth()。
- ksize:内核大小。
- dst:与源图像大小和类型相同的输出图像。
- anchor:锚点;默认值点(-1,-1)表示锚点位于内核中心。
- normalize:指定内核是否按其区域进行归一化的标志。
- borderType:用于在图像外部外推像素的边框模式。
- 这里介绍一下,boxFilter()其实是方框滤波原理,此函数可以*选择结果是像素和(normalize = False)还是像素平均值(normalize = True)。normalize=True时函数等效于blur()。
normalize = 0(False)演示:
normalize = 1(True)演示:
3.cv::filter2D:dst = cv.filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]])
- src:源图像。
- ddepth输出图像深度,若设置-1则使用src.depth()。
- kernel:卷积核(或者说相关核),单通道浮点矩阵;如果要将不同的内核应用于不同的通道,请使用“拆分”将图像拆分为不同的颜色平面,然后分别进行处理。
- anchor:锚点;默认值点(-1,-1)表示锚点位于内核中心。
- delta:偏置值,过滤后的像素值加上这个值后才存储到dst,一般为0。
- borderType:用于在图像外部外推像素的边框模式。
- filter2D()原理是自定义滤波器,可以滤波模板的参数及大小。
2.中值滤波法
尽管邻域平均法可以起到平滑图像的作用,但在消除噪音的同时,会使图像中的一部分细节变得模糊。中值滤波法则可以在消除噪音的同时保持图像的细节部分,防止图像的边缘部分变得模糊。
①逻辑层面:对某一像素而言,取周围n*n个数(也就是使用n*n模板)后取其中值作为新的像素值。
②实现层面:利用一个奇数点的移动窗口,将窗口中心值用窗口的中间值替代。
③程序演示,基于Python Opencv:
cv::medianBlur:dst = cv.medianBlur(src, ksize[, dst])
- src:输入1、3或4通道图像;当ksize为3或5时,图像深度应为CV_8U、CV_16U或CV_32F,对于较大的光圈尺寸,只能为CV_8U。
- ksize:模板大小,应为奇数。
- dst:与src大小和类型相同的dst目标数组。
3.高斯滤波法
高斯滤波法对于去除图像中的高斯噪声非常有效。
①逻辑层面:高斯滤波其实是一种带权重的均值滤波。权重参数是由高斯函数计算出来的。
公式中的σ为标准差。
所以由二维高斯图像可得中间像素值的权重占比最大(锚点为极值),后所有方向上依次权重减小。
②实现层面:使用高斯核在图像的每个像素点上平滑移动进行卷积运算。
③程序演示,基于Python Opencv:
cv::GaussianBlur:dst = cv.GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]])
- src:源图像。图像可以有任意数量的通道,这些通道是独立处理的,但深度应为CV_8U、CV_16U、CV_16S、CV_32F或CV_64F。
- ksize:高斯核大小。ksize.width和ksize.height可以不同,但它们都必须是正奇数。可以都是零,然后根据sigma计算。但是一般建议自己给定。
- sigmaX:X方向的高斯核标准差。
- dst:与src大小和类型相同的dst目标数组。
- sigmaY:Y方向高斯核标准差。如果sigmaY为零,则设置为等于sigmaX,如果两个sigma都为零,则分别从ksize.width和ksize.height计算。
- borderType:用于在图像外部外推像素的边框模式。
4.双边滤波法
双边滤波法在去除噪声的同时对保持边缘(边缘和噪音都是高频)清晰锐利非常有效,但是速度慢。
①逻辑层面:按照高斯滤波法考虑距离设置权重,同时又考虑两边值差,如果两边值差过大则结果只算自己一边的权重均值。
②实现层面:双边滤波器考虑了像素点之间的欧式距离(使用二维高斯函数生成距离模板),也考虑了像素点之间的颜色差异(使用一维高斯函数生成值域模板)。
1.距离模板系数的生成公式如下:
其中(k,l)为模板窗口的中心坐标;(i,j)为模板窗口的其他系数的坐标;σd为高斯函数的标准差。使用该公式生成的滤波器模板和高斯滤波器使用的模板是没有区别的。
2.值域模板系数的生成公式如下:
其中f(x,y)表示图像在点(x,y)处的像素值;(k,l)为模板窗口的中心坐标;(i,j)为模板窗口的其他系数的坐标;σr为高斯函数的标准差。
3.将上述两个模板相乘就得到了双边滤波器的模板:
模板可视化:
③ 程序演示,基于Python Opencv:
cv::bilateralFilter():dst = cv.bilateralFilter(src, d, sigmaColor, sigmaSpace[, dst[, borderType]])
- src:8位或浮点、1通道或3通道的源图像。
- d:过滤期间使用的每个像素邻域的直径。如果为非正,则从sigmaSpace计算。
- sigmaColor:在颜色空间中过滤sigma。该参数的值越大,意味着像素邻域中的更多颜色将混合在一起,从而产生更大的半等色区域。
- sigmaSpace:在坐标空间中过滤sigma。该参数的值越大,意味着越远的像素将相互影响,只要它们的颜色足够接近。当d>0时,它指定邻域大小而不考虑sigmaSpace。否则,d与sigmaSpace成正比。
- dst:与src大小和类型相同的dst目标数组。
- borderType:用于在图像外部外推像素的边框模式。
- 注意:对于d值来说:大型过滤器(d>5)非常慢,因此建议在实时应用程序中使用d=5,在需要大量噪声过滤的脱机应用程序中使用d=9。对于Sigma值来说,为简单起见,将2个Sigma值设置为相同。如果它们很小(<10),滤镜就不会有太大的效果,而如果它们很大(>150),滤镜的效果会非常强,使图像看起来“卡通化”。并且这个过滤器不能就地工作。
参考文档: