第二章 图像处理基础(一):图像在计算机中的表示与读取
各位同学,欢迎来到图像处理的第一课。
说实话,很多做自动驾驶的朋友,一上来就扎进深度学习模型里,结果连图像在内存里长什么样都没搞清楚。我见过不少项目,模型跑得挺欢,结果一读图就崩,一显示就花屏。说白了,就是基础没打牢。
今天咱们就把这个地基夯实。你想想看,车道线检测也好,可行驶区域计算也罢,所有操作的第一步,都是把摄像头拍到的画面,变成计算机能理解的数据。那计算机是怎么理解一张图的?
2.1 图像在计算机中的表示
计算机不认识「红色」这个词。它只认识数字。
一张彩色图像,在计算机眼里就是一个三维数组。嗯,你可以把它想象成一个巨大的Excel表格,每个格子就是一个像素。每个像素里存了三个数字:R、G、B。
核心概念:RGB 颜色模型
- R(Red):红色通道,取值范围 0~255
- G(Green):绿色通道,取值范围 0~255
- B(Blue):蓝色通道,取值范围 0~255
三个通道叠加,就能表示 256³ ≈ 1670 万种颜色。
举个例子。纯红色像素,在计算机里就是 (255, 0, 0)。纯绿色是 (0, 255, 0)。纯蓝色是 (0, 0, 255)。白色是 (255, 255, 255),黑色是 (0, 0, 0)。
那灰度图呢?灰度图只有一个通道。每个像素只有一个值,0 表示纯黑,255 表示纯白,中间是各种深浅的灰色。我在做车道线检测项目时,经常先把彩色图转成灰度图。为什么?因为车道线检测主要靠边缘和亮度信息,颜色反而是干扰。转成灰度后,数据量直接降到原来的三分之一,处理速度能快不少。
个人经验:我建议你在做预处理时,先问问自己:颜色信息对当前任务真的重要吗?如果不需要,果断转灰度。省内存、省时间,还省心。
2.2 图像读取与显示(OpenCV基础)
好,理论说完了,咱们上手实操。
OpenCV 是计算机视觉领域最常用的库。我用了快十年了,从 OpenCV 2.x 一直用到现在的 4.x。说实话,它虽然有些接口设计得不太优雅,但胜在稳定、全面。
先看读取图像:
import cv2
# 读取彩色图像
img_color = cv2.imread('road.jpg')
# 读取灰度图像
img_gray = cv2.imread('road.jpg', cv2.IMREAD_GRAYSCALE)
这里有个坑,我必须提醒你。OpenCV 读取图像的默认颜色顺序是 BGR,不是 RGB!
避坑指南:我曾经在一个项目里,用 OpenCV 读图,然后用 Matplotlib 显示,结果发现颜色全不对。查了半天,才发现 OpenCV 默认是 BGR 顺序,而 Matplotlib 默认是 RGB。解决方案很简单:
img_rgb = cv2.cvtColor(img_color, cv2.COLOR_BGR2RGB)
记住这个转换,能省你半天调试时间。
显示图像也很简单:
cv2.imshow('Window Title', img_color)
cv2.waitKey(0) # 等待按键
cv2.destroyAllWindows()
为什么会这样?waitKey(0) 的意思是无限等待按键。如果不加这一行,窗口会一闪而过,你根本看不到图像。嗯,这里要注意,waitKey 的参数单位是毫秒。如果你设成 waitKey(1000),窗口会显示 1 秒后自动关闭。
2.3 图像属性:尺寸、通道
拿到图像后,第一件事就是看它的属性。就像你拿到一张照片,先看尺寸一样。
OpenCV 里,图像是一个 NumPy 数组。所以我们可以直接用 NumPy 的属性:
import cv2
img = cv2.imread('road.jpg')
# 获取图像形状 (高度, 宽度, 通道数)
height, width, channels = img.shape
print(f"图像尺寸: {width} x {height}")
print(f"通道数: {channels}")
# 获取像素总数
total_pixels = img.size
print(f"总像素数: {total_pixels}")
# 获取数据类型
dtype = img.dtype
print(f"数据类型: {dtype}")
输出示例:
图像尺寸: 1920 x 1080
通道数: 3
总像素数: 6220800
数据类型: uint8
这里有几个关键点:
- shape:返回 (高度, 宽度, 通道数)。注意顺序,不是 (宽度, 高度)。我刚开始学的时候老搞混。
- 通道数:彩色图是 3,灰度图是 1。如果是 PNG 带透明通道,那就是 4。
- dtype:通常是 uint8,即 0~255 的整数。有些高动态范围图像会用 uint16 或 float32。
重要提醒:在自动驾驶场景中,摄像头分辨率越来越高。1080p 的一张彩色图,内存占用是 1920 × 1080 × 3 = 6.2 MB。如果每秒处理 30 帧,那就是 186 MB/s 的数据量。所以,合理选择图像尺寸和通道数,对系统性能影响巨大。
我个人习惯,在项目初期先用小尺寸图像调试,比如 640 × 480。等算法稳定了,再上全分辨率。这样能大幅缩短调试周期。
2.4 实战小练习
光说不练假把式。我建议你现在就打开 Python,跑一下这段代码:
import cv2
import numpy as np
# 创建一个纯红色的图像
red_img = np.zeros((300, 300, 3), dtype=np.uint8)
red_img[:, :] = (0, 0, 255) # BGR 顺序,所以红色是 (0, 0, 255)
# 显示图像
cv2.imshow('Red Image', red_img)
cv2.waitKey(0)
cv2.destroyAllWindows()
# 检查属性
print(f"形状: {red_img.shape}")
print(f"数据类型: {red_img.dtype}")
试试看,把 (0, 0, 255) 改成 (255, 0, 0) 会显示什么颜色?改成 (0, 255, 0) 呢?
嗯,这就是图像处理最基础的东西。下一章,我们会深入聊图像的颜色空间转换和几何变换。到时候你会发现,今天学的这些,全是后面所有操作的基础。
记住一句话:图像处理没有捷径。把基础打牢了,后面学什么都快。
公众号:蓝海资料掘金营,微信deep3321