目录
前言:
1. 大致原理说明
2. 常用参数
滤波方式
1. 高斯滤波
2. 均值滤波
3. 方框滤波
4. 中值滤波
5. 双边滤波
6. 自定义卷积核滤波
图像的平滑滤波处理本质上就是定义一个N×N的矩阵分别按照一定算法与像素值进行运算,最后改变N×N的矩阵中间点像素值的结果,也就是图像平滑的结果。
这样的话,使N×N矩阵的中心点与周围(N的平方-1)个点有着数学关系,就可以利用这种数学关系来使图像颜色的突变 变得不那么明显。这也就是平滑滤波的基本原理。
上文中的N×N矩阵被成为平滑滤波的卷积核。
下文中提到的卷积核也就是N×N矩阵。(N必须要是奇数,两个N可以不同)
一般我们使用3×3或者5×5,在传入函数参数时,应使用元组的形式(3,3),(5,5),(3,5)。
一个卷积核区域所有值与卷积核本身权重相乘再相加(有可能会归一化)得到卷积核中间像素点的值。(主要是卷积核的权重,和归不归一化)
滤波方式有高斯滤波、均值滤波、方框滤波、中值滤波和双边滤波。(5种)
还有一种称作2D卷积核滤波,也叫做自定义卷积核。也就是说他可以由我们自己设定卷积核来处理图像,而不用被以上5种方式所拘束。
先大概说一下常用的参数:(下文函数需要这些参数将不再过多阐述,请读者翻到这里查阅)
dst:返回滤波后图像的结果。
src:表示原始图像(需要进行处理的图像)。
ksize:表示滤波用的卷积核大小,卷积核的数值一定是奇数。传入为(3,3)、(5,5)。
borderType:表示以哪种方式处理边界值。(可以不传该参数)
anchor:表示图像处理的锚点,默认值为(-1,-1),表示位于卷积核中心点。可以不传该参数,使用默认值即可。
depth:表示处理后图像的深度,一般使用-1来表示与原始图像相同的深度(传参数为-1)。
normalize:表示是否进行归一化操作,(=0,不进行归一化;=1,进行归一化)。
卷积核内的权重呈现高斯分布
dst = cv2.GassianBlur(src, ksize, sigmaX, sigmaY, borderType)
sigmaX、sigmaY:这两个参数分别表示卷积核在水平方向上的权重值。一般不使用,传0即可。
例:
gauss = cv.GaussianBlur(image, (7, 7), 0, 0)
import cv2 as cv
image = cv.imread("E:/dahai.jpeg")
gauss = cv.GaussianBlur(image, (7, 7), 0, 0)
cv.imshow("gauss", gauss)
cv.waitKey()
cv.destroyAllWindows()
高斯滤波会使图片变得模糊。
也可以改变卷积核试一下比如(3,7),(7,3)
你会发现两张处理过后的图,一个横向模糊(重影)更多,一个纵向模糊(重影)更多。
卷积核内的权重都为1,它们求和后再除以(N×N)(归一化)
dst = cv2.blur(src, ksize, anchor, borderType)
anchor:表示图像处理的锚点,默认值为(-1,-1),表示位于卷积核中心点。可以不传该参数,使用默认值即可。
例:
blur1 = cv.blur(image, (5, 9))
import cv2 as cv
image = cv.imread("E:/dahai.jpeg")
blur1 = cv.blur(image, (5, 9))
blur2 = cv.blur(image, (9, 5))
cv.imshow("blur1", blur1)
cv.imshow("blur2", blur2)
cv.waitKey()
cv.destroyAllWindows()
方框滤波和均值滤波非常相似,卷积权重都为1,但它多了一个参数可以选择归不归一化。
dst = cv2.boxFilter(src, depth, ksize, anchor, normalize, borderType)
depth:表示处理后图像的深度,一般使用-1来表示与原始图像相同的深度(传参数为-1)。
normalize:表示是否进行归一化操作,(=0,不进行归一化;=1,进行归一化)。
例:
# 不归一化
box_1 = cv.boxFilter(image, -1, (3, 1), normalize=0)
# 归一化
box_2 = cv.boxFilter(image, -1, (3, 1), normalize=1)
import cv2 as cv
image = cv.imread("E:/dahai.jpeg")
# 不归一化
box_1 = cv.boxFilter(image, -1, (3, 1), normalize=0)
# 归一化
box_2 = cv.boxFilter(image, -1, (3, 1), normalize=1)
cv.imshow("box_1", box_1)
cv.imshow("box_2", box_2)
cv.waitKey()
cv.destroyAllWindows()
将卷积核内像素的值由大到小排列,取中位数代替卷积核中间的像素值。
dst = cv2.medianBlur(src, ksize)
例:
gauss = cv.medianBlur(image, 3)
import cv2 as cv
image = cv.imread("E:/dahai.jpeg")
gauss = cv.medianBlur(image, 3)
cv.imshow("gauss", gauss)
cv.waitKey()
cv.destroyAllWindows()
与上几种滤波方式的不同点:
以上四种滤波方式虽然可以完成对图像的滤波作用,但是并不能很好的保护边缘信息。双边滤波的出现解决了这几个问题,它再滤波过程中可以有效保护图像的边缘信息。
原理:
双边滤波再计算某个像素点是不仅考虑距离信息,还会考虑色差信息。
与当前像素点色差较小的像素点会赋予较大的权重值,色差较大的像素点会赋予较小的权重值。这样就可以保护边缘信息了。
函数:
dst = cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace, borderType)
d:表示再滤波时选取的空间距离参数,表示以当前像素点为中心点的半径。在实际应用中一般选取5.
sigmaColor:表示双边滤波选取的色差范围。
sigmaSpace:表示坐标空间的sigma值,它的值越大,表示越多的点参与滤波。
例:
bilateral2 = cv.bilateralFilter(image, 5, 100, 100)
import cv2 as cv
image = cv.imread("E:/dahai.jpeg")
bilateral1 = cv.bilateralFilter(image, 5, 100, 100)
bilateral2 = cv.bilateralFilter(image, 5, 100, 100)
cv.imshow("bilateral1", bilateral1)
cv.imshow("bilateral2", bilateral2)
cv.waitKey()
cv.destroyAllWindows()
可以自己设定卷积核的大小和权重分布,再来滤波。
import cv2 as cv
import numpy as np
image = cv.imread("E:/dahai.jpeg")
k1 = np.ones((3, 3), np.float32)*1/9 # 自定义卷积核k1~~k4
k2 = np.ones((3, 3), np.float32)*2/9
k3 = np.ones((3, 3), np.float32)*3/9
k4 = np.ones((3, 3), np.float32)*4/9
out1 = cv.filter2D(image, -1, k1) # 使用自定义卷积核滤波
out2 = cv.filter2D(image, -1, k2)
out3 = cv.filter2D(image, -1, k3)
out4 = cv.filter2D(image, -1, k4)
cv.imshow("out1", out1)
cv.imshow("out2", out2)
cv.imshow("out3", out3)
cv.imshow("out4", out4)
cv.waitKey()
cv.destroyAllWindows()
当然,自定义卷积核使用的是numpy库生成的数组类型。
opencv库是依赖于numpy库的。
我们学习opencv也需要对numpy库的一般用法有一个大概的了解。
总之,
对于滤波方式而言,在不同的场景下,自己选用合适的滤波方法。
其实也就双边滤波保留边缘信息比较特殊一点。其他的也区别不大。
自定义的话,也就是自己随便玩一玩。也更加的自由化。
大概知道平滑滤波的原理,会用一些常用滤波函数方法,其实也就差不多了。