python 滤波_均值高斯最大最小滤波原理及python实现

笔记:常用的图像滤波方法以及python实现,包括:均值滤波、高斯滤波、最大值滤波、最小值滤波。

之前写过一篇图像增强的文章,但是最后得到的增强结果包含很多噪声点(某师兄指出的)。所以今天来用滤波算法去除噪声。

图像的噪声来源有很多,比如成像设备的电子器件老化,或者拍摄环境中有外界因素干扰。一种简单的从图像去除噪声的方式就是进行“滤波”!

opencv已经提供了封装好的滤波方式,但是为了自己更好的理解各种算法,还是应该自己动手实现一次。所以笔记一方面对滤波算法的原理进行分析,另一方面给出了python实现代码(代码没有优化过,还是普通的双层循环,这样更直接)。

笔记分为以下几个部分:

1、均值滤波及其python实现

2、高斯滤波及其python实现

3、最大值滤波与最小值滤波及其python实现

第1节:均值滤波及其python实现

“均值”这个词表示对一些数求和,那么对于图像来说,“数”就是亮度值,“一些数”就是“一块小区域”(比如足球场中的一个足球)。这篇笔记不涉及什么是卷积核了,相信读者已经知道了这种基本知识。下面给出了均值滤波的卷积核内容:

假设这个卷积核与一个3x3的区域相乘,实际上就是实现了求和再均值功能。假设一个图片中的足球正好需要3x3=9个像素进行表示,那么通过与kernel卷积就导致这9个像素都趋于平滑,也就是说某个像素点将会被周围8个像素点“平均”。

对于图像来说,只需要遍历所有的像素点(或称为卷积核大小的区域),然后分别和卷积核kernel进行乘法加权就可以了。

from PIL import Image

import numpy as np

import matplotlib.pyplot as plt

dark_image = np.array(Image.open("dark.jpg").resize((500,700),Image.ANTIALIAS))

gama_image = (dark_image.astype(np.float32)/255)**0.25

def median(image):

"""median filter for a single RGB imageArgs:image:RGB imageReturns:filterd image"""

mean_image = np.zeros(shape=image.shape, dtype=np.float32)

for i in range(image.shape[0]):

for j in range(image.shape[1]):

for k in range(image.shape[2]):

mean_image[i][j][k] = np.mean(image[i:i+2,j:j+2,k])

return mean_image

plt.figure(figsize=(10,10))

plt.subplot(1,3,1)

plt.imshow(dark_image/255)

plt.subplot(1,3,2)

plt.imshow(gama_image)

mean_image=median(gama_image)

plt.subplot(1,3,3)

plt.imshow(mean_image)

上述代码读取了dark图片,然后进行伽马变换(前面的笔记),通过均值滤波得到了下面的结果:

可以看出,第一张dark图片经过伽马变换得到的第二张图片显然存在噪声点(不是椒盐噪声,尽管看起来黑色像素点有点像椒噪声),经过均值滤波以后明显噪声变少了。

为什么呢?我个人理解,噪声点就是“孤立点”,比如噪声周围的像素值都是76,但是噪声值为10,也就是说这个噪声点是黑色的,那么怎么让它接近76呢?使用周围8个76的点对它进行平均就可以了。平均的意思就是重新赋值:value(noise)=(8*76+10)/9=68.7,这样噪声点就不“孤立”了!它和周围的像素点值很接近了,以至于肉眼已经无法观察到它。

第2节:高斯滤波及其python实现

高斯这个名字真的是伴随我们走过好多年啊!

均值滤波导致一个像素会被周围的8个像素“平均”,比如上一节的公式value(noise)=(8*76+10)/9=68.7。仔细想一下,这个点如果不是噪声点,而是一个边缘,那么是不是就造成了它被“过度”平均了!所以说,需要进行“加权”,让中心像素的权重大一些,周围像素的权重小一些。由于这个核的数值比较多,我就直接从代码里面截图了:

