3. OpenCV基础(一)

好,咱们正式开始接触OpenCV。这一章是基本功,说白了就是学会怎么把一张图片“请”进程序里,怎么在屏幕上看一眼,再决定要不要存下来。另外,色彩空间转换这块,在门禁系统里特别常用——你想想看,摄像头拍到的原始画面是BGR格式,但很多算法(比如人脸检测)要的是灰度图或者RGB,不转的话就会出问题。

3.1 图像的读取:imread() 的用法与坑

OpenCV读取图像用的是 cv2.imread()。这个函数很简单,但有几个细节我建议你记牢。

import cv2

# 读取彩色图像(默认方式)
img = cv2.imread('face.jpg')
print(type(img))   # <class 'numpy.ndarray'>
print(img.shape)   # (高度, 宽度, 通道数)

嗯,这里要注意:imread() 默认返回的是 BGR 顺序的三通道数组,不是RGB。我在项目里第一次用的时候,直接拿它去显示,结果人脸颜色偏蓝,排查了半天才发现是通道顺序搞反了。

imread() 的第二个参数可以控制读取模式:

参数值 含义 实际用途
cv2.IMREAD_COLOR (1) 彩色模式,默认 普通场景
cv2.IMREAD_GRAYSCALE (0) 灰度模式 人脸检测前常用
cv2.IMREAD_UNCHANGED (-1) 保留Alpha通道 处理PNG透明图
路径问题:中文路径在OpenCV里经常读不出来。我曾经在Windows上放了一张“张三.jpg”,结果返回None。解决方案:要么全用英文路径,要么用 cv2.imdecode() 配合 np.fromfile() 处理。

3.2 图像的显示:imshow() 与窗口管理

读进来之后,总得看一眼吧?用 cv2.imshow()。

cv2.imshow('My Window', img)
cv2.waitKey(0)      # 等待按键,0表示无限等待
cv2.destroyAllWindows()

这里有个关键点:imshow() 之后必须跟 waitKey(),否则窗口一闪就没了。我个人习惯把 waitKey(0) 写成 cv2.waitKey(0) & 0xFF,这样在64位系统上更安全。

小技巧:如果你想让窗口自适应图像大小,可以用 cv2.namedWindow('win', cv2.WINDOW_NORMAL) 创建窗口,然后再 imshow(),这样就能手动拖拽缩放。

3.3 图像的保存:imwrite() 的格式与质量

保存图像用 cv2.imwrite()。它根据文件后缀自动判断格式。

cv2.imwrite('output.jpg', img)           # JPEG格式
cv2.imwrite('output.png', img)           # PNG格式
cv2.imwrite('output.bmp', img)           # BMP格式

对于JPEG,你可以控制压缩质量:

cv2.imwrite('output_high.jpg', img, [cv2.IMWRITE_JPEG_QUALITY, 95])

质量范围是0-100,默认95。数值越大,文件越大,画质越好。我在做门禁系统时,保存抓拍的人脸图片一般用90,既能看清人脸,又不会太占硬盘。

核心要点:imwrite() 保存的是BGR顺序的数据。如果你之前把图像转成了RGB,直接保存会颜色错乱。一定要先转回BGR再保存。

3.4 色彩空间转换:BGR ↔ RGB ↔ 灰度

这是本章的重头戏。OpenCV使用 cv2.cvtColor() 进行转换。

3.4.1 BGR 转 RGB

img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

为什么要转?因为Matplotlib显示图像时默认用RGB顺序。如果你用 plt.imshow() 直接显示OpenCV读进来的图,颜色会完全不对。我刚开始学的时候就被这个坑过,显示出来的人脸像阿凡达。

3.4.2 BGR 转灰度图

img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
print(img_gray.shape)   # (高度, 宽度) —— 只有两个维度

灰度图只有一个通道,每个像素值0-255。0是纯黑,255是纯白。门禁系统中的人脸检测算法(比如Haar Cascade)通常要求输入灰度图,因为灰度图计算量小,而且光照变化的影响相对可控。

注意:cv2.imread() 直接加参数0也能读成灰度图,但如果你后续需要彩色信息(比如肤色检测),就别用这个方式。我建议统一读成彩色,再根据需要转换。

3.4.3 其他常用转换

转换代码 用途
COLOR_BGR2HSV 色调、饱和度、明度,适合颜色分割
COLOR_BGR2LAB 亮度、绿红、蓝黄,适合颜色分析
COLOR_GRAY2BGR 灰度转三通道(伪彩色)

3.5 本章知识体系

下面这张图帮你理清本章的核心流程:

OpenCV图像基础操作流程 OpenCV 图像基础操作流程 图像来源 imread() 读取 BGR 格式 灰度图 cvtColor 转换 直接使用 RGB 格式 显示 / 保存 imshow / imwrite 核心原则:读取→转换→处理→显示/保存,每一步都要清楚当前图像的色彩空间

3.6 完整示例:读取→转灰度→显示→保存

把今天学的串起来,写一个完整的脚本:

import cv2

# 1. 读取彩色图像
img_bgr = cv2.imread('face.jpg')
if img_bgr is None:
    print("图片读取失败,检查路径")
    exit()

# 2. 转灰度图
img_gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)

# 3. 显示原图和灰度图
cv2.imshow('Original BGR', img_bgr)
cv2.imshow('Gray', img_gray)

# 4. 保存灰度图
cv2.imwrite('face_gray.jpg', img_gray)

# 5. 等待按键退出
cv2.waitKey(0)
cv2.destroyAllWindows()
避坑指南:我曾经在循环里频繁调用 imshow() 但不加 waitKey(1),结果窗口卡死。记住,waitKey() 不只是等待按键,它还负责刷新窗口事件。没有它,窗口不会更新。

好了,这一章的内容就这些。图像读取、显示、保存是OpenCV的“三板斧”,色彩空间转换是后续所有图像处理的基础。你把这些练熟了,后面做人脸检测、特征提取就会顺手很多。