第1章:实战:Python实现基础去噪滤波器
各位同学,欢迎来到《去噪算法在安防监控中的实战》课程。
我是你们的老朋友,一个在安防监控领域摸爬滚打了十来年的算法工程师。今天咱们正式开始第一课——用Python把最基础的几个去噪滤波器跑起来。
说实话,很多新手一上来就追着深度学习跑,结果连最基本的噪声都处理不好。我个人习惯是,先把地基打牢。你想想看,监控画面里的雪花点、椒盐噪声,这些用传统滤波方法处理起来又快又稳,何必杀鸡用牛刀?
1.1 环境搭建:OpenCV 的安装与验证
工欲善其事,必先利其器。咱们先搞定OpenCV。
安装其实很简单,一行命令的事。但我建议你用虚拟环境,别把系统Python搞乱了。我在项目里吃过这个亏,有一次装了个新版本的OpenCV,结果把公司服务器上跑得好好的旧项目给搞崩了……嗯,从那以后我老老实实用虚拟环境。
推荐安装方式:
# 创建虚拟环境(Python 3.8+ 都行)
python -m venv monitor_env
# 激活环境(Windows)
monitor_env\Scripts\activate
# 激活环境(Mac/Linux)
source monitor_env/bin/activate
# 安装OpenCV
pip install opencv-python opencv-contrib-python
# 验证安装
python -c "import cv2; print(cv2.__version__)"
看到版本号输出,比如 4.8.0 之类的,就说明装好了。
小提示:如果你用的是树莓派或者嵌入式设备,建议装 opencv-python-headless,不带GUI,省空间。
1.2 读取监控视频帧
监控视频说白了就是一帧一帧的图片快速播放。咱们先学会怎么把每一帧抓出来。
我当年做第一个项目时,用的是海康的RTSP流。那时候不懂,直接 cv2.VideoCapture("rtsp://...") 就上了,结果延迟高得离谱。后来才明白,要加缓存队列和丢帧策略。不过今天咱们先玩本地视频文件,把基础走通。
import cv2
# 打开视频文件(或者摄像头:0 表示第一个摄像头)
cap = cv2.VideoCapture("test_video.mp4")
# 检查是否打开成功
if not cap.isOpened():
print("视频打开失败!检查路径或权限。")
exit()
# 循环读取帧
frame_count = 0
while True:
ret, frame = cap.read()
if not ret:
print("视频读取完毕或出错。")
break
# 显示当前帧
cv2.imshow("监控画面", frame)
# 按 'q' 键退出
if cv2.waitKey(1) & 0xFF == ord('q'):
break
frame_count += 1
# 释放资源
cap.release()
cv2.destroyAllWindows()
print(f"共读取了 {frame_count} 帧")
这段代码很简单,但有几个坑我要提醒你:
waitKey(1)里的数字是等待毫秒数。监控视频一般用1-10,太快画面会闪,太慢会卡。- 记得释放
cap.release(),不然下次打开摄像头可能会报错。 - 如果视频是黑白的,可以用
cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)转灰度,后面滤波会更快。
1.3 三种基础去噪滤波器
好,现在进入正题。咱们要处理监控画面里的噪声。常见的噪声有两种:
- 椒盐噪声:画面里随机出现黑白点,像撒了盐和胡椒。老式模拟摄像头常见。
- 高斯噪声:画面整体有颗粒感,像老电视的雪花。低光照环境下特别明显。
针对这两种噪声,有三种经典滤波器:均值、高斯、中值。我一个个说。
1.3.1 均值滤波
均值滤波的原理很简单:用一个窗口(比如3x3)滑过图像,把窗口内所有像素的平均值赋给中心点。
说白了就是「和稀泥」。它能平滑噪声,但也会把边缘细节抹掉。监控画面里如果有人在走动,用了均值滤波后,人的轮廓会变模糊。
def apply_mean_filter(frame, kernel_size=5):
"""
均值滤波
kernel_size: 核大小,必须是奇数,比如3,5,7
"""
return cv2.blur(frame, (kernel_size, kernel_size))
注意:核越大,平滑效果越强,但图像越模糊。监控场景下,我一般用3x3或5x5,再大就丢失细节了。
1.3.2 高斯滤波
高斯滤波和均值滤波有点像,但它不是简单平均,而是根据高斯分布给窗口内的像素分配权重——中心点权重最大,越往边缘权重越小。
这样做的好处是:保留了更多边缘信息。对付高斯噪声特别有效。
def apply_gaussian_filter(frame, kernel_size=5, sigma=1.0):
"""
高斯滤波
sigma: 标准差,控制权重分布。sigma越大,图像越平滑。
"""
return cv2.GaussianBlur(frame, (kernel_size, kernel_size), sigma)
这里有个参数 sigma,我刚开始用的时候总搞不明白。后来发现,sigma=0 时OpenCV会自动根据核大小计算,大多数情况下够用了。但如果你想要更强的平滑效果,可以调大到1.5或2.0。
1.3.3 中值滤波
中值滤波就更有意思了。它把窗口内的像素排序,取中间值代替中心点。
为什么它厉害?因为椒盐噪声是极端值(要么特别白要么特别黑),排序后肯定在两端,中间值根本不受影响。所以中值滤波是去椒盐噪声的王牌。
def apply_median_filter(frame, kernel_size=3):
"""
中值滤波
kernel_size: 核大小,必须是奇数
"""
return cv2.medianBlur(frame, kernel_size)
避坑指南:我曾经在一个停车场监控项目里,画面全是椒盐噪声,用了均值滤波效果很差。后来换成中值滤波,瞬间干净了。但注意,中值滤波计算量比均值大,实时性要求高的场景要权衡。
1.4 对比效果:完整代码
下面我把所有东西串起来,写一个完整的对比程序。它会同时显示原图、均值、高斯、中值四种效果,方便你直观对比。
import cv2
import numpy as np
def process_frame(frame):
"""对一帧应用三种滤波"""
# 转灰度(可选,为了速度更快)
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
# 三种滤波
mean = cv2.blur(gray, (5, 5))
gaussian = cv2.GaussianBlur(gray, (5, 5), 1.0)
median = cv2.medianBlur(gray, 5)
return gray, mean, gaussian, median
def main():
cap = cv2.VideoCapture("test_video.mp4")
if not cap.isOpened():
print("无法打开视频")
return
while True:
ret, frame = cap.read()
if not ret:
break
# 处理当前帧
original, mean, gaussian, median = process_frame(frame)
# 拼接显示(2x2网格)
top = np.hstack((original, mean))
bottom = np.hstack((gaussian, median))
display = np.vstack((top, bottom))
# 添加文字标签
cv2.putText(display, "Original", (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
cv2.putText(display, "Mean", (original.shape[1] + 10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
cv2.putText(display, "Gaussian", (10, original.shape[0] + 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
cv2.putText(display, "Median", (original.shape[1] + 10, original.shape[0] + 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2)
cv2.imshow("去噪效果对比", display)
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
if __name__ == "__main__":
main()
1.5 效果对比与选择建议
跑完上面的代码,你会看到四种画面。我根据经验总结了一个选择表:
| 噪声类型 | 推荐滤波器 | 核大小建议 | 备注 |
|---|---|---|---|
| 椒盐噪声 | 中值滤波 | 3x3 或 5x5 | 效果立竿见影,边缘保留好 |
| 高斯噪声 | 高斯滤波 | 5x5, sigma=1.0 | 平滑自然,细节损失小 |
| 混合噪声 | 先中值再高斯 | 中值3x3 + 高斯5x5 | 先除椒盐,再平滑高斯 |
| 实时性要求高 | 均值滤波 | 3x3 | 计算最快,但边缘模糊 |
为什么会这样?我解释一下:
- 中值滤波对椒盐噪声是「天生克星」,因为它直接忽略极端值。
- 高斯滤波模拟了自然界噪声的分布,所以对付高斯噪声最合适。
- 均值滤波虽然简单,但在监控场景下,如果画面本身噪声不大,用均值滤波反而会「过度平滑」,把有用的细节弄没了。
我的个人经验:在安防监控中,我90%的场景用中值滤波。为什么?因为监控画面最常见的噪声就是椒盐噪声(线路干扰、传感器老化)。而且中值滤波对边缘的保护比均值好太多。你想想看,如果嫌疑人的轮廓被模糊了,那监控还有什么用?
1.6 本章知识体系
为了让你更直观地理解本章内容,我画了一张流程图:
这张图把本章的四个核心步骤串起来了。你跟着这个流程走,就能完整跑通一个基础去噪的监控处理管线。
1.7 本章小结
好了,第一课的内容就这些。咱们回顾一下:
- 搭建了OpenCV环境,学会了读取视频帧。
- 实现了三种基础去噪滤波器:均值、高斯、中值。
- 通过对比代码,直观看到了不同滤波器的效果差异。
- 根据噪声类型,给出了选择建议。
说实话,这些基础滤波器虽然简单,但它们是后续所有高级去噪算法(比如非局部均值、小波去噪、甚至深度学习去噪)的基石。你把这个基础打牢了,后面学什么都快。
下一章,咱们会深入聊聊「噪声模型」——只有真正理解了噪声是怎么产生的,你才能选对滤波器。嗯,到时候见。
公众号:蓝海资料掘金营,微信deep3321