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

好,咱们正式开始动手了。这一章我带你快速过一遍OpenCV最核心的几个基础操作。别小看这些,我见过太多项目翻车,就是因为最基础的读取和色彩空间没搞对。

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

OpenCV读取图像用的是 cv2.imread()。这个函数很简单,但有几个细节我必须要说。

import cv2

# 默认以彩色模式读取
img = cv2.imread('cat.jpg')

# 显式指定灰度模式
img_gray = cv2.imread('cat.jpg', cv2.IMREAD_GRAYSCALE)

# 保留原图通道(包括透明通道)
img_unchanged = cv2.imread('cat.jpg', cv2.IMREAD_UNCHANGED)

核心要点:

  • 默认读取结果是 BGR 格式,不是 RGB!这个我后面会细讲。
  • 如果路径不对,imread() 不会报错,而是返回 None。嗯,这里要注意,你后续操作就会直接崩溃。
  • 我习惯在读取后加一行断言:assert img is not None, "图片读取失败",省得排查半天。
我曾经踩过的坑: 有一次项目上线,客户反馈说“图片显示颜色不对”。查了半天,发现是图片路径中有中文,imread() 返回了 None,但后续代码没检查,直接用了空变量。从那以后,我每条读取路径都加断言。

2.2 图像显示:imshow() 与 waitKey() 的配合

显示图像用 cv2.imshow(),但你必须配合 cv2.waitKey() 才能看到窗口。

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

这里有几个关键点:

  • waitKey(0) 表示无限等待,直到你按键盘。如果你写 waitKey(1000),窗口只显示1秒就自动关闭。
  • 记得调用 destroyAllWindows() 释放资源。虽然程序结束会自动释放,但养成习惯没坏处。
  • 窗口标题不要用中文?其实现在OpenCV已经支持中文标题了,但某些旧版本还是乱码。我建议直接用英文或拼音。
小技巧: 调试时我经常用 cv2.imshow() 配合 cv2.waitKey(1) 做视频流的实时显示。但注意,waitKey(1) 返回的是按键的ASCII码,可以用来做交互控制。

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

保存图像用 cv2.imwrite()。它支持多种格式,但不同格式的参数不一样。

# 保存为PNG(无损)
cv2.imwrite('output.png', img)

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

# 保存为PNG,指定压缩级别(0-9)
cv2.imwrite('output.png', img, [cv2.IMWRITE_PNG_COMPRESSION, 3])

经验之谈:

  • JPEG质量我一般设95,再高文件体积大,肉眼也看不出区别。
  • PNG压缩级别默认是3,如果你要快速保存,可以设0(不压缩),但文件会很大。
  • 保存路径同样不能有中文,否则会静默失败。我遇到过好几次,保存后找不到文件,一查是路径里有中文空格。

2.4 色彩空间转换:BGR 与 RGB 的世纪难题

这是新手最容易懵的地方。OpenCV 默认是 BGR 顺序,而大多数其他库(比如 matplotlib、PIL)用的是 RGB 顺序。

为什么会这样?说白了就是历史原因。早期OpenCV开发时,BGR是相机和显示设备的通用格式,就这么沿用下来了。

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

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

# BGR 转灰度
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

你想想看: 如果你用 matplotlib 显示 OpenCV 读取的图像,颜色会完全错乱——红色变蓝色,蓝色变红色。我第一次遇到时还以为是相机坏了。

核心记忆法: OpenCV 读进来是 BGR,显示用 matplotlib 前必须转 RGB。保存时 OpenCV 会自动处理,但如果你用 PIL 保存,也要先转 RGB。

2.5 实战:一个完整的读取-转换-显示-保存流程

咱们把上面所有知识点串起来,写一个完整的例子。

import cv2
import matplotlib.pyplot as plt

# 1. 读取图像(BGR格式)
img_bgr = cv2.imread('cat.jpg')
assert img_bgr is not None, "图片读取失败,检查路径"

# 2. 显示原始BGR图像(用OpenCV)
cv2.imshow('BGR Image', img_bgr)
cv2.waitKey(0)

# 3. 转换为RGB(用于matplotlib显示)
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)

# 4. 用matplotlib显示
plt.imshow(img_rgb)
plt.title('RGB Image')
plt.axis('off')
plt.show()

# 5. 转换为灰度图
img_gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY)

# 6. 保存灰度图
cv2.imwrite('cat_gray.jpg', img_gray, [cv2.IMWRITE_JPEG_QUALITY, 90])

print("处理完成!")

这个流程我几乎每个项目都会用到。说白了,就是“读进来是BGR,显示前转RGB,保存时OpenCV自动处理”。记住这个口诀,能省掉你80%的色彩问题。

2.6 常见问题与避坑指南

问题 原因 解决方案
imread() 返回 None 路径错误、中文路径、文件不存在 加断言检查,路径用英文
imshow() 窗口一闪而过 没加 waitKey() 或 waitKey(0) 确保调用 waitKey(0)
颜色显示异常 BGR/RGB 混淆 用 cvtColor 转换
imwrite() 保存失败 路径权限、中文路径、格式不支持 检查路径,用英文命名
我曾经犯过的错: 有一次做模型部署,训练时用的RGB图像,推理时OpenCV读进来直接喂给模型,结果准确率暴跌。排查了两天才发现是色彩空间没对齐。从那以后,我所有项目的预处理流程第一行一定是 cv2.cvtColor(img, cv2.COLOR_BGR2RGB)

好了,这一章的基础操作就这些。别看简单,它们是后续所有图像处理、模型推理的基石。下一章咱们会深入图像的基本操作——裁剪、缩放、旋转,这些在数据预处理中特别常用。