第三章 空域图像增强_空域平滑
第三章 空域图像增强_空域平滑
1. 空域滤波概述
前言
一、开篇思考:为什么需要“参考邻居”处理图像?
我们拍照片时,常会遇到这些问题:照片有斑点噪点、画面模糊看不清边缘、细节被遮挡。单独调整某个像素的亮度或颜色,往往解决不了这些问题——就像生活中判断一件事需要参考周围情况,处理图像像素时,也得看看它周围的邻居像素 ,这就是邻域运算的核心逻辑。


简单说,邻域运算 就是以 某个像素 为中心,选取它周围一定范围的像素组成 邻域窗口,通过计算 窗口内像素的信息 来 更新中心像素,最终达到降噪、锐化、增强细节等效果。
二、核心概念:
上面的邻域运算概念中,涉及了一些核心概念,接下来,我们一一介绍,掌握这些概念,对理解邻域运算有很大帮助。:+1
1.邻域:
以目标像素为中心,其周围一定范围内的所有像素集合,是邻域运算的基础范围。

就上图而言,邻域指的就是8邻域
2. 邻域窗口
想象在图像上放一个“小方格”,方格中心对准目标像素,方格内的所有像素就是这个目标像素的“邻居”。常见的窗口大小有3×3(中心像素+周围8个像素)、5×5等,就像用不同大小的放大镜观察像素的周边环境。

这个窗口有不同的形式,常用的:3×3、5×5、7×7、9×9等,一般是(2a+1)×(2b+1),a、b为正整数,如果a,b=1,则窗口大小为3×3,如果a,b=2,则窗口大小为5×5,以此类推。
这个模板一般在不同的文献中叫法不一样,有的叫滤波核,有的叫掩模,有的叫模板,有的叫卷积核,还有叫滤波窗口。
3. 运算核心
对窗口内的像素进行计算(如求平均、找中间值、加权求和),用计算结果替换原来的中心像素值。不同的计算方式,对应不同的处理效果。

4.中心像素
邻域窗口的核心像素,邻域运算的最终处理对象(用窗口计算结果更新该像素值)。
上图中R0
4.空间域
图像像素所在的二维平面,邻域运算直接在此区域内操作像素,无需域转换。
就是上图的X轴和Y轴组成的二维平面
三、两大经典应用:从降噪到锐化
3.1.平滑滤波:给图像“磨皮降噪”
1. 适用场景
解决照片中的斑点噪点(如夜景照片的颗粒感、老照片的杂点),让画面更柔和。

2. 常见类型
均值滤波:最基础的平滑方法。计算窗口内所有像素的灰度平均值,用平均值替换中心像素。
- 类比:班级里求平均分,用平均分代表中心像素的“水平”,能快速弱化噪点,但会让画面轻微模糊。
高斯滤波:对均值滤波的改进,用高斯函数对窗口内像素的灰度值进行加权平均,用加权平均值替换中心像素。
- 类比:班级里用高斯函数对每个同学的分数进行加权平均,能更精准地代表班级水平,但计算量更大。

阈值邻域平滑滤波:就是将原有像素点的灰度值和均值滤波后的灰度值进行比较,如果灰度值之差小于一个阈值,认为当前像素不是噪点, 否则认为是噪点,用均值滤波后的灰度值替换当前像素的灰度值。
- 类比:班级里,如果一个同学的分数和班级平均分之差小于一个阈值,认为该同学不是“保守学生”,否则认为该同学是“保守学生”,“保守学生”的分数用班级平均分替换。
中值滤波:对窗口内的像素灰度值排序,取中间值替换中心像素。
- 类比:评选班级中等水平的同学,能精准去除“椒盐噪点”(画面中突兀的黑白小点),且比均值滤波更能保留图像细节。
3. 生活案例
把有很多雀斑的照片用中值滤波处理,雀斑(噪点)会消失,同时人脸的轮廓、五官细节不会明显模糊。
3.2 锐化滤波:给图像“加深轮廓”
- 适用场景
解决画面模糊问题(如手抖拍摄的照片),增强物体边缘细节,让图像更清晰。

