2. 图像基础与OpenCV入门:图像表示、颜色空间、OpenCV核心操作
各位同学,欢迎来到第二章。这一章咱们要聊的是自动驾驶视觉感知的「地基」——图像本身。你想想看,不管后面用多牛的深度学习模型,输入终究是一张张图像。如果连图像怎么存、怎么读、怎么转都搞不清楚,后面调参调得再欢也是空中楼阁。
我个人习惯,在开始任何项目之前,先把数据「摸」一遍。摸数据的第一步,就是搞懂图像在计算机里到底长什么样。好,咱们直接开干。
2.1 图像在计算机里是怎么表示的?
说白了,一张数字图像就是一个巨大的二维矩阵。对于灰度图,每个像素就是一个0到255的数值,0代表纯黑,255代表纯白。对于彩色图,每个像素由三个通道组成——红、绿、蓝,也就是我们常说的RGB。
举个例子,一张640×480的彩色图像,在内存里就是一个480行、640列、3层深度的三维数组。形状是 (480, 640, 3)。嗯,这里要注意:OpenCV里通道顺序是BGR,不是RGB。我第一次用OpenCV读图显示出来颜色怪怪的,查了半天才发现是通道顺序搞反了。这个坑,我替你们踩过了。
- 像素:图像的最小单元,一个点
- 分辨率:宽度×高度,比如1920×1080
- 通道:灰度图1通道,彩色图3通道(BGR)
- 位深:通常8位,即0-255
2.2 颜色空间:不只是RGB
RGB虽然直观,但在自动驾驶场景里并不总是最好用的。为什么?因为RGB三个通道高度相关,光照一变,三个值一起变,很难做阈值分割。
我建议你重点掌握以下三种颜色空间:
| 颜色空间 | 特点 | 自动驾驶中的应用 |
|---|---|---|
| RGB / BGR | 最原始,硬件直接输出 | 模型输入、显示 |
| HSV | 色调、饱和度、明度分离 | 车道线检测、交通灯识别 |
| 灰度 | 单通道,计算量小 | 边缘检测、特征匹配 |
我在做车道线检测项目时,就吃过RGB的亏。白天阳光强烈,黄色车道线在RGB下跟路面混在一起,阈值怎么调都不对。后来换成HSV空间,只对色调通道做阈值分割,效果立竿见影。说白了,选对颜色空间,比调参重要十倍。
2.3 OpenCV核心操作:读取、显示、保存
好,理论讲完了,咱们直接上代码。OpenCV的安装很简单,pip install opencv-python 就行。我个人习惯用cv2这个别名,简洁明了。
2.3.1 读取图像
import cv2
# 读取图像,默认是彩色模式(BGR)
img = cv2.imread('road.jpg')
# 读取为灰度图
img_gray = cv2.imread('road.jpg', cv2.IMREAD_GRAYSCALE)
# 检查是否读取成功
if img is None:
print("图像读取失败,检查路径!")
这里有个坑:imread如果路径不对,不会报错,而是返回None。我曾经在调试时花了半小时找bug,最后发现是文件名多打了一个空格。嗯,这种低级错误,谁还没犯过呢?
2.3.2 显示图像
# 显示图像
cv2.imshow('My Window', img)
# 等待按键,0表示无限等待
cv2.waitKey(0)
# 关闭所有窗口
cv2.destroyAllWindows()
注意:waitKey的参数单位是毫秒。如果你不调用waitKey,窗口会一闪而过。我刚开始学的时候,窗口闪一下就没了,还以为代码写错了。
2.3.3 保存图像
# 保存为PNG格式
cv2.imwrite('output.png', img)
# 保存为JPEG,第三个参数控制质量(0-100)
cv2.imwrite('output.jpg', img, [cv2.IMWRITE_JPEG_QUALITY, 95])
2.4 实战小练习:图像通道分离与合并
咱们来个小练习,把一张彩色图的三个通道分开看看:
import cv2
import numpy as np
img = cv2.imread('car.jpg')
b, g, r = cv2.split(img)
# 创建一个全黑通道
zeros = np.zeros_like(b)
# 只保留红色通道
red_only = cv2.merge([zeros, zeros, r])
cv2.imshow('Red Channel', red_only)
cv2.waitKey(0)
cv2.destroyAllWindows()
你运行一下就会发现,红色通道里,原本红色的车灯特别亮,蓝色的天空几乎全黑。这就是通道分离的魅力——你可以直观地看到每个通道对图像的贡献。
2.5 本章小结
这一章咱们把图像的基础打牢了。你学会了:
- 图像本质上是多维数组
- BGR和HSV各有各的适用场景
- OpenCV的三大核心操作:读、显、存
- 通道分离与合并的基本用法
下一章,咱们要进入图像预处理的世界。说白了,就是给图像「洗个澡」,让它更适合后续的算法处理。到时候我会分享一些我在实际项目中用到的预处理技巧,保证实用。
好,今天的课就到这里。记得动手敲代码,光看是学不会的。咱们下章见。