没错,这个就是服从高斯分布的卷积核,可以想象一下高斯分布的形状,就是中间高两边低。这个卷积核最后要除以273(卷积核所有的数值相加等于273),但是我没写,因为最后计算均值的时候除以就行了。

show me code !!!

import cv2

import numpy as np

star_rgb = cv2.imread("lena.jpg")

star_gray = cv2.cvtColor(star_rgb, cv2.COLOR_BGR2GRAY)

def gaussian(image):

"""

Gaussian filter for a RGB image

Args:

image:RGB image

Returns:

filtered image

"""

gaussian_image = np.zeros(shape=image.shape, dtype=np.float32)

gaussian_kernel = np.array([[1, 4, 7, 4, 1],

[4, 16, 26, 16, 4],

[7, 26, 41, 26, 7],

[4, 16, 26, 16, 4],

[1, 4, 7, 4, 1]], dtype=np.float32)

gaussian_kernel = gaussian_kernel / gaussian_kernel.sum()

for i in range(image.shape[0]-5):

for j in range(image.shape[1]-5):

gaussian_image[i+2, j+2] = np.sum(image[i:i+5, j:j+5]*gaussian_kernel)

return gaussian_image.astype(np.uint8)

std_gaussian_star = cv2.GaussianBlur(src=star_gray, ksize=(5, 5), sigmaX=0)

gaussian_star = gaussian(star_gray)

cv2.imshow("original star", star_gray)

cv2.imshow("my gaussian star", gaussian_star)

cv2.imshow("cv2 gaussian star", std_gaussian_star)

cv2.waitKey(0)

为了比较一下自己的实现和opencv的标准实现的差异,调用了GaussianBlur函数进行对比,没使用自己的图是因为自己那张图的噪声不明显,结果如下:

第一张是原始噪声图,第二张是自己的滤波结果,第三张是cv2标准函数的结果,视觉上效果差不多,说明实现没问题。

第3节:最大值滤波与最小值滤波及其python实现

前面两个都是线性滤波器,所谓线性就是“线性求和”,用求和的均值来代替原始像素值。那么,有没有非线性的形式呢?最大值和最小值滤波就是这个思路,不进行求和操作。

还是以足球为例,比如3x3的足球中心像素点是噪声,能不能不通过和周围像素值进行平均的方式去掉它?最值滤波(最大值和最小值的统称)提出使用最值来代替中心值。如果采用最大值代替中心值,那么就会导致中心值更亮;如果采用最小值代替中心值,就会导致中心值偏暗。

按照我的理解:如果噪声是椒噪声(黑色,亮度低)就要使用最大值代替中心值;如果噪声是盐噪声(白色,亮度高)就要使用最小值代替中心值。

最大值滤波的代码如下,最小值滤波只需要把nm.max()换成np.min()就好了:

from PIL import Image

import numpy as np

import matplotlib.pyplot as plt

dark_image = np.array(Image.open("dark.jpg").resize((500,700),Image.ANTIALIAS))

gama_image = (dark_image.astype(np.float32)/255)**0.25

def max_box(image):

mean_image = np.zeros(shape=image.shape, dtype=np.float32)

for i in range(image.shape[0]):

for j in range(image.shape[1]):

for k in range(image.shape[2]):

mean_image[i][j][k] = np.max(image[i:i+3,j:j+3,k])

return mean_image

plt.figure(figsize=(10,10))

plt.subplot(1,3,1)

plt.imshow(dark_image/255)

plt.subplot(1,3,2)

plt.imshow(gama_image)

mean_image=max_box(gama_image)

plt.subplot(1,3,3)

plt.imshow(mean_image)

plt.show())

还是使用之前的照片为例,第一张是原图,第二张是伽马变换以后的结果,第三张是去噪以后的结果显然效果好些了,噪声点变少了。(噪声主要集中在左下方):

总结一下:需要知道噪声类型才能确定使用何种滤波。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值