1. 数据采集与预处理
任务目标
本案例完成一个最小可复现的驾驶数据采集与预处理闭环:从模拟器(CARLA)采集图像、速度、转向角数据,执行清洗(剔除异常帧)、标注(生成转向角标签)并转换为标准数据集格式(HDF5)。最终交付一个可直接运行的Python脚本,输出可被后续模仿学习模型直接加载的数据文件。
环境依赖
- Python 3.8+
- CARLA 0.9.14(模拟器,需单独启动服务端)
- numpy、h5py、opencv-python
- 安装命令:
pip install numpy h5py opencv-python
实现方案
脚本通过CARLA Python API连接模拟器,控制车辆沿随机路线行驶,以10Hz频率同步采集前方摄像头图像(640×480 RGB)、车辆速度(km/h)和转向角(弧度)。采集完成后执行三步预处理:清洗——剔除图像亮度异常(过曝/过暗)及车速为0的静止帧;标注——将转向角作为唯一标签,与图像一一对应;格式转换——将图像压缩为JPEG字节流存入HDF5文件,同时保存速度数组和标签数组,形成可直接用于训练的数据集。
关键完整代码
import carla
import numpy as np
import cv2
import h5py
import time
import math
class DataCollector:
def __init__(self, host='localhost', port=2000):
self.client = carla.Client(host, port)
self.client.set_timeout(10.0)
self.world = self.client.get_world()
self.bp_lib = self.world.get_blueprint_library()
# 车辆与传感器配置
self.vehicle_bp = self.bp_lib.filter('vehicle.tesla.model3')[0]
self.camera_bp = self.bp_lib.find('sensor.camera.rgb')
self.camera_bp.set_attribute('image_size_x', '640')
self.camera_bp.set_attribute('image_size_y', '480')
self.camera_bp.set_attribute('fov', '90')
self.vehicle = None
self.camera = None
self.images = []
self.speeds = []
self.steerings = []
self._image = None
self._speed = 0.0
self._steering = 0.0
def _camera_callback(self, image):
"""将CARLA原始图像转为RGB数组"""
img = np.frombuffer(image.raw_data, dtype=np.uint8)
img = img.reshape((image.height, image.width, 4))
self._image = img[:, :, :3].copy()
def _control_callback(self, control):
"""记录当前控制指令"""
self._steering = control.steer
def start(self):
"""生成车辆并附加传感器"""
spawn_point = self.world.get_map().get_spawn_points()[0]
self.vehicle = self.world.spawn_actor(self.vehicle_bp, spawn_point)
# 摄像头挂载到车辆前挡风位置
cam_transform = carla.Transform(carla.Location(x=1.5, z=1.8))
self.camera = self.world.spawn_actor(self.camera_bp, cam_transform, attach_to=self.vehicle)
self.camera.listen(lambda img: self._camera_callback(img))
# 启用自动驾驶模式(模拟器内置控制器)
self.vehicle.set_autopilot(True)
def collect(self, duration=30):
"""采集指定时长的数据"""
start_time = time.time()
while time.time() - start_time < duration:
if self._image is not None:
# 读取车辆速度(km/h)
vel = self.vehicle.get_velocity()
self._speed = 3.6 * math.sqrt(vel.x**2 + vel.y**2 + vel.z**2)
# 读取当前转向角(由自动驾驶控制器产生)
control = self.vehicle.get_control()
self._steering = control.steer
self.images.append(self._image)
self.speeds.append(self._speed)
self.steerings.append(self._steering)
self._image = None # 重置,等待下一帧
time.sleep(0.1) # 10Hz采样
def preprocess(self):
"""清洗数据并返回有效索引"""
valid_idx = []
for i, (img, spd) in enumerate(zip(self.images, self.speeds)):
# 条件1:剔除静止帧(速度 < 0.5 km/h)
if spd < 0.5:
continue
# 条件2:剔除过暗/过曝帧(灰度均值超出[40, 200])
gray = cv2.cvtColor(img, cv2.COLOR_RGB2GRAY)
mean_brightness = gray.mean()
if mean_brightness < 40 or mean_brightness > 200:
continue
valid_idx.append(i)
return valid_idx
def save_hdf5(self, valid_idx, output_path='driving_data.h5'):
"""将有效数据保存为HDF5格式"""
with h5py.File(output_path, 'w') as f:
# 图像压缩存储
img_ds = f.create_dataset('images', (len(valid_idx),), dtype='S' + str(640*480*3))
for j, i in enumerate(valid_idx):
img_bytes = cv2.imencode('.jpg', self.images[i])[1].tobytes()
img_ds[j] = np.frombuffer(img_bytes, dtype=np.uint8)
# 速度与转向角
f.create_dataset('speeds', data=np.array([self.speeds[i] for i in valid_idx]))
f.create_dataset('steerings', data=np.array([self.steerings[i] for i in valid_idx]))
def cleanup(self):
"""释放资源"""
if self.camera:
self.camera.destroy()
if self.vehicle:
self.vehicle.destroy()
if __name__ == '__main__':
collector = DataCollector()
try:
collector.start()
print("开始采集数据...")
collector.collect(duration=30) # 采集30秒
print(f"原始帧数: {len(collector.images)}")
valid = collector.preprocess()
print(f"清洗后有效帧数: {len(valid)}")
collector.save_hdf5(valid)
print("数据已保存至 driving_data.h5")
finally:
collector.cleanup()
运行与验证
- 启动CARLA模拟器:在CARLA安装目录运行
./CarlaUE4.sh(Linux)或CarlaUE4.exe(Windows) - 运行采集脚本:
python collect_data.py - 验证数据完整性:执行以下Python代码检查输出文件
import h5py
with h5py.File('driving_data.h5', 'r') as f:
print("图像数量:", len(f['images']))
print("速度数组形状:", f['speeds'].shape)
print("转向角范围:", f['steerings'][:].min(), "~", f['steerings'][:].max())
# 解码第一张图像验证
import cv2, numpy as np
img_bytes = f['images'][0]
img = cv2.imdecode(np.frombuffer(img_bytes, dtype=np.uint8), cv2.IMREAD_COLOR)
print("图像尺寸:", img.shape)
通过条件:脚本无报错运行完毕;HDF5文件中图像数量大于0且与速度/转向角数组长度一致;解码后的图像尺寸为(480, 640, 3);转向角数值范围在[-1, 1]之间(CARLA转向角归一化值)。
常见问题
- 连接失败:确认CARLA服务端已启动,且端口(默认2000)未被占用
- 无数据采集:检查摄像头回调是否触发,可在
_camera_callback中添加打印语句调试 - 清洗后数据为空:若车辆未移动(速度始终为0),可调整采集路线或增加采集时长