与以为信号一样,我们也可以对 2D 图像实施低通滤波(LPF),高通滤波(HPF)。
在OpenCV中也可以自己定义自己的滤波器,然后使用filter2D函数进行运算。OpenCV 提供的函数 cv.filter2D() 可以让我们对一幅图像进行卷积操作。
dst=cv.filter2D(src, ddepth, kernel[, dst[, anchor[, delta[, borderType]]]])
下面我们将对一幅图像使用平均滤波器。下面是一个 5x5 的平均滤波器核:
操作过程:将核放在图像的一个像素 A 上,求与核对应的图像上 25(5x5)个像素的和,在取平均数,用这个平均数替代像素 A 的值。重复以上操作直到将图像的每一个像素值都更新一边
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('hair.jpg')
kernel = np.ones((5,5),np.float32)/25
dst = cv2.filter2D(img,-1,kernel)
# 显示图像
plt.figure(figsize = (15, 10))
plt.subplot(121),plt.imshow(img),plt.title('Original'),plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(dst),plt.title('Averaging'),plt.xticks([]), plt.yticks([])
plt.show()
使用低通滤波器可以达到图像模糊的目的。
去除噪音。其实就是去除图像中的高频成分(比如:噪音,边界)。所以边界也会被模糊一点。也有一些模糊技术不会模糊掉边界。
平滑(模糊)和滤波的区别: 它们都属于卷积,不同滤波方法之间只是卷积核不同(对线性滤波而言)
图像滤波既可以在实域进行,也可以在频域进行。图像滤波可以更改或者增强图像。通过滤波,可以强调一些特征或者去除图像中一些不需要的部分。滤波是一个邻域操作算子,利用给定像素周围的像素的值决定此像素的最终的输出值。图像滤波可以通过公式:
其中K为滤波器,在很多文献中也称之为核(kernel)。常见的应用包括去噪、图像增强、检测边缘、检测角点、模板匹配等。
OpenCV 提供五种常见的图像滤波方式:线性滤波(方框滤波、均值滤波、高斯滤波);非线性滤波(中值滤波、双边滤波)
用 cv2.boxFilter() 函数实现,当可选参数 normalize 为 True 的时候,方框滤波就是均值滤波,上式中的a就等于1/9;normalize 为 False 的时候,a=1,相当于求区域内的像素和。
相关函数:cv2.boxFilter()
import cv2
import random
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('tower.jpg')
# 前面的均值滤波也可以用方框滤波实现:normalize=True
boxFilter = cv2.boxFilter(img, -1, (3, 3), normalize=True)
plt.figure(figsize = (10, 10))
plt.subplot(121),plt.imshow(img),plt.title('Original'),plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(boxFilter),plt.title('boxFilter'),plt.xticks([]), plt.yticks([])
plt.show()
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('tower.jpg')
blur = cv2.blur(img,(5,5))
plt.figure(figsize = (10, 10))
plt.subplot(121),plt.imshow(img),plt.title('Original'),plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(blur),plt.title('Blurred'),plt.xticks([]), plt.yticks([])
plt.show()
中值又叫中位数,是所有数排序后取中间的值。顾名思义就是用与卷积框对应像素的中值来替代中心像素的值。
中值滤波器经常用来去除椒盐噪声。前面的滤波器都是用计算得到的一个新值来取代中心像素的值,而中值滤波是用中心像素周围(也可以使他本身)的值来取代他。他能有效的去除噪声。卷积核的大小也应该是一个奇数。
所以那种孤立的斑点,如0或255很容易消除掉,适用于去除椒盐噪声和斑点噪声。中值是一种非线性操作,效率相比前面几种线性滤波要慢。
在这个例子中,我们给原始图像加上噪声,然后再使用中值滤波去除噪声。
def sp_noise(image,prob):
'''
添加椒盐噪声
prob:噪声比例
'''
output = np.zeros(image.shape,np.uint8)
thres = 1 - prob
for i in range(image.shape[0]):
for j in range(image.shape[1]):
rdn = random.random()
if rdn < prob:
output[i][j] = 0
elif rdn > thres:
output[i][j] = 255
else:
output[i][j] = image[i][j]
return output
import cv2
import random
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('tower.jpg')
# 添加椒盐噪声,噪声比例为 0.02
noise_img = sp_noise(img, prob=0.02)
# 中值滤波
medianBlur = cv2.medianBlur(noise_img,5)
plt.figure(figsize = (15, 10))
plt.subplot(131),plt.imshow(img),plt.title('Original'),plt.xticks([]), plt.yticks([])
plt.subplot(132),plt.imshow(noise_img),plt.title('Noise'),plt.xticks([]), plt.yticks([])
plt.subplot(133),plt.imshow(medianBlur),plt.title('medianBlur'),plt.xticks([]), plt.yticks([])
plt.show()
现在把卷积核换成高斯核(简单来说,方框不变,将原来每个方框的值是相等的,现在里面的值是符合高斯分布的,方框中心的值最大,其余方框根据距离中心元素的距离递减,构成一个高斯小山包。原来的求平均数现在变成求加权平均数,权就是方框里的值)。
不同于均值滤波,高斯滤波的卷积核权重并不相同:中间像素点权重最高,越远离中心的像素权重越小,类似于正态分布。
实现的函数是 cv2.GaussianBlur()。我们需要指定高斯核的宽和高(必须是奇数)。以及高斯函数沿 X,Y 方向的标准差。如果我们只指定了 X 方向的的标准差,Y 方向也会取相同值。如果两个标准差都是 0,那么函数会根据核函数的大小自己计算。高斯滤波可以有效的从图像中去除高斯噪音。
如果你愿意的话,你也可以使用函数 cv2.getGaussianKernel() 自己构建一个高斯核。
import cv2
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('tower.jpg')
# 0 是指根据窗口大小(5,5)来计算高斯函数标准差
GaussianBlur = cv2.GaussianBlur(img,(5,5),0)
plt.figure(figsize = (10, 10))
plt.subplot(121),plt.imshow(img),plt.title('Original'),plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(GaussianBlur),plt.title('GaussianBlur'),plt.xticks([]), plt.yticks([])
plt.show()
模糊操作基本都会损失掉图像细节信息,使用线性滤波器,图像的边缘信息很难保留下来。边缘(edge)信息作为图像中很重要的一个特征,需要被保留,所以这才有了双边滤波。
函数 cv2.bilateralFilter() 能在保持边界清晰的情况下有效的去除噪音。 但是这种操作与其他滤波器相比会比较慢。
我们已经知道高斯滤波器是求中心点邻近区域像素的高斯加权平均值。这种高斯滤波器只考虑像素之间的空间关系,而不会考虑像素值之间的关系(像素的相似度)。所以这种方法不会考虑一个像素是否位于边界。因此边界也会别模糊掉,而这正不是我们想要。
双边滤波同时使用空间高斯权重和灰度值相似性高斯权重。
所以这种方法会确保边界不会被模糊掉,因为边界处的灰度值变化比较大。
import cv2
import random
import numpy as np
from matplotlib import pyplot as plt
img = cv2.imread('Bimodal.jpg')
# 双边滤波
#9 邻域直径,两个 75 分别是空间高斯函数标准差,灰度值相似性高斯函数标准差
bilateralFilter = cv2.bilateralFilter(img,9,75,75)
plt.figure(figsize = (15, 10))
plt.subplot(121),plt.imshow(img),plt.title('Original'),plt.xticks([]), plt.yticks([])
plt.subplot(122),plt.imshow(bilateralFilter),plt.title('bilateralFilter'),plt.xticks([]), plt.yticks([])
plt.show()
http://www.cnblogs.com/wy1996/p/10858376.html
https://zhuanlan.zhihu.com/p/60770435?utm_source=wechat_session&utm_medium=social&utm_oi=825629365701332992
https://blog.csdn.net/jiang_ming_/article/details/82594261