3、RGB与BGR转换:OpenCV默认BGR格式,如何正确显示颜色
好,咱们接着聊。上一节我们搞清楚了色彩空间的基本概念,这一节要解决一个非常实际的问题——为什么你用OpenCV读了一张图片,用matplotlib一显示,颜色全乱了?
嗯,我当年第一次遇到这个问题时,差点把电脑砸了。明明是一张蓝天白云的照片,显示出来变成了紫天橙云。后来才发现,罪魁祸首就是OpenCV的BGR格式。
3.1 为什么OpenCV要用BGR?
你可能要问:为什么OpenCV不按常理出牌?RGB不是更通用吗?
这里有个历史原因。早期的一些相机硬件和图像采集卡,内部存储顺序就是BGR。OpenCV诞生时为了兼容这些硬件,就沿用了BGR格式。说白了,这是一个历史包袱。
我个人习惯把OpenCV的BGR理解为「内部工作格式」。它就像工厂里的半成品,不适合直接展示给用户看。你要展示,就得转换。
核心结论:OpenCV用imread()读进来的图片,通道顺序是BGR,不是RGB。如果你直接用matplotlib的imshow()显示,颜色必然错乱。
3.2 颜色错乱到底长什么样?
咱们来看个具体例子。假设你有一张纯红色的图片(R=255, G=0, B=0)。
在OpenCV中,它被存储为:[B=0, G=0, R=255]。
但matplotlib以为它是RGB格式,所以它解读为:[R=0, G=0, B=255]——蓝色!
你看,红色直接变成了蓝色。这就是最常见的颜色通道互换现象。
| 原始颜色 | OpenCV存储 (BGR) | matplotlib误读 (当作RGB) | 显示结果 |
|---|---|---|---|
| 红色 (255,0,0) | (0,0,255) | (0,0,255) | 蓝色 |
| 绿色 (0,255,0) | (0,255,0) | (0,255,0) | 绿色(巧合相同) |
| 蓝色 (0,0,255) | (255,0,0) | (255,0,0) | 红色 |
注意看绿色那一行——它居然没变!因为G通道在中间位置,BGR和RGB里它都是第二个。所以纯绿色图片不会出问题,这曾经让我困惑了好一阵子。
3.3 如何正确转换?三种方法
好,问题找到了,怎么解决?我总结了三种方法,从简单到灵活,你按需选用。
方法一:用cv2.cvtColor()(最推荐)
这是OpenCV官方提供的方式,我个人最常用。
import cv2
import matplotlib.pyplot as plt
# 读取图片(默认BGR)
img_bgr = cv2.imread('example.jpg')
# 转换为RGB
img_rgb = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2RGB)
# 显示
plt.imshow(img_rgb)
plt.show()
小提示:cv2.COLOR_BGR2RGB这个常量名很直观——从BGR转到RGB。反过来也有cv2.COLOR_RGB2BGR,保存图片时可能会用到。
方法二:用NumPy手动翻转通道(适合理解原理)
你想想看,BGR转RGB本质上就是翻转通道顺序。用NumPy可以一行搞定:
import cv2
import numpy as np
img_bgr = cv2.imread('example.jpg')
img_rgb = img_bgr[:, :, ::-1] # 翻转最后一个维度
这里的::-1是什么意思?就是把通道维度倒序排列。原来索引0是B,索引2是R,翻转后索引0变成R,索引2变成B。
我曾经在嵌入式设备上用过这个方法——因为cvtColor在某些优化不足的平台上反而慢,手动翻转有时更快。
注意:这个方法会创建一个新的数组,内存开销和cvtColor差不多。不要以为它更省内存。
方法三:用cv2.imshow()直接显示(不推荐)
OpenCV自己也有显示函数:
cv2.imshow('Window', img_bgr) # 直接显示BGR图片
cv2.waitKey(0)
这个函数能正确显示BGR格式,不需要转换。但说实话,cv2.imshow()的窗口太丑了,不能缩放,不能交互。我基本只用它做快速调试。
3.4 避坑指南:我曾经踩过的三个坑
讲完了方法,我分享几个真实踩过的坑,你遇到了能少走弯路。
-
保存图片时忘记转回BGR
我曾经用
cv2.imwrite()保存一张RGB图片,结果保存出来的文件颜色全乱。因为imwrite()默认也要求BGR格式。所以保存前要转回去:img_bgr = cv2.cvtColor(img_rgb, cv2.COLOR_RGB2BGR) cv2.imwrite('output.jpg', img_bgr) -
视频帧的颜色问题
用
cv2.VideoCapture读取视频时,每一帧也是BGR格式。如果你用matplotlib实时显示,每帧都要转换。我一开始没注意,调试了半小时才发现是颜色问题。 -
深度学习推理时的通道顺序
很多深度学习框架(比如PyTorch)默认用RGB。如果你把OpenCV读的图片直接送进模型,模型会学错特征。我记得有一次训练一个分类器,准确率死活上不去,最后发现是BGR/RGB搞反了。
3.5 实战:写一个通用的图片显示函数
为了避免每次都要手动转换,我写了一个小工具函数,你可以直接拿去用:
import cv2
import matplotlib.pyplot as plt
def show_cv_image(img, title='Image'):
"""
安全显示OpenCV图片(自动处理BGR转RGB)
参数:
img: OpenCV读取的图片(BGR格式)
title: 窗口标题
"""
# 检查是否为彩色图
if len(img.shape) == 3 and img.shape[2] == 3:
img_display = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
else:
img_display = img # 灰度图不需要转换
plt.imshow(img_display)
plt.title(title)
plt.axis('off')
plt.show()
# 使用示例
img = cv2.imread('photo.jpg')
show_cv_image(img, '我的照片')
这个函数会自动判断图片类型。彩色图就转RGB,灰度图直接显示。省心。
3.6 小结
这一节的核心就一句话:OpenCV读图是BGR,显示要转RGB。
记住这个原则,你就能避免90%的颜色显示问题。下一节我们会深入另一个常见的色彩空间——HSV,它在颜色分割和物体检测中非常有用。
嗯,先消化一下今天的内容。如果你手边有图片,不妨打开Python试一下,看看转换前后的区别。实践出真知。