2. OpenCV基础回顾:图像读取、显示、保存,色彩空间转换(BGR与RGB)

好,咱们正式开始动手了。这一节我带你快速过一遍OpenCV最核心的几个基础操作。别小看这些,我在实际项目中见过太多人栽在「图像没读进来」或者「颜色搞反了」这种低级错误上。你想想看,YOLO检测前如果图像都没加载对,后面再牛的模型也是白搭。

2.1 图像读取:imread() 的坑与技巧

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

import cv2

# 最基本的用法
img = cv2.imread('cat.jpg')

# 我建议你总是显式指定读取模式
img_color = cv2.imread('cat.jpg', cv2.IMREAD_COLOR)      # 彩色图,默认
img_gray = cv2.imread('cat.jpg', cv2.IMREAD_GRAYSCALE)   # 灰度图
img_unchanged = cv2.imread('cat.jpg', cv2.IMREAD_UNCHANGED)  # 含Alpha通道
⚠️ 我曾经踩过的坑: 路径里有中文或空格,imread() 会静默返回 None。它不会报错!你后面调用 img.shape 直接崩。所以读取后一定要加个判断。
img = cv2.imread('测试图片.jpg')
if img is None:
    print("图像没读进来,检查路径!")
    exit()

还有一个事:imread() 默认返回的是 BGR 顺序,不是 RGB。这个太重要了,我后面会反复强调。

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

显示图像用 cv2.imshow()。嗯,这里有个小细节——你必须配合 waitKey() 才能看到窗口。

cv2.imshow('My Window', img)
cv2.waitKey(0)      # 等待任意按键
cv2.destroyAllWindows()

我个人习惯把 waitKey(0) 写成 cv2.waitKey(0) & 0xFF,这样在有些系统上更稳定。为什么?因为 waitKey() 返回值在不同平台上可能高位有数据,加个掩码更保险。

💡 实用技巧: 如果你想让窗口自适应大小,用 cv2.WINDOW_NORMAL 标志:
cv2.namedWindow('My Window', cv2.WINDOW_NORMAL)
cv2.imshow('My Window', img)
这样窗口就可以拖拽缩放了。

2.3 图像保存:imwrite() 的格式控制

保存图像用 cv2.imwrite()。它支持很多格式,但有个参数你可能不知道——压缩质量。

# 保存为PNG,压缩级别9(0-9,9最小文件)
cv2.imwrite('output.png', img, [cv2.IMWRITE_PNG_COMPRESSION, 9])

# 保存为JPEG,质量95(0-100,100最好)
cv2.imwrite('output.jpg', img, [cv2.IMWRITE_JPEG_QUALITY, 95])

我在项目中遇到过一个问题:保存的图片颜色不对。后来发现是因为 imwrite() 默认也是按 BGR 存的。如果你之前把图像转成了 RGB,直接保存就会偏蓝。所以保存前一定要确认色彩空间。

2.4 色彩空间转换:BGR ↔ RGB 的生死攸关

好,重点来了。OpenCV 读图是 BGR,但 YOLO 训练时用的是 RGB。如果你不转换,检测结果会一塌糊涂。

为什么会这样?因为 YOLO 模型在训练时,数据预处理会把图像转成 RGB 再喂给网络。如果你直接拿 BGR 图像去推理,模型看到的颜色分布完全不对,相当于你戴着蓝色眼镜看世界。

# BGR 转 RGB
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)

# RGB 转 BGR(保存或显示时用)
img_bgr = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2BGR)
🔴 核心原则:
  • 用 OpenCV 读取 → 得到 BGR
  • 送入 YOLO 推理前 → 转成 RGB
  • 用 OpenCV 显示/保存 → 转回 BGR

你想想看,如果忘了转换,模型会把红色物体识别成蓝色,那检测框再准也没用。我记得有一次帮同事调试,他死活说模型不准,结果一看——RGB 和 BGR 搞反了。折腾了两天。

2.5 其他常用转换

除了 BGR↔RGB,还有几个转换在 ROI 提取时很常用:

转换 代码 用途
BGR → 灰度 cv2.COLOR_BGR2GRAY 边缘检测、模板匹配
BGR → HSV cv2.COLOR_BGR2HSV 颜色分割、ROI提取
BGR → LAB cv2.COLOR_BGR2LAB 颜色特征分析
# 灰度图
gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)

# HSV —— 我经常用它做颜色过滤
hsv = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2HSV)
💡 我的经验: 做颜色相关的 ROI 提取时,HSV 比 BGR 好用得多。因为 HSV 把「颜色」和「亮度」分开了,你只需要调 H(色调)和 S(饱和度)两个通道,不受光照影响。

2.6 完整示例:一条龙操作

最后,我给你一个完整的示例,把读取、转换、显示、保存串起来。这也是我写代码时的标准模板。

import cv2

# 1. 读取图像(BGR)
img_bgr = cv2.imread('test.jpg')
if img_bgr is None:
    print("读取失败,检查文件路径")
    exit()

# 2. 转成 RGB(准备送给 YOLO)
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)

# 3. 显示原始图像(OpenCV 显示需要 BGR)
cv2.imshow('Original BGR', img_bgr)

# 4. 显示 RGB 图像(颜色会偏蓝,因为 imshow 期望 BGR)
cv2.imshow('RGB (wrong color)', img_rgb)

# 5. 保存 RGB 图像(imwrite 期望 BGR,所以先转回去)
img_bgr_save = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2BGR)
cv2.imwrite('output.jpg', img_bgr_save)

cv2.waitKey(0)
cv2.destroyAllWindows()

嗯,这一节的内容就这些。说白了就是三件事:读图、显图、存图,外加一个色彩空间转换。但你别觉得简单,我敢说 80% 的 OpenCV 新手都在 BGR/RGB 上翻过车。下一节我们开始讲 ROI 提取,到时候你会看到这些基础操作有多重要。


公众号:蓝海资料掘金营,微信deep3321