- 常见类型
- 拉普拉斯算子:通过计算窗口内像素的灰度差异,突出中心像素与周围像素的对比,从而强化边缘。
- 类比:让班级里成绩好的同学更突出、成绩差的更明显,放大差异感,让边缘“更立体”。
- Sobel算子:分别对图像的水平方向和垂直方向计算灰度变化,精准捕捉水平边缘(如地平线)和垂直边缘(如门框)。
- 生活案例
把模糊的文字照片用拉普拉斯算子处理,文字的笔画边缘会变清晰,更容易识别;处理风景照时,山脉、建筑的轮廓会更突出。
2. 空域滤波的实现 ❤️
前言
均值滤波就是对窗口内所有像素的灰度值求平均,用平均值替换中心像素。一般滤波核有多重形式,如4邻域和8邻域,见教材62面。
1.准确工作,定义方法处理图片
# 用均值滤波、中值滤波、高斯滤波处理高斯噪声和椒盐噪声
import matplotlib.pyplot as plt
import cv2
import numpy as np
import random
# from ImageAddNoise import *
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负
# 添加高斯噪声
def addGaussianNoise(src,mu,sigma):
NoiseImg=src.copy()
NoiseImg=NoiseImg/NoiseImg.max()
rows,cols=NoiseImg.shape[:2]
for i in range(rows):
for j in range(cols):
#python里使用random.gauss函数加高斯噪声
NoiseImg[i,j]=NoiseImg[i,j]+random.gauss(mu,sigma)
# NoiseImg[i,j]=NoiseImg[i,j]+np.random.normal(mu,sigma)
if NoiseImg[i,j]< 0:
NoiseImg[i,j]=0
elif NoiseImg[i,j]>1:
NoiseImg[i,j]=1
NoiseImg=np.uint8(NoiseImg*255)
return NoiseImg
#给图像添加椒盐噪声
def addSaltAndPepper(src, percentage):
#NoiseImg = src #使用此语句传递的是地址,程序会出错
NoiseImg = src.copy() #在此要使用copy函数,否则src和主程序中的img都会跟着改变
NoiseNum = int(percentage * src.shape[0] * src.shape[1])
for i in range(NoiseNum):
randX = random.randint(0, src.shape[0] - 1) #产生[0, src.shape[0] - 1]之间随机整数
randY = random.randint(0, src.shape[1] - 1)
if random.randint(0, 1) == 0:
NoiseImg[randX, randY] = 0
else:
NoiseImg[randX, randY] = 255
return NoiseImg2. 核心代码
# 均值滤波处理高斯噪声
import matplotlib.pyplot as plt
import cv2
import numpy as np
import random
# from ImageAddNoise import *
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负
img = cv2.imread(r"./img/train1.jpg",0)
ImgGuassNoise = addGaussianNoise(img,0,0.1) #添加0均值,0.2方差的高斯分布噪声
imgAver3=cv2.blur(ImgGuassNoise,(3,3)) #使用table或者shift+table帮助查看参数形式
imgAver7=cv2.blur(ImgGuassNoise,(7,7))
plt.figure(figsize=(8,5))
plt.subplot(221)
plt.imshow(img,cmap='gray')
plt.title("原图")
plt.axis('off') #不显示坐标轴
plt.subplot(222)
plt.imshow(ImgGuassNoise,cmap='gray')
plt.title("加高斯噪声图像")
plt.axis('off') #不显示坐标轴
plt.subplot(223)
plt.imshow(imgAver3,cmap='gray')
plt.title("3x3均值滤波")
plt.axis('off') #不显示坐标轴
plt.subplot(224)
plt.imshow(imgAver7,cmap='gray')
plt.title("7x7均值滤波")
plt.axis('off') #不显示坐标轴
# plt.show()
plt.savefig("ch03-28-blur.jpg")3. 运行效果👇


