OpenCV中的滤波器
图像滤波
- 图像滤波:一副图像通过滤波器得到另一幅图像,其中滤波器又被称为卷积核,滤波的过程被称为卷积;
- 卷积核的大小:
3x3 5x5 9x9 11x11
... - 锚点:
- 边界扩充: 对于一张图片在卷积之后,他的卷积结果会比原始图像小,有时候我们需要输出结果与原始图像一样大,此时需要做边界扩充。
- 步长: 我们在卷积的过程中,每次扫描的范围长度是多少,需要跨几步。
卷积相关概念
-
卷积核的大小:卷积就是滤波器,卷积是有大小的
- 卷积核一般为奇数,如3x3 5x5 7x7等
- 为什么是卷积核大小是奇数呢
- 一方面是增加padding的原因,扩充我们图像的尺寸,主要是为了使我们输出的图像大小和我们原始的图像大小保持一致。
- 另一方面是保证锚点在卷积核的正中间,放置位置发生偏移的原因。
-
卷积核大小的影响
- 在深度学习中,卷积核越大,看到的信息(感受野)越多,提取的特征越好,同时计算量也就越大。
-
锚点
-
边界扩充
-
步长
图像卷积
filter2D(src, ddepth, kernel, anchor, delta, borderType)
src
: 图片源ddepth
: 图像的位深,可以输出图像为8位/16位/32位kernel
: 卷积核anchor
: 锚点 默认是-1delta
: 滤波之后卷积之后得到的元素加一个delta
值,默认为0borderType
: 边界的类型,映射、黑边...import cv2 from cv2 import imshow import numpy as np img = cv2.imread('./dog.jpeg'); # 创建卷积核 为5x5 float32位的阵列,给每个元素除以50,也就是每个元素值为50分之1 kernel = np.ones((5, 5), np.float32) / 50 dst = cv2.filter2D(img, -1, kernel) cv2.imshow('img', img) cv2.imshow('filter', dst) cv2.waitKey(0)
低通滤波与高通滤波
- 低通滤波:低于某个阈值是可以通过的,低通滤波是可以去除噪音或平滑图像
- 高通滤波:高于某个阈值是可以通过的,高通滤波可以帮助查找图像的边缘
低通滤波
方盒滤波与均值滤波
-
方盒滤波API:
boxFilter(src, ddepth, ksize, anchor, normalize, borderType)
- normalize = true, a = 1 / W x H
- 当normalize为true时,假设是3x3的滤波,那么a的值就是9分之1。5x5的滤波就是25分之1。
- normalize = false, a = 1
- 当normalize为false时,a等于1,不进行均值化。最终我们输出的结果就是每个元素之和。
- 当normalize == true时,方盒滤波 == 均值滤波
- 参数释义:
src
: 图像源ddepth
: 输出图像的位深,一般情况下输出图像的位深与原图像的位深是一致的。ksize
: kernel size,卷积核的大小3x3 5x5 7x7 ...anchor
: 锚点,默认值是-1,取卷积核的中心点。normalize
: true与false,简介参照以上,默认值为trueborderType
: 边界的类型,映射、黑边...
-
均值滤波API:
blur(src, ksize, anchor, borderType)
高斯滤波
-
什么是高斯滤波:如下图,每一个滤波都是一个钟形(两边低中间高),所以高斯滤波也叫钟形滤波。高斯滤波主要解决的是高斯噪点。
-
高斯滤波API:
GaussianBlur(src, kernel, sigmaX, sigmaY, ...)
src
: 图像源kernel
: kernel size,卷积核的大小3x3 5x5 7x7 ...sigmaX
: 钟形滤波的延展宽度,x与中心点最大的误差。sigmaY
: 钟形滤波的延展宽度,y与中心点最大的误差。
中值滤波
- 什么是中值滤波,假设有一个数组[1556789],取其中的中间值作为卷积后的结果值6,每一个元素都输出这样一个元素,取其中的中间值,这就是中值滤波
- 中值滤波的优点:对胡椒噪音效果明显
胡椒噪音图 - 中值滤波API:
medianBlur(img, ksize)
双边滤波
- 双边滤波的优点
-
双边滤波API:
bilateralFilter(img, d, sigmaColor, sigmaSpace, ...)
- img:
- d: 直径,filter的大小
- sigmaColor: 颜色的sigma
- sigmaSpace: 空间的sigma
import cv2 from cv2 import imshow import numpy as np # 双边滤波 img = imread('./fat.png') dst = cv2.bilateralFilter(img, 30, 155, 8000) cv2.imshow('img', img) cv2.imshow('filter', dst) cv2.waitKey(0)
高通滤波
索贝尔算子
- Sobel(索贝尔)(高斯)
- 优点:在内部实现的时候首先使用的高斯滤波,对噪音进行了过滤。之后通过一阶导数求得图像的边缘,对抗噪音性比较强。
- 缺点:在检测边缘的时候只能求一个方向的 要码横轴 要码纵轴。最终的检测结果需要将横轴检测边缘与纵轴检测边缘加起来,才能得出最终的结果。
- 流程
- 先向x方向求导
- 再向y方向求导
- 最终结果累加:|G| = |Gx| + |Gy|
-
API:
Sobel(src, ddepth, dx, dy, ksize=3, scale=1, delta=0, borderType=BORDER_DEFAULT)
src
: 源ddepth
: 位深dx
: 对x求导得出ydy
: 对y求导得出xksize
: kernel size,如果等于-1就变成沙尔算法scale = 1
: 缩放delta = 0
: 结果加delta值borderType=BORDER_DEFAULT
: 边框类型
import cv2 import numpy as np img = cv2.imread('./chess.png') #索贝尔算子y方向边缘 d1 = cv2.Sobel(img, cv2.CV_64F, 1, 0, ksize=5) #索贝尔算子x方向边缘 d2 = cv2.Sobel(img, cv2.CV_64F, 0, 1, ksize=5) dst = d1 + d2 cv2.imshow('img', img) cv2.imshow('d1', d1) cv2.imshow('d2', d2) cv2.imshow('dst', dst) cv2.waitKey(0)
沙尔算子
- Scharr(沙尔):只支持3x3的卷积核
- 优点:卷积核大小不会改变的3x3的卷积核。当我们给其他卷积核设定为-1,默认就会使用沙尔算子。该卷积核显示图像细腻。
- 缺点:在检测边缘的时候只能求一个方向的 要码横轴 要码纵轴。最终的检测结果需要将横轴检测边缘与纵轴检测边缘加起来,才能得出最终的结果
- 与Soble类似,只不过使用的kernel值不同
- Scharr只能求x方向或y方向的边缘
- API:
Scharr(src, ddepth, dx, dy, scale = 1, delta=0, borderType=BORDER_DEFAULT)
import cv2 import numpy as np img = cv2.imread('./chess.png') #沙尔 d1 = cv2.Scharr(img, cv2.CV_64F, 1, 0) #沙尔 d2 = cv2.Scharr(img, cv2.CV_64F, 0, 1) dst = cv2.add(d1, d2) cv2.imshow('img', img) cv2.imshow('d1', d1) cv2.imshow('d2', d2) cv2.imshow('dst', dst) cv2.waitKey(0)
拉普拉斯算子
- Laplacian(拉普拉斯)
- 优点:不用单独求 x y的边缘,直接可以一次检测横轴与纵轴的边缘。
- 缺点:对于噪音比较敏感,我们在使用拉普拉斯时需要先对图像进行降噪处理。
- API:
Laplacian(img, ddepth, ksize=1, scale=1, borderType=BORDER_DEFAULT)
边缘检测 Canny
- 为了降低噪音的影响,canny会使用5x5的高斯滤波来消除噪声
- 之后调用索贝尔计算图像梯度的方向(0度、45度、90度、135度)
- 之后会取局部极大值,确定该边缘是最好的边缘
- 阈值计算:
如果超过maxVal肯定就是边缘,如果低于minVal就不是边缘。如果在maxVal与minVal之间有没有联系,a是边缘c和a在连线上那么c也就是边缘,由于b不在maxVal边缘相关的连线上,所以b就不是边缘 - API:
Canny(img, minVal, maxVal, ...)
import cv2 from cv2 import imread img = imread('./lena.png') dst = cv2.Canny(img, 50, 80) cv2.imshow('img', img) cv2.imshow('canny', dst) cv2.waitKey(0)