3. OpenCV图像处理基础
各位同学,欢迎来到第三章。从这章开始,我们正式进入 OpenCV 的世界。说白了,OpenCV 就是咱们做视觉开发的“瑞士军刀”。你后面所有摄像头对接、人脸检测,底层都离不开它。
我个人习惯,学一个新库,第一件事就是搞清楚它怎么“看”图片。所以这一章,咱们就把图像读取、显示、色彩转换、缩放裁剪和滤波这几个基本功练扎实。嗯,别小看这些操作,我在项目里踩过的坑,有一半都跟这些基础操作没处理好有关。
3.1 图像读取与显示:OpenCV 的“Hello World”
先来写第一行代码。OpenCV 读取图像用 imread(),显示用 imshow()。就这么简单。
import cv2
# 读取图像
img = cv2.imread('test.jpg')
# 显示图像
cv2.imshow('Window Title', img)
cv2.waitKey(0) # 等待按键
cv2.destroyAllWindows()
这里有个关键点,waitKey(0) 是必须的。没有它,窗口会一闪而过。我曾经在给客户做演示时,忘了加这行,结果窗口闪了一下就没了,场面一度非常尴尬。
imread() 如果读不到文件,不会报错,而是返回 None。你后续操作就会崩溃。所以,建议每次读取后都检查一下:
if img is None:
print("图片没读到,检查路径!")
exit()
3.2 色彩空间转换:BGR、RGB 与灰度
你想想看,OpenCV 默认读取的彩色图像是什么顺序?是 BGR,不是我们常见的 RGB。这是历史遗留问题,但坑了不少新手。
我记得有一次,我用 Matplotlib 显示 OpenCV 读进来的图,结果颜色全偏蓝。折腾了半天才发现,Matplotlib 认 RGB,而 OpenCV 给的是 BGR。所以必须转一下。
3.2.1 BGR 转 RGB
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
3.2.2 BGR 转灰度
灰度图是人脸识别中最常用的输入。因为它去掉了颜色干扰,只保留亮度信息,计算量小很多。
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
3.2.3 常用色彩空间对比
| 色彩空间 | 通道含义 | 适用场景 |
|---|---|---|
| BGR | 蓝、绿、红 | OpenCV 默认格式 |
| RGB | 红、绿、蓝 | 显示、Matplotlib、网页 |
| 灰度 | 单通道亮度 | 人脸检测、边缘检测 |
| HSV | 色调、饱和度、明度 | 颜色分割、物体跟踪 |
3.3 图像缩放与裁剪:ROI 提取
实际项目中,摄像头传来的画面往往很大。1920x1080 是常态。但人脸检测不需要那么大的图,缩小一点,速度能快好几倍。
3.3.1 缩放
# 缩小到原来的一半
img_small = cv2.resize(img, (0, 0), fx=0.5, fy=0.5)
# 指定固定尺寸
img_fixed = cv2.resize(img, (640, 480))
interpolation 插值方法。缩小用 cv2.INTER_AREA,放大用 cv2.INTER_LINEAR 或 cv2.INTER_CUBIC。效果差别挺大的。
3.3.2 裁剪(ROI)
裁剪其实就是数组切片。OpenCV 的图像就是一个 NumPy 数组。
# 裁剪出人脸区域 [y1:y2, x1:x2]
face_roi = img[100:300, 200:400]
嗯,这里要注意坐标顺序:先是行(y),再是列(x)。跟数学里的 (x, y) 是反的。我刚开始写的时候,经常搞反,裁出来的东西完全不对。
3.4 图像滤波:去噪与平滑
摄像头采集的图像,多少都有噪声。尤其是光线不好的时候,噪点特别多。滤波就是用来处理这个的。
3.4.1 均值滤波
最简单,也最暴力。把每个像素替换成周围像素的平均值。
blurred = cv2.blur(img, (5, 5)) # 5x5 的核
3.4.2 高斯滤波
比均值滤波更自然。它给中心像素更高的权重,边缘保留得更好。
gaussian = cv2.GaussianBlur(img, (5, 5), 0)
3.4.3 中值滤波
对付“椒盐噪声”(黑白点)特别有效。它取的是中位数,而不是平均值。
median = cv2.medianBlur(img, 5)
3.4.4 三种滤波对比
| 滤波类型 | 特点 | 适用噪声 | 速度 |
|---|---|---|---|
| 均值滤波 | 简单、平滑强 | 高斯噪声 | 快 |
| 高斯滤波 | 边缘保留较好 | 高斯噪声 | 中等 |
| 中值滤波 | 抗椒盐噪声强 | 椒盐噪声 | 较慢 |
3.5 本章知识体系
下面这张图,帮你把本章的核心操作串起来。从图像读取开始,到预处理结束,每一步都是后续人脸识别的基础。
3.6 避坑指南与个人经验
- 路径问题: 我建议用路径,或者把图片放在项目根目录下。相对路径容易出错,尤其是用 PyCharm 或 VS Code 时,工作目录可能不是你想象的那个。
- 显示窗口卡死: 如果
imshow()后窗口没反应,检查一下是不是忘了waitKey()。或者你开了多个窗口,但只等了一个按键。 - 性能优化: 在实时摄像头处理中,尽量先缩小图像,再做滤波。先滤波再缩小,计算量会大很多。我曾经在 4K 画面上直接做高斯滤波,帧率直接掉到个位数。
- 数据类型: OpenCV 的图像默认是
uint8(0-255)。做数学运算时,注意溢出。比如两个像素相加,结果超过 255 会被截断,而不是你想的 256。
cv2.imwrite('debug.jpg', img) 把中间结果保存下来看看。比盯着屏幕猜要靠谱得多。
好了,这一章的内容就到这里。图像读取、色彩转换、缩放裁剪、滤波,这四个操作你练熟了,后面的人脸识别 API 对接就会顺畅很多。记住,基础不牢,地动山摇。去多敲几遍代码吧。