传感器初探:RGB相机原理与配置、深度相机数据解读、语义分割相机、传感器数据流与回调函数
各位同学,欢迎来到传感器实战的第一课。
说实话,做自动驾驶感知这么多年,我最大的体会就是:传感器是算法的眼睛。你算法再牛,传感器数据没用好,那就是巧妇难为无米之炊。今天咱们就来聊聊CARLA里最常用的三种相机——RGB相机、深度相机、语义分割相机。
RGB相机:原理与配置
RGB相机大家最熟悉了,就是咱们平时用的彩色摄像头。在CARLA里,它模拟的是真实世界的光学成像过程。
核心原理其实不复杂:光线通过镜头,打到CMOS传感器上,光电转换后生成数字图像。CARLA用虚幻引擎的渲染管线,直接给你输出一张1920x1080的彩色图。
配置起来也很直接,我贴一段我常用的代码:
import carla
# 连接到CARLA服务器
client = carla.Client('localhost', 2000)
world = client.get_world()
# 创建RGB相机蓝图
bp_library = world.get_blueprint_library()
rgb_bp = bp_library.find('sensor.camera.rgb')
# 配置参数
rgb_bp.set_attribute('image_size_x', '1920')
rgb_bp.set_attribute('image_size_y', '1080')
rgb_bp.set_attribute('fov', '90.0') # 视场角
rgb_bp.set_attribute('sensor_tick', '0.05') # 20FPS
# 挂载到车辆上
transform = carla.Transform(carla.Location(x=1.5, z=2.4))
sensor = world.spawn_actor(rgb_bp, transform, attach_to=vehicle)
这里我特别想提一下视场角(FOV)。我在项目中遇到过,FOV设太大,图像边缘畸变严重;设太小,盲区又大。一般自动驾驶用90度比较均衡,但如果你做环视拼接,可能需要120度甚至更大。
深度相机:数据解读
深度相机,说白了就是能告诉你每个像素离相机有多远。CARLA里它输出的是灰度图,像素值代表距离。
嗯,这里要注意:CARLA的深度相机输出的是归一化深度。什么意思?就是它把实际距离映射到了0到1之间。你需要自己反算回去。
我给大家看个数据解读的例子:
import numpy as np
def depth_to_meters(depth_image):
# CARLA深度图是3通道的,需要先解码
# 实际距离 = 1000 * (R + G * 256 + B * 256 * 256) / (256 * 256 * 256 - 1)
normalized = np.dot(depth_image, [1.0, 256.0, 65536.0])
normalized /= 16777215.0 # 2^24 - 1
in_meters = normalized * 1000.0 # 最大1000米
return in_meters
你想想看,为什么是1000米?因为CARLA的深度相机有效范围就是0到1000米。超过这个范围,数据就不可靠了。
语义分割相机:像素级理解
语义分割相机,这是CARLA给咱们的作弊神器。它直接输出每个像素的语义标签——哪块是路,哪块是车,哪块是人。
配置方式和RGB相机几乎一样,只是蓝图名字不同:
ss_bp = bp_library.find('sensor.camera.semantic_segmentation')
# 同样可以设置分辨率、FOV等
ss_bp.set_attribute('image_size_x', '1920')
ss_bp.set_attribute('image_size_y', '1080')
输出的图像里,每个像素值对应一个标签ID。比如:
| 标签ID | 含义 | 颜色 |
|---|---|---|
| 0 | 未标注 | 黑色 |
| 1 | 道路 | 灰色 |
| 2 | 人行道 | 蓝色 |
| 3 | 建筑 | 红色 |
| 4 | 车辆 | 绿色 |
| 5 | 行人 | 黄色 |
我个人习惯用这个数据来做真值验证。比如你训练了一个语义分割模型,不知道效果怎么样?拿CARLA的语义分割相机输出当ground truth,一比就知道差距了。
传感器数据流与回调函数
好了,传感器配好了,数据怎么拿?这就涉及到回调函数了。
CARLA的传感器是异步工作的。你启动传感器后,它会在后台不断采集数据,每采集一帧就调用你注册的回调函数。
看这个例子:
# 定义回调函数
def process_rgb_image(image):
# image是carla.Image对象
array = np.frombuffer(image.raw_data, dtype=np.uint8)
array = array.reshape((image.height, image.width, 4))
# 去掉alpha通道
rgb = array[:, :, :3]
# 这里可以做你的感知算法处理
print(f"收到RGB图像,尺寸:{rgb.shape}")
# 注册回调
sensor.listen(process_rgb_image)
为什么用回调而不是轮询?你想想看,如果每帧都去轮询,CPU得空转多少?回调是事件驱动的,数据来了才处理,效率高得多。
最后,给大家画个图,把今天的内容串起来:
这张图把今天的核心逻辑都串起来了。三种传感器各自独立工作,通过回调函数把数据传给算法层。记住这个架构,后面做多传感器融合的时候,思路就清晰了。
好了,传感器初探就到这里。下一节课咱们会实际动手,在CARLA里跑通第一个感知算法。到时候见。