引言
今天学习图像的平滑处理。
本文包括:均值滤波 方框滤波 高斯滤波 中值滤波
本次学习用的图像还是前几篇文章一样的图像。如果大家学习的时候没有文件,随便用几张jpg图片都可以学习,代码都是通用的。
图像准备
在网上没有找到噪声图的资源,我们先自己创造一个噪声图。
原图:bird.jpg
现在需要把这张图加点噪声:
import cv2 #opencv读取BGR文件
import matplotlib.pyplot as plt
import numpy as np
img = cv2.imread('bird.jpg')
img.shape
#对于图像的三个波段,每个波段都找那么1000个点给他赋值255
for r in range(3):
for i in range(1000):
x = np.random.randint(0,427)
y = np.random.randint(0,640)
img[x,y,r] = 255
#出图函数
def cv_show(title,img):
cv2.imshow(title,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
return
cv_show('noise',img)
cv2.imwrite('bird_noise.jpg',img)#保存图片
可以看出图像上多出了很多噪声点,大家如果有自己的资源,也可以用自己的。
现在对此图进行降噪处理。
均值滤波
cv2.blur(src,ksize,anchor,borderType)
src:就是输入的图片矩阵,可以是单通道可以是多通道。
ksize:代表滤波核大小。假设ksize = (3,3)就是对于一个图形矩阵中,以每个像素点为中心,当前3*3范围内的矩阵进行求平均并赋值给该像素点。
anchor: 是锚点,其默认值是(-1,-1),表示当前计算均值的点位于核的中心点位置。该值使用默认值即可,在特殊情况下可以指定不同的点作为锚点。
borderType:是边界样式,该值决定了以何种方式处理边界。一般情况下不需要考虑该值的取值,直接采用默认值即可。
对于边缘的像素点,假设ksize = (3,3)
均值滤波也称为线性滤波,其采用的主要方法为邻域平均法。线性滤波的基本原理是用均值代替原图像中的各个像素值。即每个像素的值都取周围若干各像素点的平均值。若干个取决于你传入的滤波核矩阵的大小
假设ksize = (3,3)
那么每个像素点的值(例如下图中绿色框内的值)就等于红色框区域内9个像素点的均值。
对于边缘区域的像素点,例如下图中绿色框区域,就相当于红色框区域内4个数的均值
上代码:
import cv2 #opencv读取BGR文件
#出图函数
def cv_show(title,img):
cv2.imshow(title,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
return
#读取上文咱们自己搞的噪声图
img = cv2.imread('bird_noise.jpg')
#均值滤波
blur = cv2.blur(img,(5,5))#
cv_show('blur',blur)
出图:
发现噪声点是几乎看不见了,但是图像也变得模糊了起来。均值滤波的特点就是会降低图像的清晰度。滤波核越大,降噪效果越好,但是图像越模糊。
方框滤波
方框滤波的计算方式取决于normalize参数,如果=True,那么他的计算方式就和均值滤波一模一样。如果=False,那么他的计算方式就是求和完了之后不取平均值。如果求和之后超过255那么就取255.
cv2.boxFilter(src,ddepth,ksize,anchor,normalize,borderType)
src:就是输入的图片矩阵,可以是单通道可以是多通道。
ddepth:一般为-1,表示得到的图像通道数和输入的图像保持一致,一般不用改。
ksize:表示滤波核大小。
anchor: 是锚点。
borderType:是边界样式。
normalize: 参数是布尔类型的,表示做不做归一化,归一化就是取平均的意思。如果是True,那么和均值滤波一摸一样,如果是Flase,就表示不做归一化,那如果不做归一化的话,就会出现数值越界的问题。前文说了uint8类型最大值只能是255.如果不取平均值,那结果就会大于255,对于这种情况,方框滤波算法会直接取255作为当前像素点的值。
上代码:
import cv2 #opencv读取BGR文件
def cv_show(title,img):
cv2.imshow(title,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
return
img = cv2.imread('bird_noise.jpg')
#均值滤波
box = cv2.boxFilter(img,-1,(3,3),normalize = False)#我们选择不做归一化
cv_show('box',box)
结果
normalize = False,所以上图中所有像素点的值是由周围像素点求和算出来的,超过255就取255。由于大多数像素点的值都超过了255,所以基本都取255就出现了上图的效果。
高斯滤波
cv2.GaussianBlur( SRC,ksize,sigmaX [,DST [,sigmaY [,borderType ] ] ] )
src :输入图像
ksize :高斯滤波核大小。只能取奇数
sigmaX :X方向上的高斯核标准偏差。
sigmaY : Y方向上的高斯核标准差
如果 sigmaY =0,即不传入参数,那么默认sigmaY = sigmaX
如果sigmaX和Y都=0,那么他们的大小取决于ksize。
和均值滤波不同的是,邻域内不同位置的像素会被赋予不同的权重,而不是直接取平均。这个权重是根据高斯模板来确定的。而高斯模板是通过高斯函数计算出来的。高斯函数就是正态分布函数。
对于正太分布就呈现出中间高两边低的分布特征。放在高斯滤波中就是越靠近像素点的像素点权重越高,越远离像素点的像素点权重越低。
实际操作一下:
import cv2 #opencv读取BGR文件
def cv_show(title,img):
cv2.imshow(title,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
return
img = cv2.imread('bird_noise.jpg')
gauss = cv2.GaussianBlur(img,(3,3),1)#sigmaX和Y都=1
cv_show('Gaussian', gauss)
结果:高斯滤波的效果要比均值滤波效果更好,降噪效果明显且图像更清晰。能够更好地保留图像的灰度分布。
中值滤波
cv2.medianBlur(src,ksize)
src:传入图像
ksize:滤波核大小
中值滤波的原理:
将滤波核内的所有元素进行排序,可以是升序也可以是降序,取中值作为所求像素点的值。
上图中就是红框内的元素排序{2,8,10,34,46,53,64,66,97},取中值就是46,作为所求像素点的值。
上代码:
import cv2 #opencv读取BGR文件
def cv_show(title,img):
cv2.imshow(title,img)
cv2.waitKey(0)
cv2.destroyAllWindows()
return
img = cv2.imread('bird_noise.jpg')
median = cv2.medianBlur(img,3)
cv_show('median',median)
结果:能够较好的消除椒盐噪声,不会使图像产生显著的模糊。椒盐噪声就是离散分布的纯白色或纯黑色的点,本文中的噪声点之所以不是白色或者黑色是因为并不是灰度图而是三个波段融合之后的图像。
那么今天就学到这里