目录
[核心函数:filter2D 自定义卷积](#核心函数:filter2D 自定义卷积)
[官方封装:cv2.blur 均值模糊](#官方封装:cv2.blur 均值模糊)
[二、高斯滤波 GaussianBlur(通用平滑降噪)](#二、高斯滤波 GaussianBlur(通用平滑降噪))
[三、中值滤波 medianBlur(专门去除椒盐噪点)](#三、中值滤波 medianBlur(专门去除椒盐噪点))
[四、双边滤波 bilateralFilter(美颜磨皮,模糊同时保留边缘)](#四、双边滤波 bilateralFilter(美颜磨皮,模糊同时保留边缘))
上一章我们搞懂图像底层原理,掌握了通道拆分合并、深浅拷贝,学会直接操作图片像素。真实拍摄的照片往往带有噪点、颗粒杂色,这时就需要图像滤波做降噪平滑处理。滤波是图像预处理非常关键的一环,很多边缘检测、目标识别算法之前,都要先做降噪。
本章学习卷积基础,以及4种常用滤波:均值卷积、高斯滤波、中值滤波、双边滤波,结合完整示例代码,理解不同滤波适用场景。
一、什么是图像滤波与卷积
通俗理解
滤波就好比给照片做美颜磨皮。利用一个小矩阵(卷积核)在图片上逐像素滑动,把周边相邻像素做加权计算,输出新像素值,实现降噪、模糊、锐化、浮雕等效果。
- 模糊降噪:把相邻像素做平均,消除细碎噪点;
- 锐化:强化像素差异,让轮廓更清晰;
注意:卷积核尺寸几乎都要求 奇数(3×3、5×5),保证有一个中心点对齐像素。
核心函数:filter2D 自定义卷积
cv2.filter2D(src, ddepth, kernel)
- src:输入图像
- ddepth:输出图像深度,填
-1代表和原图保持一致 - kernel:卷积核,numpy数组,float32类型
python
# opencv滤波器卷积.py
import cv2
import numpy as np
读取图片,失败时给出友好提示并退出
img = cv2.imread(r'D:\PYTHON\your name.jpg')
if img is None:
print("图片读取失败,请检查文件路径是否正确")
exit()
1. 均值模糊卷积核:5*5全部为1,求像素平均值
kernel_avg = np.ones((5, 5), np.float32) / 25
res_avg = cv2.filter2D(img, -1, kernel_avg)
2. 锐化卷积核:增强图片轮廓
kernel_sharp = np.array([[0, -1, 0],
[-1, 5, -1],
[0, -1, 0]])
res_sharp = cv2.filter2D(img, -1, kernel_sharp)
3. 浮雕效果:适合灰度图使用
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
kernel_relief = np.array([[-2, 1, 0],
[-1, 1, 1],
[0, 1, 2]])
res_relief = cv2.filter2D(gray_img, -1, kernel_relief)
浮雕卷积核未归一化,结果可能超出0-255,用clip截断避免大片全白/全黑
res_relief = np.clip(res_relief, 0, 255).astype(np.uint8)
显示原图与各滤波效果
cv2.imshow('原图', img)
cv2.imshow('均值模糊', res_avg)
cv2.imshow('锐化效果', res_sharp)
cv2.imshow('浮雕(灰度)', res_relief)
循环等待按键,按 q 或 Esc 退出
while True:
key = cv2.waitKey(10)
if key == ord('q') or key == 27:
break
cv2.destroyAllWindows()
cv2.waitKey(1)
小提示:浮雕卷积核未归一化,运算后像素可能超出 0-255 范围,建议用
np.clip(res_relief, 0, 255).astype(np.uint8)截断像素区间,避免画面出现大片全白或全黑。
filter2D可以自由自定义卷积核,想实现特殊图片效果优先用这个函数。OpenCV也封装好了常用滤波API,不用手写卷积核。
补充:均值模糊 OpenCV 内置封装函数 cv2.blur(img,(5,5)),等价于手写 np.ones((5,5),np.float32)/25 卷积核。
官方封装:cv2.blur 均值模糊
上面手写了 5×5 均值卷积核,其实 OpenCV 已经封装好了均值模糊函数 cv2.blur(src, ksize),效果和手写卷积核完全一致,日常开发直接用这个内置 API 更省事。
- src:输入图像
- ksize:卷积核大小,奇数元组,例如
(5,5)
python
# opencv均值模糊.py
import cv2
读取图片,失败时给出友好提示并退出
img = cv2.imread(r'D:\PYTHON\your name.jpg')
if img is None:
print("图片读取失败,请检查文件路径是否正确")
exit()
官方封装均值模糊,5×5卷积核,等价于手写 np.ones((5,5),np.float32)/25
res = cv2.blur(img, (5, 5))
显示原图与均值模糊结果
cv2.imshow('原图', img)
cv2.imshow('均值模糊结果', res)
循环等待按键,按 q 或 Esc 退出
while True:
key = cv2.waitKey(10)
if key == ord('q') or key == 27:
break
cv2.destroyAllWindows()
cv2.waitKey(1)
小提示:
cv2.blur内部就是均值卷积,适合快速做基础降噪;需要自定义卷积核效果时再用filter2D。
二、高斯滤波 GaussianBlur(通用平滑降噪)
高斯滤波是日常最常用的平滑降噪工具。离中心点越近像素权重越高,越远权重越低,模拟正态分布做模糊。
- 参数:
cv2.GaussianBlur(原图, ksize, sigmaX) - ksize:卷积核,必须是奇数元组,例如
(5,5) - sigmaX:X方向标准差,数值越大,图片越模糊。sigmaX=0会根据ksize自动计算。
python
# opencv高斯滤波.py
import cv2
读取图片,失败时给出友好提示并退出
img = cv2.imread(r'D:\PYTHON\your name.jpg')
if img is None:
print("图片读取失败,请检查文件路径是否正确")
exit()
高斯滤波,5×5卷积核,sigmaX=0自动计算
res = cv2.GaussianBlur(img, (5, 5), sigmaX=0)
显示原图与高斯滤波结果
cv2.imshow('原图', img)
cv2.imshow('高斯滤波结果', res)
循环等待按键,按 q 或 Esc 退出
while True:
key = cv2.waitKey(10)
if key == ord('q') or key == 27:
break
cv2.destroyAllWindows()
cv2.waitKey(1)
适用场景:普通照片颗粒噪点,图像预处理,为后续边缘检测做平滑。
不适合:椒盐噪点(黑白斑点),高斯只会把斑点变模糊,不能消除。
三、中值滤波 medianBlur(专门去除椒盐噪点)
读者手上不一定有带椒盐噪点的图片,这里先用代码给原图随机撒上黑白斑点,再分别用高斯和中值滤波处理,直观对比两种滤波对椒盐噪点的去噪效果。
python
# opencv椒盐噪声模拟.py
import cv2
import numpy as np
读取图片,失败时给出友好提示并退出
img = cv2.imread(r'D:\PYTHON\your name.jpg')
if img is None:
print("图片读取失败,请检查文件路径是否正确")
exit()
模拟椒盐噪声,生成带黑白斑点图片,方便测试中值滤波
def add_salt_pepper_noise(image, rate=0.04):
img = image.copy()
row, col, ch = img.shape
num = int(rate * row * col)
# 随机撒白点
for _ in range(num):
x = np.random.randint(0, col)
y = np.random.randint(0, row)
img[y, x] = 255
# 随机撒黑点
for _ in range(num):
x = np.random.randint(0, col)
y = np.random.randint(0, row)
img[y, x] = 0
return img
生成椒盐噪声图
noise_img = add_salt_pepper_noise(img)
显示椒盐噪声图
cv2.imshow("椒盐噪声图", noise_img)
循环等待按键,按 q 或 Esc 退出
while True:
key = cv2.waitKey(10)
if key == ord('q') or key == 27:
break
cv2.destroyAllWindows()
cv2.waitKey(1)
运行后可以看到:高斯滤波把黑白斑点糊成一片灰蒙蒙的痕迹,斑点依然可见;中值滤波则能基本还原干净画面,这正是椒盐噪点场景优先选择medianBlur的原因。
椒盐噪点:图像随机出现白点、黑点,类似撒上胡椒盐。
中值滤波取卷积范围内像素的中位数代替当前像素,噪点这种极端黑白值会直接被丢弃。
注意:ksize参数直接填整数,不是元组,且必须为奇数。
python
# opencv中值滤波.py
import cv2
读取图片,失败时给出友好提示并退出
img = cv2.imread(r'D:\PYTHON\your name.jpg')
if img is None:
print("图片读取失败,请检查文件路径是否正确")
exit()
中值滤波,核大小5
img_median = cv2.medianBlur(img, 5)
显示原图与中值滤波结果
cv2.imshow('原图', img)
cv2.imshow('中值滤波结果', img_median)
循环等待按键,按 q 或 Esc 退出
while True:
key = cv2.waitKey(10)
if key == ord('q') or key == 27:
break
cv2.destroyAllWindows()
cv2.waitKey(1)
适用场景:椒盐噪点(黑白斑点噪声)。
缺点:会抹除一部分图片细节。
四、双边滤波 bilateralFilter(美颜磨皮,模糊同时保留边缘)
普通高斯滤波会连同物体边缘一起糊掉。双边滤波同时参考像素空间距离 + 像素颜色相似度。颜色差异大的边缘位置不会做过度模糊,颜色接近的区域做平滑,这就是美颜磨皮底层原理。
函数:cv2.bilateralFilter(src, d, sigmaColor, sigmaSpace)
- d:卷积核直径。特殊规则:d≤0 时,d 会由 sigmaSpace 自动计算,实际开发经常直接写 d=0,让 OpenCV 自动决定核大小。
- sigmaColor:色彩标准差,越大越多颜色被认为相近,模糊越强
- sigmaSpace:空间标准差,越大更远像素参与计算
小提示:d 设置为小于等于 0 时,会依据 sigmaSpace 自动推算卷积核直径,项目中经常直接写 d=0。
python
# opencv双边滤波.py
import cv2
img = cv2.imread(r'D:\PYTHON\your name.jpg')
if img is None:
print("图片读取失败,请检查路径")
exit()
双边滤波,模拟美颜效果
res = cv2.bilateralFilter(img, 9, 75, 75)
cv2.imshow('原图', img)
cv2.imshow('双边滤波美颜效果', res)
while 1:
key = cv2.waitKey(10)
if key == ord('q') or key == 27:
break
cv2.destroyAllWindows()
cv2.waitKey(1)
适用:人像照片磨皮,希望降噪同时保留物体轮廓边缘。
注意:双边滤波运算量大,相比高斯滤波运行速度更慢。
五、四种滤波对比与选型指南
四种滤波的计算速度大致为:均值模糊(cv2.blur)> 高斯滤波 > 中值滤波 > 双边滤波。均值和高斯都是线性卷积,OpenCV 底层做了高度优化,速度最快;中值滤波需要逐窗口排序取中位数,开销明显更高;双边滤波要同时计算空间距离和颜色相似度,计算量最大,速度最慢。
选型建议:在 CPU 上处理单张图片时,优先考虑效果,双边滤波可以放心用;但在嵌入式设备或需要实时处理视频的场景,双边滤波很容易成为性能瓶颈,建议改用高斯滤波或均值模糊,或适当调小 d、sigma 参数。若既要保留边缘又要控制耗时,可先用高斯滤波降噪,再配合边缘检测或锐化来补偿细节。
| 滤波类型 | 函数 | 典型参数示例 | 计算复杂度 | 特点 | 适合场景 |
|---|---|---|---|---|---|
| 自定义卷积 filter2D | filter2D | kernel = np.ones((5,5), np.float32)/25 | O(N×K²),K为核大小 | 自由手写卷积核,模糊/锐化/浮雕均可 | 需要自定义特殊图像效果 |
| 均值模糊 blur | cv2.blur | ksize=(5,5) | O(N×K²),线性卷积,底层高度优化 | 简单平均,平滑模糊 | 快速基础降噪 |
| 高斯滤波 GaussianBlur | GaussianBlur | ksize=(5,5),sigmaX=0(自动计算) | O(N×K²),线性卷积,底层高度优化 | 平滑模糊,权重按距离分配 | 普通颗粒噪点,预处理 |
| 中值滤波 medianBlur | medianBlur | ksize=5(整数,非元组) | O(N×K²logK),逐窗口排序取中位数 | 取中位数,消除黑白斑点 | 椒盐噪声 |
| 双边滤波 bilateralFilter | bilateralFilter | d=9,sigmaColor=75,sigmaSpace=75 | O(N×K²),需同时计算空间距离和颜色相似度,最慢 | 磨皮降噪,保留边缘 | 人像美颜,物体轮廓保留 |
六、综合案例:给图片先降噪再锐化
实际项目经常多级滤波,先降噪再做锐化。
python
import cv2
import numpy as np
img = cv2.imread(r'D:\PYTHON\your name.jpg')
if img is None:
print("图片读取失败,请检查路径")
exit()
#第一步:高斯降噪
blur = cv2.GaussianBlur(img,(3,3),sigmaX=0)
#第二步:锐化卷积
kernel_sharp = np.array([[0,-1,0],[-1,5,-1],[0,-1,0]])
result = cv2.filter2D(blur,-1,kernel_sharp)
cv2.imshow("原图",img)
cv2.imshow("降噪+锐化",result)
while True:
key = cv2.waitKey(10)
if key == ord('q') or key == 27:
break
cv2.destroyAllWindows()
cv2.waitKey(1)
七、本章高频踩坑清单
- 卷积核大小必须是奇数:3,5,7......;偶数核会直接报错。
medianBlur的ksize是整数 ,不是元组,不要写成(5,5)。- 双边滤波速度慢,视频实时处理不要设置过大d、sigma参数,容易卡顿。
- filter2D的kernel必须是
np.float32类型,用int类型会出现颜色溢出异常。 - 椒盐噪点用高斯效果差,优先选
medianBlur;人像美颜优先双边滤波。 - 图片路径记得使用r原始字符串,防止转义符号造成读取返回None。
八、本章知识小结
- 滤波依靠卷积核在图片滑动运算,实现降噪、模糊、锐化、浮雕;
filter2D支持自定义卷积; - 高斯滤波适合通用平滑降噪;中值滤波专门对付椒盐黑白斑点噪声;
- 双边滤波是美颜核心算法,可以做到降噪同时保留物体边缘,但计算开销更大;
- 不同噪点场景选择对应滤波,工程上常多级组合:先降噪,再锐化;
- 注意各函数参数格式差异:高斯是元组ksize,中值滤波是单个整数。
下一章我们学习边缘检测算子:Sobel、Scharr、Laplacian、Canny,从滤波平滑过渡到提取图片物体轮廓,是目标检测的重要前置基础。