目录
前言
概念介绍
基本原理
Opencv实现中值滤波
Python手写实现均值滤波
参考文章
前言
在此之前,我曾在此篇中推导过图像处理:推导五种滤波算法(均值、中值、高斯、双边、引导)。这在此基础上,我想更深入地研究和推导这些算法,以便为将来处理图像的项目打下基础。
概念介绍
均值滤波是一种简单的图像平滑处理方法,其基本思想是用像素点周围的邻域像素的平均值来代替该像素的值。在图像处理中,均值滤波可以用于去除图像中的噪声,使图像变得更加平滑。它的计算简单易懂,但在滤波过程中可能会导致图像细节的损失。因此,在实际应用中,需要根据具体的情况选择适合的滤波算法。
基本原理
我们以5x5大小为例,均值滤波的原理只需要理解到,它其实是将这个范围内的25个值进行求和的平均值,以这个新值来代替这个区域的中心值。
配合这里的图进行理解:
右图是经过左图进行均值变换后的值。
print((197+25+106+156+159+149+40+107+17+71+163+198+226+223+156+222+37+68+193+157+42+72+250+41+75)/25)
运行之后,获得新值126,覆盖掉中心值得像素226。
对于边缘像素,只仅仅计算在这个范围内得数值。
假如,左上角为中心值,而其左边和上边都没有值,我们只需要计算在这5x5区域内有的值就可以了。
计算如下:
print((23+0+25+158+140+238+67+199+197)/9)
得出新值为116,替换中心点23的值。
Opencv实现中值滤波
def blur(src, ksize, dst=None, anchor=None, borderType=None):
在OpenCV中,我们可以使用cv2.blur()函数来实现均值滤波。在使用该函数时,我们需要输入原始图像、滤波核的大小以及边界样式等参数。一般情况下,我们可以直接采用函数默认值即可。
这里我拿的是我个人的一个使用情况来看待的,像锚点,边界样式这种,我基本上没有遇到要修改的情况,现在我们来看看滤波核的大小对图片的影响。
import cv2
import pyps.pyzjr.utility as zjr
path = 'Images/Colnoiselena.jpg'
img = cv2.imread(path)
imgAverage_1 = cv2.blur(img, (1, 1))
imgAverage_3 = cv2.blur(img, (3, 3))
imgAverage_5 = cv2.blur(img, (5, 5))
imgAverage_7 = cv2.blur(img, (7, 7))
imgStack = zjr.stackImages(0.6, ([imgAverage_1, imgAverage_3], [imgAverage_5, imgAverage_7]))
cv2.imshow("imges",imgStack)
cv2.waitKey(0)
实现效果:
经典的lena的图片,可以看到,随着滤波核的大小逐渐增加,去噪效果越好,但相应的图片会变的模糊,计算时间会增长。所以,还是应了我开头就说过的话,在实际处理中,选择合适的滤波核大小,让模糊与去噪效果之间取得平衡。
pyps并不是什么第三方库,只是我集成在一起的函数文件,你无需在意。
Python手写实现均值滤波
import cv2
import numpy as np
import pyps.pyzjr.utility as zjr
path = 'Images/Colnoiselena.jpg'
img = cv2.imread(path)
def Arerage_Filtering(img, k_size=3):
if k_size % 2 == 0:
k_size += 1
rows, cols = img.shape[:2]
pad_width = (k_size - 1) // 2
img_pad = cv2.copyMakeBorder(img, pad_width, pad_width, pad_width, pad_width, cv2.BORDER_REPLICATE)
img_filter = np.zeros_like(img)
for i in range(rows):
for j in range(cols):
pixel_values = img_pad[i:i+k_size, j:j+k_size].flatten()
img_filter[i, j] = np.mean(pixel_values)
return img_filter
imgAverage_1 = Arerage_Filtering(img,k_size=1)
imgAverage_3 = Arerage_Filtering(img,k_size=3)
imgAverage_5 = Arerage_Filtering(img,k_size=5)
imgAverage_7 = Arerage_Filtering(img,k_size=7)
imgStack = zjr.stackImages(0.6, ([imgAverage_1, imgAverage_3], [imgAverage_5, imgAverage_7]))
cv2.imshow("imges",imgStack)
cv2.waitKey(0)
cv2.destroyAllWindows()
这个算法相对来说比较容易实现,但是相比调用OpenCV的函数,它的计算时间要长很多,而且我这里还只考虑了图像的两个通道,最终输出的结果是灰度图的情况下。
下面是这个函数的具体实现过程:
- 首先,判断卷积核的大小是否为奇数,如果为偶数,则将其加1,确保其大小为奇数。
- 获取图像的行数和列数。
- 计算填充的宽度,即卷积核宽度的一半,用于处理图像边缘。
- 使用cv2.copyMakeBorder函数进行边缘填充,将图像的边缘复制并填充到周围,以防止边缘像素点无法进行卷积。
- 初始化一个和原始图像大小一样的零矩阵。
- 遍历图像中的每一个像素点,计算该像素点周围邻域内的像素值,并求取其平均值,然后将其赋值给零矩阵中的对应像素点。
- 返回处理后的图像。
最后,函数通过stackImages函数将处理后的四张图像以2x2的网格形式拼接成一张图像,并展示结果。
参考文章
(6条消息) 图像处理:推导五种滤波算法(均值、中值、高斯、双边、引导)_高斯滤波,均值滤波,中值滤波_夏天是冰红茶的博客-CSDN博客
(6条消息) 均值滤波(Mean filtering)_半濠春水的博客-CSDN博客
(7条消息) Opencv之图像滤波:2.均值滤波(cv2.blur)_Justth.的博客-CSDN博客