从图片中可以看到,均值滤波对高斯噪声的图片有明细的降低噪声的效果,但是同时也模糊了,且滤波核越大,越模糊,
均值滤波对对椒盐噪声的处理效果并不理想。
均值滤波就是对窗口内所有像素的灰度值求平均,用平均值替换中心像素,这样不能体现邻域中各个像素的重要程度。
加权的平滑滤波核中比较常用的是高斯滤波,其核心思想是:
对窗口内像素的灰度值进行加权平均,用加权平均值替换中心像素。常见的有

前置代码是上一节的准备工作代码
# 高斯滤波处理高斯噪声
import matplotlib.pyplot as plt
import cv2
import numpy as np
import random
# from ImageAddNoise import *
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负
img = cv2.imread(r"./img/train1.jpg",0) #打开图片,0表示读取灰度图像
ImgGuassNoise = addGaussianNoise(img,0,0.1) #添加0均值,0.2方差的高斯分布噪声
imgAverG=cv2.GaussianBlur(ImgGuassNoise,(5,5),1) #高斯滤波,参数为(5,5),sigma=1,表示滤波核大小为5x5,sigma表示高斯函数的标准差,越大越模糊
plt.figure(figsize=(12,5))
plt.subplot(131)
plt.imshow(img,cmap='gray')
plt.title("原图")
plt.axis('off') #不显示坐标轴
plt.subplot(132)
plt.imshow(ImgGuassNoise,cmap='gray')
plt.title("加高斯噪声图像")
plt.axis('off') #不显示坐标轴
plt.subplot(133)
plt.imshow(imgAverG,cmap='gray')
plt.title("5x5高斯滤波")
plt.axis('off') #不显示坐标轴
# plt.show()
plt.savefig("ch03-29-gaussianBlur.jpg")
阈值邻域平滑滤波:就是将原有像素点的灰度值和均值滤波后的灰度值进行比较,如果灰度值之差小于一个阈值,认为当前像素不是噪点, 否则认为是噪点,用均值滤波后的灰度值替换当前像素的灰度值。
- 类比:班级里,如果一个同学的分数和班级平均分之差小于一个阈值,认为该同学不是“保守学生”,否则认为该同学是“保守学生”,“保守学生”的分数用班级平均分替换。
前置代码是上一节的准备工作代码
# 阈值邻域平滑滤波和均值滤波
import matplotlib.pyplot as plt
import cv2
import numpy as np
import random
# from ImageAddNoise import *
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负
#阈值均值平滑滤波
def threshAverFilter(imgNoise,T):
imgAver=cv2.blur(imgNoise,(5,5))
row,col=imgNoise.shape
imgThresh=np.zeros((row,col))
for i in range(row):
for j in range(col):
if np.abs(imgNoise[i,j]-imgAver[i,j])>T:
imgThresh[i,j]=imgAver[i,j]
else:
imgThresh[i,j]=imgNoise[i,j]
return imgThresh
img = cv2.imread(r"./img/lena.jpg",0)
imgNoise=addSaltAndPepper(img, 0.1) #添加0.1%的椒盐噪声
imgAver=cv2.blur(imgNoise,(5,5)) #均值滤波 5x5
imgThresh1=threshAverFilter(imgNoise,0) #阈值均值平滑滤波,T=0
imgThresh2=threshAverFilter(imgNoise,30) #阈值均值平滑滤波,T=30
imgThresh3=threshAverFilter(imgNoise,255) #阈值均值平滑滤波,T=255
plt.figure(figsize=(12,7))
plt.subplot(231)
plt.imshow(img,cmap='gray')
plt.title("原图")
plt.axis('off') #不显示坐标轴
plt.subplot(232)
plt.imshow(imgNoise,cmap='gray')
plt.title("加椒盐噪声图像")
plt.axis('off') #不显示坐标轴
plt.subplot(233)
plt.imshow(imgAver,cmap='gray')
plt.title("5x5均值滤波")
plt.axis('off') #不显示坐标轴
plt.subplot(234)
plt.imshow(imgThresh1,cmap='gray')
plt.title("T=0的阈值邻域平滑滤波")
plt.axis('off') #不显示坐标轴
plt.subplot(235)
plt.imshow(imgThresh2,cmap='gray')
plt.title("T=30的阈值邻域平滑滤波")
plt.axis('off') #不显示坐标轴
plt.subplot(236)
plt.imshow(imgThresh3,cmap='gray')
plt.title("T=255的阈值邻域平滑滤波")
plt.axis('off') #不显示坐标轴
# plt.show()
plt.savefig("ch03-29-thresh.jpg")
从上图可知: 👇
当阈值T=0的时候,算法认为所有的像素点都是噪声点,所有点都会取均值滤波后的灰度值,这时候算法退化为均值滤波,
当阈值T=255的时候,算法认为所有的像素点都是非噪声点,所有点都会取原有像素点的灰度值,这时候算法退化为不做任何处理。
当阈值T=30的时候,与均值滤波的结果比较,可以看到,噪声点被平滑掉了,去噪效果明显改善。
- 中值滤波:对窗口内的像素灰度值排序,取中间值替换中心像素。
- 类比:评选班级中等水平的同学,能精准去除“椒盐噪点”(画面中突兀的黑白小点),且比均值滤波更能保留图像细节。
前置代码是上一节的准备工作代码
# 中值滤波处理高斯噪声
import matplotlib.pyplot as plt
import cv2
import numpy as np
import random
# from ImageAddNoise import *
plt.rcParams['font.sans-serif']=['SimHei'] #用来正常显示中文标签
plt.rcParams['axes.unicode_minus']=False #用来正常显示负
img = cv2.imread(r"./img/train1.jpg",0)
imgNoise = addSaltAndPepper(img, 0.1) #添加0均值,0.2方差的高斯分布噪声
imgAver=cv2.blur(imgNoise,(5,5)) #均值滤波 5x5
imgMedian=cv2.medianBlur(imgNoise,5) #中值滤波 5x5
plt.figure(figsize=(10,6))
plt.subplot(141) # 1行4列,第一个图
plt.imshow(img,cmap='gray')
plt.title("原图")
plt.axis('off') #不显示坐标轴
plt.subplot(142)# 1行4列,第二个图
plt.imshow(imgNoise,cmap='gray')
plt.title("加椒盐噪声图像")
plt.axis('off') #不显示坐标轴
plt.subplot(143)
plt.imshow(imgAver,cmap='gray')
plt.title("5x5均值滤波")
plt.axis('off') #不显示坐标轴
plt.subplot(144)
plt.imshow(imgMedian,cmap='gray')
plt.title("5x5中值滤波")
plt.axis('off') #不显示坐标轴
# plt.show()
plt.savefig("ch03-34-Median.jpg")
相比均值会产生模糊,中值滤波在去除校验噪声的时候,模糊程度较轻
试试中值滤波处理高斯噪声,效果如何?
3. 边界处理
前言
当模板滑动到图像边界时,可能会因缺少邻域像素,而使邻域运算无法顺利进行。

解决方法:
扩展:在滤波操作开始之前,先增加边缘像素,确保图像的边缘能被处理.
若原图像大小AxB,滤波核大小为CxD,则图像至少要扩展为:(A+C-1)x(B+D-1)

还原大小:在滤波处理之后再去掉这些边缘,还原成原图像大小。
扩展边缘像素方法有:
- 常量法(BORDER_CONSTANT): 用常数值填充边界
- 复制法(BORDER_REFLICATE): 用最临近的像素值填充边界
- 反射法(BORDER_REFLECT): 用边界像素的对称值填充边界
- 外包装法(BORDER_WRAP): 用边界像素的镜像值填充边界
