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)
💡 我的习惯: 在做任何人脸检测前,我都会先把图像转成灰度。一来速度快,二来很多检测算法(比如 Haar Cascade)本身就是为灰度图设计的。

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, 5, 7)都必须是奇数。否则 OpenCV 会报错。我当初写了个 4,查了半天才反应过来。

3.4.4 三种滤波对比

滤波类型 特点 适用噪声 速度
均值滤波 简单、平滑强 高斯噪声 快
高斯滤波 边缘保留较好 高斯噪声 中等
中值滤波 抗椒盐噪声强 椒盐噪声 较慢

3.5 本章知识体系

下面这张图,帮你把本章的核心操作串起来。从图像读取开始,到预处理结束,每一步都是后续人脸识别的基础。

OpenCV 图像处理基础流程 OpenCV 图像处理基础流程 图像读取 imread() 色彩空间转换 cvtColor() 缩放 resize() / 裁剪 ROI 图像滤波 blur / Gaussian / median 预处理完成 → 送入人脸检测 💡 核心要点 • 检查 img 是否为 None • BGR vs RGB 区别 • 滤波核必须为奇数

3.6 避坑指南与个人经验

  • 路径问题: 我建议用路径,或者把图片放在项目根目录下。相对路径容易出错,尤其是用 PyCharm 或 VS Code 时,工作目录可能不是你想象的那个。
  • 显示窗口卡死: 如果 imshow() 后窗口没反应,检查一下是不是忘了 waitKey()。或者你开了多个窗口,但只等了一个按键。
  • 性能优化: 在实时摄像头处理中,尽量先缩小图像,再做滤波。先滤波再缩小,计算量会大很多。我曾经在 4K 画面上直接做高斯滤波,帧率直接掉到个位数。
  • 数据类型: OpenCV 的图像默认是 uint8(0-255)。做数学运算时,注意溢出。比如两个像素相加,结果超过 255 会被截断,而不是你想的 256。
🔧 调试小技巧: 不确定图像处理结果对不对?用 cv2.imwrite('debug.jpg', img) 把中间结果保存下来看看。比盯着屏幕猜要靠谱得多。

好了,这一章的内容就到这里。图像读取、色彩转换、缩放裁剪、滤波,这四个操作你练熟了,后面的人脸识别 API 对接就会顺畅很多。记住,基础不牢,地动山摇。去多敲几遍代码吧。