参考博客:https://www.cnblogs.com/FHC1994/p/9097231.html
https://blog.csdn.net/wsp_1138886114/article/details/82872838#11__7
https://blog.csdn.net/wangleixian/article/details/78237597
https://www.zhihu.com/question/54918332/answer/142137732
**过滤 :**是信号和图像处理中基本的任务。其目的是根据应用环境的不同,选择性的提取图像中某些认为是重要的信息。过滤可以移除图像中的噪音、提取感兴趣的可视特征、允许图像重采样等等。
**频域分析 :**将图像分成从低频到高频的不同部分。低频对应图像强度变化小的区域,而高频是图像强度变化非常大的区域。在频率分析领域的框架中,滤波器是一个用来增强图像中某个波段或频率并阻塞(或降低)其他频率波段的操作。低通滤波器是消除图像中高频部分,但保留低频部分。高通滤波器消除低频部分。
import cv2
import numpy as np
def blur_demo(image):
"""
均值模糊 : 去随机噪声有很好的去噪效果
(1, 15)是垂直方向模糊,(15, 1)是水平方向模糊
"""
dst = cv2.blur(image, (1, 15))
cv2.imshow("avg_blur_demo", dst)
def median_blur_demo(image): # 中值模糊 对椒盐噪声有很好的去燥效果
dst = cv2.medianBlur(image, 5)
cv2.imshow("median_blur_demo", dst)
def custom_blur_demo(image):
"""
用户自定义模糊
下面除以25是防止数值溢出
"""
kernel = np.ones([5, 5], np.float32)/25
dst = cv2.filter2D(image, -1, kernel)
cv2.imshow("custom_blur_demo", dst)
src = cv2.imread("C:\\Users\\Tony.Hsu\\Desktop\\cat.jpg")
img = cv2.resize(src, None, fx=0.8, fy=0.8, interpolation=cv2.INTER_CUBIC)
cv2.imshow('input_image', img)
blur_demo(img)
median_blur_demo(img)
custom_blur_demo(img)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果如下:
注意:
# 高斯模糊 轮廓还在,保留图像的主要特征 高斯模糊比均值模糊去噪效果好
import cv2
import numpy as np
def clamp(pv):
"""防止颜色值超出颜色取值范围(0-255)"""
if pv > 255:
return 255
if pv < 0:
return 0
else:
return pv
def gaussian_noise(image): # 加高斯噪声
h, w, c = image.shape
for row in range(h):
for col in range(w):
# 获取三个高斯随机数
# 第一个参数:概率分布的均值,对应着整个分布的中心
# 第二个参数:概率分布的标准差,对应于分布的宽度
# 第三个参数:生成高斯随机数数量
s = np.random.normal(0, 20, 3)
# 获取每个像素点的bgr值
b = image[row, col, 0] # blue
g = image[row, col, 1] # green
r = image[row, col, 2] # red
# 给每个像素值设置新的bgr值
image[row, col, 0] = clamp(b + s[0])
image[row, col, 1] = clamp(g + s[1])
image[row, col, 2] = clamp(r + s[2])
cv2.namedWindow("noise image", cv2.WINDOW_NORMAL)
cv2.imshow("noise image", image)
dst = cv2.GaussianBlur(image, (15, 15), 0) # 高斯模糊
cv2.namedWindow("Gaussian", cv2.WINDOW_NORMAL)
cv2.imshow("Gaussian", dst)
# 读入图片
src = cv2.imread('C:\\Users\\Tony.Hsu\\Desktop\\cat.jpg')
cv2.namedWindow("input_image", cv2.WINDOW_NORMAL)
cv2.imshow('input_image', src)
gaussian_noise(src)
# 给图片创建毛玻璃特效
# 第二个参数:高斯核的宽和高(建议是奇数)
# 第三个参数:x和y轴的标准差
dst = cv2.GaussianBlur(src, (15, 15), 0) # 高斯模糊
cv2.namedWindow("Gaussian Blur", cv2.WINDOW_NORMAL)
cv2.imshow("Gaussian Blur", dst)
结果如下:
注意:
1.高斯模糊实质上就是一种均值模糊,只是高斯模糊是按照加权平均的,距离越近的点权重越大,距离越远的点权重越小。通俗的讲,高斯滤波就是对整幅图像进行加权平均的过程,每一个像素点的值,都由其本身和邻域内的其他像素值经过加权平均后得到。
2. 高斯模糊GaussianBlur函数原型:GaussianBlur(src, ksize, sigmaX[, dst[, sigmaY[, borderType]]]) -> dst
src参数表示待处理的输入图像。
ksize参数表示高斯滤波器模板大小。 ksize.width和ksize.height可以不同,但它们都必须是正数和奇数。或者,它们可以是零,即(0, 0),然后从σ计算出来。
sigmaX参数表示 X方向上的高斯内核标准差。
sigmaY参数表示 Y方向上的高斯内核标准差。 如果sigmaY为零,则设置为等于sigmaX,如果两个sigma均为零,则分别从ksize.width和ksize.height计算得到。
补:若ksize不为(0, 0),则按照ksize计算,后面的sigmaX没有意义。若ksize为(0, 0),则根据后面的sigmaX计算ksize
3.numpy包里的random模块用于生成随机数,random模块里的normal函数表示的是生成高斯随机数。
normal函数默认原型:normal(loc=0.0, scale=1.0, size=None)。
loc参数表示高斯分布的中心点。
scale参数表示高斯分布的标准差σ。
size参数表示产生随机数的个数。size取值可以为(m,n,k),表示绘制mnk个样本。
4.高斯模糊具体原理见博文:https://blog.csdn.net/u012992171/article/details/51023768
"""
bilateralFilter(src, d, sigmaColor, sigmaSpace[, dst[, borderType]]) -> dst
- src: 输入图像。
- d: 在过滤期间使用的每个像素邻域的直径。如果输入d非0,则sigmaSpace由d计算得出,如果sigmaColor没输入,则sigmaColor由sigmaSpace计算得出。
- sigmaColor: 色彩空间的标准方差,一般尽可能大。
较大的参数值意味着像素邻域内较远的颜色会混合在一起,
从而产生更大面积的半相等颜色。
- sigmaSpace: 坐标空间的标准方差(像素单位),一般尽可能小。
参数值越大意味着只要它们的颜色足够接近,越远的像素都会相互影响。
当d > 0时,它指定邻域大小而不考虑sigmaSpace。
否则,d与sigmaSpace成正比。
"""
# 边缘保留滤波(EPF) 高斯双边、均值迁移
import cv2
def bi_demo(image): # 双边滤波
dst = cv2.bilateralFilter(image, 0, 100, 15)
cv2.namedWindow("bi_demo", cv2.WINDOW_NORMAL)
cv2.imshow("bi_demo", dst)
def shift_demo(image): # 均值迁移
dst = cv2.pyrMeanShiftFiltering(image, 10, 50)
cv2.namedWindow("shift_demo", cv2.WINDOW_NORMAL)
cv2.imshow("shift_demo", dst)
src = cv2.imread('C:\\Users\\Tony.Hsu\\Desktop\\cat.jpg')
cv2.namedWindow('input_image', cv2.WINDOW_NORMAL)
cv2.imshow('input_image', src)
bi_demo(src)
shift_demo(src)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果如下:
注意:
1.双边滤波(Bilateral filter)是一种非线性的滤波方法,是结合图像的空间邻近度和像素值相似度的一种折中处理,同时考虑空域信息和灰度相似性,达到保边去噪的目的。双边滤波器顾名思义比高斯滤波多了一个高斯方差sigma-d,它是基于空间分布的高斯滤波函数,所以在边缘附近,离的较远的像素不会太多影响到边缘上的像素值,这样就保证了边缘附近像素值的保存。但是由于保存了过多的高频信息,对于彩色图像里的高频噪声,双边滤波器不能够干净的滤掉,只能够对于低频信息进行较好的滤波
2.双边滤波函数原型:bilateralFilter(src, d, sigmaColor, sigmaSpace[, dst[, borderType]]) -> dst
src参数表示待处理的输入图像。
d参数表示在过滤期间使用的每个像素邻域的直径。如果输入d非0,则sigmaSpace由d计算得出,如果sigmaColor没输入,则sigmaColor由sigmaSpace计算得出。
sigmaColor参数表示色彩空间的标准方差,一般尽可能大。较大的参数值意味着像素邻域内较远的颜色会混合在一起,从而产生更大面积的半相等颜色。
sigmaSpace参数表示坐标空间的标准方差(像素单位),一般尽可能小。参数值越大意味着只要它们的颜色足够接近,越远的像素都会相互影响。当d > 0时,它指定邻域大小而不考虑sigmaSpace。 否则,d与sigmaSpace成正比。
双边滤波原理:
https://blog.csdn.net/edogawachia/article/details/78837988,https://blog.csdn.net/MoFMan/article/details/77482794 ,https://www.cnblogs.com/qiqibaby/p/5296681.html
3.均值漂移pyrMeanShiftFiltering函数原型:pyrMeanShiftFiltering(src, sp, sr[, dst[, maxLevel[, termcrit]]]) -> dst
src参数表示输入图像,8位,三通道图像。
sp参数表示漂移物理空间半径大小。
sr参数表示漂移色彩空间半径大小。
dst参数表示和源图象相同大小、相同格式的输出图象。
maxLevel参数表示金字塔的最大层数。
termcrit参数表示漂移迭代终止条件。
均值漂移原理:
https://blog.csdn.net/dcrmg/article/details/52705087
https://blog.csdn.net/qq_23968185/article/details/51804574
https://blog.csdn.net/jinshengtao/article/details/30258833
使用的函数有:cv2.Sobel() , cv2.Schar() , cv2.Laplacian()
Sobel,scharr其实是求一阶或者二阶导数。scharr是对Sobel的优化。
Laplacian是求二阶导数。
"""
dst = cv2.Sobel(src, ddepth, dx, dy[, dst[, ksize[, scale[, delta[, borderType]]]]])
src: 需要处理的图像;
ddepth: 图像的深度,-1表示采用的是与原图像相同的深度。
目标图像的深度必须大于等于原图像的深度;
dx和dy: 求导的阶数,0表示这个方向上没有求导,一般为0、1、2。
dst 不用解释了;
ksize: Sobel算子的大小,必须为1、3、5、7。 ksize=-1时,会用3x3的Scharr滤波器,
它的效果要比3x3的Sobel滤波器要好
scale: 是缩放导数的比例常数,默认没有伸缩系数;
delta: 是一个可选的增量,将会加到最终的dst中, 默认情况下没有额外的值加到dst中
borderType: 是判断图像边界的模式。这个参数默认值为cv2.BORDER_DEFAULT。
"""
import cv2
img = cv2.imread('C:\\Users\\Tony.Hsu\\Desktop\\cat.jpg', cv2.IMREAD_COLOR)
x = cv2.Sobel(img, cv2.CV_16S, 1, 0)
y = cv2.Sobel(img, cv2.CV_16S, 0, 1)
absx = cv2.convertScaleAbs(x)
absy = cv2.convertScaleAbs(y)
dist = cv2.addWeighted(absx, 0.5, absy, 0.5, 0)
cv2.imshow('original_img', img)
cv2.imshow('y', absy)
cv2.imshow('x', absx)
cv2.imshow('dsit', dist)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果如下:
import cv2
img = cv2.imread('C:\\Users\\Tony.Hsu\\Desktop\\cat.jpg', cv2.IMREAD_COLOR)
laplace = cv2.Laplacian(img, cv2.CV_16S, ksize=3)
laplacian = cv2.convertScaleAbs(laplace)
cv2.imshow('laplacian', laplacian)
cv2.waitKey(0)
cv2.destroyAllWindows()
结果如下:
注意:
1.Sobel算子依然是一种过滤器,只是其是带有方向的。在OpenCV-Python中,使用Sobel的算子的函数原型如下:
dst = cv2.Sobel(src,ddepth,dx,dy[, dst[, ksize[, scale[, delta[, borderType]]]]])
函数返回其处理结果。
前四个是必须的参数:
第一个参数是需要处理的图像;
第二个参数是图像的深度,-1表示采用的是与原图像相同的深度。目标图像的深度必须大于等于原图像的深度;
dx和dy表示的是求导的阶数,0表示这个方向上没有求导,一般为0、1、2。
其后是可选的参数:
dst不用解释了;ksize是Sobel算子的大小,必须为1、3、5、7。 ksize=-1时,会用3x3的Scharr滤波器,它的效果要比3x3的Sobel滤波器要好;
scale是缩放导数的比例常数,默认情况下没有伸缩系数;
delta是一个可选的增量,将会加到最终的dst中,同样,默认情况下没有额外的值加到dst中;
borderType是判断图像边界的模式。这个参数默认值为cv2.BORDER_DEFAULT。
2.在Sobel函数的第二个参数这里使用了cv2.CV_16S.因为OpenCV文档中对Sobel算子的介绍中有这么一句:“in the case of 8-bit input images it will result in truncated derivatives".即Sobel建立的图像位数不够,会有截断。因此要使用16位有符号的数据类型,即cv2.CV_16S.在经过处理后,别忘了用convertScaleAbs()函数将其转回原来的uint8形式。否则将无法显示图像,而只是一个黑色窗口。
convertScaleAbs()的原型位——dst = cv2.convertScaleAbs(src[, dst[, alpha[, beta]]]),其中可选参数alpha是伸缩系数,beta是加到结果上的一个值。结果返回uint8类型的图片。
3.Laplace算子的函数原型如下: dst = cv2.Laplacian(src, ddepth[, dst[, ksize[, scale[, delta[, borderType]]]]])——前两个是必须的参数:第一个参数是需要处理的图像,第二个参数是图像的深度,-1表示采用的是与原图相同的深度。目标图像的深度必须大于等于原图的深度。
dst不用解释了;ksize是Sobel算子的大小,必须为1、3、5、7。 ksize=-1时,会用3x3的Scharr滤波器,它的效果要比3x3的Sobel滤波器要好;
scale是缩放导数的比例常数,默认情况下没有伸缩系数;
delta是一个可选的增量,将会加到最终的dst中,同样,默认情况下没有额外的值加到dst中;
borderType是判断图像边界的模式。这个参数默认值为cv2.BORDER_DEFAULT。
4.opencv官方文档:
https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_imgproc/py_filtering/py_filtering.html?highlight=filter