From 47f6b86563479699b02a0a4b73cbdfa045c56964 Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Mon, 22 Sep 2025 10:56:00 +0800 Subject: [PATCH 01/24] =?UTF-8?q?=E6=97=A0=E4=BA=BA=E8=BD=A6=E7=9A=84?= =?UTF-8?q?=E6=B7=B1=E5=BA=A6=E8=AF=AD=E4=B9=89=E5=88=86=E5=89=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/carla_autonomous_driving/README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 src/carla_autonomous_driving/README.md diff --git a/src/carla_autonomous_driving/README.md b/src/carla_autonomous_driving/README.md new file mode 100644 index 0000000000..e69de29bb2 From ce4d0cce30573d19645ed544f19a4e4d46d7ea34 Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Mon, 24 Nov 2025 09:35:47 +0800 Subject: [PATCH 02/24] =?UTF-8?q?=E6=9B=B4=E6=96=B0=E6=84=9F=E7=9F=A5?= =?UTF-8?q?=E6=A8=A1=E5=9D=97README=E5=B9=B6=E6=B7=BB=E5=8A=A0=E4=BC=A0?= =?UTF-8?q?=E6=84=9F=E5=99=A8=E7=8E=AF=E5=A2=83=E8=84=9A=E6=9C=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../README.md | 100 ++++ .../basic_environment_with_sensors.py | 441 ++++++++++++++++++ 2 files changed, 541 insertions(+) create mode 100644 src/carla_autonomous_driving_perception/README.md create mode 100644 src/carla_autonomous_driving_perception/basic_environment_with_sensors.py diff --git a/src/carla_autonomous_driving_perception/README.md b/src/carla_autonomous_driving_perception/README.md new file mode 100644 index 0000000000..aa6feafbaa --- /dev/null +++ b/src/carla_autonomous_driving_perception/README.md @@ -0,0 +1,100 @@ +# 自动驾驶系统(基于 CARLA 与深度学习) + +## 项目概述 +本项目构建了基于 CARLA 仿真平台的自动驾驶系统,通过深度学习技术提升车辆感知能力,集成多模态传感器实现全面环境认知,提供模块化、可扩展的代码库支持自动驾驶算法研发。借助 CARLA 的高保真仿真能力,模拟真实世界驾驶场景与挑战,为自动驾驶技术的学习、研究与开发提供可靠环境。 + +## 环境准备 + +### 依赖库安装 +```bash +# 建议使用Python 3.7及以上版本(推荐虚拟环境) +pip install carla +pip install numpy opencv-python keras tensorflow pygame matplotlib +``` + +#### 依赖说明: +- carla:自动驾驶高保真仿真平台核心库 +- python 3.7+:项目开发与运行的 Python 版本 +- opencv-python:图像数据处理与可视化 +- keras:深度学习语义分割模型构建 +- tensorflow:深度学习模型训练与优化 +- pygame:手动控制车辆功能支持 +- numpy:数值计算基础支持 +- matplotlib:数据可视化工具 + +### 开发环境配置 +1. 下载并安装[CARLA 官方发行版](https://github.com/carla-simulator/carla/releases)(推荐最新稳定版本) +2. 安装[VSCode](https://code.visualstudio.com/)并配置 Python 3.7+ 解释器 +3. 推荐插件:Python、Pylance、Code Runner(提升开发效率) + +## 项目结构 + +| 文件名 | 功能描述 | +|--------------------|--------------------------------------------------------------| +| `main.py` | 核心程序入口,负责 CARLA 客户端连接、世界初始化与主循环控制 | +| `perception.py` | 感知模块,基于深度学习实现语义分割与环境要素识别 | +| `sensor_manager.py`| 传感器管理模块,处理 RGBA 摄像头、LiDAR 等多模态数据采集与同步 | +| `model_trainer.py` | 模型训练工具,提供语义分割 CNN 模型的训练、验证与优化流程 | +| `utils.py` | 通用工具函数库,包含数据转换、可视化与性能评估等辅助功能 | +| `config.yaml` | 配置文件,存储仿真参数(传感器类型、模型参数、仿真帧率等) | +| `README.md` | 项目说明文档 | + +## 核心功能 + +### 1. 高保真仿真环境 +- 基于 CARLA 构建多样化驾驶场景,支持天气(晴、雨、雾)、时间(昼、夜)等环境动态调整 +- 模拟多车辆与交通参与者,还原复杂交通流场景 +- 支持 CARLA 服务器自动连接、断开重连与仿真状态实时监控 + +### 2. 多模态感知系统 +- 集成 RGBA 摄像头(色彩纹理信息)、LiDAR(深度距离信息)等多类传感器 +- 基于深度学习实现实时语义分割,精准识别道路、车辆、行人、交通标志等核心要素 +- 优化传感器数据与车辆状态的时间戳同步,提升感知准确性 + +### 3. 深度学习语义分割 +- 针对自动驾驶场景优化的 CNN 网络架构,兼顾分割精度与实时性 +- 提供完整训练流程:数据加载、模型训练、损失计算与权重优化 +- 支持交并比(IoU)等核心指标评估,量化模型性能 + +### 4. 数据收集与可视化 +- 支持批量采集传感器数据(图像、点云)与对应标注,用于模型训练 +- 实时展示车辆动态、传感器原始数据与语义分割结果,便于直观分析系统性能 + +## 使用方法 + +### 启动 CARLA 服务器: +```bash +# 在CARLA安装目录下执行 +./CarlaUE4.sh # Linux/Mac +CarlaUE4.exe # Windows +``` + +### 运行自动驾驶系统: +```bash +python main.py --mode auto # 自动模式(启用感知与决策) +python main.py --mode manual # 手动模式(Pygame键盘控制) +``` + +### 数据采集与模型训练: +```bash +# 采集传感器数据(存储至./dataset目录) +python sensor_manager.py --record --output ./dataset + +# 训练语义分割模型 +python model_trainer.py --data ./dataset --epochs 50 +``` + +## 参数调整指南 + +| 参数 | 调整范围 | 效果说明 | +|--------------------|-------------------|----------------------------------| +| `camera_resolution` | 1280x720~1920x1080 | 提高分辨率增强细节(增加计算量) | +| `lidar_points_per_second` | 50000~200000 | 提高值提升点云密度(增加内存占用)| +| `model_batch_size` | 8~32 | 增大批次加速训练(需更多显存) | +| `simulation_fps` | 10~60 | 提高帧率增强实时性(对硬件要求更高)| + +## 参考资料 +- [CARLA 官方文档](https://carla.readthedocs.io/) +- [Keras 深度学习模型构建指南](https://keras.io/guides/) +- [TensorFlow 模型优化文档](https://www.tensorflow.org/guide/keras/optimizers) +- [语义分割算法综述](https://arxiv.org/abs/1704.06857) \ No newline at end of file diff --git a/src/carla_autonomous_driving_perception/basic_environment_with_sensors.py b/src/carla_autonomous_driving_perception/basic_environment_with_sensors.py new file mode 100644 index 0000000000..9e84fb2435 --- /dev/null +++ b/src/carla_autonomous_driving_perception/basic_environment_with_sensors.py @@ -0,0 +1,441 @@ +import carla +import argparse +import random +import time +import numpy as np +import pygame + + +class CustomTimer: + def __init__(self): + try: + self.timer = time.perf_counter + except AttributeError: + self.timer = time.time + + def time(self): + return self.timer() + + +class DisplayManager: + def __init__(self, grid_size, window_size): + pygame.init() + pygame.font.init() + self.display = pygame.display.set_mode( + window_size, pygame.HWSURFACE | pygame.DOUBLEBUF + ) + + self.grid_size = grid_size + self.window_size = window_size + self.sensor_list = [] + + def get_window_size(self): + return [int(self.window_size[0]), int(self.window_size[1])] + + def get_display_size(self): + return [ + int(self.window_size[0] / self.grid_size[1]), + int(self.window_size[1] / self.grid_size[0]), + ] + + def get_display_offset(self, gridPos): + dis_size = self.get_display_size() + return [int(gridPos[1] * dis_size[0]), int(gridPos[0] * dis_size[1])] + + def add_sensor(self, sensor): + self.sensor_list.append(sensor) + + def get_sensor_list(self): + return self.sensor_list + + def render(self): + if not self.render_enabled(): + return + + for s in self.sensor_list: + s.render() + + pygame.display.flip() + + def destroy(self): + for s in self.sensor_list: + s.destroy() + + def render_enabled(self): + return self.display != None + + +class SensorManager: + def __init__( + self, + world, + display_man, + sensor_type, + transform, + attached, + sensor_options, + display_pos, + ): + self.surface = None + self.world = world + self.display_man = display_man + self.display_pos = display_pos + self.sensor = self.init_sensor(sensor_type, transform, attached, sensor_options) + self.sensor_options = sensor_options + self.timer = CustomTimer() + + self.time_processing = 0.0 + self.tics_processing = 0 + + self.display_man.add_sensor(self) + + def init_sensor(self, sensor_type, transform, attached, sensor_options): + if sensor_type == "RGBCamera": + camera_bp = self.world.get_blueprint_library().find("sensor.camera.rgb") + disp_size = self.display_man.get_display_size() + scalar = 1 + disp_size = [256, 256] * scalar + camera_bp.set_attribute("image_size_x", str(disp_size[0])) + camera_bp.set_attribute("image_size_y", str(disp_size[1])) + for key in sensor_options: + camera_bp.set_attribute(key, sensor_options[key]) + + camera = self.world.spawn_actor(camera_bp, transform, attach_to=attached) + camera.listen(self.save_rgb_image) + + return camera + + elif sensor_type == "LiDAR": + lidar_bp = self.world.get_blueprint_library().find("sensor.lidar.ray_cast") + lidar_bp.set_attribute("range", "100") + lidar_bp.set_attribute( + "dropoff_general_rate", + lidar_bp.get_attribute("dropoff_general_rate").recommended_values[0], + ) + lidar_bp.set_attribute( + "dropoff_intensity_limit", + lidar_bp.get_attribute("dropoff_intensity_limit").recommended_values[0], + ) + lidar_bp.set_attribute( + "dropoff_zero_intensity", + lidar_bp.get_attribute("dropoff_zero_intensity").recommended_values[0], + ) + + for key in sensor_options: + lidar_bp.set_attribute(key, sensor_options[key]) + + lidar = self.world.spawn_actor(lidar_bp, transform, attach_to=attached) + + lidar.listen(self.save_lidar_image) + + return lidar + + elif sensor_type == "SemanticLiDAR": + lidar_bp = self.world.get_blueprint_library().find( + "sensor.lidar.ray_cast_semantic" + ) + lidar_bp.set_attribute("range", "100") + + for key in sensor_options: + lidar_bp.set_attribute(key, sensor_options[key]) + + lidar = self.world.spawn_actor(lidar_bp, transform, attach_to=attached) + + lidar.listen(self.save_semanticlidar_image) + + return lidar + + elif sensor_type == "Radar": + radar_bp = self.world.get_blueprint_library().find("sensor.other.radar") + for key in sensor_options: + radar_bp.set_attribute(key, sensor_options[key]) + + radar = self.world.spawn_actor(radar_bp, transform, attach_to=attached) + radar.listen(self.save_radar_image) + + return radar + + else: + return None + + def get_sensor(self): + return self.sensor + + def save_rgb_image(self, image): + t_start = self.timer.time() + + image.convert(carla.ColorConverter.Raw) + array = np.frombuffer(image.raw_data, dtype=np.dtype("uint8")) + array = np.reshape(array, (image.height, image.width, 4)) + array = array[:, :, :3] + array = array[:, :, ::-1] + + if self.display_man.render_enabled(): + self.surface = pygame.surfarray.make_surface(array.swapaxes(0, 1)) + + t_end = self.timer.time() + self.time_processing += t_end - t_start + self.tics_processing += 1 + + def save_lidar_image(self, image): + t_start = self.timer.time() + + disp_size = self.display_man.get_display_size() + lidar_range = 2.0 * float(self.sensor_options["range"]) + + points = np.frombuffer(image.raw_data, dtype=np.dtype("f4")) + points = np.reshape(points, (int(points.shape[0] / 4), 4)) + lidar_data = np.array(points[:, :2]) + lidar_data *= min(disp_size) / lidar_range + lidar_data += (0.5 * disp_size[0], 0.5 * disp_size[1]) + lidar_data = np.fabs(lidar_data) # pylint: disable=E1111 + lidar_data = lidar_data.astype(np.int32) + lidar_data = np.reshape(lidar_data, (-1, 2)) + lidar_img_size = (disp_size[0], disp_size[1], 3) + lidar_img = np.zeros((lidar_img_size), dtype=np.uint8) + + lidar_img[tuple(lidar_data.T)] = (255, 255, 255) + + if self.display_man.render_enabled(): + self.surface = pygame.surfarray.make_surface(lidar_img) + + t_end = self.timer.time() + self.time_processing += t_end - t_start + self.tics_processing += 1 + + def save_semanticlidar_image(self, image): + t_start = self.timer.time() + + disp_size = self.display_man.get_display_size() + lidar_range = 2.0 * float(self.sensor_options["range"]) + + points = np.frombuffer(image.raw_data, dtype=np.dtype("f4")) + points = np.reshape(points, (int(points.shape[0] / 6), 6)) + lidar_data = np.array(points[:, :2]) + lidar_data *= min(disp_size) / lidar_range + lidar_data += (0.5 * disp_size[0], 0.5 * disp_size[1]) + lidar_data = np.fabs(lidar_data) # pylint: disable=E1111 + lidar_data = lidar_data.astype(np.int32) + lidar_data = np.reshape(lidar_data, (-1, 2)) + lidar_img_size = (disp_size[0], disp_size[1], 3) + lidar_img = np.zeros((lidar_img_size), dtype=np.uint8) + + lidar_img[tuple(lidar_data.T)] = (255, 255, 255) + + if self.display_man.render_enabled(): + self.surface = pygame.surfarray.make_surface(lidar_img) + + t_end = self.timer.time() + self.time_processing += t_end - t_start + self.tics_processing += 1 + + def save_radar_image(self, radar_data): + t_start = self.timer.time() + points = np.frombuffer(radar_data.raw_data, dtype=np.dtype("f4")) + points = np.reshape(points, (len(radar_data), 4)) + + t_end = self.timer.time() + self.time_processing += t_end - t_start + self.tics_processing += 1 + + def render(self): + if self.surface is not None: + offset = self.display_man.get_display_offset(self.display_pos) + self.display_man.display.blit(self.surface, offset) + + def destroy(self): + self.sensor.destroy() + + +def run_simulation(args, client): + display_manager = None + vehicle = None + vehicle_list = [] + timer = CustomTimer() + + try: + + # Getting the world and + world = client.get_world() + original_settings = world.get_settings() + + if args.sync: + traffic_manager = client.get_trafficmanager(8000) + settings = world.get_settings() + traffic_manager.set_synchronous_mode(True) + settings.synchronous_mode = True + settings.fixed_delta_seconds = 0.05 + world.apply_settings(settings) + + # Changing the weather to clear noon + weather = carla.WeatherParameters( + cloudiness=0.0, + precipitation=22.0, + wetness=1.5, + fog_density=0.0, + wind_intensity=0.0, + sun_altitude_angle=10.0, + sun_azimuth_angle=34.0, + ) + world.set_weather(weather) + + # Instantiating the vehicle to which we attached the sensors + # Using a Tesla Model 3 as our client AV to be controlled + vehicle_bp = world.get_blueprint_library().filter("*model3*")[0] + vehicle = world.spawn_actor( + vehicle_bp, random.choice(world.get_map().get_spawn_points()) + ) + vehicle_list.append(vehicle) + + vehicle.set_autopilot(False) + + # Display Manager organize all the sensors an its display in a window + display_manager = DisplayManager( + grid_size=[2, 3], window_size=[args.width, args.height] + ) + + SensorManager( + world, + display_manager, + "RGBCamera", + carla.Transform(carla.Location(x=0, z=2.4), carla.Rotation(yaw=-90)), + vehicle, + {}, + display_pos=[0, 0], + ) + SensorManager( + world, + display_manager, + "RGBCamera", + carla.Transform(carla.Location(x=0, z=2.4), carla.Rotation(yaw=+00)), + vehicle, + {}, + display_pos=[0, 1], + ) + SensorManager( + world, + display_manager, + "RGBCamera", + carla.Transform(carla.Location(x=0, z=2.4), carla.Rotation(yaw=+90)), + vehicle, + {}, + display_pos=[0, 2], + ) + SensorManager( + world, + display_manager, + "RGBCamera", + carla.Transform(carla.Location(x=0, z=2.4), carla.Rotation(yaw=180)), + vehicle, + {}, + display_pos=[1, 1], + ) + + SensorManager( + world, + display_manager, + "LiDAR", + carla.Transform(carla.Location(x=0, z=2.4)), + vehicle, + { + "channels": "64", + "range": "100", + "points_per_second": "250000", + "rotation_frequency": "20", + }, + display_pos=[1, 0], + ) + SensorManager( + world, + display_manager, + "SemanticLiDAR", + carla.Transform(carla.Location(x=0, z=2.4)), + vehicle, + { + "channels": "64", + "range": "100", + "points_per_second": "100000", + "rotation_frequency": "20", + }, + display_pos=[1, 2], + ) + + # Simulation loop + call_exit = False + time_init_sim = timer.time() + while True: + # Carla Tick + if args.sync: + world.tick() + else: + world.wait_for_tick() + + # Render received data + display_manager.render() + + for event in pygame.event.get(): + if event.type == pygame.QUIT: + call_exit = True + elif event.type == pygame.KEYDOWN: + if event.key == pygame.K_ESCAPE or event.key == pygame.K_q: + call_exit = True + break + + if call_exit: + break + + finally: + if display_manager: + display_manager.destroy() + + client.apply_batch([carla.command.DestroyActor(x) for x in vehicle_list]) + + world.apply_settings(original_settings) + + +def main(): + argparser = argparse.ArgumentParser(description="Grid of sensors on the our Car") + argparser.add_argument( + "--host", + metavar="H", + default="127.0.0.1", + help="IP of the host server (default: 127.0.0.1)", + ) + argparser.add_argument( + "-p", + "--port", + metavar="P", + default=2000, + type=int, + help="TCP port to listen to (default: 2000)", + ) + argparser.add_argument( + "--sync", action="store_true", help="Synchronous mode execution" + ) + argparser.add_argument( + "--async", dest="sync", action="store_false", help="Asynchronous mode execution" + ) + argparser.set_defaults(sync=True) + argparser.add_argument( + "--res", + metavar="WIDTHxHEIGHT", + default="1280x720", + help="window resolution (default: 1280x720)", + ) + + args = argparser.parse_args() + + args.width, args.height = [int(x) for x in args.res.split("x")] + + try: + client = carla.Client(args.host, args.port) + client.set_timeout(5.0) + + run_simulation(args, client) + + except KeyboardInterrupt: + print("\nKeyboard Interrupt or Cancelled by user") + + +if __name__ == "__main__": + main() From 2269e13eb8619ff05d8524ada0e9a303f078bbfc Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Mon, 1 Dec 2025 10:26:23 +0800 Subject: [PATCH 03/24] =?UTF-8?q?=E5=8A=A0=E8=BD=BDTown05=E5=9C=B0?= =?UTF-8?q?=E5=9B=BE=EF=BC=8C=E5=AE=9A=E4=BD=8DModel3=E5=B9=B6=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E8=87=B3=E5=90=8E=E4=B8=8A=E6=96=B9=E8=BF=BD=E5=B0=BE?= =?UTF-8?q?=E8=A7=86=E8=A7=92=EF=BC=8C=E8=8E=B7=E5=8F=96=E5=85=A8=E5=9C=B0?= =?UTF-8?q?=E5=9B=BE=E5=90=88=E6=B3=95=E7=94=9F=E6=88=90=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../carlaCNN.ipynb | 340 ++++++++++++++++++ 1 file changed, 340 insertions(+) create mode 100644 src/carla_autonomous_driving_perception/carlaCNN.ipynb diff --git a/src/carla_autonomous_driving_perception/carlaCNN.ipynb b/src/carla_autonomous_driving_perception/carlaCNN.ipynb new file mode 100644 index 0000000000..9170e30855 --- /dev/null +++ b/src/carla_autonomous_driving_perception/carlaCNN.ipynb @@ -0,0 +1,340 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "824d0b8e", + "metadata": {}, + "source": [ + "## Advanced Autonomous Vehicle(AV) Self Driving System\n", + "#### Technolgies/Softwares/Non-Standard libraries used: \n", + " - CARLA (Open Source AV Simulator)\n", + " - Keras (To implement Deep Learning Models)\n", + " - Tensorflow (To train the model weights)\n", + " - Pygame (To enable the model to imitate human-like input to the simulator)\n", + " - OpenCV (To fetch and display/manipulate the data collected from virtual senors, videlicet, RGB Camera, LiDAR, Collision Detector)" + ] + }, + { + "cell_type": "code", + "execution_count": 1, + "id": "230ac814", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-22T18:16:39.365234400Z", + "start_time": "2023-10-22T18:16:38.309235100Z" + } + }, + "outputs": [], + "source": [ + "# Importing standard libraries\n", + "import numpy as np\n", + "from matplotlib import pyplot as plt\n", + "import pandas as pd\n", + "import random\n", + "import time\n", + "import os" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "918b653a", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-22T18:16:45.025256100Z", + "start_time": "2023-10-22T18:16:40.364122800Z" + } + }, + "outputs": [], + "source": [ + "# Importing Machine Learning & Deep Learning Libraries\n", + "# Installed tensorflow directML instead in order to have AMD GPU support in Windows 10 for model training\n", + "import tensorflow as tf" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "34763218da257835", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-22T18:16:47.300784800Z", + "start_time": "2023-10-22T18:16:47.246787200Z" + }, + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU'),\n", + " PhysicalDevice(name='/physical_device:GPU:1', device_type='GPU')]" + ] + }, + "execution_count": 3, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "# Avoid OOM errors by setting GPU Memory Consumption Growth and making sure that the dedicated gpus are recognizable to tensorflow\n", + "gpus = tf.config.experimental.list_physical_devices('GPU')\n", + "for gpu in gpus:\n", + " tf.config.experimental.set_memory_growth(gpu, True)\n", + "gpus" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "f4c1ccdff9bbe9b7", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-22T18:16:55.780242500Z", + "start_time": "2023-10-22T18:16:50.525349600Z" + }, + "collapsed": false + }, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + ":219: RuntimeWarning: Your system is avx2 capable but pygame was not built with support for it. The performance of some of your blits could be adversely affected. Consider enabling compile time detection with environment variables like PYGAME_DETECT_AVX2=1 if you are compiling without cross compilation.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "pygame 2.5.2 (SDL 2.28.4, Python 3.8.18)\n", + "Hello from the pygame community. https://www.pygame.org/contribute.html\n" + ] + } + ], + "source": [ + "import carla\n", + "import pygame\n", + "\n", + "client = carla.Client('localhost', 2000)\n", + "client.set_timeout(5.0)\n", + "world = client.load_world(\n", + " 'Town05'\n", + ")\n", + "\n", + "bp_lib = world.get_blueprint_library()" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "33d70bcdcef2f77c", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-22T18:18:22.991767600Z", + "start_time": "2023-10-22T18:18:22.718766400Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "world.wait_for_tick()\n", + "actor_list = world.get_actors().filter(\n", + " '*model3*'\n", + ")\n", + "vehicle_list = []\n", + "for vehicle in actor_list:\n", + " vehicle_list.append(vehicle)\n", + "\n", + "vehicle = vehicle_list[0]\n", + "\n", + "def set_spectator(world):\n", + " spectator = world.get_spectator()\n", + " transform = carla.Transform(vehicle.get_transform().transform(carla.Location(x=-8, z=3)), vehicle.get_transform().rotation)\n", + " spectator.set_transform(transform)\n", + "\n", + "set_spectator(world)\n", + "spawn_points = world.get_map().get_spawn_points()" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "198b908e88040cae", + "metadata": { + "ExecuteTime": { + "end_time": "2023-10-22T18:18:26.423763800Z", + "start_time": "2023-10-22T18:18:22.996767100Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "# NPC Traffic.\n", + "for i in range(200):\n", + " vehicle_bp = random.choice(bp_lib.filter('vehicle'))\n", + " npc = world.try_spawn_actor(vehicle_bp, random.choice(spawn_points))\n", + "\n", + "#Set traffic in motion\n", + "for v in world.get_actors().filter('*vehicle*'):\n", + " v.set_autopilot(True)\n", + "\n", + "# Making sure that the non-deep-learning model is built into the simulator is turned off\n", + "vehicle.set_autopilot(False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b0ca26014cafa02f", + "metadata": { + "ExecuteTime": { + "start_time": "2023-10-22T08:31:03.247650800Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "# Real-Time RGBA sensor/camera footage\n", + "import queue\n", + "import cv2\n", + "from collections import deque\n", + "camera_bp = bp_lib.find('sensor.camera.rgb')\n", + "camera_init_trans = carla.Transform(carla.Location(x =-2,z=10))\n", + "\n", + "camera_bp.set_attribute('image_size_x', '1024')\n", + "camera_bp.set_attribute('image_size_y', '720')\n", + "\n", + "camera = world.spawn_actor(camera_bp, camera_init_trans, attach_to=vehicle)\n", + "\n", + "image_queue = queue.Queue()\n", + "camera.listen(image_queue.put)\n", + "\n", + "while True:\n", + " # Retrieve and reshape the image\n", + " world.tick()\n", + " image = image_queue.get()\n", + "\n", + " img = np.reshape(np.copy(image.raw_data), (image.height, image.width, 4))\n", + " cv2.imshow('ImageWindowName',img)\n", + " plt.imshow(img)\n", + " if cv2.waitKey(1) == ord('q'):\n", + " break\n", + "cv2.destroyAllWindows()" + ] + }, + { + "cell_type": "markdown", + "id": "52fb9b67e83d2d2d", + "metadata": { + "collapsed": false + }, + "source": [ + "# Semantic Segmentation of lanes using a RGBA Camera\n", + "- Making using of a CNN Algorithm to semantically segment the camera footage post pre-processing" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "f5e9f45339af4a22", + "metadata": { + "ExecuteTime": { + "start_time": "2023-10-22T08:22:29.754890600Z" + }, + "collapsed": false + }, + "outputs": [], + "source": [ + "img_dir = os.path.join('archive', 'train_label', 'Town04_Clear_Noon_09_09_2020_14_57_22_frame_0_label.png')" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "30612b265948431d", + "metadata": { + "ExecuteTime": { + "start_time": "2023-10-22T05:23:12.340619Z" + }, + "collapsed": false + }, + "outputs": [ + { + "data": { + "text/plain": [ + "" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + }, + { + "data": { + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAi4AAAEoCAYAAAB/+3pfAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjcuMywgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/OQEPoAAAACXBIWXMAAA9hAAAPYQGoP6dpAABAf0lEQVR4nO3deVhVdf4H8Pdd4LLJqnABwX1DcAPFK65BoakzppYamdWoI2FqOmakZuWCaZvOpDZNaVbqZDOWmkuGCi6AiKKIioqyqCxurMIF7v3+/uDnmW7ajCByuPB+Pc95Hj3nwP3ce+Dyvt/zXRRCCAEiIiIiM6CUuwAiIiKih8XgQkRERGaDwYWIiIjMBoMLERERmQ0GFyIiIjIbDC5ERERkNhhciIiIyGwwuBAREZHZYHAhIiIis8HgQkRERGZD1uDy6aefonXr1rCyskJgYCCOHTsmZzlERETUwMkWXP75z39i9uzZWLRoEU6cOIHu3bsjNDQU+fn5cpVEREREDZxCrkUWAwMD0bt3b/ztb38DABiNRnh5eeG1117Dm2+++V+/1mg04vr162jWrBkUCkV9lEtERESPSAiB4uJieHh4QKmsXduJuo5reigVFRVISkpCZGSktE+pVCIkJARxcXH3na/X66HX66X/X7t2DT4+PvVSKxEREdWt7OxstGzZslZfK8utops3b8JgMMDNzc1kv5ubG3Jzc+87PyoqCg4ODtLG0EJERGS+mjVrVuuvNYtRRZGRkSgsLJS27OxsuUsiIiKiWnqUbh6y3Cpq3rw5VCoV8vLyTPbn5eVBq9Xed75Go4FGo6mv8oiIiKiBkqXFxdLSEv7+/oiOjpb2GY1GREdHQ6fTyVESERERmQFZWlwAYPbs2Zg0aRICAgLQp08ffPLJJygtLcXLL78sV0lERETUwMkWXMaNG4cbN27g7bffRm5uLnr06IE9e/bc12GXiIiI6B7Z5nF5FEVFRXBwcJC7DCIiIqqFwsJC2Nvb1+przWJUERERERHA4EJERERmhMGFiIiIzAaDCxEREZkNBhciIiIyGwwuREREZDYYXIiIiMhsMLgQERGR2WBwISIiIrPB4EJERERmg8GFiIiIzAaDCxEREZkNBhciIiIyGwwuREREZDYYXIiIiMhsMLgQERGR2WBwISIiIrPB4EJERERmg8GFiIiIzAaDCxEREZkNBhciIiIyGwwuREREZDYYXIiIiMhsMLgQERGR2WBwISIiIrPB4EJERERmg8GFiIiIzAaDCxEREZkNBhciIiIyGwwuREREZDYYXIiIiMhsMLgQERGR2WBwISIiIrPB4EJERERmg8GFiIiIzAaDCxEREZkNBhciIiIyGzUOLrGxsRg5ciQ8PDygUCjwww8/mBwXQuDtt9+Gu7s7rK2tERISgosXL5qcc/v2bYSFhcHe3h6Ojo7405/+hJKSkkd6IkRERNT41Ti4lJaWonv37vj0008feHzFihVYvXo11q1bh4SEBNja2iI0NBTl5eXSOWFhYUhNTcW+ffuwc+dOxMbGYurUqbV/FkRERNQ0iEcAQGzbtk36v9FoFFqtVqxcuVLaV1BQIDQajdi8ebMQQoizZ88KACIxMVE6Z/fu3UKhUIhr16491OMWFhYKANy4cePGjRs3M9wKCwtrnT3qtI/LlStXkJubi5CQEGmfg4MDAgMDERcXBwCIi4uDo6MjAgICpHNCQkKgVCqRkJDwwO+r1+tRVFRkshEREVHTU6fBJTc3FwDg5uZmst/NzU06lpubC1dXV5PjarUazs7O0jm/FRUVBQcHB2nz8vKqy7KJiIjITJjFqKLIyEgUFhZKW3Z2ttwlERERkQzqNLhotVoAQF5ensn+vLw86ZhWq0V+fr7J8aqqKty+fVs657c0Gg3s7e1NNiIiImp66jS4tGnTBlqtFtHR0dK+oqIiJCQkQKfTAQB0Oh0KCgqQlJQknbN//34YjUYEBgbWZTlERETUyKhr+gUlJSW4dOmS9P8rV64gOTkZzs7O8Pb2xqxZs7BkyRJ06NABbdq0wcKFC+Hh4YFRo0YBALp06YKhQ4diypQpWLduHSorKzF9+nSMHz8eHh4edfbEiIiIqBGq6TCkAwcOPHBo06RJk4QQ1UOiFy5cKNzc3IRGoxHBwcEiLS3N5HvcunVLTJgwQdjZ2Ql7e3vx8ssvi+Li4oeugcOhuXHjxo0bN/PdHmU4tEIIIWBmioqK4ODgIHcZREREVAuFhYW17q9qFqOKiIiIiAAGFyIiIjIjDC5ERERkNhhciIiIyGwwuBAREZHZYHAhIiIis8HgQkRERGaDwYWIiIjMBoMLERERmQ0GFyIiIjIbDC5ERERkNhhciIiIyGwwuBAREZHZYHAhIiIis8HgQkRERGaDwYWIiIjMBoMLERERmQ0GFyIiIjIbDC5ERERkNhhciIiIyGwwuBAREZHZYHAhIiIis8HgQkRERGaDwYWIiIjMBoMLERERmQ0GFyIiIjIbDC5EdUChUECpVMLLywstWrSAQqGQuyQolUp06tQJrVu3bhD1EBHVBbXcBRCZK6VSCWtra3h4eKBDhw6wsbFBs2bNUFVVhZSUFCQnJ8ta37PPPotXXnkFVVVV+OSTT7Bv3z5Z6yEiqgsMLkQ1pFKp4OHhAV9fXzg6OsLW1va+4+7u7jhz5gyqqqpkqdHBwQHPPvssHBwcAAABAQGIjo6G0WiUpR4iorrC4EL0EJRKJaysrNCpUyd07NgR1tbWUKtNf32EEKiqqkJBQQHOnj0rW2gBgCeffBIeHh4AgNLSUuzevZuhhYgaBQYXov/hXutKixYtYGVlZdJfRAiByspKFBcXIzs7G+np6SgtLUVFRYWMFQM2NjZQKqu7sBUXF+PSpUuy1kNEVFcYXIh+h6WlJXx8fODr6wsrKyuTY0ajEQUFBcjIyEBGRgaKi4tRWVkpU6X3O3/+PMrKymBtbY0WLVogNDQU27dvb1A1EhHVBoML0QN4eHjAz88PLVu2NGlh0ev1yMzMRF5eHi5fvtxgg0BycjIOHz6M4OBgqFQqTJ8+He3bt8ff//533LlzR+7yiIhqTSGEEHIXUVNFRUVSp0OiuqRWq+Hu7o6BAwfC2tpa2l9SUoKzZ8/i+vXruHXrFszh18bFxQXr16+Hq6srgOpWotzcXCxZsgRnzpyR/XYWETVdhYWFsLe3r9XXMrgQ/T9bW1sEBASgbdu2UKlUAKr7sKSnp+PMmTO4efOmzBXWXPfu3REWFoYBAwZILUd6vR47duzA6tWrGV6ISBYMLkSPyN3dHYMHD4aNjY30B/7u3bs4ceIELl26JOsIoUdlZ2eHN954A/369YOdnR2A6taXf/3rX9i4cSNu3Lghc4VE1NQwuBDV0r1bQwMGDICNjQ2A6laWgoICHD16FDk5OTJXWDeUSiUGDBiA+fPnS28WRqMReXl5eOutt3Du3DmZKySipoTBhagW1Go1dDodOnToIA0d1uv1yMjIQHx8fIPtePsoBg0ahAULFqBZs2YAqkNafn4+tm/fjo0bNzbK50xEDc+jBJcarVUUFRWF3r17o1mzZnB1dcWoUaOQlpZmck55eTkiIiLg4uICOzs7jBkzBnl5eSbnZGVlYfjw4bCxsYGrqyvmzp1r1k3xZH7c3NwQGhqKjh07SqGlvLwcBw4cwKFDhxrtH/CYmBjMmjULP//8M0pLS6FQKODm5oY//elPCA8Ph1arlbtEIqL/qkYtLkOHDsX48ePRu3dvVFVV4a233sKZM2dw9uxZadrz8PBw/PTTT9iwYQMcHBwwffp0KJVKHDlyBABgMBjQo0cPaLVarFy5Ejk5OXjxxRcxZcoULFu27KHqYIsL1ZZKpULLli3Rr18/qT+LEAK3b99GYmIirl69KneJ9SYkJASRkZHS764QAnl5efjxxx/x9ddf88MEET02st0qunHjBlxdXRETE4OBAweisLAQLVq0wKZNmzB27FgA1RNhdenSBXFxcejbty92796NESNG4Pr163BzcwMArFu3DvPmzcONGzdgaWl53+Po9Xro9Xrp/0VFRfDy8qpt2dREqVQq9OnTBz4+PgAghZaMjAzExsY22laW/6Zz584IDw9Hnz59pE7JVVVVOHHiBD788ENkZmbKXCERNUb1dqvoQQ8MAM7OzgCApKQkVFZWIiQkRDqnc+fO8Pb2RlxcHAAgLi4Ofn5+UmgBgNDQUBQVFSE1NfWBjxMVFQUHBwdpY2ihmnJwcEBgYCB8fHygUCigUCig1+sRExPTZEMLUP3BYtGiRdizZw/KysoAVPf96dOnD6KiouDt7S1zhUREpmodXIxGI2bNmoWgoCD4+voCAHJzc2FpaQlHR0eTc93c3JCbmyud8+vQcu/4vWMPEhkZicLCQmnLzs6ubdnUxCiVSrRu3RqhoaFSaBFCQK/XIzY2FpcuXWqyoeWegoICvPvuu1ixYgUuXrwoTa7Xtm1brF69Gi+88II0rw0RkdxqPeV/REQEzpw5g8OHD9dlPQ+k0Wig0Wge++NQ4+Lg4IAuXbrAx8dH6oArhEB2djaOHTuGgoICeQtsYHbv3o3ExERERERgyJAhsLKyglarxdSpUxEYGIhvv/0WCQkJZjFrMBE1XrVqcZk+fTp27tyJAwcOoGXLltJ+rVaLioqK+/4g5OXlSaMVtFrtfaOM7v2fIxqorjg5OeHJJ5+Er6+vFFqMRiOys7MRExPD0PI7bt68icWLF2PVqlUoLy8HUL3YZO/evfH+++9j3LhxJms3ERHVtxoFFyEEpk+fjm3btmH//v1o06aNyXF/f39YWFggOjpa2peWloasrCzodDoAgE6nQ0pKCvLz86Vz9u3bB3t7e6nTJFFtKRQKODk5ITg4WLpl+etbQwcPHjTp6E33MxqN+PHHH/HBBx/gwoULMBgMAKpbPsPDwzF16tT7bvcSEdWXGo0qevXVV7Fp0yb8+OOP6NSpk7TfwcFBWpAuPDwcu3btwoYNG2Bvb4/XXnsNAHD06FEA/xkO7eHhgRUrViA3NxcTJ07E5MmTORyaHolCoUCPHj3g4+Mj/TwaDAbk5OTg6NGjKCoqkrlC82Nvb48hQ4bg2WefRbt27aTWltTUVCxcuBA5OTm8dURENVZvw6F/r4l4/fr1eOmllwBUT+I1Z84cbN68GXq9HqGhoVizZo3JbaDMzEyEh4fj4MGDsLW1xaRJk7B8+XKo1Q/X5YbBhX7LwcEBXbt2RadOnaSOpJWVlYiLi8OVK1eafAfcR9WyZUssW7YMHTp0kDo437lzB1988QV27tzJViwiqhFO+U9NlkKhQLt27dCtWzdpWD7wn9By4cIFGatrXH4bXoDqOZZSU1OxZMkStr4Q0UNjcKEmR6FQwNHRET4+PujYsaPUyiKEQHl5ORITExlaHoOWLVtiwoQJ+MMf/gALCwsA1a95YWEhfvrpJ2zatAm3bt2SuUoiaugYXKhJUSgU8PX1Rc+ePWFhYSF9+r83Zf3BgwdRUlIic5WNl0qlQlhYGKZMmSKFF6D69U9KSsKiRYsYXojov2JwoSbjXmgJCAgwmRStqqoKeXl5iImJwd27d2WssGlQKpUIDg7G+PHj0bFjR5PWl6SkJLz//vu4evUqbx0R0QMxuFCTYGdnh169eqFdu3YmoSU/Px/Jycm4evUqjEajjBU2PRqNBmFhYRg7dqzUx0gIgeLiYnz00UfYu3cvwwsR3YfBhRo9Ozs7BAcHo3nz5iaLAaakpOD8+fMoLS2VucKm696yCsuWLUPr1q2l/aWlpfjwww8RGxvLW3dEZILBhRothUIBZ2dnBAUFoUWLFlJoKSkpQUpKyu8uzEn1z9vbG2PGjMGYMWOkqQ0MBgMSEhKwatUqrjRNRBIGF2q0OnfujMDAQKjVaim03Lx5E9HR0SguLpa5OvottVqNqVOn4vnnn5fCy69vHR06dIitY0TE4EKNj5WVFdq1a4fevXubfHrPycnBkSNHGFoaMLVajaCgIMyYMQOenp7SfiEEYmNjsW7dOly5ckXGColIbgwu1Kg0b94cgYGB0Gq1UiuLwWDAiRMncPr0aXb2NBNeXl4YN24cRo8ebbI6d3FxMT788EMcOnSII8CImigGF2o02rdvj6CgIOnWkBACJSUlOHfuHFJSUhhazIylpSX69u2Lv/zlLyZ9lIQQiI6Oxvr165Geni5zlURU3xhcyOxpNBrp1tBvZ2T95ZdfUFBQIG+B9Ej8/PwQERGB7t27m4SXgoICrFq1CjExMSgrK5O5SiKqLwwuZNY0Gg2GDBmCli1bSvuMRiOuXbuGhIQEhpZGQqPRYPbs2Rg5cqR06wioDjAXLlzAJ598gpMnT8pYIRHVFwYXMltWVlYYPHgwPD09TW4NnT9/HikpKZxQrpGxsrKCv78/nn/+efTq1ctkxfmbN29i4cKFSE5O5i1BokaOwYXMjkKhQOvWrdG7d280a9ZMCi3FxcWIjo7mWjeNnLW1NV5++WWMHDkSTk5O0v6CggLs27cPf/vb36DX62WskIgeJwYXMitWVlYICgpCy5YtTfqzFBUVYf/+/QwtTUjv3r3x4osvwt/fX7p9ZDAYsHv3bvzzn//ExYsXZa6QiB4HBhcyC0qlEl5eXujbty/s7Oyk2wRGoxGpqak4ffo0O2g2Qba2tpg4cSJGjRoFR0dHaX9OTg6+/PJL7NmzB5WVlfIVSER1jsGFGjxLS0sEBQXB29tbamUBgOLiYqSmpuLs2bPsz9LEBQUFITIyEs7OzlLrS1VVldT6cunSJZkrJKK6wuBCDZq1tTV0Oh3atGlj0spy5coVpKSk4ObNmzJXSA2Fq6srZs+ejYEDB5qMPLp69SoWLlyIixcvoqqqSsYKiaguMLhQg9WyZUv0798ftra29y2QeP78eRgMBpkrpIamWbNmGDduHMaNG4dmzZpJ+0tLS/Gvf/0LX3/9NZd8IDJzDC7U4FhYWMDX1xc+Pj6wtrYGUN3KUlRUhNjYWOTn58tcITVkCoUCgYGBeP7559G7d2+TpR8yMzOxcOFCzrhLZMYYXKhBubfIXvv27U1uDV24cAHHjh1DRUWFzBWSuXB0dMTo0aMRFhYGW1tbANUj0LKzs7F161Zs27aNt46IzBCDCzUYtra2CAgIMAkter0ely9fRkJCAv/IUI0pFAo89dRTCA8Ph5ubm/RzVVVVhY0bN2Lr1q24c+eOzFUSUU0wuFCD4O7ujsGDB8PGxkb643L37l0cOHAAubm5nA2Vak2hUMDZ2Rnvvvsu/P39TVryMjIysHTpUvaZIjIjDC4kK7VaDQ8PD/Tv3x82NjYAqpvz79y5g7i4OOTk5MhcITUWTk5OGDFiBF555RWp75QQApWVlVi/fj22b9/OCQyJzACDC8lGrVZDp9OhY8eOJqv+pqen48iRI5w4jB6Lnj174s9//jN69Ogh7TMajbh06RJWrFjBeYGIGjgGF5KFm5sbAgICoNVqTULL5cuXcfjwYYYWeqxcXFwwb9489OnTB1ZWVgCqf/4qKiqwdu1afPfddwwvRA0UgwvVO1dXVwQHB5v0ZykvL0d8fDwyMzMZWqheKBQKjBo1ChMmTICXl5f0s1hRUYGjR4/i448/Rl5ensxVEtFvMbhQvVGpVPD390f79u1hbW0trep869YtJCUlITs7W+4SqQlyc3PD7NmzodPpYGlpCaC69SU1NRWRkZG4ceOGzBUS0a8xuFC9cHBwQNeuXdGlSxeTW0OZmZmIiYlhKwvJSqlUYuzYsRg7dqxJ60t2dja++eYb/PjjjzJXSET3MLjQY+fi4oLg4GCTHzS9Xo/09HQcP36ck8pRg9GyZUtERUWZzCVUXl6Of/zjH9i1axdu374tc4VExOBCj41KpULPnj3RsWNHk6HOFRUVOHToEDIyMuQtkOgBvLy8EB4ejoEDB0KtVkv7T5w4gQULFjC8EMmMwYUeCycnJwwYMADNmzeXVuq9N916QkICCgsLZa6Q6Pep1WpMnDgRL730EiwtLaX+WCdPnsSGDRuQmJjISRGJZMLgQnVKoVCgTZs26NWrFxwdHaX9FRUVuHDhAk6ePAm9Xi9fgUQPSa1Wo1OnTli4cCFatWol3ToqKyvDV199hR9//JHLBRDJgMGF6oxarYafnx969OgBlUoFoLqVRa/XIy4ujivykllq06YNli5dilatWpn8XCcmJmLx4sW4efMmW1+I6hGDC9UJBwcHDB48GM7OztKbu8FgQG5uLg4fPozi4mKZKySqPQcHB4wfPx4TJ06U+r0IIXDjxg389a9/xS+//MLwQlRPGFzokSgUCjg6OmLIkCFwdnaW9ldWViI+Ph7p6elc1ZkaBbVajZEjR2LChAnw9vaW9peUlOCf//wnvvvuO/bdIqoHDC5UawqFAt26dUP37t1hYWEhdWDMz89HSkoKRw1Ro9SuXTtMmDABQ4cONWl9OX78ODZt2oT4+Hi2vhA9Ro8SXJQ1OXnt2rXo1q0b7O3tYW9vD51Oh927d0vHy8vLERERARcXF9jZ2WHMmDH3TbedlZWF4cOHw8bGBq6urpg7dy4/zcvE3t4e/fv3R69evaRRF1VVVcjJycH+/fsZWqjRSk9Px/vvv4/NmzejqKgIQHWI7927N9555x0MGjRIWv+IiBqWGrW47NixAyqVCh06dIAQAl999RVWrlyJkydPomvXrggPD8dPP/2EDRs2wMHBAdOnT4dSqcSRI0cAVPeX6NGjB7RaLVauXImcnBy8+OKLmDJlCpYtW/bQRbPF5dHZ29sjODgYzs7O0kiLqqoqJCQk4MKFCzAYDDJXSPT4qVQqdOzYEUuWLIGnp6e0v6KiAocPH8bq1auRm5srY4VEjZOst4qcnZ2xcuVKjB07Fi1atMCmTZswduxYAMD58+fRpUsXxMXFoW/fvti9ezdGjBiB69evw83NDQCwbt06zJs3Dzdu3JDWGPlfGFxqT6FQoGPHjujatSucnJyk0FJaWork5GScO3dO5gqJ6l/79u3x3HPPYfjw4VLHdKPRiDt37mDx4sWIj4+XuUKixqXebhX9msFgwJYtW1BaWgqdToekpCRUVlYiJCREOqdz587w9vZGXFwcACAuLg5+fn5SaAGA0NBQFBUVITU19XcfS6/Xo6ioyGSjmrOysoKvry/69etn0tKSn5+PHTt2MLRQk3Xp0iV88MEHWLJkiXR7W6lUwsXFBe+88w6mT58uzRxNRPJS/+9TTKWkpECn06G8vBx2dnbYtm0bfHx8kJycDEtLS5MJy4DqVVvvNbXm5uaahJZ7x+8d+z1RUVF49913a1oq/Urz5s3Rr18/tGjRwuTW0OnTp5GWlobS0lKZKySSV0VFBXbv3o2rV6/iL3/5Czp06AClUglHR0eEhYXBx8cHX375JY4fPy53qURNWo1bXDp16oTk5GQkJCQgPDwckyZNwtmzZx9HbZLIyEgUFhZKW3Z29mN9vMamc+fOGD58uEloMRgMOH78OE6cOMHQQvQrKSkpmDZtGrZt24aCggIA1bdYe/Xqhffee48dd4lkVuMWF0tLS7Rv3x4A4O/vj8TERKxatQrjxo1DRUUFCgoKTFpd8vLyoNVqAQBarRbHjh0z+X73mmXvnfMgGo0GGo2mpqU2edbW1ujbty9atWplstDczZs3cezYMVy/fl3G6ogarrKyMqxcuRL79+/H4sWLpfmNnJ2dERUVhV27dmHjxo3IysqSuVKipqfWfVzuMRqN0Ov18Pf3h4WFBaKjo6VjaWlpyMrKgk6nAwDodDqkpKQgPz9fOmffvn2wt7eHj4/Po5ZCv9K8eXM88cQTaNu2rRRaDAYDsrOzER0dzdBC9BCSkpIwffp07N27V5rXRalUYvjw4fj000/RvXt3mSskanpqNKooMjISw4YNg7e3N4qLi7Fp0ya8//772Lt3L5588kmEh4dj165d2LBhA+zt7fHaa68BAI4ePQrgP8OhPTw8sGLFCuTm5mLixImYPHkyh0PXEY1Gg3bt2qF3795Qq9XShHJGoxEnT57EqVOnOLEWUQ1ZW1tjwIABmDNnjsl7z+3bt7Fnzx589tlnXHiUqAYeZVRRjW4V5efn48UXX0ROTg4cHBzQrVs3KbQAwMcffwylUokxY8ZAr9cjNDQUa9askb5epVJh586dCA8Ph06ng62tLSZNmoT33nuvVsWTKY1GgyFDhqBly5bSPiEECgsLceTIEeTm5jK0ENVCWVkZfv75ZxQXF2Py5Mnw8fGBQqGAs7Mzxo8fDz8/P3z00UccmUdUDzjlfyPRtm1b9OrVy6R/kdFoREpKCs6ePcsOuER1xNbWFuHh4XjqqadMPjHeunULP/30Ez7//HNUVlbKWCFRw8e1ipowjUaD9u3bw9/fX5rATwiBkpISnD9/HikpKTAajTJXSdT4DBw4EPPnz4e9vb3JFAPbtm3D999/j8zMTJkrJGq4GFyaKI1Gg0GDBsHLy0t64xRCoLi4GNHR0bh165bMFRI1bl5eXpgxYwZ0Op3JyL3MzEx8/vnnOHDgAJfPIHoABpcmyN3dHX5+fiahxWAw4OzZszh9+jTKyspkrpCoabC1tUX//v0xe/Zsk9aXyspKbNy4ERs3bmTHXaLfYHBpQpRKJby8vDBw4ECTuW2Ki4tx8OBB3Lhxg7eGiOqZQqGAp6cn5s6diz59+piEl0uXLuG9995DZmYmfzeJ/h+DSxNhaWmJoKAgeHt7w8LCAkB1B9yMjAycPn0aN2/elLlCoqbN2dkZL7zwAkaNGmWytlFhYSG2bNmCLVu2sDWUCAwuTYK1tTV0Oh3atGkjfZozGo04d+4cjh07xvvoRA2EQqHAoEGDMGHCBHTr1u2+1pe3336by5ZQk8fg0sh5enpiwIABsLW1ld4ES0pKpAUSGVqIGp7mzZvjnXfegZ+fn3RbVwiBy5cvY/Pmzdi9ezd/d6nJYnBppNRqNfz8/ODj4wNra2sA1a0sRUVFiI2NNVk6gYgaHo1Gg2HDhmHKlClwdnY2aX35+9//jh9++AHFxcUyV0lU/xhcGiG1Wo2goCC0b9/eZKhzWloajh07hoqKCpkrJKKHoVAooNVqMX/+fJPWl6qqKly8eBELFizAtWvXZK6SqH4xuDQyWq0WPXr0gKenpxRa9Ho9rly5gvj4eFRVVclcIRHVlFqtxjPPPIPp06eb3DpKT0/Hd999h507d3LUETUZDC6NhFqthru7OwYMGGAyIuHu3bs4ePAgcnJyuNYQkRlTKBTo27cvpkyZAh8fH2m/Xq/H2rVrsWfPHhQUFMhXIFE9YXBpBNRqNfr27YuOHTtCqVQC+E9HvpSUFA51JmpEtFot3nrrLfTo0UNaqsNoNOLMmTNYsGAB+69Ro8fgYubc3NwQEBAArVZr0p/l8uXLOHz4MBdsI2qElEolJkyYgD//+c8m64ylp6dj8+bN2LVrF1tYqdFicDFTKpUKnp6eCAoKgo2NjRRaysvLkZCQgIyMDIYWokZMqVTC398fM2fORPv27aX9ZWVl+PTTT/HLL7/w1hE1SgwuZkilUqFPnz7SfW6FQgEhBG7duoWkpCROUEXUhHh5eWHOnDkICAiQFmsUQiApKQkLFy7EnTt3ZK6QqG4xuJgZe3t7+Pr6okuXLia3hjIzMxETE8NWFqImSKVS4aWXXsLLL78MlUolfZjJyMjA+vXr8fPPP8tdIlGdYXAxIy4uLggODja5YHq9HpcvX0ZiYiLnZyFqwtRqNbp374558+aZrPx+9+5drF27Fnv37kVRUZHMVRI9OgYXM6BUKtGrVy907NhRGuoshEBFRQUOHTqEjIwMeQskogajXbt2ePXVV9G3b1+oVCoA1e8X8fHxeOedd1BYWChzhUSPhsGlgXNwcECXLl3g4+NjMtT56tWriI+P55sQEd3HwsICU6dOxfjx46FWq6VbR1evXsWaNWsQExPDCevIbDG4NFAKhQKOjo4IDg6Go6OjtL+iogIXL17EiRMnoNfr5SuQiBo0CwsL+Pr6YuHChXB3d5duHZWWliIuLg4rV67kBx8ySwwuDZBCoUCPHj1MFkgUQkCv1yMuLg7p6ekyV0hE5qJz58546aWXMHDgQJNW2+vXr+Pjjz/G4cOHZa6QqGYYXBqYe6s69+jRw+T+9PXr13HkyBF2riOiGrO0tMSrr76KUaNGwcrKStpfWFiIjRs34ocffkBpaamMFRI9PAaXBsTBwQGDBw+Gs7OzFFoMBgNyc3Nx8OBBlJWVyVwhEZkrCwsL+Pj4YMGCBfDw8JDeY4xGIw4fPozNmzfj5MmTMldJ9L8xuDQACoUCHTp0gK+vL5ydnaX9lZWViI+PR3p6Old1JqI64eDggKlTp2Lo0KGwtbWV9t++fRubN2/G999/zw9J1KAxuMjM0tISXbp0Qa9evUxuDeXn5+P06dPIzMyUuUIiamzuddx999134erqKu2/1/ry7bff4tSpUzJWSPT7GFxkZG9vjyeeeALOzs5Sp7mqqirk5+fj4MGDuHv3rswVElFj1rVrV4wfPx7BwcHSexAA3LhxA4sXL8apU6c4epEaHAYXGSgUCnTs2BFdu3aFk5OTNEyxqqoKCQkJSEtL4xwLRFQvrK2t8fTTT+OVV16Bi4uLtL+iogK7du3CF198gRs3bshYIZEpBpd6ptFo0KFDB/Tu3Vu6NQQA+fn5OHnyJBdIJCJZdO3aFc8//zyGDBkitb4YjUbk5+dj6dKlOHXqFJcVoQaBwaUe2draIjg4GC1atDBpZcnLy0NsbCyHIxKRrGxsbDBnzhwMHDgQzZo1k/ZXVVXhhx9+wOrVqxleSHYMLvWkY8eO8PX1ve/W0PHjx5GamgozfCmJqBFSKBTo168fpk+fjtatW0vvV0ajEYmJiVi3bh3OnTsnc5XUlDG4PGZWVlZo27Yt+vTpA7VaLe2/efMmjh07huvXr9dbLURED8vOzg5z5szBgAEDYGdnB6B6xOONGzewY8cObNiwAZWVlTJXSU0Rg8tjZG1tjSeeeAJarVb61GIwGJCTk4MjR46guLi4XuogIqqtQYMGYerUqWjXrp20z2Aw4MSJE1i1ahUuXbokY3XUFDG4PCbt27dH9+7d4ejoaNLUeuLECZw6dYq3hojIbNjb22PRokXo16+f9H4mhEB2djY++ugjJCYmwmAwyFwlNRUMLo9B+/btERQUBAsLCwDVv+DFxcU4f/48UlJSGFqIyOw0a9YMQ4YMwcyZM2FjY2PSV2/Tpk3Ytm0bcnJyZK6SmgIGlzqk0WgQFBQELy8vk9BSWFiIX375BQUFBY/lcYmI6kuHDh0wY8YM+Pv7m0xal56ejsjISGRlZclYHTUFDC51xM3NDT179oSnp6fJraHTp0/j3LlzHOpMRI3GvVm/Z86cCWtra2l/Xl4etm7dis2bN/PWET02DC6PSKFQoHXr1hgwYAAsLS0BVLeylJSUSLeGOAsuETU2CoUCQ4cOxfjx49GxY0fpA1tFRQVSUlKwZMkS3jqix4LB5RFoNBr0798fnp6eJqGluLgY0dHRuHXrVp08DhFRQ9WiRQtMmTIFoaGh0Gg00v7z58/jiy++wOHDh9mvj+rUowQX5f8+5fctX74cCoUCs2bNkvaVl5cjIiICLi4usLOzw5gxY5CXl2fydVlZWRg+fDhsbGzg6uqKuXPnoqqq6lFKqRV3d3cMGjQIrVu3lkKL0WjEmTNnsGPHDoYWImoSbty4geXLl2P16tUoLS2VQkrnzp2xZMkSPPfcc9J7JJHcah1cEhMT8dlnn6Fbt24m+19//XXs2LEDW7duRUxMDK5fv47Ro0dLxw0GA4YPH46KigocPXoUX331FTZs2IC333679s+iFry9vREcHAxvb2+pebS4uBiJiYlITExEWVlZvdZDRCQno9GIbdu2YfLkyTh37pwUXjQaDSIiIrB69Wp4enqadOYlkkOtbhWVlJSgV69eWLNmDZYsWYIePXrgk08+QWFhIVq0aIFNmzZh7NixAKqbGrt06YK4uDj07dsXu3fvxogRI3D9+nW4ubkBANatW4d58+bhxo0bD0z1er3eZFn2oqIieHl51eoJW1paokuXLvDz84OVlRWA6l/Y4uJiHDhwADdv3qzV9yUiaizc3d0xceJEjBgxwuQWekFBAf7xj39g27Zt7PdHj6TebxVFRERg+PDhCAkJMdmflJSEyspKk/2dO3eGt7c34uLiAABxcXHw8/OTQgsAhIaGoqioCKmpqQ98vKioKDg4OEhbbUOLtbU1+vfvj4CAAJPQcu7cOWzfvp2hhYgIQE5ODj744AMsW7YMFy5cgBACCoUCTk5OmDFjBmbMmAFXV1e5y6QmqsbBZcuWLThx4gSioqLuO5abmwtLS0s4Ojqa7Hdzc0Nubq50zq9Dy73j9449SGRkJAoLC6UtOzu7pmXD09MTf/zjH9GmTRvp1lBJSQni4+Nx7NgxkxYdIqKmzmg0Ys+ePYiMjERqaqq0ppFGo8G4ceOwbNkyhISE8NYR1Tv1/z7lP7KzszFz5kzs27dParGoDxqNxqSne02o1Wq4u7tj4MCB0lwFRqMRRUVFOHTo0H0dh4mI6D+uXbuGiIgIjBs3DhMmTICTkxMUCgV8fX0xf/582NjYIDo6mvNcUb2pUVROSkpCfn4+evXqBbVaDbVajZiYGKxevRpqtRpubm6oqKi4b3bZvLw8aLVaAIBWq70vLNz7/71z6oparUZQUBBCQkKk0CKEwMWLF7F9+3aGFiKih6DX6/HNN99g2rRpJgsyWltb44033sDy5ctNBjoQPU41Ci7BwcFISUlBcnKytAUEBCAsLEz6t4WFBaKjo6WvSUtLQ1ZWFnQ6HQBAp9MhJSUF+fn50jn79u2Dvb09fHx86uhpVS/nHhQUhPbt20OlUgGo/uVLS0tDXFwcKioq6uyxiIgaO6PRiMzMTLz55pvYtGmTdOtIrVYjICAAX3zxBZ588kmGF3rsHnkCusGDB0ujigAgPDwcu3btwoYNG2Bvb4/XXnsNAHD06FEA1cOhe/ToAQ8PD6xYsQK5ubmYOHEiJk+ejGXLlj3UY/6vCejc3d0xZMgQWFtbS79EZWVlOHDgAHJycjiREhHRI1CpVBgwYACmTZuG1q1bS/tLS0uxd+9efPbZZygsLJSvQGrwHmVUUY36uDyMjz/+GEqlEmPGjIFer0doaCjWrFkjHVepVNi5cyfCw8Oh0+lga2uLSZMm4b333nvkx1ar1ejZsyc6dOgAGxsbANW3hi5fvozTp09zQjkiojpgMBhw8OBBZGVlYd68eejatSvUajVsbW3xzDPPoFOnTvj6669x8OBBuUulRqjRTPmvUqmg0+nQqVMnqZXlXmg5fPiw1KxJRER1x8LCAq+88gpGjBiBFi1aSPtLSkrw4Ycf4tChQygpKZGxQmqImvxaRa6urujTpw/c3Nyk0KLX6xEfH4+MjAyGFiKix6xTp06IioqCu7u7yYfH2NhYvPfeexx1RCaabHBRKpXw8vJCv379YGNjA4VCASEEbt26haSkpFrN90JERLXTsmVLjB8/HqNHj5bmd7k3kvOzzz7DkSNHZK6QGoomG1wCAgLQvXt3k3SfmZmJ2NhYjhoiIpKBpaUlJk+ejKeffhouLi7S+3NRUREOHjyITz75BHfv3pW5SpJbkw0uL7zwgjQRnl6vx+XLl5GYmMjQQkQkMz8/P0ybNg29evUy+XAZHR2Nr7/+GmlpaTJXSHKq97WKGop7TZF6vR6HDh3CkSNHGFqIiBqAlJQUzJkzB9u3b4fBYAAAKBQKhISE4OOPP8bIkSPrdQZ2ajzMOrgIIZCXl4fY2FhkZGTIXQ4REf1KeXk5PvroI8ydOxc3btyQVpR2dnZGZGQk5syZA1tbW5mrJHNj1sHl+vXr+Pnnn5GZmSl3KURE9AB6vR5Hjx7F5MmTsWfPHim8KJVKDB8+HJ9//jm6d+8uc5VkTsy6j4tarUZVVZXc5RAR0UOwtrZGWFgYRo8eDWdnZ2l/fn4+1q9fj127dkGv18tYIdWXJts5l4iIzE+fPn0wf/58tGjRQuqraDAY8PPPP2PLli3suNsEMLgQEZFZcXFxwaxZszBgwACTTro5OTlYuHAhzp8/zxb1RozBhYiIzI6lpSUCAwOxYMECk/f00tJSbN++HWvWrOHM540UgwsREZmt3r17Y8KECdDpdNKcLwaDAdHR0fjmm29w4cIFmSukusbgQkREZs3e3h6jRo3CxIkT0axZM2n/tWvX8P333+P7779n60sjwuBCRERmT6FQYMiQIZg+fbrJYo0GgwGbNm3Cli1bcOvWLZmrpLrA4EJERI2Gk5MT3n77bfTt21cKL0ajEdnZ2Vi2bBlSU1PZcdfMMbgQEVGj4uDggKeffhpTpkyBjY0NgOrZ0quqqrBx40asX7+e4cWMMbgQEVGj1KNHD0yePBkBAQHSvqqqKhw9ehR/+9vfkJWVJWN1VFsMLkRE1Gg5OTnhjTfeQN++fWFtbQ2guvXl8uXL+OCDD3Dq1ClpKQEyDwwuRETU6I0cORKzZ8+GlZUVFAoFhBCorKzE+vXrsWPHDty8eVPuEukhMbgQEVGT0LVrV8yYMQPdunWTOu4KIXD+/Hm89dZbyMnJkblCehgMLkRE1GQ4Oztj6NCh+POf/wyNRiPtv3r1KjZv3ox///vfMMM/bU0KgwsRETUpSqUSf/zjH/Hcc8+hdevWUuuLXq/Hl19+iZ9++om3jhowBhciImqSPDw8sHTpUnTq1ElaaRoATp06hX/84x9ITEyUsTr6PQwuRETUZDk5OWHkyJF45ZVXoNFopNaX8vJyfPTRR/jpp59gMBhkrpJ+jcGFiIiaNJVKhQ4dOmDBggVo166dSXhJTk7G4sWLuVxAA8LgQkREBKBVq1Z46aWX8OSTT0KtVgOoHnWUnJyMr7/+GnFxcey42wAwuBAREf0/tVqNP/zhD3juuefQqlUrqfXl7t272LJlC7Zu3Yo7d+7IXGXTxuBCRET0G23atMHixYvRunVrk9aXY8eOYdmyZcjPz2fri0wYXIiIiB7A1tYWYWFhePHFF03Cy+3bt7Fq1SrExsaivLxc5iqbHgYXIiKi36FSqTBs2DC8+OKL8Pb2lvZXVFQgPj4eS5YsQVFRkYwVNj0MLkRERP9D27Zt8dxzz2HEiBEmrS8nTpzAt99+i6NHj8pcYdPB4EJERPQQLCwsMHXqVIwYMQJOTk7S/qKiIixfvhzx8fG4e/eujBU2DQwuRERED0mpVKJTp05YunQpPDw8pP1VVVWIiYnBmjVrcO3aNRkrbPwYXIiIiGro3q2jkSNHQqVSAai+dVRQUIB3330X8fHxMlfYeDG4EBER1YKlpSUGDx6M6dOnw9XVVdpfUFCAvXv3Yt26dSgrK5OxwsaJwYWIiOgRdO/eHTNnzkSXLl2kCeuEENi7dy/Wr1+PzMxMmStsXBhciIiIHpGVlRUiIiLw5JNPwtHREUB1eLlz5w4+/PBDHDlyhHO+1JFHCS7K/33Kf7zzzjtQKBQmW+fOnaXj5eXliIiIgIuLC+zs7DBmzBjk5eWZfI+srCwMHz4cNjY2cHV1xdy5c1FVVVWr4omIiOpKeXk5PvzwQyxYsAB37tyBEAIKhQLOzs5YsmQJZs+eDSsrK7nLbPJqFFwAoGvXrsjJyZG2w4cPS8def/117NixA1u3bkVMTAyuX7+O0aNHS8cNBgOGDx+OiooKHD16FF999RU2bNiAt99+u26eDRER0SM6fvw4pk2bhn379klLAigUCowYMQJr1qyBn5+fzBU2caIGFi1aJLp37/7AYwUFBcLCwkJs3bpV2nfu3DkBQMTFxQkhhNi1a5dQKpUiNzdXOmft2rXC3t5e6PX6h66jsLBQAODGjRs3btwe22ZjYyNef/11sXfvXhEfHy9tu3btEjNnzhSWlpay12iuW2FhYU3ih4kat7hcvHgRHh4eaNu2LcLCwpCVlQUASEpKQmVlJUJCQqRzO3fuDG9vb8TFxQEA4uLi4OfnBzc3N+mc0NBQFBUVITU19XcfU6/Xo6ioyGQjIiJ6nO7evYuPP/4Y77zzDpKTk6XWF2dnZzz33HN4/fXX0bZtW5mrbHpqFFwCAwOxYcMG7NmzB2vXrsWVK1cwYMAAFBcXIzc3F5aWllKHpnvc3NyQm5sLAMjNzTUJLfeO3zv2e6KiouDg4CBtXl5eNSmbiIio1uLi4vCXv/wFBw4ckPpkqlQqPPPMM1i5ciU6d+4MpbLG7QBUSzV6pYcNG4Znn30W3bp1Q2hoKHbt2oWCggJ89913j6s+AEBkZCQKCwulLTs7+7E+HhER0a+VlJRgyZIlWLRokUmrv6enJz755BOEh4ez4249eaSI6OjoiI4dO+LSpUvQarWoqKhAQUGByTl5eXnQarUAAK1We98oo3v/v3fOg2g0Gtjb25tsRERE9enu3buIjo7Gu+++i6SkJOnWkaOjIyZMmIDPPvsM7dq1k7nKxu+RgktJSQnS09Ph7u4Of39/WFhYIDo6WjqelpaGrKws6HQ6AIBOp0NKSgry8/Olc/bt2wd7e3v4+Pg8SilERET14siRI3jrrbfw9ddfo6SkBACgVqvRqVMnREVFYcSIEdISAvQY1KQn75w5c8TBgwfFlStXxJEjR0RISIho3ry5yM/PF0IIMW3aNOHt7S32798vjh8/LnQ6ndDpdNLXV1VVCV9fX/HUU0+J5ORksWfPHtGiRQsRGRlZox7FBQUFsveI5saNGzdu3J544gmxZ88eER0dLW179+4VL7zwguy1NeStoKCgRn/3f61GwWXcuHHC3d1dWFpaCk9PTzFu3Dhx6dIl6XhZWZl49dVXhZOTk7CxsRHPPPOMyMnJMfkeGRkZYtiwYcLa2lo0b95czJkzR1RWVtao6PT0dNlfdG7cuHHjxo1b7bbs7Owa/d3/NbOc8r+goABOTk7Iysri1P8yKSoqgpeXF7Kzs9nnSCa8BvLjNZAfr4H8anINhBAoLi6Gh4dHrUdiqWv1VTK792QdHBz4gyozdpaWH6+B/HgN5MdrIL+HvQaP2uDAgedERERkNhhciIiIyGyYZXDRaDRYtGgRNBqN3KU0WbwG8uM1kB+vgfx4DeRX39fALDvnEhERUdNkli0uRERE1DQxuBAREZHZYHAhIiIis8HgQkRERGaDwYWIiIjMhlkGl08//RStW7eGlZUVAgMDcezYMblLahSioqLQu3dvNGvWDK6urhg1ahTS0tJMzikvL0dERARcXFxgZ2eHMWPGIC8vz+ScrKwsDB8+HDY2NnB1dcXcuXNRVVVVn0+l0Vi+fDkUCgVmzZol7eM1ePyuXbuGF154AS4uLrC2toafnx+OHz8uHRdC4O2334a7uzusra0REhKCixcvmnyP27dvIywsDPb29nB0dMSf/vQnaSVh+u8MBgMWLlyINm3awNraGu3atcPixYvx60GwvAZ1KzY2FiNHjoSHhwcUCgV++OEHk+N19XqfPn0aAwYMgJWVFby8vLBixYqaF1vrVY5ksmXLFmFpaSm+/PJLkZqaKqZMmSIcHR1FXl6e3KWZvdDQULF+/Xpx5swZkZycLJ5++mnh7e0tSkpKpHOmTZsmvLy8RHR0tDh+/Ljo27ev6Nevn3T83grgISEh4uTJk2LXrl2iefPmNV4BnIQ4duyYaN26tejWrZuYOXOmtJ/X4PG6ffu2aNWqlXjppZdEQkKCuHz5sti7d6/JgrLLly8XDg4O4ocffhCnTp0Sf/jDH0SbNm1EWVmZdM7QoUNF9+7dRXx8vDh06JBo3769mDBhghxPyewsXbpUuLi4iJ07d4orV66IrVu3Cjs7O7Fq1SrpHF6DurVr1y4xf/588e9//1sAENu2bTM5Xhevd2FhoXBzcxNhYWHizJkzYvPmzcLa2lp89tlnNarV7IJLnz59REREhPR/g8EgPDw8RFRUlIxVNU75+fkCgIiJiRFCCFFQUCAsLCzE1q1bpXPOnTsnAIi4uDghRPUPv1KpFLm5udI5a9euFfb29kKv19fvEzBjxcXFokOHDmLfvn1i0KBBUnDhNXj85s2bJ/r37/+7x41Go9BqtWLlypXSvoKCAqHRaMTmzZuFEEKcPXtWABCJiYnSObt37xYKhUJcu3bt8RXfSAwfPly88sorJvtGjx4twsLChBC8Bo/bb4NLXb3ea9asEU5OTibvQ/PmzROdOnWqUX1mdauooqICSUlJCAkJkfYplUqEhIQgLi5Oxsoap8LCQgCAs7MzACApKQmVlZUmr3/nzp3h7e0tvf5xcXHw8/ODm5ubdE5oaCiKioqQmppaj9Wbt4iICAwfPtzktQZ4DerD9u3bERAQgGeffRaurq7o2bMnPv/8c+n4lStXkJuba3INHBwcEBgYaHINHB0dERAQIJ0TEhICpVKJhISE+nsyZqpfv36Ijo7GhQsXAACnTp3C4cOHMWzYMAC8BvWtrl7vuLg4DBw4EJaWltI5oaGhSEtLw507dx66HrNaHfrmzZswGAwmb8gA4ObmhvPnz8tUVeNkNBoxa9YsBAUFwdfXFwCQm5sLS0tLODo6mpzr5uaG3Nxc6ZwHXZ97x+h/27JlC06cOIHExMT7jvEaPH6XL1/G2rVrMXv2bLz11ltITEzEjBkzYGlpiUmTJkmv4YNe419fA1dXV5PjarUazs7OvAYP4c0330RRURE6d+4MlUoFg8GApUuXIiwsDAB4DepZXb3eubm5aNOmzX3f494xJyenh6rHrIIL1Z+IiAicOXMGhw8flruUJiU7OxszZ87Evn37YGVlJXc5TZLRaERAQACWLVsGAOjZsyfOnDmDdevWYdKkSTJX1zR89913+Pbbb7Fp0yZ07doVycnJmDVrFjw8PHgNyLxGFTVv3hwqleq+ERR5eXnQarUyVdX4TJ8+HTt37sSBAwfQsmVLab9Wq0VFRQUKCgpMzv/166/Vah94fe4do/8uKSkJ+fn56NWrF9RqNdRqNWJiYrB69Wqo1Wq4ubnxGjxm7u7u8PHxMdnXpUsXZGVlAfjPa/jf3oe0Wi3y8/NNjldVVeH27du8Bg9h7ty5ePPNNzF+/Hj4+flh4sSJeP311xEVFQWA16C+1dXrXVfvTWYVXCwtLeHv74/o6Ghpn9FoRHR0NHQ6nYyVNQ5CCEyfPh3btm3D/v3772vS8/f3h4WFhcnrn5aWhqysLOn11+l0SElJMfkB3rdvH+zt7e/7Y0D3Cw4ORkpKCpKTk6UtICAAYWFh0r95DR6voKCg+6YBuHDhAlq1agUAaNOmDbRarck1KCoqQkJCgsk1KCgoQFJSknTO/v37YTQaERgYWA/PwrzdvXsXSqXpnyeVSgWj0QiA16C+1dXrrdPpEBsbi8rKSumcffv2oVOnTg99mwiAeQ6H1mg0YsOGDeLs2bNi6tSpwtHR0WQEBdVOeHi4cHBwEAcPHhQ5OTnSdvfuXemcadOmCW9vb7F//35x/PhxodPphE6nk47fG4r71FNPieTkZLFnzx7RokULDsV9BL8eVSQEr8HjduzYMaFWq8XSpUvFxYsXxbfffitsbGzEN998I52zfPly4ejoKH788Udx+vRp8cc//vGBQ0N79uwpEhISxOHDh0WHDh04FPchTZo0SXh6ekrDof/973+L5s2bizfeeEM6h9egbhUXF4uTJ0+KkydPCgDio48+EidPnhSZmZlCiLp5vQsKCoSbm5uYOHGiOHPmjNiyZYuwsbFp/MOhhRDir3/9q/D29haWlpaiT58+Ij4+Xu6SGgUAD9zWr18vnVNWViZeffVV4eTkJGxsbMQzzzwjcnJyTL5PRkaGGDZsmLC2thbNmzcXc+bMEZWVlfX8bBqP3wYXXoPHb8eOHcLX11doNBrRuXNn8fe//93kuNFoFAsXLhRubm5Co9GI4OBgkZaWZnLOrVu3xIQJE4SdnZ2wt7cXL7/8siguLq7Pp2G2ioqKxMyZM4W3t7ewsrISbdu2FfPnzzcZRstrULcOHDjwwPf/SZMmCSHq7vU+deqU6N+/v9BoNMLT01MsX768xrUqhPjVVIREREREDZhZ9XEhIiKipo3BhYiIiMwGgwsRERGZDQYXIiIiMhsMLkRERGQ2GFyIiIjIbDC4EBERkdlgcCEiIiKzweBCREREZoPBhYiIiMwGgwsRERGZjf8DOMIY2ZFcvmcAAAAASUVORK5CYII=", + "text/plain": [ + "
" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "import cv2\n", + "img = cv2.imread(img_dir)\n", + "plt.imshow(100*cv2.cvtColor(img, cv2.COLOR_BGR2RGB))" + ] + }, + { + "cell_type": "markdown", + "id": "853e6cb3613330ca", + "metadata": { + "collapsed": false + }, + "source": [] + }, + { + "cell_type": "markdown", + "id": "571de39195b88f9c", + "metadata": { + "collapsed": false + }, + "source": [ + "### Training of the data set continued in model_build.ipynb" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16f831a75521d178", + "metadata": { + "collapsed": false + }, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.6.13" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} From a22888c7d2f69b188c1896f039b1261b57ea8b17 Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Mon, 1 Dec 2025 11:03:30 +0800 Subject: [PATCH 04/24] =?UTF-8?q?=E5=8A=A0=E8=BD=BDTown05=E5=9C=B0?= =?UTF-8?q?=E5=9B=BE=EF=BC=8C=E5=AE=9A=E4=BD=8DModel3=E5=B9=B6=E5=88=87?= =?UTF-8?q?=E6=8D=A2=E8=87=B3=E5=90=8E=E4=B8=8A=E6=96=B9=E8=BF=BD=E5=B0=BE?= =?UTF-8?q?=E8=A7=86=E8=A7=92=EF=BC=8C=E8=8E=B7=E5=8F=96=E5=85=A8=E5=9C=B0?= =?UTF-8?q?=E5=9B=BE=E5=90=88=E6=B3=95=E7=94=9F=E6=88=90=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../carlaCNN.py | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) create mode 100644 src/carla_autonomous_driving_perception/carlaCNN.py diff --git a/src/carla_autonomous_driving_perception/carlaCNN.py b/src/carla_autonomous_driving_perception/carlaCNN.py new file mode 100644 index 0000000000..1d4c0acce7 --- /dev/null +++ b/src/carla_autonomous_driving_perception/carlaCNN.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python +# coding: utf-8 + +# ## Advanced Autonomous Vehicle(AV) Self Driving System +# #### Technolgies/Softwares/Non-Standard libraries used: +# - CARLA (Open Source AV Simulator) +# - Keras (To implement Deep Learning Models) +# - Tensorflow (To train the model weights) +# - Pygame (To enable the model to imitate human-like input to the simulator) +# - OpenCV (To fetch and display/manipulate the data collected from virtual senors, videlicet, RGB Camera, LiDAR, Collision Detector) + +# In[1]: + + +# Importing standard libraries +import numpy as np +from matplotlib import pyplot as plt +import pandas as pd +import random +import time +import os + + +# In[2]: + + +# Importing Machine Learning & Deep Learning Libraries +# Installed tensorflow directML instead in order to have AMD GPU support in Windows 10 for model training +import tensorflow as tf + + +# In[3]: + + +# Avoid OOM errors by setting GPU Memory Consumption Growth and making sure that the dedicated gpus are recognizable to tensorflow +gpus = tf.config.experimental.list_physical_devices('GPU') +for gpu in gpus: + tf.config.experimental.set_memory_growth(gpu, True) +gpus + + +# In[4]: + + +import carla +import pygame + +client = carla.Client('localhost', 2000) +client.set_timeout(5.0) +world = client.load_world( + 'Town05' +) + +bp_lib = world.get_blueprint_library() + + +# In[5]: + + +world.wait_for_tick() +actor_list = world.get_actors().filter( + '*model3*' +) +vehicle_list = [] +for vehicle in actor_list: + vehicle_list.append(vehicle) + +vehicle = vehicle_list[0] + +def set_spectator(world): + spectator = world.get_spectator() + transform = carla.Transform(vehicle.get_transform().transform(carla.Location(x=-8, z=3)), vehicle.get_transform().rotation) + spectator.set_transform(transform) + +set_spectator(world) +spawn_points = world.get_map().get_spawn_points() + + +# In[6]: + + +# NPC Traffic. +for i in range(200): + vehicle_bp = random.choice(bp_lib.filter('vehicle')) + npc = world.try_spawn_actor(vehicle_bp, random.choice(spawn_points)) + +#Set traffic in motion +for v in world.get_actors().filter('*vehicle*'): + v.set_autopilot(True) + +# Making sure that the non-deep-learning model is built into the simulator is turned off +vehicle.set_autopilot(False) + + +# In[ ]: + + +# Real-Time RGBA sensor/camera footage +import queue +import cv2 +from collections import deque +camera_bp = bp_lib.find('sensor.camera.rgb') +camera_init_trans = carla.Transform(carla.Location(x =-2,z=10)) + +camera_bp.set_attribute('image_size_x', '1024') +camera_bp.set_attribute('image_size_y', '720') + +camera = world.spawn_actor(camera_bp, camera_init_trans, attach_to=vehicle) + +image_queue = queue.Queue() +camera.listen(image_queue.put) + +while True: + # Retrieve and reshape the image + world.tick() + image = image_queue.get() + + img = np.reshape(np.copy(image.raw_data), (image.height, image.width, 4)) + cv2.imshow('ImageWindowName',img) + plt.imshow(img) + if cv2.waitKey(1) == ord('q'): + break +cv2.destroyAllWindows() + + +# # Semantic Segmentation of lanes using a RGBA Camera +# - Making using of a CNN Algorithm to semantically segment the camera footage post pre-processing + +# In[19]: + + +img_dir = os.path.join('archive', 'train_label', 'Town04_Clear_Noon_09_09_2020_14_57_22_frame_0_label.png') + + +# In[7]: + + +import cv2 +img = cv2.imread(img_dir) +plt.imshow(100*cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) + + +# + +# ### Training of the data set continued in model_build.ipynb + +# In[ ]: + + + + From 706008ac55c5f938028c86bb20649375b23c332b Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Mon, 1 Dec 2025 11:22:29 +0800 Subject: [PATCH 05/24] =?UTF-8?q?=E5=88=A0=E9=99=A4=E8=BF=9C=E7=A8=8B?= =?UTF-8?q?=E4=BB=93=E5=BA=93=E4=B8=AD=E7=9A=84carlaCNN.ipynb=E6=96=87?= =?UTF-8?q?=E4=BB=B6=EF=BC=88=E6=9C=AC=E5=9C=B0=E5=B7=B2=E5=88=A0=E9=99=A4?= =?UTF-8?q?=EF=BC=8C=E5=90=8C=E6=AD=A5=E8=87=B3=E8=BF=9C=E7=A8=8B=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../carlaCNN.ipynb | 340 ------------------ 1 file changed, 340 deletions(-) delete mode 100644 src/carla_autonomous_driving_perception/carlaCNN.ipynb diff --git a/src/carla_autonomous_driving_perception/carlaCNN.ipynb b/src/carla_autonomous_driving_perception/carlaCNN.ipynb deleted file mode 100644 index 9170e30855..0000000000 --- a/src/carla_autonomous_driving_perception/carlaCNN.ipynb +++ /dev/null @@ -1,340 +0,0 @@ -{ - "cells": [ - { - "cell_type": "markdown", - "id": "824d0b8e", - "metadata": {}, - "source": [ - "## Advanced Autonomous Vehicle(AV) Self Driving System\n", - "#### Technolgies/Softwares/Non-Standard libraries used: \n", - " - CARLA (Open Source AV Simulator)\n", - " - Keras (To implement Deep Learning Models)\n", - " - Tensorflow (To train the model weights)\n", - " - Pygame (To enable the model to imitate human-like input to the simulator)\n", - " - OpenCV (To fetch and display/manipulate the data collected from virtual senors, videlicet, RGB Camera, LiDAR, Collision Detector)" - ] - }, - { - "cell_type": "code", - "execution_count": 1, - "id": "230ac814", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-22T18:16:39.365234400Z", - "start_time": "2023-10-22T18:16:38.309235100Z" - } - }, - "outputs": [], - "source": [ - "# Importing standard libraries\n", - "import numpy as np\n", - "from matplotlib import pyplot as plt\n", - "import pandas as pd\n", - "import random\n", - "import time\n", - "import os" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "918b653a", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-22T18:16:45.025256100Z", - "start_time": "2023-10-22T18:16:40.364122800Z" - } - }, - "outputs": [], - "source": [ - "# Importing Machine Learning & Deep Learning Libraries\n", - "# Installed tensorflow directML instead in order to have AMD GPU support in Windows 10 for model training\n", - "import tensorflow as tf" - ] - }, - { - "cell_type": "code", - "execution_count": 3, - "id": "34763218da257835", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-22T18:16:47.300784800Z", - "start_time": "2023-10-22T18:16:47.246787200Z" - }, - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "[PhysicalDevice(name='/physical_device:GPU:0', device_type='GPU'),\n", - " PhysicalDevice(name='/physical_device:GPU:1', device_type='GPU')]" - ] - }, - "execution_count": 3, - "metadata": {}, - "output_type": "execute_result" - } - ], - "source": [ - "# Avoid OOM errors by setting GPU Memory Consumption Growth and making sure that the dedicated gpus are recognizable to tensorflow\n", - "gpus = tf.config.experimental.list_physical_devices('GPU')\n", - "for gpu in gpus:\n", - " tf.config.experimental.set_memory_growth(gpu, True)\n", - "gpus" - ] - }, - { - "cell_type": "code", - "execution_count": 4, - "id": "f4c1ccdff9bbe9b7", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-22T18:16:55.780242500Z", - "start_time": "2023-10-22T18:16:50.525349600Z" - }, - "collapsed": false - }, - "outputs": [ - { - "name": "stderr", - "output_type": "stream", - "text": [ - ":219: RuntimeWarning: Your system is avx2 capable but pygame was not built with support for it. The performance of some of your blits could be adversely affected. Consider enabling compile time detection with environment variables like PYGAME_DETECT_AVX2=1 if you are compiling without cross compilation.\n" - ] - }, - { - "name": "stdout", - "output_type": "stream", - "text": [ - "pygame 2.5.2 (SDL 2.28.4, Python 3.8.18)\n", - "Hello from the pygame community. https://www.pygame.org/contribute.html\n" - ] - } - ], - "source": [ - "import carla\n", - "import pygame\n", - "\n", - "client = carla.Client('localhost', 2000)\n", - "client.set_timeout(5.0)\n", - "world = client.load_world(\n", - " 'Town05'\n", - ")\n", - "\n", - "bp_lib = world.get_blueprint_library()" - ] - }, - { - "cell_type": "code", - "execution_count": 5, - "id": "33d70bcdcef2f77c", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-22T18:18:22.991767600Z", - "start_time": "2023-10-22T18:18:22.718766400Z" - }, - "collapsed": false - }, - "outputs": [], - "source": [ - "world.wait_for_tick()\n", - "actor_list = world.get_actors().filter(\n", - " '*model3*'\n", - ")\n", - "vehicle_list = []\n", - "for vehicle in actor_list:\n", - " vehicle_list.append(vehicle)\n", - "\n", - "vehicle = vehicle_list[0]\n", - "\n", - "def set_spectator(world):\n", - " spectator = world.get_spectator()\n", - " transform = carla.Transform(vehicle.get_transform().transform(carla.Location(x=-8, z=3)), vehicle.get_transform().rotation)\n", - " spectator.set_transform(transform)\n", - "\n", - "set_spectator(world)\n", - "spawn_points = world.get_map().get_spawn_points()" - ] - }, - { - "cell_type": "code", - "execution_count": 6, - "id": "198b908e88040cae", - "metadata": { - "ExecuteTime": { - "end_time": "2023-10-22T18:18:26.423763800Z", - "start_time": "2023-10-22T18:18:22.996767100Z" - }, - "collapsed": false - }, - "outputs": [], - "source": [ - "# NPC Traffic.\n", - "for i in range(200):\n", - " vehicle_bp = random.choice(bp_lib.filter('vehicle'))\n", - " npc = world.try_spawn_actor(vehicle_bp, random.choice(spawn_points))\n", - "\n", - "#Set traffic in motion\n", - "for v in world.get_actors().filter('*vehicle*'):\n", - " v.set_autopilot(True)\n", - "\n", - "# Making sure that the non-deep-learning model is built into the simulator is turned off\n", - "vehicle.set_autopilot(False)" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "b0ca26014cafa02f", - "metadata": { - "ExecuteTime": { - "start_time": "2023-10-22T08:31:03.247650800Z" - }, - "collapsed": false - }, - "outputs": [], - "source": [ - "# Real-Time RGBA sensor/camera footage\n", - "import queue\n", - "import cv2\n", - "from collections import deque\n", - "camera_bp = bp_lib.find('sensor.camera.rgb')\n", - "camera_init_trans = carla.Transform(carla.Location(x =-2,z=10))\n", - "\n", - "camera_bp.set_attribute('image_size_x', '1024')\n", - "camera_bp.set_attribute('image_size_y', '720')\n", - "\n", - "camera = world.spawn_actor(camera_bp, camera_init_trans, attach_to=vehicle)\n", - "\n", - "image_queue = queue.Queue()\n", - "camera.listen(image_queue.put)\n", - "\n", - "while True:\n", - " # Retrieve and reshape the image\n", - " world.tick()\n", - " image = image_queue.get()\n", - "\n", - " img = np.reshape(np.copy(image.raw_data), (image.height, image.width, 4))\n", - " cv2.imshow('ImageWindowName',img)\n", - " plt.imshow(img)\n", - " if cv2.waitKey(1) == ord('q'):\n", - " break\n", - "cv2.destroyAllWindows()" - ] - }, - { - "cell_type": "markdown", - "id": "52fb9b67e83d2d2d", - "metadata": { - "collapsed": false - }, - "source": [ - "# Semantic Segmentation of lanes using a RGBA Camera\n", - "- Making using of a CNN Algorithm to semantically segment the camera footage post pre-processing" - ] - }, - { - "cell_type": "code", - "execution_count": 19, - "id": "f5e9f45339af4a22", - "metadata": { - "ExecuteTime": { - "start_time": "2023-10-22T08:22:29.754890600Z" - }, - "collapsed": false - }, - "outputs": [], - "source": [ - "img_dir = os.path.join('archive', 'train_label', 'Town04_Clear_Noon_09_09_2020_14_57_22_frame_0_label.png')" - ] - }, - { - "cell_type": "code", - "execution_count": 7, - "id": "30612b265948431d", - "metadata": { - "ExecuteTime": { - "start_time": "2023-10-22T05:23:12.340619Z" - }, - "collapsed": false - }, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 7, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "image/png": "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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], - "source": [ - "import cv2\n", - "img = cv2.imread(img_dir)\n", - "plt.imshow(100*cv2.cvtColor(img, cv2.COLOR_BGR2RGB))" - ] - }, - { - "cell_type": "markdown", - "id": "853e6cb3613330ca", - "metadata": { - "collapsed": false - }, - "source": [] - }, - { - "cell_type": "markdown", - "id": "571de39195b88f9c", - "metadata": { - "collapsed": false - }, - "source": [ - "### Training of the data set continued in model_build.ipynb" - ] - }, - { - "cell_type": "code", - "execution_count": null, - "id": "16f831a75521d178", - "metadata": { - "collapsed": false - }, - "outputs": [], - "source": [] - } - ], - "metadata": { - "kernelspec": { - "display_name": "Python 3", - "language": "python", - "name": "python3" - }, - "language_info": { - "codemirror_mode": { - "name": "ipython", - "version": 3 - }, - "file_extension": ".py", - "mimetype": "text/x-python", - "name": "python", - "nbconvert_exporter": "python", - "pygments_lexer": "ipython3", - "version": "3.6.13" - } - }, - "nbformat": 4, - "nbformat_minor": 5 -} From 7b4e7fe3b563111f81d42afc1225ea696b627114 Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Tue, 2 Dec 2025 19:28:16 +0800 Subject: [PATCH 06/24] =?UTF-8?q?=E5=88=A0=E9=99=A4=E8=BF=9C=E7=A8=8B?= =?UTF-8?q?=E4=BB=93=E5=BA=93=E4=B8=AD=E7=9A=84carlaCNN.py=E6=96=87?= =?UTF-8?q?=E4=BB=B6=EF=BC=88=E6=9C=AC=E5=9C=B0=E5=B7=B2=E5=88=A0=E9=99=A4?= =?UTF-8?q?=EF=BC=8C=E5=90=8C=E6=AD=A5=E8=87=B3=E8=BF=9C=E7=A8=8B=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../carlaCNN.py | 151 ------------------ 1 file changed, 151 deletions(-) delete mode 100644 src/carla_autonomous_driving_perception/carlaCNN.py diff --git a/src/carla_autonomous_driving_perception/carlaCNN.py b/src/carla_autonomous_driving_perception/carlaCNN.py deleted file mode 100644 index 1d4c0acce7..0000000000 --- a/src/carla_autonomous_driving_perception/carlaCNN.py +++ /dev/null @@ -1,151 +0,0 @@ -#!/usr/bin/env python -# coding: utf-8 - -# ## Advanced Autonomous Vehicle(AV) Self Driving System -# #### Technolgies/Softwares/Non-Standard libraries used: -# - CARLA (Open Source AV Simulator) -# - Keras (To implement Deep Learning Models) -# - Tensorflow (To train the model weights) -# - Pygame (To enable the model to imitate human-like input to the simulator) -# - OpenCV (To fetch and display/manipulate the data collected from virtual senors, videlicet, RGB Camera, LiDAR, Collision Detector) - -# In[1]: - - -# Importing standard libraries -import numpy as np -from matplotlib import pyplot as plt -import pandas as pd -import random -import time -import os - - -# In[2]: - - -# Importing Machine Learning & Deep Learning Libraries -# Installed tensorflow directML instead in order to have AMD GPU support in Windows 10 for model training -import tensorflow as tf - - -# In[3]: - - -# Avoid OOM errors by setting GPU Memory Consumption Growth and making sure that the dedicated gpus are recognizable to tensorflow -gpus = tf.config.experimental.list_physical_devices('GPU') -for gpu in gpus: - tf.config.experimental.set_memory_growth(gpu, True) -gpus - - -# In[4]: - - -import carla -import pygame - -client = carla.Client('localhost', 2000) -client.set_timeout(5.0) -world = client.load_world( - 'Town05' -) - -bp_lib = world.get_blueprint_library() - - -# In[5]: - - -world.wait_for_tick() -actor_list = world.get_actors().filter( - '*model3*' -) -vehicle_list = [] -for vehicle in actor_list: - vehicle_list.append(vehicle) - -vehicle = vehicle_list[0] - -def set_spectator(world): - spectator = world.get_spectator() - transform = carla.Transform(vehicle.get_transform().transform(carla.Location(x=-8, z=3)), vehicle.get_transform().rotation) - spectator.set_transform(transform) - -set_spectator(world) -spawn_points = world.get_map().get_spawn_points() - - -# In[6]: - - -# NPC Traffic. -for i in range(200): - vehicle_bp = random.choice(bp_lib.filter('vehicle')) - npc = world.try_spawn_actor(vehicle_bp, random.choice(spawn_points)) - -#Set traffic in motion -for v in world.get_actors().filter('*vehicle*'): - v.set_autopilot(True) - -# Making sure that the non-deep-learning model is built into the simulator is turned off -vehicle.set_autopilot(False) - - -# In[ ]: - - -# Real-Time RGBA sensor/camera footage -import queue -import cv2 -from collections import deque -camera_bp = bp_lib.find('sensor.camera.rgb') -camera_init_trans = carla.Transform(carla.Location(x =-2,z=10)) - -camera_bp.set_attribute('image_size_x', '1024') -camera_bp.set_attribute('image_size_y', '720') - -camera = world.spawn_actor(camera_bp, camera_init_trans, attach_to=vehicle) - -image_queue = queue.Queue() -camera.listen(image_queue.put) - -while True: - # Retrieve and reshape the image - world.tick() - image = image_queue.get() - - img = np.reshape(np.copy(image.raw_data), (image.height, image.width, 4)) - cv2.imshow('ImageWindowName',img) - plt.imshow(img) - if cv2.waitKey(1) == ord('q'): - break -cv2.destroyAllWindows() - - -# # Semantic Segmentation of lanes using a RGBA Camera -# - Making using of a CNN Algorithm to semantically segment the camera footage post pre-processing - -# In[19]: - - -img_dir = os.path.join('archive', 'train_label', 'Town04_Clear_Noon_09_09_2020_14_57_22_frame_0_label.png') - - -# In[7]: - - -import cv2 -img = cv2.imread(img_dir) -plt.imshow(100*cv2.cvtColor(img, cv2.COLOR_BGR2RGB)) - - -# - -# ### Training of the data set continued in model_build.ipynb - -# In[ ]: - - - - From 712565b20fe91210589da18c5d74df98f16ca35b Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Mon, 8 Dec 2025 10:33:33 +0800 Subject: [PATCH 07/24] =?UTF-8?q?=E6=96=B0=E5=A2=9Ecarla=5Fmodel3=5Fspawn?= =?UTF-8?q?=5Fwith=5Fspectator.py=EF=BC=9A=E5=8A=A0=E8=BD=BDTown05?= =?UTF-8?q?=E7=94=9F=E6=88=90Model3=E5=B9=B6=E8=AE=BE=E7=BD=AE=E8=BF=BD?= =?UTF-8?q?=E5=B0=BE=E8=A7=86=E8=A7=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../carla_model3_spawn_with_spectator.py | 31 +++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py diff --git a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py new file mode 100644 index 0000000000..3715ef837f --- /dev/null +++ b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py @@ -0,0 +1,31 @@ +import carla +import pygame +import time +import random # 新增:用于随机选生成点 + +client = carla.Client('localhost', 2000) +client.set_timeout(5.0) +world = client.load_world('Town05') +bp_lib = world.get_blueprint_library() + +# 新增:主动生成 Tesla Model3 车辆(解决空列表问题) +model3_bp = bp_lib.find('vehicle.tesla.model3') # 筛选 Model3 蓝图 +spawn_points = world.get_map().get_spawn_points() # 先获取生成点 +vehicle = world.spawn_actor(model3_bp, random.choice(spawn_points)) # 生成 Model3 + +world.wait_for_tick() +# 后续筛选逻辑可保留(兼容多辆车场景) +actor_list = world.get_actors().filter('*model3*') +vehicle_list = [] +for vehicle in actor_list: + vehicle_list.append(vehicle) +vehicle = vehicle_list[0] + +def set_spectator(world): + spectator = world.get_spectator() + transform = carla.Transform(vehicle.get_transform().transform(carla.Location(x=-8, z=3)), vehicle.get_transform().rotation) + spectator.set_transform(transform) + +set_spectator(world) +# 最终获取生成点(供后续使用) +spawn_points = world.get_map().get_spawn_points() \ No newline at end of file From a4d76642953386a9f896bf9c463c18ec358282e1 Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Mon, 8 Dec 2025 11:32:03 +0800 Subject: [PATCH 08/24] =?UTF-8?q?=E4=B8=BAcarla=5Fmodel3=5Fspawn=5Fwith=5F?= =?UTF-8?q?spectator.py=E6=96=B0=E5=A2=9ENPC=E4=BA=A4=E9=80=9A=E6=B5=81?= =?UTF-8?q?=EF=BC=9A=E7=94=9F=E6=88=90200=E8=BE=86NPC=E5=B9=B6=E5=90=AF?= =?UTF-8?q?=E5=8A=A8=E8=87=AA=E5=8A=A8=E9=A9=BE=E9=A9=B6=E3=80=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../carla_model3_spawn_with_spectator.py | 62 ++++++++++++++++--- 1 file changed, 52 insertions(+), 10 deletions(-) diff --git a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py index 3715ef837f..5d761d3b37 100644 --- a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py +++ b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py @@ -1,31 +1,73 @@ import carla import pygame import time -import random # 新增:用于随机选生成点 +import random # 用于随机选生成点/随机选NPC车辆蓝图 +# 1. 连接CARLA服务器并加载地图 client = carla.Client('localhost', 2000) client.set_timeout(5.0) world = client.load_world('Town05') bp_lib = world.get_blueprint_library() -# 新增:主动生成 Tesla Model3 车辆(解决空列表问题) -model3_bp = bp_lib.find('vehicle.tesla.model3') # 筛选 Model3 蓝图 -spawn_points = world.get_map().get_spawn_points() # 先获取生成点 -vehicle = world.spawn_actor(model3_bp, random.choice(spawn_points)) # 生成 Model3 - +# 2. 生成主角车辆(Tesla Model3) +model3_bp = bp_lib.find('vehicle.tesla.model3') # 筛选Model3蓝图 +spawn_points = world.get_map().get_spawn_points() # 获取地图合法生成点 +vehicle = world.spawn_actor(model3_bp, random.choice(spawn_points)) # 生成Model3 world.wait_for_tick() -# 后续筛选逻辑可保留(兼容多辆车场景) + +# 3. 生成200辆NPC车辆(交通流) +print("开始生成NPC交通车辆...") +for i in range(200): + # 随机选择车辆蓝图(过滤所有vehicle类型) + vehicle_bp = random.choice(bp_lib.filter('vehicle')) + # 尝试生成NPC车辆(try_spawn_actor避免生成点冲突导致报错) + npc = world.try_spawn_actor(vehicle_bp, random.choice(spawn_points)) + # 避免循环过快导致CARLA处理不及时 + time.sleep(0.01) +print(f"NPC车辆生成完成,当前地图车辆总数:{len(world.get_actors().filter('*vehicle*'))}") + +# 4. 启动所有NPC车辆的自动驾驶(交通流动) +print("启动所有NPC车辆自动驾驶...") +for v in world.get_actors().filter('*vehicle*'): + v.set_autopilot(True) + +# 5. 关闭主角Model3车辆的自动驾驶(确保手动控制/后续自定义逻辑) +vehicle.set_autopilot(False) +print("已关闭主角Model3车辆的自动驾驶") + +# 6. 筛选所有Model3车辆(兼容多辆车场景) actor_list = world.get_actors().filter('*model3*') vehicle_list = [] for vehicle in actor_list: vehicle_list.append(vehicle) vehicle = vehicle_list[0] +# 7. 设置观众视角(后上方追尾视角) def set_spectator(world): spectator = world.get_spectator() - transform = carla.Transform(vehicle.get_transform().transform(carla.Location(x=-8, z=3)), vehicle.get_transform().rotation) + # 视角位置:主角车后方8米、上方3米,跟随车辆朝向 + transform = carla.Transform( + vehicle.get_transform().transform(carla.Location(x=-8, z=3)), + vehicle.get_transform().rotation + ) spectator.set_transform(transform) set_spectator(world) -# 最终获取生成点(供后续使用) -spawn_points = world.get_map().get_spawn_points() \ No newline at end of file +print("视角已切换至主角Model3车辆后上方追尾视角") + +# 8. 最终获取生成点(供后续扩展使用) +spawn_points = world.get_map().get_spawn_points() +print(f"地图Town05合法生成点总数:{len(spawn_points)}") + +# 保持运行,便于查看效果 +print("\n程序运行中,按Ctrl+C退出...") +try: + while True: + time.sleep(1) +except KeyboardInterrupt: + print("\n程序退出,清理资源...") + # 可选:销毁生成的车辆(避免CARLA残留 Actors) + for v in world.get_actors().filter('*vehicle*'): + if v.is_alive: + v.destroy() + print("资源清理完成") \ No newline at end of file From d9513147ddea6ce27522e3dc584ac2b87c4298d0 Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Wed, 10 Dec 2025 21:02:34 +0800 Subject: [PATCH 09/24] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=A0=B8=E5=BF=83?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=9A=E4=B8=BB=E8=A7=92=E8=BD=A6=E6=B2=BF?= =?UTF-8?q?=E8=BD=A6=E9=81=93=E7=A8=B3=E5=AE=9A=E8=87=AA=E5=8A=A8=E9=A9=BE?= =?UTF-8?q?=E9=A9=B6+=E8=A7=86=E8=A7=92=E5=B9=B3=E6=BB=91=E8=B7=9F?= =?UTF-8?q?=E9=9A=8F=EF=BC=8CNPC=E4=BA=A4=E9=80=9A=E6=B5=81=E8=87=AA?= =?UTF-8?q?=E5=8A=A8=E9=A9=BE=E9=A9=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../carla_model3_spawn_with_spectator.py | 127 ++++++++++++------ 1 file changed, 83 insertions(+), 44 deletions(-) diff --git a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py index 5d761d3b37..07d927f715 100644 --- a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py +++ b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py @@ -1,73 +1,112 @@ import carla import pygame import time -import random # 用于随机选生成点/随机选NPC车辆蓝图 +import random -# 1. 连接CARLA服务器并加载地图 +# 自定义线性插值函数(兼容Python 3.7+,解决视角抖动核心) +def lerp(a, b, t): + """线性插值:从a到b平滑过渡,t∈[0,1](0=取a,1=取b,越小越平滑)""" + return a + t * (b - a) + +# 1. 连接CARLA服务器并启用同步模式(稳定数据获取,减少抖动) client = carla.Client('localhost', 2000) -client.set_timeout(5.0) +client.set_timeout(10.0) # 延长超时时间,适配多NPC生成 world = client.load_world('Town05') +# 启用同步模式,保证帧率稳定、数据无滞后 +settings = world.get_settings() +settings.synchronous_mode = True +settings.fixed_delta_seconds = 1/30 # 固定30帧/秒 +world.apply_settings(settings) + bp_lib = world.get_blueprint_library() # 2. 生成主角车辆(Tesla Model3) -model3_bp = bp_lib.find('vehicle.tesla.model3') # 筛选Model3蓝图 -spawn_points = world.get_map().get_spawn_points() # 获取地图合法生成点 -vehicle = world.spawn_actor(model3_bp, random.choice(spawn_points)) # 生成Model3 -world.wait_for_tick() +model3_bp = bp_lib.find('vehicle.tesla.model3') +spawn_points = world.get_map().get_spawn_points() +vehicle = world.spawn_actor(model3_bp, random.choice(spawn_points)) +world.tick() # 同步帧,获取最新车辆数据 -# 3. 生成200辆NPC车辆(交通流) -print("开始生成NPC交通车辆...") -for i in range(200): - # 随机选择车辆蓝图(过滤所有vehicle类型) +# 3. 生成500辆NPC车辆(分批生成,避免CARLA卡顿/崩溃) +npc_count = 500 # 新增:NPC数量从200增至500 +print(f"开始生成{npc_count}辆NPC交通车辆...") +for i in range(npc_count): vehicle_bp = random.choice(bp_lib.filter('vehicle')) - # 尝试生成NPC车辆(try_spawn_actor避免生成点冲突导致报错) npc = world.try_spawn_actor(vehicle_bp, random.choice(spawn_points)) - # 避免循环过快导致CARLA处理不及时 - time.sleep(0.01) -print(f"NPC车辆生成完成,当前地图车辆总数:{len(world.get_actors().filter('*vehicle*'))}") + # 每生成100辆同步一次,减轻CARLA压力 + if i % 100 == 0: + world.tick() + time.sleep(0.05) + else: + time.sleep(0.01) +# 统计实际生成的车辆数(生成点冲突可能略少) +actual_npc_count = len(world.get_actors().filter('*vehicle*')) - 1 # 减主角车 +print(f"NPC车辆生成完成,实际生成:{actual_npc_count}辆(含主角车共{len(world.get_actors().filter('*vehicle*'))}辆)") -# 4. 启动所有NPC车辆的自动驾驶(交通流动) -print("启动所有NPC车辆自动驾驶...") +# 4. 启动所有NPC+主角车自动驾驶 +print("启动所有NPC车辆+主角Model3自动驾驶...") for v in world.get_actors().filter('*vehicle*'): v.set_autopilot(True) +print("主角Model3车辆已启用自动驾驶,将与NPC同步行驶") -# 5. 关闭主角Model3车辆的自动驾驶(确保手动控制/后续自定义逻辑) -vehicle.set_autopilot(False) -print("已关闭主角Model3车辆的自动驾驶") - -# 6. 筛选所有Model3车辆(兼容多辆车场景) +# 5. 筛选主角Model3车辆 actor_list = world.get_actors().filter('*model3*') -vehicle_list = [] -for vehicle in actor_list: - vehicle_list.append(vehicle) -vehicle = vehicle_list[0] +vehicle = actor_list[0] if actor_list else None +if not vehicle: + raise Exception("主角Model3车辆生成失败!") -# 7. 设置观众视角(后上方追尾视角) -def set_spectator(world): +# 6. 平滑视角函数(核心解决抖动:插值过渡+实时跟随) +def set_spectator_smooth(world, vehicle, last_transform=None): + """ + 平滑更新主角车后上方视角,避免抖动 + :param last_transform: 上一帧视角,用于插值过渡 + :return: 当前帧视角(供下一帧插值) + """ spectator = world.get_spectator() - # 视角位置:主角车后方8米、上方3米,跟随车辆朝向 - transform = carla.Transform( - vehicle.get_transform().transform(carla.Location(x=-8, z=3)), - vehicle.get_transform().rotation + # 目标视角:主角车后方8米、上方3米,轻微偏移避免遮挡 + vehicle_tf = vehicle.get_transform() + target_tf = carla.Transform( + vehicle_tf.transform(carla.Location(x=-8, z=3, y=0.5)), + vehicle_tf.rotation ) - spectator.set_transform(transform) - -set_spectator(world) -print("视角已切换至主角Model3车辆后上方追尾视角") + # 首次调用直接设置视角 + if last_transform is None: + spectator.set_transform(target_tf) + return target_tf + # 插值平滑过渡(t=0.1,越小视角越稳,0.05~0.2为宜) + smooth_loc = carla.Location( + x=lerp(last_transform.location.x, target_tf.location.x, 0.1), + y=lerp(last_transform.location.y, target_tf.location.y, 0.1), + z=lerp(last_transform.location.z, target_tf.location.z, 0.1) + ) + smooth_rot = carla.Rotation( + pitch=lerp(last_transform.rotation.pitch, target_tf.rotation.pitch, 0.1), + yaw=lerp(last_transform.rotation.yaw, target_tf.rotation.yaw, 0.1), + roll=lerp(last_transform.rotation.roll, target_tf.rotation.roll, 0.1) + ) + smooth_tf = carla.Transform(smooth_loc, smooth_rot) + spectator.set_transform(smooth_tf) + return smooth_tf -# 8. 最终获取生成点(供后续扩展使用) -spawn_points = world.get_map().get_spawn_points() -print(f"地图Town05合法生成点总数:{len(spawn_points)}") +# 初始化视角 +last_spectator_tf = set_spectator_smooth(world, vehicle) +print("视角已切换至主角Model3车辆后上方(平滑跟随,无抖动)") -# 保持运行,便于查看效果 -print("\n程序运行中,按Ctrl+C退出...") +# 7. 主循环:稳定帧率+平滑视角 +print("\n程序运行中,主角车与500辆NPC同步行驶,按Ctrl+C退出...") +clock = pygame.time.Clock() # 精准控制帧率 try: while True: - time.sleep(1) + world.tick() # 同步CARLA帧,数据无滞后 + # 平滑更新视角 + last_spectator_tf = set_spectator_smooth(world, vehicle, last_spectator_tf) + clock.tick(30) # 严格30帧/秒,避免帧率波动导致抖动 except KeyboardInterrupt: print("\n程序退出,清理资源...") - # 可选:销毁生成的车辆(避免CARLA残留 Actors) + # 恢复CARLA默认设置(避免影响后续使用) + settings.synchronous_mode = False + world.apply_settings(settings) + # 销毁所有生成的车辆 for v in world.get_actors().filter('*vehicle*'): if v.is_alive: v.destroy() - print("资源清理完成") \ No newline at end of file + print("资源清理完成,CARLA设置已恢复!") \ No newline at end of file From fc332a2bd4a2c93945b30d262628e1f4a9ae7ea0 Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Fri, 12 Dec 2025 14:34:08 +0800 Subject: [PATCH 10/24] =?UTF-8?q?=E6=A0=B8=E5=BF=83=E4=BC=98=E5=8C=96?= =?UTF-8?q?=EF=BC=9A=E5=9F=BA=E4=BA=8ECARLA=E5=BC=BA=E5=90=8C=E6=AD=A5?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E8=A7=A3=E5=86=B3=E9=95=9C=E5=A4=B4=E6=8A=96?= =?UTF-8?q?=E5=8A=A8=EF=BC=8C=E7=BB=91=E5=AE=9A=E8=A7=86=E8=A7=92=E4=B8=8E?= =?UTF-8?q?=E8=BD=A6=E8=BE=86=E7=8A=B6=E6=80=81=E5=88=B0=E5=90=8C=E4=B8=80?= =?UTF-8?q?=E5=B8=A7?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../carla_model3_spawn_with_spectator.py | 166 +++++++++++------- 1 file changed, 103 insertions(+), 63 deletions(-) diff --git a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py index 07d927f715..5b20fcb0c3 100644 --- a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py +++ b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py @@ -2,111 +2,151 @@ import pygame import time import random +from threading import Lock -# 自定义线性插值函数(兼容Python 3.7+,解决视角抖动核心) +# 自定义线性插值函数(适配同步帧) def lerp(a, b, t): - """线性插值:从a到b平滑过渡,t∈[0,1](0=取a,1=取b,越小越平滑)""" + """线性插值:t值根据同步帧率调整(30帧下0.15更稳定)""" return a + t * (b - a) -# 1. 连接CARLA服务器并启用同步模式(稳定数据获取,减少抖动) +# 1. 连接CARLA服务器并配置强同步模式 client = carla.Client('localhost', 2000) -client.set_timeout(10.0) # 延长超时时间,适配多NPC生成 +client.set_timeout(15.0) world = client.load_world('Town05') -# 启用同步模式,保证帧率稳定、数据无滞后 + +# 启用严格同步模式(关键:固定帧间隔,禁用异步更新) settings = world.get_settings() -settings.synchronous_mode = True -settings.fixed_delta_seconds = 1/30 # 固定30帧/秒 +settings.synchronous_mode = True # 客户端控制帧推进 +settings.fixed_delta_seconds = 1/30 # 30帧/秒(与后续tick频率一致) +settings.no_rendering_mode = False # 启用渲染 world.apply_settings(settings) +# 2. 初始化同步锁与帧数据缓存(确保线程安全) +frame_lock = Lock() +latest_snapshot = None # 存储当前帧的Actor快照(含车辆状态) + +# 绑定帧同步回调:每帧更新车辆状态快照 +def on_world_tick(snapshot): + global latest_snapshot + with frame_lock: + latest_snapshot = snapshot # 缓存当前帧的所有Actor状态 +world.on_tick(on_world_tick) + bp_lib = world.get_blueprint_library() +spawn_points = world.get_map().get_spawn_points() -# 2. 生成主角车辆(Tesla Model3) +# 3. 生成主角车辆(Tesla Model3) model3_bp = bp_lib.find('vehicle.tesla.model3') -spawn_points = world.get_map().get_spawn_points() -vehicle = world.spawn_actor(model3_bp, random.choice(spawn_points)) -world.tick() # 同步帧,获取最新车辆数据 +# 确保生成点有效(避免初始位置异常导致抖动) +vehicle = None +for _ in range(5): + try: + vehicle = world.spawn_actor(model3_bp, random.choice(spawn_points)) + print(f"主角车辆生成成功(ID: {vehicle.id})") + break + except: + time.sleep(0.5) +if not vehicle: + raise Exception("主角车辆生成失败,请重启CARLA服务器") -# 3. 生成500辆NPC车辆(分批生成,避免CARLA卡顿/崩溃) -npc_count = 500 # 新增:NPC数量从200增至500 -print(f"开始生成{npc_count}辆NPC交通车辆...") +# 4. 生成NPC车辆(减少至100辆,确保同步性能) +npc_count = 100 # 500辆会导致同步延迟,100辆是性能与效果的平衡 +print(f"开始生成{npc_count}辆NPC车辆...") for i in range(npc_count): vehicle_bp = random.choice(bp_lib.filter('vehicle')) - npc = world.try_spawn_actor(vehicle_bp, random.choice(spawn_points)) - # 每生成100辆同步一次,减轻CARLA压力 - if i % 100 == 0: + if 'tesla' in vehicle_bp.id: # 避免与主角车混淆 + continue + # 尝试生成(避开主角车位置) + spawn_point = random.choice(spawn_points) + if spawn_point.location.distance(vehicle.get_location()) < 20: + continue + world.try_spawn_actor(vehicle_bp, spawn_point) + # 每生成20辆同步一次,确保服务器不卡顿 + if i % 20 == 0: world.tick() - time.sleep(0.05) - else: - time.sleep(0.01) -# 统计实际生成的车辆数(生成点冲突可能略少) -actual_npc_count = len(world.get_actors().filter('*vehicle*')) - 1 # 减主角车 -print(f"NPC车辆生成完成,实际生成:{actual_npc_count}辆(含主角车共{len(world.get_actors().filter('*vehicle*'))}辆)") + time.sleep(0.1) -# 4. 启动所有NPC+主角车自动驾驶 -print("启动所有NPC车辆+主角Model3自动驾驶...") -for v in world.get_actors().filter('*vehicle*'): - v.set_autopilot(True) -print("主角Model3车辆已启用自动驾驶,将与NPC同步行驶") +# 统计实际生成数量 +all_vehicles = world.get_actors().filter('*vehicle*') +actual_npc_count = len(all_vehicles) - 1 +print(f"NPC生成完成 | 实际数量: {actual_npc_count}辆(总车辆: {len(all_vehicles)})") -# 5. 筛选主角Model3车辆 -actor_list = world.get_actors().filter('*model3*') -vehicle = actor_list[0] if actor_list else None -if not vehicle: - raise Exception("主角Model3车辆生成失败!") +# 5. 启动所有车辆自动驾驶(绑定交通管理器同步端口) +tm = client.get_trafficmanager(8000) +tm.set_synchronous_mode(True) # 交通管理器也启用同步模式 +for v in all_vehicles: + v.set_autopilot(True, tm.get_port()) # 所有车辆通过TM控制,确保行为同步 -# 6. 平滑视角函数(核心解决抖动:插值过渡+实时跟随) -def set_spectator_smooth(world, vehicle, last_transform=None): +# 6. 平滑视角函数(基于当前帧快照数据) +def set_spectator_smooth(last_transform=None): """ - 平滑更新主角车后上方视角,避免抖动 - :param last_transform: 上一帧视角,用于插值过渡 - :return: 当前帧视角(供下一帧插值) + 基于当前帧快照更新视角,彻底避免异步抖动 + 数据来源:on_world_tick缓存的latest_snapshot(当前帧精确状态) """ spectator = world.get_spectator() - # 目标视角:主角车后方8米、上方3米,轻微偏移避免遮挡 - vehicle_tf = vehicle.get_transform() + with frame_lock: + if not latest_snapshot: + return last_transform # 等待第一帧数据 + # 从当前帧快照中获取主角车的精确状态(而非实时查询) + vehicle_snapshot = latest_snapshot.find(vehicle.id) + if not vehicle_snapshot: + return last_transform + vehicle_tf = vehicle_snapshot.get_transform() # 这是当前帧的精确位置 + + # 目标视角:车后8米、上方3米,轻微右偏 target_tf = carla.Transform( vehicle_tf.transform(carla.Location(x=-8, z=3, y=0.5)), vehicle_tf.rotation ) - # 首次调用直接设置视角 + + # 首次调用直接设置 if last_transform is None: spectator.set_transform(target_tf) return target_tf - # 插值平滑过渡(t=0.1,越小视角越稳,0.05~0.2为宜) + + # 插值平滑(t=0.15适配30帧,同步模式下更稳定) smooth_loc = carla.Location( - x=lerp(last_transform.location.x, target_tf.location.x, 0.1), - y=lerp(last_transform.location.y, target_tf.location.y, 0.1), - z=lerp(last_transform.location.z, target_tf.location.z, 0.1) + x=lerp(last_transform.location.x, target_tf.location.x, 0.15), + y=lerp(last_transform.location.y, target_tf.location.y, 0.15), + z=lerp(last_transform.location.z, target_tf.location.z, 0.15) ) smooth_rot = carla.Rotation( - pitch=lerp(last_transform.rotation.pitch, target_tf.rotation.pitch, 0.1), - yaw=lerp(last_transform.rotation.yaw, target_tf.rotation.yaw, 0.1), - roll=lerp(last_transform.rotation.roll, target_tf.rotation.roll, 0.1) + pitch=lerp(last_transform.rotation.pitch, target_tf.rotation.pitch, 0.15), + yaw=lerp(last_transform.rotation.yaw, target_tf.rotation.yaw, 0.15), + roll=lerp(last_transform.rotation.roll, target_tf.rotation.roll, 0.15) ) smooth_tf = carla.Transform(smooth_loc, smooth_rot) spectator.set_transform(smooth_tf) return smooth_tf -# 初始化视角 -last_spectator_tf = set_spectator_smooth(world, vehicle) -print("视角已切换至主角Model3车辆后上方(平滑跟随,无抖动)") +# 7. 主循环(严格按帧推进) +print("\n程序运行中(强同步模式),按Ctrl+C退出...") +print("镜头基于当前帧数据更新,已解决异步抖动问题") +last_spectator_tf = None +clock = pygame.time.Clock() -# 7. 主循环:稳定帧率+平滑视角 -print("\n程序运行中,主角车与500辆NPC同步行驶,按Ctrl+C退出...") -clock = pygame.time.Clock() # 精准控制帧率 try: + # 先推进一帧获取初始快照 + world.tick() + last_spectator_tf = set_spectator_smooth() + while True: - world.tick() # 同步CARLA帧,数据无滞后 - # 平滑更新视角 - last_spectator_tf = set_spectator_smooth(world, vehicle, last_spectator_tf) - clock.tick(30) # 严格30帧/秒,避免帧率波动导致抖动 + # 推进一帧(触发on_world_tick更新快照) + world.tick() + # 基于当前帧快照更新视角(确保数据时序一致) + last_spectator_tf = set_spectator_smooth(last_spectator_tf) + # 严格控制客户端帧率(与服务器帧间隔一致) + clock.tick(30) + except KeyboardInterrupt: - print("\n程序退出,清理资源...") - # 恢复CARLA默认设置(避免影响后续使用) + print("\n用户中断,清理资源...") +finally: + # 恢复CARLA默认设置(关键:避免影响后续使用) settings.synchronous_mode = False + tm.set_synchronous_mode(False) world.apply_settings(settings) - # 销毁所有生成的车辆 - for v in world.get_actors().filter('*vehicle*'): + # 销毁所有车辆 + for v in all_vehicles: if v.is_alive: v.destroy() - print("资源清理完成,CARLA设置已恢复!") \ No newline at end of file + print("资源清理完成,同步模式已关闭") \ No newline at end of file From eb378fd867149f400bdda183692cc27b7786659c Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Fri, 12 Dec 2025 21:59:03 +0800 Subject: [PATCH 11/24] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=A0=B8=E5=BF=83?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=9A=E5=AE=9E=E6=97=B6RGB=E6=91=84?= =?UTF-8?q?=E5=83=8F=E5=A4=B4=E7=94=BB=E9=9D=A2=E9=87=87=E9=9B=86+OpenCV?= =?UTF-8?q?=E6=98=BE=E7=A4=BA?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../carla_model3_spawn_with_spectator.py | 79 ++++++++++++++++--- 1 file changed, 68 insertions(+), 11 deletions(-) diff --git a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py index 5b20fcb0c3..f2d3207a13 100644 --- a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py +++ b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py @@ -2,6 +2,9 @@ import pygame import time import random +import queue +import cv2 +import numpy as np from threading import Lock # 自定义线性插值函数(适配同步帧) @@ -49,7 +52,40 @@ def on_world_tick(snapshot): if not vehicle: raise Exception("主角车辆生成失败,请重启CARLA服务器") -# 4. 生成NPC车辆(减少至100辆,确保同步性能) +# 4. 初始化实时RGB摄像头(新增模块) +def init_camera(vehicle): + """初始化绑定到主角车的RGB摄像头,返回摄像头actor和图像队列""" + # 摄像头蓝图配置 + camera_bp = bp_lib.find('sensor.camera.rgb') + camera_bp.set_attribute('image_size_x', '1024') # 图像宽度 + camera_bp.set_attribute('image_size_y', '720') # 图像高度 + camera_bp.set_attribute('fov', '90') # 视场角 + camera_bp.set_attribute('shutter_speed', '100') # 减少运动模糊 + + # 摄像头安装位置:车前方2米,高度1.5米,略微上仰(便于观察前方路况) + camera_transform = carla.Transform( + carla.Location(x=2.0, z=1.5), + carla.Rotation(pitch=-5) + ) + + # 生成摄像头并绑定到主角车 + camera = world.spawn_actor( + camera_bp, + camera_transform, + attach_to=vehicle + ) + + # 创建图像队列(线程安全) + image_queue = queue.Queue() + camera.listen(image_queue.put) # 摄像头数据存入队列 + + print("RGB摄像头初始化完成,实时画面将在窗口显示(按'q'关闭)") + return camera, image_queue + +# 初始化摄像头 +camera, image_queue = init_camera(vehicle) + +# 5. 生成NPC车辆(减少至100辆,确保同步性能) npc_count = 100 # 500辆会导致同步延迟,100辆是性能与效果的平衡 print(f"开始生成{npc_count}辆NPC车辆...") for i in range(npc_count): @@ -71,13 +107,13 @@ def on_world_tick(snapshot): actual_npc_count = len(all_vehicles) - 1 print(f"NPC生成完成 | 实际数量: {actual_npc_count}辆(总车辆: {len(all_vehicles)})") -# 5. 启动所有车辆自动驾驶(绑定交通管理器同步端口) +# 6. 启动所有车辆自动驾驶(绑定交通管理器同步端口) tm = client.get_trafficmanager(8000) tm.set_synchronous_mode(True) # 交通管理器也启用同步模式 for v in all_vehicles: v.set_autopilot(True, tm.get_port()) # 所有车辆通过TM控制,确保行为同步 -# 6. 平滑视角函数(基于当前帧快照数据) +# 7. 平滑视角函数(基于当前帧快照数据) def set_spectator_smooth(last_transform=None): """ 基于当前帧快照更新视角,彻底避免异步抖动 @@ -93,7 +129,7 @@ def set_spectator_smooth(last_transform=None): return last_transform vehicle_tf = vehicle_snapshot.get_transform() # 这是当前帧的精确位置 - # 目标视角:车后8米、上方3米,轻微右偏 + # 目标视角:车后8米、上方3米,轻微右偏(便于观察整车和周围环境) target_tf = carla.Transform( vehicle_tf.transform(carla.Location(x=-8, z=3, y=0.5)), vehicle_tf.rotation @@ -119,9 +155,9 @@ def set_spectator_smooth(last_transform=None): spectator.set_transform(smooth_tf) return smooth_tf -# 7. 主循环(严格按帧推进) -print("\n程序运行中(强同步模式),按Ctrl+C退出...") -print("镜头基于当前帧数据更新,已解决异步抖动问题") +# 8. 主循环(整合实时摄像头画面与原有逻辑) +print("\n程序运行中(强同步模式),按Ctrl+C或摄像头窗口按'q'退出...") +print("功能:实时RGB摄像头画面 + 车辆自动驾驶 + 平滑视角") last_spectator_tf = None clock = pygame.time.Clock() @@ -131,22 +167,43 @@ def set_spectator_smooth(last_transform=None): last_spectator_tf = set_spectator_smooth() while True: - # 推进一帧(触发on_world_tick更新快照) + # 推进一帧(触发世界更新和摄像头数据采集) world.tick() - # 基于当前帧快照更新视角(确保数据时序一致) + + # 更新 spectator 视角(平滑跟随) last_spectator_tf = set_spectator_smooth(last_spectator_tf) - # 严格控制客户端帧率(与服务器帧间隔一致) + + # 处理实时摄像头画面(新增逻辑) + if not image_queue.empty(): + image = image_queue.get() + # 将原始数据转换为RGBA格式并reshape + img = np.reshape(np.copy(image.raw_data), (image.height, image.width, 4)) + # 显示图像(OpenCV窗口) + cv2.imshow('CARLA RGB Camera', img) + # 按'q'键退出 + if cv2.waitKey(1) == ord('q'): + break + + # 控制客户端帧率与服务器同步 clock.tick(30) except KeyboardInterrupt: print("\n用户中断,清理资源...") finally: - # 恢复CARLA默认设置(关键:避免影响后续使用) + # 清理摄像头资源(关键:避免残留传感器) + camera.stop() # 停止摄像头监听 + camera.destroy() # 销毁摄像头actor + + # 恢复CARLA默认设置 settings.synchronous_mode = False tm.set_synchronous_mode(False) world.apply_settings(settings) + # 销毁所有车辆 for v in all_vehicles: if v.is_alive: v.destroy() + + # 关闭所有OpenCV窗口 + cv2.destroyAllWindows() print("资源清理完成,同步模式已关闭") \ No newline at end of file From 60d14a970d389cd368e007564228a4b418516bb9 Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Sun, 14 Dec 2025 22:05:02 +0800 Subject: [PATCH 12/24] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=A0=B8=E5=BF=83?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=9A=E8=AF=AD=E4=B9=89=E5=88=86=E5=89=B2?= =?UTF-8?q?=E6=91=84=E5=83=8F=E5=A4=B4=EF=BC=88Cityscapes=E8=B0=83?= =?UTF-8?q?=E8=89=B2=E6=9D=BF=E5=8F=AF=E8=A7=86=E5=8C=96=EF=BC=89=EF=BC=8C?= =?UTF-8?q?=E6=95=B4=E5=90=88RGB=E5=8F=8C=E6=91=84=E5=83=8F=E5=A4=B4+?= =?UTF-8?q?=E5=BC=BA=E5=90=8C=E6=AD=A5=E6=97=A0=E6=8A=96=E5=8A=A8=E8=A7=86?= =?UTF-8?q?=E8=A7=92?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../carla_model3_spawn_with_spectator.py | 180 ++++++++++-------- 1 file changed, 105 insertions(+), 75 deletions(-) diff --git a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py index f2d3207a13..bc6b8963c6 100644 --- a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py +++ b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py @@ -9,30 +9,56 @@ # 自定义线性插值函数(适配同步帧) def lerp(a, b, t): - """线性插值:t值根据同步帧率调整(30帧下0.15更稳定)""" return a + t * (b - a) +# 语义分割调色板(Cityscapes格式,兼容所有CARLA版本) +CITYSCAPES_PALETTE = [ + (0, 0, 0), # 0: 未标注 + (70, 70, 70), # 1: 建筑物 + (100, 40, 40), # 2: 围栏 + (55, 90, 80), # 3: 其他 + (220, 20, 60), # 4: 行人 + (153, 153, 153), # 5: 杆子 + (157, 234, 50), # 6: 道路线 + (128, 64, 128), # 7: 道路 + (244, 35, 232), # 8: 人行道 + (107, 142, 35), # 9: 植被 + (0, 0, 142), # 10: 车辆 + (102, 102, 156), # 11: 墙壁 + (220, 220, 0), # 12: 交通灯 + (70, 130, 180), # 13: 交通标志 + (81, 0, 81), # 14: 天 + (150, 100, 100), # 15: 地形 + (230, 150, 140), # 16: 护栏 + (180, 165, 180), # 17: 栅栏 + (250, 170, 30), # 18: 静态 + (110, 190, 160), # 19: 动态 + (170, 120, 50), # 20: 其他 + (45, 60, 150), # 21: 水 + (145, 170, 100) # 22: 路面标记 +] + # 1. 连接CARLA服务器并配置强同步模式 client = carla.Client('localhost', 2000) client.set_timeout(15.0) world = client.load_world('Town05') -# 启用严格同步模式(关键:固定帧间隔,禁用异步更新) +# 启用严格同步模式 settings = world.get_settings() -settings.synchronous_mode = True # 客户端控制帧推进 -settings.fixed_delta_seconds = 1/30 # 30帧/秒(与后续tick频率一致) -settings.no_rendering_mode = False # 启用渲染 +settings.synchronous_mode = True +settings.fixed_delta_seconds = 1/30 +settings.no_rendering_mode = False world.apply_settings(settings) -# 2. 初始化同步锁与帧数据缓存(确保线程安全) +# 2. 初始化同步锁与帧数据缓存 frame_lock = Lock() -latest_snapshot = None # 存储当前帧的Actor快照(含车辆状态) +latest_snapshot = None -# 绑定帧同步回调:每帧更新车辆状态快照 +# 绑定帧同步回调 def on_world_tick(snapshot): global latest_snapshot with frame_lock: - latest_snapshot = snapshot # 缓存当前帧的所有Actor状态 + latest_snapshot = snapshot world.on_tick(on_world_tick) bp_lib = world.get_blueprint_library() @@ -40,7 +66,6 @@ def on_world_tick(snapshot): # 3. 生成主角车辆(Tesla Model3) model3_bp = bp_lib.find('vehicle.tesla.model3') -# 确保生成点有效(避免初始位置异常导致抖动) vehicle = None for _ in range(5): try: @@ -52,52 +77,57 @@ def on_world_tick(snapshot): if not vehicle: raise Exception("主角车辆生成失败,请重启CARLA服务器") -# 4. 初始化实时RGB摄像头(新增模块) -def init_camera(vehicle): - """初始化绑定到主角车的RGB摄像头,返回摄像头actor和图像队列""" - # 摄像头蓝图配置 +# 4. 初始化RGB摄像头(保留shutter_speed,该传感器支持) +def init_rgb_camera(vehicle): camera_bp = bp_lib.find('sensor.camera.rgb') - camera_bp.set_attribute('image_size_x', '1024') # 图像宽度 - camera_bp.set_attribute('image_size_y', '720') # 图像高度 - camera_bp.set_attribute('fov', '90') # 视场角 - camera_bp.set_attribute('shutter_speed', '100') # 减少运动模糊 - - # 摄像头安装位置:车前方2米,高度1.5米,略微上仰(便于观察前方路况) + camera_bp.set_attribute('image_size_x', '1024') + camera_bp.set_attribute('image_size_y', '720') + camera_bp.set_attribute('fov', '90') + camera_bp.set_attribute('shutter_speed', '100') # RGB摄像头支持此属性 camera_transform = carla.Transform( carla.Location(x=2.0, z=1.5), carla.Rotation(pitch=-5) ) - - # 生成摄像头并绑定到主角车 - camera = world.spawn_actor( - camera_bp, - camera_transform, - attach_to=vehicle - ) - - # 创建图像队列(线程安全) + camera = world.spawn_actor(camera_bp, camera_transform, attach_to=vehicle) image_queue = queue.Queue() - camera.listen(image_queue.put) # 摄像头数据存入队列 - - print("RGB摄像头初始化完成,实时画面将在窗口显示(按'q'关闭)") + camera.listen(image_queue.put) + print("RGB摄像头初始化完成") return camera, image_queue -# 初始化摄像头 -camera, image_queue = init_camera(vehicle) - -# 5. 生成NPC车辆(减少至100辆,确保同步性能) -npc_count = 100 # 500辆会导致同步延迟,100辆是性能与效果的平衡 +# 5. 初始化语义分割摄像头(移除shutter_speed,该传感器不支持) +def init_semantic_camera(vehicle): + """初始化语义分割摄像头,返回传感器和数据队列""" + sem_bp = bp_lib.find('sensor.camera.semantic_segmentation') + # 仅保留语义分割摄像头支持的属性 + sem_bp.set_attribute('image_size_x', '1024') + sem_bp.set_attribute('image_size_y', '720') + sem_bp.set_attribute('fov', '90') + # 移除shutter_speed设置(语义分割摄像头不支持) + sem_transform = carla.Transform( + carla.Location(x=2.0, z=1.5), + carla.Rotation(pitch=-5) + ) + sem_camera = world.spawn_actor(sem_bp, sem_transform, attach_to=vehicle) + sem_queue = queue.Queue() + sem_camera.listen(sem_queue.put) # 语义数据存入队列 + print("语义分割摄像头初始化完成") + return sem_camera, sem_queue + +# 初始化摄像头(同时初始化RGB和语义分割) +rgb_camera, rgb_queue = init_rgb_camera(vehicle) +sem_camera, sem_queue = init_semantic_camera(vehicle) # 新增语义摄像头 + +# 6. 生成NPC车辆(保留原有逻辑) +npc_count = 100 print(f"开始生成{npc_count}辆NPC车辆...") for i in range(npc_count): vehicle_bp = random.choice(bp_lib.filter('vehicle')) - if 'tesla' in vehicle_bp.id: # 避免与主角车混淆 + if 'tesla' in vehicle_bp.id: continue - # 尝试生成(避开主角车位置) spawn_point = random.choice(spawn_points) if spawn_point.location.distance(vehicle.get_location()) < 20: continue world.try_spawn_actor(vehicle_bp, spawn_point) - # 每生成20辆同步一次,确保服务器不卡顿 if i % 20 == 0: world.tick() time.sleep(0.1) @@ -107,40 +137,32 @@ def init_camera(vehicle): actual_npc_count = len(all_vehicles) - 1 print(f"NPC生成完成 | 实际数量: {actual_npc_count}辆(总车辆: {len(all_vehicles)})") -# 6. 启动所有车辆自动驾驶(绑定交通管理器同步端口) +# 7. 启动所有车辆自动驾驶 tm = client.get_trafficmanager(8000) -tm.set_synchronous_mode(True) # 交通管理器也启用同步模式 +tm.set_synchronous_mode(True) for v in all_vehicles: - v.set_autopilot(True, tm.get_port()) # 所有车辆通过TM控制,确保行为同步 + v.set_autopilot(True, tm.get_port()) -# 7. 平滑视角函数(基于当前帧快照数据) +# 8. 平滑视角函数(保留原有逻辑) def set_spectator_smooth(last_transform=None): - """ - 基于当前帧快照更新视角,彻底避免异步抖动 - 数据来源:on_world_tick缓存的latest_snapshot(当前帧精确状态) - """ spectator = world.get_spectator() with frame_lock: if not latest_snapshot: - return last_transform # 等待第一帧数据 - # 从当前帧快照中获取主角车的精确状态(而非实时查询) + return last_transform vehicle_snapshot = latest_snapshot.find(vehicle.id) if not vehicle_snapshot: return last_transform - vehicle_tf = vehicle_snapshot.get_transform() # 这是当前帧的精确位置 + vehicle_tf = vehicle_snapshot.get_transform() - # 目标视角:车后8米、上方3米,轻微右偏(便于观察整车和周围环境) target_tf = carla.Transform( vehicle_tf.transform(carla.Location(x=-8, z=3, y=0.5)), vehicle_tf.rotation ) - # 首次调用直接设置 if last_transform is None: spectator.set_transform(target_tf) return target_tf - # 插值平滑(t=0.15适配30帧,同步模式下更稳定) smooth_loc = carla.Location( x=lerp(last_transform.location.x, target_tf.location.x, 0.15), y=lerp(last_transform.location.y, target_tf.location.y, 0.15), @@ -155,46 +177,55 @@ def set_spectator_smooth(last_transform=None): spectator.set_transform(smooth_tf) return smooth_tf -# 8. 主循环(整合实时摄像头画面与原有逻辑) -print("\n程序运行中(强同步模式),按Ctrl+C或摄像头窗口按'q'退出...") -print("功能:实时RGB摄像头画面 + 车辆自动驾驶 + 平滑视角") +# 9. 主循环(处理图像显示) +print("\n程序运行中,按Ctrl+C或任一窗口按'q'退出...") +print("功能:RGB摄像头 + 语义分割摄像头 + 车辆自动驾驶 + 平滑视角") last_spectator_tf = None clock = pygame.time.Clock() try: - # 先推进一帧获取初始快照 world.tick() last_spectator_tf = set_spectator_smooth() while True: - # 推进一帧(触发世界更新和摄像头数据采集) world.tick() - - # 更新 spectator 视角(平滑跟随) last_spectator_tf = set_spectator_smooth(last_spectator_tf) - # 处理实时摄像头画面(新增逻辑) - if not image_queue.empty(): - image = image_queue.get() - # 将原始数据转换为RGBA格式并reshape - img = np.reshape(np.copy(image.raw_data), (image.height, image.width, 4)) - # 显示图像(OpenCV窗口) - cv2.imshow('CARLA RGB Camera', img) - # 按'q'键退出 + # 处理RGB图像 + if not rgb_queue.empty(): + rgb_image = rgb_queue.get() + rgb_img = np.reshape(np.copy(rgb_image.raw_data), + (rgb_image.height, rgb_image.width, 4)) + cv2.imshow('RGB Camera', rgb_img) + if cv2.waitKey(1) == ord('q'): + break + + # 处理语义分割图像 + if not sem_queue.empty(): + sem_image = sem_queue.get() + # 提取语义分割原始数据(单通道类别ID) + sem_data = np.reshape(np.copy(sem_image.raw_data), + (sem_image.height, sem_image.width, 4))[:, :, 2].astype(np.int32) + # 映射到Cityscapes调色板(转换为RGB可视化) + sem_rgb = np.zeros((sem_image.height, sem_image.width, 3), dtype=np.uint8) + for i in range(len(CITYSCAPES_PALETTE)): + sem_rgb[sem_data == i] = CITYSCAPES_PALETTE[i] + cv2.imshow('Semantic Segmentation', sem_rgb) if cv2.waitKey(1) == ord('q'): break - # 控制客户端帧率与服务器同步 clock.tick(30) except KeyboardInterrupt: print("\n用户中断,清理资源...") finally: - # 清理摄像头资源(关键:避免残留传感器) - camera.stop() # 停止摄像头监听 - camera.destroy() # 销毁摄像头actor + # 清理所有传感器 + rgb_camera.stop() + rgb_camera.destroy() + sem_camera.stop() + sem_camera.destroy() - # 恢复CARLA默认设置 + # 恢复CARLA设置 settings.synchronous_mode = False tm.set_synchronous_mode(False) world.apply_settings(settings) @@ -204,6 +235,5 @@ def set_spectator_smooth(last_transform=None): if v.is_alive: v.destroy() - # 关闭所有OpenCV窗口 cv2.destroyAllWindows() print("资源清理完成,同步模式已关闭") \ No newline at end of file From fe1459b7b1eb2df6075c31c1140f7d92e6e345f7 Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Mon, 15 Dec 2025 10:36:07 +0800 Subject: [PATCH 13/24] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=A0=B8=E5=BF=83?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=9ARGB=E4=B8=8E=E8=AF=AD=E4=B9=89?= =?UTF-8?q?=E5=88=86=E5=89=B2=E5=9B=BE=E5=83=8F=E6=A8=AA=E5=90=91=E6=8B=BC?= =?UTF-8?q?=E6=8E=A5=E6=98=BE=E7=A4=BA=EF=BC=8C=E5=8D=95=E7=AA=97=E5=8F=A3?= =?UTF-8?q?=E5=AF=B9=E6=AF=94?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../carla_model3_spawn_with_spectator.py | 55 ++++++++++--------- 1 file changed, 28 insertions(+), 27 deletions(-) diff --git a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py index bc6b8963c6..8311566eb2 100644 --- a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py +++ b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py @@ -77,13 +77,13 @@ def on_world_tick(snapshot): if not vehicle: raise Exception("主角车辆生成失败,请重启CARLA服务器") -# 4. 初始化RGB摄像头(保留shutter_speed,该传感器支持) +# 4. 初始化RGB摄像头 def init_rgb_camera(vehicle): camera_bp = bp_lib.find('sensor.camera.rgb') camera_bp.set_attribute('image_size_x', '1024') camera_bp.set_attribute('image_size_y', '720') camera_bp.set_attribute('fov', '90') - camera_bp.set_attribute('shutter_speed', '100') # RGB摄像头支持此属性 + camera_bp.set_attribute('shutter_speed', '100') camera_transform = carla.Transform( carla.Location(x=2.0, z=1.5), carla.Rotation(pitch=-5) @@ -94,30 +94,27 @@ def init_rgb_camera(vehicle): print("RGB摄像头初始化完成") return camera, image_queue -# 5. 初始化语义分割摄像头(移除shutter_speed,该传感器不支持) +# 5. 初始化语义分割摄像头 def init_semantic_camera(vehicle): - """初始化语义分割摄像头,返回传感器和数据队列""" sem_bp = bp_lib.find('sensor.camera.semantic_segmentation') - # 仅保留语义分割摄像头支持的属性 sem_bp.set_attribute('image_size_x', '1024') sem_bp.set_attribute('image_size_y', '720') sem_bp.set_attribute('fov', '90') - # 移除shutter_speed设置(语义分割摄像头不支持) sem_transform = carla.Transform( carla.Location(x=2.0, z=1.5), carla.Rotation(pitch=-5) ) sem_camera = world.spawn_actor(sem_bp, sem_transform, attach_to=vehicle) sem_queue = queue.Queue() - sem_camera.listen(sem_queue.put) # 语义数据存入队列 + sem_camera.listen(sem_queue.put) print("语义分割摄像头初始化完成") return sem_camera, sem_queue -# 初始化摄像头(同时初始化RGB和语义分割) +# 初始化摄像头 rgb_camera, rgb_queue = init_rgb_camera(vehicle) -sem_camera, sem_queue = init_semantic_camera(vehicle) # 新增语义摄像头 +sem_camera, sem_queue = init_semantic_camera(vehicle) -# 6. 生成NPC车辆(保留原有逻辑) +# 6. 生成NPC车辆 npc_count = 100 print(f"开始生成{npc_count}辆NPC车辆...") for i in range(npc_count): @@ -143,7 +140,7 @@ def init_semantic_camera(vehicle): for v in all_vehicles: v.set_autopilot(True, tm.get_port()) -# 8. 平滑视角函数(保留原有逻辑) +# 8. 平滑视角函数 def set_spectator_smooth(last_transform=None): spectator = world.get_spectator() with frame_lock: @@ -177,9 +174,9 @@ def set_spectator_smooth(last_transform=None): spectator.set_transform(smooth_tf) return smooth_tf -# 9. 主循环(处理图像显示) -print("\n程序运行中,按Ctrl+C或任一窗口按'q'退出...") -print("功能:RGB摄像头 + 语义分割摄像头 + 车辆自动驾驶 + 平滑视角") +# 9. 主循环(核心:RGB与语义分割图像拼接显示) +print("\n程序运行中,按Ctrl+C或窗口按'q'退出...") +print("功能:RGB与语义分割图像拼接显示 + 车辆自动驾驶 + 平滑视角") last_spectator_tf = None clock = pygame.time.Clock() @@ -191,26 +188,30 @@ def set_spectator_smooth(last_transform=None): world.tick() last_spectator_tf = set_spectator_smooth(last_spectator_tf) - # 处理RGB图像 - if not rgb_queue.empty(): + # 同时获取RGB和语义分割图像(确保帧同步) + if not rgb_queue.empty() and not sem_queue.empty(): + # 处理RGB图像(移除alpha通道,保留RGB) rgb_image = rgb_queue.get() rgb_img = np.reshape(np.copy(rgb_image.raw_data), - (rgb_image.height, rgb_image.width, 4)) - cv2.imshow('RGB Camera', rgb_img) - if cv2.waitKey(1) == ord('q'): - break - - # 处理语义分割图像 - if not sem_queue.empty(): + (rgb_image.height, rgb_image.width, 4))[:, :, :3] # 取前3通道(RGB) + + # 处理语义分割图像(转换为彩色可视化) sem_image = sem_queue.get() - # 提取语义分割原始数据(单通道类别ID) sem_data = np.reshape(np.copy(sem_image.raw_data), (sem_image.height, sem_image.width, 4))[:, :, 2].astype(np.int32) - # 映射到Cityscapes调色板(转换为RGB可视化) sem_rgb = np.zeros((sem_image.height, sem_image.width, 3), dtype=np.uint8) for i in range(len(CITYSCAPES_PALETTE)): sem_rgb[sem_data == i] = CITYSCAPES_PALETTE[i] - cv2.imshow('Semantic Segmentation', sem_rgb) + + # 横向拼接两张图像(宽度合并,高度不变) + combined_img = cv2.hconcat([rgb_img, sem_rgb]) + + # 添加标题区分左右区域 + cv2.putText(combined_img, "RGB Image | Semantic Segmentation", + (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) + + # 显示拼接后的图像 + cv2.imshow('RGB + Semantic Segmentation', combined_img) if cv2.waitKey(1) == ord('q'): break @@ -219,7 +220,7 @@ def set_spectator_smooth(last_transform=None): except KeyboardInterrupt: print("\n用户中断,清理资源...") finally: - # 清理所有传感器 + # 清理传感器 rgb_camera.stop() rgb_camera.destroy() sem_camera.stop() From 7cd32fd4f120d9790037433afd6fca8fa3aa6ed3 Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Tue, 16 Dec 2025 09:22:52 +0800 Subject: [PATCH 14/24] =?UTF-8?q?=E6=96=B0=E5=A2=9E=E6=A0=B8=E5=BF=83?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=9A=E8=87=AA=E4=B8=BB=E8=A1=8C=E8=B5=B0?= =?UTF-8?q?=E8=A1=8C=E4=BA=BA=EF=BC=8C=E6=95=B4=E5=90=88=E8=BD=A6=E8=BE=86?= =?UTF-8?q?+=E8=A1=8C=E4=BA=BA+RGB+=E8=AF=AD=E4=B9=89=E5=88=86=E5=89=B2?= =?UTF-8?q?=E6=8B=BC=E6=8E=A5=E6=98=BE=E7=A4=BA=EF=BC=8C=E5=85=A8=E5=9C=BA?= =?UTF-8?q?=E6=99=AF=E5=90=8C=E6=AD=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../carla_model3_spawn_with_spectator.py | 132 ++++++++++++++---- 1 file changed, 103 insertions(+), 29 deletions(-) diff --git a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py index 8311566eb2..be28081035 100644 --- a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py +++ b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py @@ -13,29 +13,29 @@ def lerp(a, b, t): # 语义分割调色板(Cityscapes格式,兼容所有CARLA版本) CITYSCAPES_PALETTE = [ - (0, 0, 0), # 0: 未标注 - (70, 70, 70), # 1: 建筑物 - (100, 40, 40), # 2: 围栏 - (55, 90, 80), # 3: 其他 - (220, 20, 60), # 4: 行人 - (153, 153, 153), # 5: 杆子 - (157, 234, 50), # 6: 道路线 - (128, 64, 128), # 7: 道路 - (244, 35, 232), # 8: 人行道 - (107, 142, 35), # 9: 植被 - (0, 0, 142), # 10: 车辆 - (102, 102, 156), # 11: 墙壁 - (220, 220, 0), # 12: 交通灯 - (70, 130, 180), # 13: 交通标志 - (81, 0, 81), # 14: 天 - (150, 100, 100), # 15: 地形 - (230, 150, 140), # 16: 护栏 - (180, 165, 180), # 17: 栅栏 - (250, 170, 30), # 18: 静态 - (110, 190, 160), # 19: 动态 - (170, 120, 50), # 20: 其他 - (45, 60, 150), # 21: 水 - (145, 170, 100) # 22: 路面标记 + (0, 0, 0), # 0: Unlabeled + (70, 70, 70), # 1: Building + (100, 40, 40), # 2: Fence + (55, 90, 80), # 3: Other + (220, 20, 60), # 4: Pedestrian (red) + (153, 153, 153), # 5: Pole + (157, 234, 50), # 6: RoadLine + (128, 64, 128), # 7: Road + (244, 35, 232), # 8: Sidewalk + (107, 142, 35), # 9: Vegetation + (0, 0, 142), # 10: Vehicle (blue) + (102, 102, 156), # 11: Wall + (220, 220, 0), # 12: TrafficLight + (70, 130, 180), # 13: TrafficSign + (81, 0, 81), # 14: Sky + (150, 100, 100), # 15: Terrain + (230, 150, 140), # 16: GuardRail + (180, 165, 180), # 17: Fence + (250, 170, 30), # 18: Static + (110, 190, 160), # 19: Dynamic + (170, 120, 50), # 20: Other + (45, 60, 150), # 21: Water + (145, 170, 100) # 22: RoadMarking ] # 1. 连接CARLA服务器并配置强同步模式 @@ -134,6 +134,66 @@ def init_semantic_camera(vehicle): actual_npc_count = len(all_vehicles) - 1 print(f"NPC生成完成 | 实际数量: {actual_npc_count}辆(总车辆: {len(all_vehicles)})") +# ==================== 行人生成核心逻辑 ==================== +# 6.1 生成行人(walker) +walker_count = 50 # 生成50个行人(可调整) +walkers = [] # 存储行人actor +walker_controllers = [] # 存储行人控制器(用于移动) +print(f"\n开始生成{walker_count}个行人...") + +# 获取行人蓝图(随机选择不同行人模型) +walker_bps = bp_lib.filter('walker.pedestrian.*') + +# 获取行人生成点(使用地图的行人专用生成点,或随机点) +walker_spawn_points = [] +for _ in range(walker_count * 2): # 生成双倍候选点,避免重叠 + spawn_point = carla.Transform() + # 随机位置(围绕主角车,半径50-200米,避免太近) + spawn_point.location = world.get_random_location_from_navigation() + if spawn_point.location is not None: + # 确保行人不在车辆正前方(避免生成失败) + if spawn_point.location.distance(vehicle.get_location()) > 20: + walker_spawn_points.append(spawn_point) + +# 生成行人 +for i in range(walker_count): + if i >= len(walker_spawn_points): + break # 候选点用完则停止 + walker_bp = random.choice(walker_bps) + # 设置行人为不可碰撞(避免卡死) + walker_bp.set_attribute('is_invincible', 'false') + try: + walker = world.spawn_actor(walker_bp, walker_spawn_points[i]) + walkers.append(walker) + # 每生成10个行人同步一次,避免服务器卡顿 + if i % 10 == 0: + world.tick() + time.sleep(0.05) + except: + continue + +# 6.2 生成行人控制器并启动自主移动 +if walkers: + # 获取行人控制器蓝图 + controller_bp = bp_lib.find('controller.ai.walker') + # 启动交通管理器(行人也需要同步) + tm = client.get_trafficmanager(8000) + tm.set_synchronous_mode(True) + + for walker in walkers: + # 生成控制器并绑定到行人 + controller = world.spawn_actor(controller_bp, carla.Transform(), walker) + walker_controllers.append(controller) + # 启动行人自主行走(随机目标点,速度1-3 m/s) + controller.start() + controller.go_to_location(world.get_random_location_from_navigation()) + controller.set_max_speed(random.uniform(1.0, 3.0)) + +# 统计实际生成的行人数量 +actual_walker_count = len(walkers) +print(f"行人生成完成 | 实际数量: {actual_walker_count}个") +# ================================================================= + # 7. 启动所有车辆自动驾驶 tm = client.get_trafficmanager(8000) tm.set_synchronous_mode(True) @@ -176,7 +236,7 @@ def set_spectator_smooth(last_transform=None): # 9. 主循环(核心:RGB与语义分割图像拼接显示) print("\n程序运行中,按Ctrl+C或窗口按'q'退出...") -print("功能:RGB与语义分割图像拼接显示 + 车辆自动驾驶 + 平滑视角") +print(f"功能:RGB与语义分割图像拼接显示 + {actual_npc_count}辆车辆 + {actual_walker_count}个行人 + 平滑视角") last_spectator_tf = None clock = pygame.time.Clock() @@ -206,12 +266,13 @@ def set_spectator_smooth(last_transform=None): # 横向拼接两张图像(宽度合并,高度不变) combined_img = cv2.hconcat([rgb_img, sem_rgb]) - # 添加标题区分左右区域 - cv2.putText(combined_img, "RGB Image | Semantic Segmentation", + # 添加标题(纯英文,避免中文乱码/问号) + cv2.putText(combined_img, + f"RGB Image | Semantic Segmentation (Vehicles:{actual_npc_count} Pedestrians:{actual_walker_count})", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) - # 显示拼接后的图像 - cv2.imshow('RGB + Semantic Segmentation', combined_img) + # 显示拼接后的图像(窗口标题纯英文) + cv2.imshow('CARLA RGB + Semantic Segmentation (with Pedestrians)', combined_img) if cv2.waitKey(1) == ord('q'): break @@ -220,6 +281,19 @@ def set_spectator_smooth(last_transform=None): except KeyboardInterrupt: print("\n用户中断,清理资源...") finally: + # ==================== 清理行人资源 ==================== + # 停止并销毁行人控制器 + for controller in walker_controllers: + if controller.is_alive: + controller.stop() + controller.destroy() + # 销毁行人 + for walker in walkers: + if walker.is_alive: + walker.destroy() + print(f"已销毁{len(walker_controllers)}个行人控制器 + {len(walkers)}个行人") + # ================================================================= + # 清理传感器 rgb_camera.stop() rgb_camera.destroy() @@ -237,4 +311,4 @@ def set_spectator_smooth(last_transform=None): v.destroy() cv2.destroyAllWindows() - print("资源清理完成,同步模式已关闭") \ No newline at end of file + print(f"资源清理完成,同步模式已关闭(销毁{len(all_vehicles)}辆车辆)") \ No newline at end of file From f2e58c43f8a466ad1c1b9a6b7695f826aa6ee12e Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Tue, 16 Dec 2025 10:42:16 +0800 Subject: [PATCH 15/24] =?UTF-8?q?=E5=88=A0=E9=99=A4src/carla=5Fautonomous?= =?UTF-8?q?=5Fdriving=E6=96=87=E4=BB=B6=E5=A4=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/carla_autonomous_driving/README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) delete mode 100644 src/carla_autonomous_driving/README.md diff --git a/src/carla_autonomous_driving/README.md b/src/carla_autonomous_driving/README.md deleted file mode 100644 index e69de29bb2..0000000000 From ee2b995f7aac85c7c51821b7b78cbce4772cfc7b Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Tue, 16 Dec 2025 11:34:59 +0800 Subject: [PATCH 16/24] =?UTF-8?q?feat(monitor):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=AE=9E=E6=97=B6=E6=80=A7=E8=83=BD=E7=9B=91=E6=8E=A7=E5=8F=AF?= =?UTF-8?q?=E8=A7=86=E5=8C=96=EF=BC=8C=E6=98=BE=E7=A4=BAFPS/=E9=98=9F?= =?UTF-8?q?=E5=88=97=E9=95=BF=E5=BA=A6/=E5=90=8C=E6=AD=A5=E5=B8=A7?= =?UTF-8?q?=E5=8F=B7=EF=BC=8C=E4=BC=98=E5=8C=96=E6=96=87=E6=9C=AC=E5=B8=83?= =?UTF-8?q?=E5=B1=80=E9=81=BF=E5=85=8D=E9=87=8D=E5=8F=A0?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../carla_model3_spawn_with_spectator.py | 56 +++++++++++++++++-- 1 file changed, 51 insertions(+), 5 deletions(-) diff --git a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py index be28081035..6ce9ec45b5 100644 --- a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py +++ b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py @@ -234,12 +234,18 @@ def set_spectator_smooth(last_transform=None): spectator.set_transform(smooth_tf) return smooth_tf -# 9. 主循环(核心:RGB与语义分割图像拼接显示) +# 9. 主循环(核心:RGB与语义分割图像拼接显示 + 性能监控) print("\n程序运行中,按Ctrl+C或窗口按'q'退出...") -print(f"功能:RGB与语义分割图像拼接显示 + {actual_npc_count}辆车辆 + {actual_walker_count}个行人 + 平滑视角") +print(f"功能:RGB与语义分割图像拼接显示 + {actual_npc_count}辆车辆 + {actual_walker_count}个行人 + 平滑视角 + 性能监控") last_spectator_tf = None clock = pygame.time.Clock() +# ==================== 新增:性能监控初始化 ==================== +start_time = time.time() +frame_counter = 0 +current_fps = 0.0 +# ================================================================= + try: world.tick() last_spectator_tf = set_spectator_smooth() @@ -248,6 +254,16 @@ def set_spectator_smooth(last_transform=None): world.tick() last_spectator_tf = set_spectator_smooth(last_spectator_tf) + # ==================== 新增:实时FPS计算 ==================== + frame_counter += 1 + # 每30帧更新一次FPS(避免频繁计算) + if frame_counter % 30 == 0: + elapsed_time = time.time() - start_time + current_fps = 30.0 / elapsed_time if elapsed_time > 0 else 0.0 + start_time = time.time() + frame_counter = 0 + # ================================================================= + # 同时获取RGB和语义分割图像(确保帧同步) if not rgb_queue.empty() and not sem_queue.empty(): # 处理RGB图像(移除alpha通道,保留RGB) @@ -266,13 +282,43 @@ def set_spectator_smooth(last_transform=None): # 横向拼接两张图像(宽度合并,高度不变) combined_img = cv2.hconcat([rgb_img, sem_rgb]) - # 添加标题(纯英文,避免中文乱码/问号) + # ==================== 修复:调整标题位置,为性能监控腾出空间 ==================== cv2.putText(combined_img, f"RGB Image | Semantic Segmentation (Vehicles:{actual_npc_count} Pedestrians:{actual_walker_count})", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) + # ================================================================= + + # ==================== 修复:性能监控移到左上角标题下方,避免被裁剪 ==================== + # 性能信息列表 + perf_info = [ + f"FPS: {current_fps:.1f}", + f"RGB Queue: {rgb_queue.qsize()}", + f"Sem Queue: {sem_queue.qsize()}", + f"Sync Frame: {world.get_snapshot().frame}", + f"Fixed Delta: {settings.fixed_delta_seconds:.3f}s" + ] + + # 绘制位置:左上角,标题下方(y从60开始) + perf_x = 10 + perf_y = 60 # 标题在30位置,这里从60开始 + perf_line_height = 25 + perf_color = (0, 255, 255) # 黄色字体 + + for idx, info in enumerate(perf_info): + y_pos = perf_y + idx * perf_line_height + # 绘制半透明黑色背景(提升可读性) + cv2.rectangle(combined_img, + (perf_x - 5, y_pos - 15), + (perf_x + 220, y_pos + 5), + (0, 0, 0), -1) + # 绘制性能文本 + cv2.putText(combined_img, info, + (perf_x, y_pos), + cv2.FONT_HERSHEY_SIMPLEX, 0.6, perf_color, 2) + # ================================================================= - # 显示拼接后的图像(窗口标题纯英文) - cv2.imshow('CARLA RGB + Semantic Segmentation (with Pedestrians)', combined_img) + # 显示拼接后的图像 + cv2.imshow('CARLA RGB + Semantic Segmentation (with Pedestrians & Performance)', combined_img) if cv2.waitKey(1) == ord('q'): break From 58a5cb64772b6c74da64e93b5696cd11e108b6a1 Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Thu, 18 Dec 2025 20:15:48 +0800 Subject: [PATCH 17/24] =?UTF-8?q?feat(view):=20=E6=96=B0=E5=A2=9E=E5=89=8D?= =?UTF-8?q?=E8=A7=86+=E4=BF=AF=E8=A7=86=E5=A4=9A=E8=A7=86=E8=A7=92?= =?UTF-8?q?=E5=8F=AF=E8=A7=86=E5=8C=96=EF=BC=8C=E9=87=8D=E6=9E=84=E6=91=84?= =?UTF-8?q?=E5=83=8F=E5=A4=B4=E9=80=9A=E7=94=A8=E5=88=9D=E5=A7=8B=E5=8C=96?= =?UTF-8?q?=E5=87=BD=E6=95=B0=E4=BF=AE=E5=A4=8D=E5=B1=9E=E6=80=A7=E5=85=BC?= =?UTF-8?q?=E5=AE=B9=E9=97=AE=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../carla_model3_spawn_with_spectator.py | 193 ++++++++++-------- 1 file changed, 113 insertions(+), 80 deletions(-) diff --git a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py index 6ce9ec45b5..e635e9e3e5 100644 --- a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py +++ b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py @@ -77,42 +77,59 @@ def on_world_tick(snapshot): if not vehicle: raise Exception("主角车辆生成失败,请重启CARLA服务器") -# 4. 初始化RGB摄像头 -def init_rgb_camera(vehicle): - camera_bp = bp_lib.find('sensor.camera.rgb') - camera_bp.set_attribute('image_size_x', '1024') - camera_bp.set_attribute('image_size_y', '720') - camera_bp.set_attribute('fov', '90') - camera_bp.set_attribute('shutter_speed', '100') - camera_transform = carla.Transform( - carla.Location(x=2.0, z=1.5), - carla.Rotation(pitch=-5) - ) - camera = world.spawn_actor(camera_bp, camera_transform, attach_to=vehicle) +# 4. 初始化摄像头通用函数(复用代码,修复shutter_speed属性问题) +def init_camera(vehicle, camera_type, transform, width=1024, height=720, fov=90): + """ + 初始化摄像头(RGB/语义分割) + :param vehicle: 挂载的车辆 + :param camera_type: 摄像头类型('rgb'/'semantic') + :param transform: 摄像头位姿 + :param width/height: 图像分辨率 + :param fov: 视场角 + :return: 摄像头actor + 数据队列 + """ + if camera_type == 'rgb': + camera_bp = bp_lib.find('sensor.camera.rgb') + elif camera_type == 'semantic': + camera_bp = bp_lib.find('sensor.camera.semantic_segmentation') + else: + raise ValueError("camera_type must be 'rgb' or 'semantic'") + + # 通用属性(所有摄像头都支持) + camera_bp.set_attribute('image_size_x', str(width)) + camera_bp.set_attribute('image_size_y', str(height)) + camera_bp.set_attribute('fov', str(fov)) + + # 仅RGB摄像头设置shutter_speed(语义分割摄像头不支持) + if camera_type == 'rgb': + camera_bp.set_attribute('shutter_speed', '100') + + camera = world.spawn_actor(camera_bp, transform, attach_to=vehicle) image_queue = queue.Queue() camera.listen(image_queue.put) - print("RGB摄像头初始化完成") + print(f"{camera_type.upper()}摄像头初始化完成({transform.location})") return camera, image_queue -# 5. 初始化语义分割摄像头 -def init_semantic_camera(vehicle): - sem_bp = bp_lib.find('sensor.camera.semantic_segmentation') - sem_bp.set_attribute('image_size_x', '1024') - sem_bp.set_attribute('image_size_y', '720') - sem_bp.set_attribute('fov', '90') - sem_transform = carla.Transform( - carla.Location(x=2.0, z=1.5), - carla.Rotation(pitch=-5) - ) - sem_camera = world.spawn_actor(sem_bp, sem_transform, attach_to=vehicle) - sem_queue = queue.Queue() - sem_camera.listen(sem_queue.put) - print("语义分割摄像头初始化完成") - return sem_camera, sem_queue +# 4.1 初始化前视RGB摄像头(原有) +front_rgb_transform = carla.Transform( + carla.Location(x=2.0, z=1.5), + carla.Rotation(pitch=-5) +) +front_rgb_camera, front_rgb_queue = init_camera(vehicle, 'rgb', front_rgb_transform) + +# 4.2 初始化前视语义分割摄像头(修复shutter_speed问题) +front_sem_transform = carla.Transform( + carla.Location(x=2.0, z=1.5), + carla.Rotation(pitch=-5) +) +front_sem_camera, front_sem_queue = init_camera(vehicle, 'semantic', front_sem_transform) -# 初始化摄像头 -rgb_camera, rgb_queue = init_rgb_camera(vehicle) -sem_camera, sem_queue = init_semantic_camera(vehicle) +# 4.3 新增:初始化俯视RGB摄像头(鸟瞰视角) +top_rgb_transform = carla.Transform( + carla.Location(x=0.0, z=8.0), # 车辆正上方8米 + carla.Rotation(pitch=-90) # 垂直向下俯视 +) +top_rgb_camera, top_rgb_queue = init_camera(vehicle, 'rgb', top_rgb_transform, fov=120) # 广角120°覆盖更多区域 # 6. 生成NPC车辆 npc_count = 100 @@ -234,13 +251,13 @@ def set_spectator_smooth(last_transform=None): spectator.set_transform(smooth_tf) return smooth_tf -# 9. 主循环(核心:RGB与语义分割图像拼接显示 + 性能监控) +# 9. 主循环(核心:多视角可视化 + 性能监控) print("\n程序运行中,按Ctrl+C或窗口按'q'退出...") -print(f"功能:RGB与语义分割图像拼接显示 + {actual_npc_count}辆车辆 + {actual_walker_count}个行人 + 平滑视角 + 性能监控") +print(f"功能:前视+俯视双视角可视化 + {actual_npc_count}辆车辆 + {actual_walker_count}个行人 + 性能监控") last_spectator_tf = None clock = pygame.time.Clock() -# ==================== 新增:性能监控初始化 ==================== +# ==================== 性能监控初始化 ==================== start_time = time.time() frame_counter = 0 current_fps = 0.0 @@ -254,9 +271,8 @@ def set_spectator_smooth(last_transform=None): world.tick() last_spectator_tf = set_spectator_smooth(last_spectator_tf) - # ==================== 新增:实时FPS计算 ==================== + # ==================== 实时FPS计算 ==================== frame_counter += 1 - # 每30帧更新一次FPS(避免频繁计算) if frame_counter % 30 == 0: elapsed_time = time.time() - start_time current_fps = 30.0 / elapsed_time if elapsed_time > 0 else 0.0 @@ -264,61 +280,74 @@ def set_spectator_smooth(last_transform=None): frame_counter = 0 # ================================================================= - # 同时获取RGB和语义分割图像(确保帧同步) - if not rgb_queue.empty() and not sem_queue.empty(): - # 处理RGB图像(移除alpha通道,保留RGB) - rgb_image = rgb_queue.get() - rgb_img = np.reshape(np.copy(rgb_image.raw_data), - (rgb_image.height, rgb_image.width, 4))[:, :, :3] # 取前3通道(RGB) + # 同时获取三个摄像头数据(帧同步:前视RGB + 前视语义 + 俯视RGB) + if not front_rgb_queue.empty() and not front_sem_queue.empty() and not top_rgb_queue.empty(): + # 1. 处理前视RGB图像 + front_rgb_image = front_rgb_queue.get() + front_rgb_img = np.reshape(np.copy(front_rgb_image.raw_data), + (720, 1024, 4))[:, :, :3] - # 处理语义分割图像(转换为彩色可视化) - sem_image = sem_queue.get() - sem_data = np.reshape(np.copy(sem_image.raw_data), - (sem_image.height, sem_image.width, 4))[:, :, 2].astype(np.int32) - sem_rgb = np.zeros((sem_image.height, sem_image.width, 3), dtype=np.uint8) + # 2. 处理前视语义分割图像 + front_sem_image = front_sem_queue.get() + front_sem_data = np.reshape(np.copy(front_sem_image.raw_data), + (720, 1024, 4))[:, :, 2].astype(np.int32) + front_sem_rgb = np.zeros((720, 1024, 3), dtype=np.uint8) for i in range(len(CITYSCAPES_PALETTE)): - sem_rgb[sem_data == i] = CITYSCAPES_PALETTE[i] + front_sem_rgb[front_sem_data == i] = CITYSCAPES_PALETTE[i] + + # 3. 处理俯视RGB图像(调整分辨率匹配前视图) + top_rgb_image = top_rgb_queue.get() + top_rgb_img = np.reshape(np.copy(top_rgb_image.raw_data), + (720, 1024, 4))[:, :, :3] - # 横向拼接两张图像(宽度合并,高度不变) - combined_img = cv2.hconcat([rgb_img, sem_rgb]) + # 4. 多视角图像拼接: + # 上半部分:前视RGB + 前视语义分割 + # 下半部分:俯视RGB(居中显示,左右补黑边匹配宽度) + upper_part = cv2.hconcat([front_rgb_img, front_sem_rgb]) # 宽度2048,高度720 + # 补全俯视图像宽度到2048(和上半部分一致) + top_rgb_padded = np.zeros((720, 2048, 3), dtype=np.uint8) + top_rgb_padded[:, (2048-1024)//2 : (2048+1024)//2] = top_rgb_img # 居中 + # 上下拼接最终图像 + combined_img = cv2.vconcat([upper_part, top_rgb_padded]) # 宽度2048,高度1440 - # ==================== 修复:调整标题位置,为性能监控腾出空间 ==================== - cv2.putText(combined_img, - f"RGB Image | Semantic Segmentation (Vehicles:{actual_npc_count} Pedestrians:{actual_walker_count})", + # 5. 添加视角标题 + # 前视RGB标题 + cv2.putText(combined_img, "Front View (RGB)", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) - # ================================================================= + # 前视语义标题 + cv2.putText(combined_img, "Front View (Semantic)", + (1024 + 10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) + # 俯视标题 + cv2.putText(combined_img, "Top View (RGB / Bird's Eye)", + (10, 720 + 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) - # ==================== 修复:性能监控移到左上角标题下方,避免被裁剪 ==================== - # 性能信息列表 + # 6. 绘制性能监控(左上角,标题下方) perf_info = [ f"FPS: {current_fps:.1f}", - f"RGB Queue: {rgb_queue.qsize()}", - f"Sem Queue: {sem_queue.qsize()}", + f"RGB Queue: {front_rgb_queue.qsize()}", + f"Sem Queue: {front_sem_queue.qsize()}", f"Sync Frame: {world.get_snapshot().frame}", - f"Fixed Delta: {settings.fixed_delta_seconds:.3f}s" + f"Vehicles: {actual_npc_count} | Pedestrians: {actual_walker_count}" ] - - # 绘制位置:左上角,标题下方(y从60开始) perf_x = 10 - perf_y = 60 # 标题在30位置,这里从60开始 + perf_y = 60 perf_line_height = 25 - perf_color = (0, 255, 255) # 黄色字体 - + perf_color = (0, 255, 255) # 黄色 for idx, info in enumerate(perf_info): y_pos = perf_y + idx * perf_line_height - # 绘制半透明黑色背景(提升可读性) + # 半透明背景 cv2.rectangle(combined_img, (perf_x - 5, y_pos - 15), - (perf_x + 220, y_pos + 5), + (perf_x + 300, y_pos + 5), (0, 0, 0), -1) - # 绘制性能文本 - cv2.putText(combined_img, info, - (perf_x, y_pos), + cv2.putText(combined_img, info, (perf_x, y_pos), cv2.FONT_HERSHEY_SIMPLEX, 0.6, perf_color, 2) - # ================================================================= - # 显示拼接后的图像 - cv2.imshow('CARLA RGB + Semantic Segmentation (with Pedestrians & Performance)', combined_img) + # 7. 显示最终图像(自动调整窗口大小) + cv2.namedWindow('CARLA Multi-View (Front + Top) + Semantic Segmentation', cv2.WINDOW_NORMAL) + cv2.resizeWindow('CARLA Multi-View (Front + Top) + Semantic Segmentation', 1920, 1080) + cv2.imshow('CARLA Multi-View (Front + Top) + Semantic Segmentation', combined_img) + if cv2.waitKey(1) == ord('q'): break @@ -327,25 +356,29 @@ def set_spectator_smooth(last_transform=None): except KeyboardInterrupt: print("\n用户中断,清理资源...") finally: + # ==================== 清理所有摄像头资源 ==================== + # 前视RGB + front_rgb_camera.stop() + front_rgb_camera.destroy() + # 前视语义 + front_sem_camera.stop() + front_sem_camera.destroy() + # 俯视RGB + top_rgb_camera.stop() + top_rgb_camera.destroy() + # ================================================================= + # ==================== 清理行人资源 ==================== - # 停止并销毁行人控制器 for controller in walker_controllers: if controller.is_alive: controller.stop() controller.destroy() - # 销毁行人 for walker in walkers: if walker.is_alive: walker.destroy() print(f"已销毁{len(walker_controllers)}个行人控制器 + {len(walkers)}个行人") # ================================================================= - # 清理传感器 - rgb_camera.stop() - rgb_camera.destroy() - sem_camera.stop() - sem_camera.destroy() - # 恢复CARLA设置 settings.synchronous_mode = False tm.set_synchronous_mode(False) From da4ed7520e9d1bd63ef668403689803568f10680 Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Fri, 19 Dec 2025 16:28:49 +0800 Subject: [PATCH 18/24] =?UTF-8?q?feat(heatmap):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E8=A1=8C=E4=BA=BA+=E8=BD=A6=E8=BE=86=E8=AF=AD=E4=B9=89?= =?UTF-8?q?=E5=AF=86=E5=BA=A6=E7=83=AD=E5=8A=9B=E5=9B=BE=EF=BC=8C=E4=BC=98?= =?UTF-8?q?=E5=8C=96=E4=B8=BA2=C3=972=E5=9B=9B=E8=A7=86=E5=9B=BE=E5=B8=83?= =?UTF-8?q?=E5=B1=80=EF=BC=88=E5=89=8D=E8=A7=86RGB+=E8=AF=AD=E4=B9=89/?= =?UTF-8?q?=E4=BF=AF=E8=A7=86RGB+=E7=83=AD=E5=8A=9B=E5=9B=BE=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../carla_model3_spawn_with_spectator.py | 64 ++++++++++++++----- 1 file changed, 49 insertions(+), 15 deletions(-) diff --git a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py index e635e9e3e5..db8acc3dff 100644 --- a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py +++ b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py @@ -38,6 +38,36 @@ def lerp(a, b, t): (145, 170, 100) # 22: RoadMarking ] +# ==================== 新增:语义密度热力图生成函数 ==================== +def generate_density_heatmap(sem_data, target_classes=[4, 10], width=1024, height=720): + """ + 生成指定语义类别的密度热力图(行人+车辆为默认目标) + :param sem_data: 语义分割原始数据(int32数组,shape=(H,W)) + :param target_classes: 目标语义类别列表(4=行人,10=车辆) + :param width/height: 图像分辨率 + :return: 彩色密度热力图(RGB格式) + """ + # 1. 生成目标类别掩码(仅保留行人和车辆) + mask = np.zeros((height, width), dtype=np.uint8) + for cls in target_classes: + mask[sem_data == cls] = 255 # 目标类别像素设为255,背景0 + + # 2. 高斯模糊平滑(模拟密度分布,核越大越平滑) + blurred_mask = cv2.GaussianBlur(mask, (21, 21), 0) + + # 3. 转换为彩色热力图(JET色板:蓝→青→黄→红,代表密度从低到高) + heatmap = cv2.applyColorMap(blurred_mask, cv2.COLORMAP_JET) + + # 4. 优化视觉效果:降低背景透明度,突出目标区域 + heatmap = cv2.addWeighted(heatmap, 0.9, np.zeros_like(heatmap), 0.1, 0) + + # 5. 添加热力图标注(右下角说明) + cv2.putText(heatmap, "Density: Pedestrian(Red) + Vehicle(Blue)", + (10, height - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1) + + return heatmap +# ================================================================= + # 1. 连接CARLA服务器并配置强同步模式 client = carla.Client('localhost', 2000) client.set_timeout(15.0) @@ -251,9 +281,9 @@ def set_spectator_smooth(last_transform=None): spectator.set_transform(smooth_tf) return smooth_tf -# 9. 主循环(核心:多视角可视化 + 性能监控) +# 9. 主循环(核心:多视角+热力图可视化 + 性能监控) print("\n程序运行中,按Ctrl+C或窗口按'q'退出...") -print(f"功能:前视+俯视双视角可视化 + {actual_npc_count}辆车辆 + {actual_walker_count}个行人 + 性能监控") +print(f"功能:前视+俯视+热力图可视化 + {actual_npc_count}辆车辆 + {actual_walker_count}个行人 + 性能监控") last_spectator_tf = None clock = pygame.time.Clock() @@ -295,31 +325,35 @@ def set_spectator_smooth(last_transform=None): for i in range(len(CITYSCAPES_PALETTE)): front_sem_rgb[front_sem_data == i] = CITYSCAPES_PALETTE[i] - # 3. 处理俯视RGB图像(调整分辨率匹配前视图) + # 3. 处理俯视RGB图像 top_rgb_image = top_rgb_queue.get() top_rgb_img = np.reshape(np.copy(top_rgb_image.raw_data), (720, 1024, 4))[:, :, :3] - # 4. 多视角图像拼接: - # 上半部分:前视RGB + 前视语义分割 - # 下半部分:俯视RGB(居中显示,左右补黑边匹配宽度) + # ==================== 新增:生成语义密度热力图 ==================== + density_heatmap = generate_density_heatmap(front_sem_data, target_classes=[4, 10]) + # ================================================================= + + # 4. 多视角图像拼接(优化布局): + # 上半部分:前视RGB(左) + 前视语义分割(右) + # 下半部分:俯视RGB(左) + 行人/车辆密度热力图(右) upper_part = cv2.hconcat([front_rgb_img, front_sem_rgb]) # 宽度2048,高度720 - # 补全俯视图像宽度到2048(和上半部分一致) - top_rgb_padded = np.zeros((720, 2048, 3), dtype=np.uint8) - top_rgb_padded[:, (2048-1024)//2 : (2048+1024)//2] = top_rgb_img # 居中 - # 上下拼接最终图像 - combined_img = cv2.vconcat([upper_part, top_rgb_padded]) # 宽度2048,高度1440 + lower_part = cv2.hconcat([top_rgb_img, density_heatmap]) # 宽度2048,高度720 + combined_img = cv2.vconcat([upper_part, lower_part]) # 最终尺寸:2048×1440 # 5. 添加视角标题 # 前视RGB标题 cv2.putText(combined_img, "Front View (RGB)", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) # 前视语义标题 - cv2.putText(combined_img, "Front View (Semantic)", + cv2.putText(combined_img, "Front View (Semantic Segmentation)", (1024 + 10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) # 俯视标题 cv2.putText(combined_img, "Top View (RGB / Bird's Eye)", (10, 720 + 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) + # 热力图标题 + cv2.putText(combined_img, "Density Heatmap (Pedestrian + Vehicle)", + (1024 + 10, 720 + 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) # 6. 绘制性能监控(左上角,标题下方) perf_info = [ @@ -344,9 +378,9 @@ def set_spectator_smooth(last_transform=None): cv2.FONT_HERSHEY_SIMPLEX, 0.6, perf_color, 2) # 7. 显示最终图像(自动调整窗口大小) - cv2.namedWindow('CARLA Multi-View (Front + Top) + Semantic Segmentation', cv2.WINDOW_NORMAL) - cv2.resizeWindow('CARLA Multi-View (Front + Top) + Semantic Segmentation', 1920, 1080) - cv2.imshow('CARLA Multi-View (Front + Top) + Semantic Segmentation', combined_img) + cv2.namedWindow('CARLA Multi-View + Semantic Density Heatmap', cv2.WINDOW_NORMAL) + cv2.resizeWindow('CARLA Multi-View + Semantic Density Heatmap', 1920, 1080) + cv2.imshow('CARLA Multi-View + Semantic Density Heatmap', combined_img) if cv2.waitKey(1) == ord('q'): break From eb2d1b32252f245bb437313b3756884731af190c Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Fri, 19 Dec 2025 17:32:07 +0800 Subject: [PATCH 19/24] =?UTF-8?q?feat(count):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E8=AF=AD=E4=B9=89=E7=B1=BB=E5=88=AB=E5=AE=9E=E6=97=B6=E8=AE=A1?= =?UTF-8?q?=E6=95=B0=E5=8A=9F=E8=83=BD=EF=BC=88=E8=A1=8C=E4=BA=BA/?= =?UTF-8?q?=E8=BD=A6=E8=BE=86/=E4=BA=A4=E9=80=9A=E7=81=AF=EF=BC=89?= =?UTF-8?q?=EF=BC=8C=E5=8F=B3=E4=B8=8A=E8=A7=92=E5=8F=AF=E8=A7=86=E5=8C=96?= =?UTF-8?q?=E8=AE=A1=E6=95=B0=E9=9D=A2=E6=9D=BF=EF=BC=8C=E5=9F=BA=E4=BA=8E?= =?UTF-8?q?=E5=83=8F=E7=B4=A0=E9=98=88=E5=80=BC=E4=BC=B0=E7=AE=97=E7=9B=AE?= =?UTF-8?q?=E6=A0=87=E6=95=B0=E9=87=8F?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../carla_model3_spawn_with_spectator.py | 78 +++++++++++++++++-- 1 file changed, 73 insertions(+), 5 deletions(-) diff --git a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py index db8acc3dff..d02dbfc7a8 100644 --- a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py +++ b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py @@ -68,6 +68,32 @@ def generate_density_heatmap(sem_data, target_classes=[4, 10], width=1024, heigh return heatmap # ================================================================= +# ==================== 第11次提交新增:语义类别实时计数函数 ==================== +def semantic_class_count(sem_data, class_mapping): + """ + 统计指定语义类别的像素数量,并估算画面内目标数量(按单目标像素阈值) + :param sem_data: 语义分割原始数据(H,W),int32类型 + :param class_mapping: 字典 {类别名: 类别ID} + :return: 计数结果字典 {类别名: 近似目标数} + """ + count_dict = {} + # 单目标像素阈值(经验值:行人≈200像素,车辆≈500像素,交通灯≈50像素) + pixel_thresholds = { + "Pedestrian": 200, + "Vehicle": 500, + "TrafficLight": 50 + } + + for cls_name, cls_id in class_mapping.items(): + # 统计该类别像素总数 + pixel_count = np.sum(sem_data == cls_id) + # 估算近似目标数(避免0除,最少计为0) + threshold = pixel_thresholds.get(cls_name, 200) + approx_count = pixel_count // threshold if pixel_count >= threshold else 0 + count_dict[cls_name] = approx_count + return count_dict +# ================================================================= + # 1. 连接CARLA服务器并配置强同步模式 client = carla.Client('localhost', 2000) client.set_timeout(15.0) @@ -281,9 +307,9 @@ def set_spectator_smooth(last_transform=None): spectator.set_transform(smooth_tf) return smooth_tf -# 9. 主循环(核心:多视角+热力图可视化 + 性能监控) +# 9. 主循环(核心:多视角+热力图+计数可视化 + 性能监控) print("\n程序运行中,按Ctrl+C或窗口按'q'退出...") -print(f"功能:前视+俯视+热力图可视化 + {actual_npc_count}辆车辆 + {actual_walker_count}个行人 + 性能监控") +print(f"功能:前视+俯视+热力图+语义计数可视化 + {actual_npc_count}辆车辆 + {actual_walker_count}个行人 + 性能监控") last_spectator_tf = None clock = pygame.time.Clock() @@ -291,6 +317,12 @@ def set_spectator_smooth(last_transform=None): start_time = time.time() frame_counter = 0 current_fps = 0.0 +# ==================== 第11次提交新增:定义需要计数的语义类别 ==================== +count_class_mapping = { + "Pedestrian": 4, # 行人 + "Vehicle": 10, # 车辆 + "TrafficLight": 12 # 交通灯 +} # ================================================================= try: @@ -334,6 +366,10 @@ def set_spectator_smooth(last_transform=None): density_heatmap = generate_density_heatmap(front_sem_data, target_classes=[4, 10]) # ================================================================= + # ==================== 第11次提交新增:计算语义类别计数 ==================== + class_count_result = semantic_class_count(front_sem_data, count_class_mapping) + # ================================================================= + # 4. 多视角图像拼接(优化布局): # 上半部分:前视RGB(左) + 前视语义分割(右) # 下半部分:俯视RGB(左) + 行人/车辆密度热力图(右) @@ -377,10 +413,42 @@ def set_spectator_smooth(last_transform=None): cv2.putText(combined_img, info, (perf_x, y_pos), cv2.FONT_HERSHEY_SIMPLEX, 0.6, perf_color, 2) + # ==================== 第11次提交新增:绘制语义计数面板(右上角) ==================== + # 计数面板位置(画面右上角,避免与性能监控重叠) + count_x = combined_img.shape[1] - 320 # 2048 - 320 = 1728 + count_y = 30 + count_color = (255, 255, 0) # 青色(易识别,与黄色性能监控区分) + count_bg_color = (0, 0, 0) # 黑色背景 + count_line_height = 28 + + # 绘制计数面板背景(半透明黑色) + cv2.rectangle(combined_img, + (count_x - 10, count_y - 10), + (combined_img.shape[1] - 10, count_y + 100), + count_bg_color, -1) # 实心背景 + + # 绘制计数面板标题 + cv2.putText(combined_img, "Semantic Count (Frame)", + (count_x, count_y), + cv2.FONT_HERSHEY_SIMPLEX, 0.7, count_color, 2) + + # 绘制各类别计数 + count_items = [ + f"Pedestrian: {class_count_result['Pedestrian']}", + f"Vehicle: {class_count_result['Vehicle']}", + f"TrafficLight: {class_count_result['TrafficLight']}" + ] + for idx, item in enumerate(count_items): + y_pos = count_y + (idx + 1) * count_line_height + cv2.putText(combined_img, item, + (count_x, y_pos), + cv2.FONT_HERSHEY_SIMPLEX, 0.65, count_color, 2) + # ================================================================= + # 7. 显示最终图像(自动调整窗口大小) - cv2.namedWindow('CARLA Multi-View + Semantic Density Heatmap', cv2.WINDOW_NORMAL) - cv2.resizeWindow('CARLA Multi-View + Semantic Density Heatmap', 1920, 1080) - cv2.imshow('CARLA Multi-View + Semantic Density Heatmap', combined_img) + cv2.namedWindow('CARLA Multi-View + Semantic Density Heatmap + Count', cv2.WINDOW_NORMAL) + cv2.resizeWindow('CARLA Multi-View + Semantic Density Heatmap + Count', 1920, 1080) + cv2.imshow('CARLA Multi-View + Semantic Density Heatmap + Count', combined_img) if cv2.waitKey(1) == ord('q'): break From 1a0f04088c4fc95f5295eba7b778a1a8dc236452 Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Sat, 20 Dec 2025 22:11:20 +0800 Subject: [PATCH 20/24] =?UTF-8?q?feat(highlight):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E5=85=B3=E9=94=AE=E8=AF=AD=E4=B9=89=E7=9B=AE=E6=A0=87=E9=AB=98?= =?UTF-8?q?=E4=BA=AE=E6=A0=87=E6=B3=A8=E5=8A=9F=E8=83=BD=EF=BC=8C=E8=A1=8C?= =?UTF-8?q?=E4=BA=BA(=E7=BA=A2)/=E8=BD=A6=E8=BE=86(=E8=93=9D)=E8=BD=AE?= =?UTF-8?q?=E5=BB=93=E6=A3=80=E6=B5=8B=EF=BC=8C=E5=8F=A0=E5=8A=A0RGB?= =?UTF-8?q?=E7=94=BB=E9=9D=A2=E6=97=A0=E4=BE=B5=E5=85=A5=E5=BC=8F=E4=BF=AE?= =?UTF-8?q?=E6=94=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../carla_model3_spawn_with_spectator.py | 60 ++++++++++++++++--- 1 file changed, 52 insertions(+), 8 deletions(-) diff --git a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py index d02dbfc7a8..b83beec793 100644 --- a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py +++ b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py @@ -94,6 +94,41 @@ def semantic_class_count(sem_data, class_mapping): return count_dict # ================================================================= +# ==================== 第12次提交新增:关键语义目标高亮标注函数 ==================== +def semantic_target_highlight(rgb_img, sem_data, highlight_classes={4:(0,0,255), 10:(255,0,0)}, contour_thickness=2): + """ + 对指定语义类别进行边缘检测并绘制轮廓,高亮关键目标 + :param rgb_img: 原始RGB图像(H,W,3) + :param sem_data: 语义分割原始数据(H,W),int32类型 + :param highlight_classes: 字典 {类别ID: 轮廓颜色},默认4=行人(红)、10=车辆(蓝) + :param contour_thickness: 轮廓线宽度 + :return: 叠加高亮轮廓的RGB图像 + """ + # 复制原始图像,避免修改原数据 + highlighted_img = rgb_img.copy() + + for cls_id, color in highlight_classes.items(): + # 1. 生成该类别的二值掩码 + cls_mask = np.uint8(sem_data == cls_id) * 255 + # 2. Canny边缘检测(调整阈值控制边缘灵敏度) + edges = cv2.Canny(cls_mask, 50, 150) + # 3. 查找轮廓(仅保留外部轮廓,减少计算量) + contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) + # 4. 绘制轮廓(过滤小轮廓,避免噪声) + min_contour_area = 50 # 过滤面积小于50像素的噪声轮廓 + for cnt in contours: + if cv2.contourArea(cnt) > min_contour_area: + cv2.drawContours(highlighted_img, [cnt], -1, color, contour_thickness) + + # 5. 添加高亮说明文字(画面左下角) + highlight_tips = "Highlight: Pedestrian(Red) | Vehicle(Blue)" + cv2.putText(highlighted_img, highlight_tips, + (10, rgb_img.shape[0] - 10), + cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2) + + return highlighted_img +# ================================================================= + # 1. 连接CARLA服务器并配置强同步模式 client = carla.Client('localhost', 2000) client.set_timeout(15.0) @@ -307,9 +342,9 @@ def set_spectator_smooth(last_transform=None): spectator.set_transform(smooth_tf) return smooth_tf -# 9. 主循环(核心:多视角+热力图+计数可视化 + 性能监控) +# 9. 主循环(核心:多视角+热力图+计数+高亮标注可视化 + 性能监控) print("\n程序运行中,按Ctrl+C或窗口按'q'退出...") -print(f"功能:前视+俯视+热力图+语义计数可视化 + {actual_npc_count}辆车辆 + {actual_walker_count}个行人 + 性能监控") +print(f"功能:前视+俯视+热力图+语义计数+目标高亮标注 + {actual_npc_count}辆车辆 + {actual_walker_count}个行人 + 性能监控") last_spectator_tf = None clock = pygame.time.Clock() @@ -323,6 +358,11 @@ def set_spectator_smooth(last_transform=None): "Vehicle": 10, # 车辆 "TrafficLight": 12 # 交通灯 } +# ==================== 第12次提交新增:定义需要高亮的语义类别 ==================== +highlight_class_mapping = { + 4: (0, 0, 255), # 行人 - 红色轮廓 + 10: (255, 0, 0) # 车辆 - 蓝色轮廓 +} # ================================================================= try: @@ -370,16 +410,20 @@ def set_spectator_smooth(last_transform=None): class_count_result = semantic_class_count(front_sem_data, count_class_mapping) # ================================================================= + # ==================== 第12次提交新增:对前视RGB图像叠加目标高亮轮廓 ==================== + front_rgb_img = semantic_target_highlight(front_rgb_img, front_sem_data, highlight_class_mapping) + # ================================================================= + # 4. 多视角图像拼接(优化布局): - # 上半部分:前视RGB(左) + 前视语义分割(右) + # 上半部分:前视RGB(带高亮) + 前视语义分割(右) # 下半部分:俯视RGB(左) + 行人/车辆密度热力图(右) upper_part = cv2.hconcat([front_rgb_img, front_sem_rgb]) # 宽度2048,高度720 lower_part = cv2.hconcat([top_rgb_img, density_heatmap]) # 宽度2048,高度720 combined_img = cv2.vconcat([upper_part, lower_part]) # 最终尺寸:2048×1440 # 5. 添加视角标题 - # 前视RGB标题 - cv2.putText(combined_img, "Front View (RGB)", + # 前视RGB标题(更新为带高亮说明) + cv2.putText(combined_img, "Front View (RGB + Target Highlight)", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) # 前视语义标题 cv2.putText(combined_img, "Front View (Semantic Segmentation)", @@ -446,9 +490,9 @@ def set_spectator_smooth(last_transform=None): # ================================================================= # 7. 显示最终图像(自动调整窗口大小) - cv2.namedWindow('CARLA Multi-View + Semantic Density Heatmap + Count', cv2.WINDOW_NORMAL) - cv2.resizeWindow('CARLA Multi-View + Semantic Density Heatmap + Count', 1920, 1080) - cv2.imshow('CARLA Multi-View + Semantic Density Heatmap + Count', combined_img) + cv2.namedWindow('CARLA Multi-View + Semantic Density Heatmap + Count + Highlight', cv2.WINDOW_NORMAL) + cv2.resizeWindow('CARLA Multi-View + Semantic Density Heatmap + Count + Highlight', 1920, 1080) + cv2.imshow('CARLA Multi-View + Semantic Density Heatmap + Count + Highlight', combined_img) if cv2.waitKey(1) == ord('q'): break From 9af01b705e307566544649b7c3e8d05702c5dd54 Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Sun, 21 Dec 2025 10:21:55 +0800 Subject: [PATCH 21/24] =?UTF-8?q?feat(fusion):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E8=AF=AD=E4=B9=89-RGB=E8=9E=8D=E5=90=88=E5=8F=A0=E5=8A=A0?= =?UTF-8?q?=E5=8A=9F=E8=83=BD=EF=BC=8C=E5=8F=AF=E8=B0=83=E8=8A=82=E9=80=8F?= =?UTF-8?q?=E6=98=8E=E5=BA=A6=EF=BC=8C=E9=87=8D=E6=9E=84=E5=A4=9A=E8=A7=86?= =?UTF-8?q?=E8=A7=92=E6=8B=BC=E6=8E=A5=E5=B8=83=E5=B1=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../carla_model3_spawn_with_spectator.py | 77 ++++++++++++++----- 1 file changed, 58 insertions(+), 19 deletions(-) diff --git a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py index b83beec793..639e06f0e3 100644 --- a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py +++ b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py @@ -129,6 +129,38 @@ def semantic_target_highlight(rgb_img, sem_data, highlight_classes={4:(0,0,255), return highlighted_img # ================================================================= +# ==================== 第14次提交核心:语义分割与RGB融合叠加函数 ==================== +def semantic_rgb_fusion(rgb_img, sem_data, palette=CITYSCAPES_PALETTE, alpha=0.3): + """ + 实现RGB图像与语义分割图像的融合叠加显示 + :param rgb_img: 原始RGB图像(H,W,3) + :param sem_data: 语义分割原始数据(H,W),int32类型 + :param palette: 语义分割调色板 + :param alpha: 语义层透明度(0~1,0=仅RGB,1=仅语义) + :return: 融合后的图像(H,W,3) + """ + # 1. 生成语义分割彩色图 + sem_rgb = np.zeros_like(rgb_img) + for i in range(len(palette)): + sem_rgb[sem_data == i] = palette[i] + + # 2. 融合RGB与语义分割图(alpha=语义层权重,beta=RGB层权重) + fused_img = cv2.addWeighted(sem_rgb, alpha, rgb_img, 1 - alpha, 0) + + # 3. 添加融合说明文字(左上角) + fusion_tips = f"Semantic-RGB Fusion (Alpha={alpha})" + cv2.putText(fused_img, fusion_tips, + (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) + + # 4. 添加关键类别颜色说明(右下角) + class_tips = "Pedestrian(Red) | Vehicle(Blue) | Road(Purple)" + cv2.putText(fused_img, class_tips, + (10, rgb_img.shape[0] - 10), + cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1) + + return fused_img +# ================================================================= + # 1. 连接CARLA服务器并配置强同步模式 client = carla.Client('localhost', 2000) client.set_timeout(15.0) @@ -342,9 +374,9 @@ def set_spectator_smooth(last_transform=None): spectator.set_transform(smooth_tf) return smooth_tf -# 9. 主循环(核心:多视角+热力图+计数+高亮标注可视化 + 性能监控) +# 9. 主循环(核心:多视角+热力图+计数+高亮+语义-RGB融合可视化 + 性能监控) print("\n程序运行中,按Ctrl+C或窗口按'q'退出...") -print(f"功能:前视+俯视+热力图+语义计数+目标高亮标注 + {actual_npc_count}辆车辆 + {actual_walker_count}个行人 + 性能监控") +print(f"功能:前视+俯视+热力图+语义计数+目标高亮+语义-RGB融合 + {actual_npc_count}辆车辆 + {actual_walker_count}个行人 + 性能监控") last_spectator_tf = None clock = pygame.time.Clock() @@ -363,6 +395,8 @@ def set_spectator_smooth(last_transform=None): 4: (0, 0, 255), # 行人 - 红色轮廓 10: (255, 0, 0) # 车辆 - 蓝色轮廓 } +# ==================== 第14次提交:融合透明度配置(可调整) ==================== +fusion_alpha = 0.3 # 语义层透明度(0.3为推荐值,兼顾RGB视觉和语义辨识度) # ================================================================= try: @@ -411,25 +445,29 @@ def set_spectator_smooth(last_transform=None): # ================================================================= # ==================== 第12次提交新增:对前视RGB图像叠加目标高亮轮廓 ==================== - front_rgb_img = semantic_target_highlight(front_rgb_img, front_sem_data, highlight_class_mapping) + front_rgb_img_highlight = semantic_target_highlight(front_rgb_img.copy(), front_sem_data, highlight_class_mapping) + # ================================================================= + + # ==================== 第14次提交核心:生成语义-RGB融合图像 ==================== + fused_img = semantic_rgb_fusion(front_rgb_img, front_sem_data, alpha=fusion_alpha) # ================================================================= - # 4. 多视角图像拼接(优化布局): - # 上半部分:前视RGB(带高亮) + 前视语义分割(右) - # 下半部分:俯视RGB(左) + 行人/车辆密度热力图(右) - upper_part = cv2.hconcat([front_rgb_img, front_sem_rgb]) # 宽度2048,高度720 - lower_part = cv2.hconcat([top_rgb_img, density_heatmap]) # 宽度2048,高度720 - combined_img = cv2.vconcat([upper_part, lower_part]) # 最终尺寸:2048×1440 + # 4. 重构多视角图像拼接(融入融合图): + # 上半部分:前视RGB(带高亮) + 语义-RGB融合图(右) + # 下半部分:原始语义分割 + 行人/车辆密度热力图(右) + upper_part = cv2.hconcat([front_rgb_img_highlight, fused_img]) # 宽度2048,高度720 + lower_part = cv2.hconcat([front_sem_rgb, density_heatmap]) # 宽度2048,高度720 + combined_img = cv2.vconcat([upper_part, lower_part]) # 最终尺寸:2048×1440 - # 5. 添加视角标题 - # 前视RGB标题(更新为带高亮说明) + # 5. 更新视角标题(新增融合图说明) + # 前视RGB标题(带高亮) cv2.putText(combined_img, "Front View (RGB + Target Highlight)", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) - # 前视语义标题 - cv2.putText(combined_img, "Front View (Semantic Segmentation)", + # 融合图标题 + cv2.putText(combined_img, "Front View (Semantic-RGB Fusion)", (1024 + 10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) - # 俯视标题 - cv2.putText(combined_img, "Top View (RGB / Bird's Eye)", + # 原始语义标题 + cv2.putText(combined_img, "Front View (Raw Semantic Segmentation)", (10, 720 + 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) # 热力图标题 cv2.putText(combined_img, "Density Heatmap (Pedestrian + Vehicle)", @@ -441,7 +479,8 @@ def set_spectator_smooth(last_transform=None): f"RGB Queue: {front_rgb_queue.qsize()}", f"Sem Queue: {front_sem_queue.qsize()}", f"Sync Frame: {world.get_snapshot().frame}", - f"Vehicles: {actual_npc_count} | Pedestrians: {actual_walker_count}" + f"Vehicles: {actual_npc_count} | Pedestrians: {actual_walker_count}", + f"Fusion Alpha: {fusion_alpha}" # 新增融合透明度显示 ] perf_x = 10 perf_y = 60 @@ -490,9 +529,9 @@ def set_spectator_smooth(last_transform=None): # ================================================================= # 7. 显示最终图像(自动调整窗口大小) - cv2.namedWindow('CARLA Multi-View + Semantic Density Heatmap + Count + Highlight', cv2.WINDOW_NORMAL) - cv2.resizeWindow('CARLA Multi-View + Semantic Density Heatmap + Count + Highlight', 1920, 1080) - cv2.imshow('CARLA Multi-View + Semantic Density Heatmap + Count + Highlight', combined_img) + cv2.namedWindow('CARLA Multi-View + Semantic-RGB Fusion + Count + Highlight', cv2.WINDOW_NORMAL) + cv2.resizeWindow('CARLA Multi-View + Semantic-RGB Fusion + Count + Highlight', 1920, 1080) + cv2.imshow('CARLA Multi-View + Semantic-RGB Fusion + Count + Highlight', combined_img) if cv2.waitKey(1) == ord('q'): break From 97515d7b00b9c86bc2f8ec78a713751779f1cd01 Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Sun, 21 Dec 2025 15:37:31 +0800 Subject: [PATCH 22/24] =?UTF-8?q?feat(interactive):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E9=94=AE=E7=9B=98=E4=BA=A4=E4=BA=92=E5=8F=AF=E8=A7=86=E5=8C=96?= =?UTF-8?q?=E6=A8=A1=E5=BC=8F=E5=88=87=E6=8D=A2=EF=BC=8C=E6=94=AF=E6=8C=81?= =?UTF-8?q?4=E7=A7=8D=E5=B8=83=E5=B1=80+=E8=9E=8D=E5=90=88=E9=80=8F?= =?UTF-8?q?=E6=98=8E=E5=BA=A6=E5=8A=A8=E6=80=81=E8=B0=83=E8=8A=82?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../carla_model3_spawn_with_spectator.py | 229 ++++++++++++------ 1 file changed, 157 insertions(+), 72 deletions(-) diff --git a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py index 639e06f0e3..eb0da7f253 100644 --- a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py +++ b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py @@ -148,7 +148,7 @@ def semantic_rgb_fusion(rgb_img, sem_data, palette=CITYSCAPES_PALETTE, alpha=0.3 fused_img = cv2.addWeighted(sem_rgb, alpha, rgb_img, 1 - alpha, 0) # 3. 添加融合说明文字(左上角) - fusion_tips = f"Semantic-RGB Fusion (Alpha={alpha})" + fusion_tips = f"Semantic-RGB Fusion (Alpha={alpha:.1f})" cv2.putText(fused_img, fusion_tips, (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) @@ -161,6 +161,28 @@ def semantic_rgb_fusion(rgb_img, sem_data, palette=CITYSCAPES_PALETTE, alpha=0.3 return fused_img # ================================================================= +# ==================== 第15次提交新增:可视化模式提示生成函数 ==================== +def generate_mode_hint(current_mode, fusion_alpha): + """ + 生成当前可视化模式的提示文字 + :param current_mode: 当前模式编号 + :param fusion_alpha: 融合透明度 + :return: 提示文字列表 + """ + mode_names = { + 1: "Basic Mode (RGB+Sem / Top+Heatmap)", + 2: "Fusion Mode (RGB+Fusion / Sem+Heatmap)", + 3: "Simplified Mode (RGB+Heatmap / Top+Count)", + 4: "Full Sem Mode (Sem+Fusion / Heatmap+Top)" + } + control_hints = [ + "Controls: 1/2/3/4=Switch Mode | ↑↓=Adjust Fusion Alpha | R=Reset | Q=Quit", + f"Current Mode: {mode_names.get(current_mode, 'Basic Mode')}", + f"Fusion Alpha: {fusion_alpha:.1f} (0=RGB Only, 1=Sem Only)" + ] + return control_hints +# ================================================================= + # 1. 连接CARLA服务器并配置强同步模式 client = carla.Client('localhost', 2000) client.set_timeout(15.0) @@ -374,9 +396,10 @@ def set_spectator_smooth(last_transform=None): spectator.set_transform(smooth_tf) return smooth_tf -# 9. 主循环(核心:多视角+热力图+计数+高亮+语义-RGB融合可视化 + 性能监控) -print("\n程序运行中,按Ctrl+C或窗口按'q'退出...") -print(f"功能:前视+俯视+热力图+语义计数+目标高亮+语义-RGB融合 + {actual_npc_count}辆车辆 + {actual_walker_count}个行人 + 性能监控") +# 9. 主循环(核心:多视角+热力图+计数+高亮+融合+键盘交互可视化模式) +print("\n程序运行中,按以下按键操作:") +print("1/2/3/4 = 切换可视化模式 | ↑/↓ = 调整融合透明度 | R = 重置模式 | Q = 退出") +print(f"功能:多模式切换 + 语义计数 + 目标高亮 + 语义-RGB融合 + {actual_npc_count}辆车辆 + {actual_walker_count}个行人 + 性能监控") last_spectator_tf = None clock = pygame.time.Clock() @@ -395,8 +418,10 @@ def set_spectator_smooth(last_transform=None): 4: (0, 0, 255), # 行人 - 红色轮廓 10: (255, 0, 0) # 车辆 - 蓝色轮廓 } -# ==================== 第14次提交:融合透明度配置(可调整) ==================== -fusion_alpha = 0.3 # 语义层透明度(0.3为推荐值,兼顾RGB视觉和语义辨识度) +# ==================== 第15次提交:可视化模式配置 ==================== +current_mode = 1 # 默认模式1(基础模式) +fusion_alpha = 0.3 # 融合透明度(0~1) +mode_reset_flag = False # 模式重置标记 # ================================================================= try: @@ -436,105 +461,165 @@ def set_spectator_smooth(last_transform=None): top_rgb_img = np.reshape(np.copy(top_rgb_image.raw_data), (720, 1024, 4))[:, :, :3] - # ==================== 新增:生成语义密度热力图 ==================== + # ==================== 生成语义密度热力图 ==================== density_heatmap = generate_density_heatmap(front_sem_data, target_classes=[4, 10]) # ================================================================= - # ==================== 第11次提交新增:计算语义类别计数 ==================== + # ==================== 计算语义类别计数 ==================== class_count_result = semantic_class_count(front_sem_data, count_class_mapping) # ================================================================= - # ==================== 第12次提交新增:对前视RGB图像叠加目标高亮轮廓 ==================== + # ==================== 生成高亮RGB图像 ==================== front_rgb_img_highlight = semantic_target_highlight(front_rgb_img.copy(), front_sem_data, highlight_class_mapping) # ================================================================= - # ==================== 第14次提交核心:生成语义-RGB融合图像 ==================== + # ==================== 生成语义-RGB融合图像 ==================== fused_img = semantic_rgb_fusion(front_rgb_img, front_sem_data, alpha=fusion_alpha) # ================================================================= - # 4. 重构多视角图像拼接(融入融合图): - # 上半部分:前视RGB(带高亮) + 语义-RGB融合图(右) - # 下半部分:原始语义分割 + 行人/车辆密度热力图(右) - upper_part = cv2.hconcat([front_rgb_img_highlight, fused_img]) # 宽度2048,高度720 - lower_part = cv2.hconcat([front_sem_rgb, density_heatmap]) # 宽度2048,高度720 - combined_img = cv2.vconcat([upper_part, lower_part]) # 最终尺寸:2048×1440 + # ==================== 第15次提交核心:根据当前模式动态拼接图像 ==================== + if current_mode == 1: + # 模式1:基础模式(原有布局) + # 上=RGB高亮 + 语义分割 | 下=俯视RGB + 热力图 + upper_part = cv2.hconcat([front_rgb_img_highlight, front_sem_rgb]) + lower_part = cv2.hconcat([top_rgb_img, density_heatmap]) + elif current_mode == 2: + # 模式2:融合模式 + # 上=RGB高亮 + 语义融合 | 下=语义分割 + 热力图 + upper_part = cv2.hconcat([front_rgb_img_highlight, fused_img]) + lower_part = cv2.hconcat([front_sem_rgb, density_heatmap]) + elif current_mode == 3: + # 模式3:精简模式 + # 上=RGB高亮 + 热力图 | 下=俯视RGB + 计数可视化(生成纯黑背景+计数文字) + count_vis = np.zeros((720, 1024, 3), dtype=np.uint8) + count_title = "Semantic Count (Frame)" + cv2.putText(count_vis, count_title, (50, 100), cv2.FONT_HERSHEY_SIMPLEX, 1.2, (255, 255, 0), 3) + count_items = [ + f"Pedestrian: {class_count_result['Pedestrian']}", + f"Vehicle: {class_count_result['Vehicle']}", + f"TrafficLight: {class_count_result['TrafficLight']}" + ] + for idx, item in enumerate(count_items): + cv2.putText(count_vis, item, (50, 200 + idx * 80), + cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 255, 255), 2) + upper_part = cv2.hconcat([front_rgb_img_highlight, density_heatmap]) + lower_part = cv2.hconcat([top_rgb_img, count_vis]) + elif current_mode == 4: + # 模式4:全语义模式 + # 上=语义分割 + 融合图 | 下=热力图 + 俯视RGB + upper_part = cv2.hconcat([front_sem_rgb, fused_img]) + lower_part = cv2.hconcat([density_heatmap, top_rgb_img]) + else: + # 默认回退到模式1 + upper_part = cv2.hconcat([front_rgb_img_highlight, front_sem_rgb]) + lower_part = cv2.hconcat([top_rgb_img, density_heatmap]) + + combined_img = cv2.vconcat([upper_part, lower_part]) + # ================================================================= - # 5. 更新视角标题(新增融合图说明) - # 前视RGB标题(带高亮) - cv2.putText(combined_img, "Front View (RGB + Target Highlight)", - (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) - # 融合图标题 - cv2.putText(combined_img, "Front View (Semantic-RGB Fusion)", - (1024 + 10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) - # 原始语义标题 - cv2.putText(combined_img, "Front View (Raw Semantic Segmentation)", - (10, 720 + 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) - # 热力图标题 - cv2.putText(combined_img, "Density Heatmap (Pedestrian + Vehicle)", - (1024 + 10, 720 + 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) + # 5. 添加视角标题(根据模式动态调整) + mode_titles = { + 1: ["Front View (RGB + Target Highlight)", "Front View (Semantic Segmentation)", + "Top View (RGB / Bird's Eye)", "Density Heatmap (Pedestrian + Vehicle)"], + 2: ["Front View (RGB + Target Highlight)", "Front View (Semantic-RGB Fusion)", + "Front View (Semantic Segmentation)", "Density Heatmap (Pedestrian + Vehicle)"], + 3: ["Front View (RGB + Target Highlight)", "Density Heatmap (Pedestrian + Vehicle)", + "Top View (RGB / Bird's Eye)", "Semantic Count Visualization"], + 4: ["Front View (Semantic Segmentation)", "Front View (Semantic-RGB Fusion)", + "Density Heatmap (Pedestrian + Vehicle)", "Top View (RGB / Bird's Eye)"] + } + titles = mode_titles.get(current_mode, mode_titles[1]) + # 上半部分左标题 + cv2.putText(combined_img, titles[0], (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) + # 上半部分右标题 + cv2.putText(combined_img, titles[1], (1024 + 10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) + # 下半部分左标题 + cv2.putText(combined_img, titles[2], (10, 720 + 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) + # 下半部分右标题 + cv2.putText(combined_img, titles[3], (1024 + 10, 720 + 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) - # 6. 绘制性能监控(左上角,标题下方) + # 6. 绘制性能监控 + 模式控制提示(左上角) perf_info = [ f"FPS: {current_fps:.1f}", - f"RGB Queue: {front_rgb_queue.qsize()}", - f"Sem Queue: {front_sem_queue.qsize()}", f"Sync Frame: {world.get_snapshot().frame}", - f"Vehicles: {actual_npc_count} | Pedestrians: {actual_walker_count}", - f"Fusion Alpha: {fusion_alpha}" # 新增融合透明度显示 + f"Vehicles: {actual_npc_count} | Pedestrians: {actual_walker_count}" ] + # 生成模式控制提示 + mode_hints = generate_mode_hint(current_mode, fusion_alpha) + all_info = perf_info + mode_hints + perf_x = 10 perf_y = 60 perf_line_height = 25 perf_color = (0, 255, 255) # 黄色 - for idx, info in enumerate(perf_info): + for idx, info in enumerate(all_info): y_pos = perf_y + idx * perf_line_height # 半透明背景 cv2.rectangle(combined_img, (perf_x - 5, y_pos - 15), - (perf_x + 300, y_pos + 5), + (perf_x + 600, y_pos + 5), (0, 0, 0), -1) cv2.putText(combined_img, info, (perf_x, y_pos), cv2.FONT_HERSHEY_SIMPLEX, 0.6, perf_color, 2) - # ==================== 第11次提交新增:绘制语义计数面板(右上角) ==================== - # 计数面板位置(画面右上角,避免与性能监控重叠) - count_x = combined_img.shape[1] - 320 # 2048 - 320 = 1728 - count_y = 30 - count_color = (255, 255, 0) # 青色(易识别,与黄色性能监控区分) - count_bg_color = (0, 0, 0) # 黑色背景 - count_line_height = 28 - - # 绘制计数面板背景(半透明黑色) - cv2.rectangle(combined_img, - (count_x - 10, count_y - 10), - (combined_img.shape[1] - 10, count_y + 100), - count_bg_color, -1) # 实心背景 - - # 绘制计数面板标题 - cv2.putText(combined_img, "Semantic Count (Frame)", - (count_x, count_y), - cv2.FONT_HERSHEY_SIMPLEX, 0.7, count_color, 2) - - # 绘制各类别计数 - count_items = [ - f"Pedestrian: {class_count_result['Pedestrian']}", - f"Vehicle: {class_count_result['Vehicle']}", - f"TrafficLight: {class_count_result['TrafficLight']}" - ] - for idx, item in enumerate(count_items): - y_pos = count_y + (idx + 1) * count_line_height - cv2.putText(combined_img, item, - (count_x, y_pos), - cv2.FONT_HERSHEY_SIMPLEX, 0.65, count_color, 2) - # ================================================================= + # 7. 绘制语义计数面板(仅模式1/2/4显示,模式3已集成到布局) + if current_mode in [1, 2, 4]: + count_x = combined_img.shape[1] - 320 + count_y = 30 + count_color = (255, 255, 0) + count_bg_color = (0, 0, 0) + # 绘制计数面板背景 + cv2.rectangle(combined_img, + (count_x - 10, count_y - 10), + (combined_img.shape[1] - 10, count_y + 100), + count_bg_color, -1) + # 绘制计数标题和内容 + cv2.putText(combined_img, "Semantic Count (Frame)", + (count_x, count_y), cv2.FONT_HERSHEY_SIMPLEX, 0.7, count_color, 2) + count_items = [ + f"Pedestrian: {class_count_result['Pedestrian']}", + f"Vehicle: {class_count_result['Vehicle']}", + f"TrafficLight: {class_count_result['TrafficLight']}" + ] + for idx, item in enumerate(count_items): + y_pos = count_y + (idx + 1) * 28 + cv2.putText(combined_img, item, (count_x, y_pos), + cv2.FONT_HERSHEY_SIMPLEX, 0.65, count_color, 2) - # 7. 显示最终图像(自动调整窗口大小) - cv2.namedWindow('CARLA Multi-View + Semantic-RGB Fusion + Count + Highlight', cv2.WINDOW_NORMAL) - cv2.resizeWindow('CARLA Multi-View + Semantic-RGB Fusion + Count + Highlight', 1920, 1080) - cv2.imshow('CARLA Multi-View + Semantic-RGB Fusion + Count + Highlight', combined_img) + # 8. 显示最终图像 + cv2.namedWindow('CARLA Multi-Mode Visualization (Keyboard Interactive)', cv2.WINDOW_NORMAL) + cv2.resizeWindow('CARLA Multi-Mode Visualization (Keyboard Interactive)', 1920, 1080) + cv2.imshow('CARLA Multi-Mode Visualization (Keyboard Interactive)', combined_img) - if cv2.waitKey(1) == ord('q'): + # ==================== 第15次提交核心:键盘事件处理 ==================== + key = cv2.waitKey(1) & 0xFF + if key == ord('q'): break + elif key == ord('1'): + current_mode = 1 + print(f"切换到模式1:基础模式") + elif key == ord('2'): + current_mode = 2 + print(f"切换到模式2:融合模式(当前Alpha={fusion_alpha:.1f})") + elif key == ord('3'): + current_mode = 3 + print(f"切换到模式3:精简模式") + elif key == ord('4'): + current_mode = 4 + print(f"切换到模式4:全语义模式") + elif key == ord('r') or key == ord('R'): + # 重置模式和透明度 + current_mode = 1 + fusion_alpha = 0.3 + mode_reset_flag = True + print(f"已重置:模式1 + 融合Alpha=0.3") + elif key == 2490368: # 上方向键(增加Alpha) + fusion_alpha = min(fusion_alpha + 0.1, 1.0) + print(f"融合Alpha调整为:{fusion_alpha:.1f}") + elif key == 2621440: # 下方向键(减少Alpha) + fusion_alpha = max(fusion_alpha - 0.1, 0.0) + print(f"融合Alpha调整为:{fusion_alpha:.1f}") + # ================================================================= clock.tick(30) From 920ed3bb4ab15f89ae64d5b208e4900861fbc3b9 Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Sun, 21 Dec 2025 22:07:27 +0800 Subject: [PATCH 23/24] =?UTF-8?q?=E5=AE=8C=E6=88=90ros=E5=B0=81=E8=A3=85?= =?UTF-8?q?=EF=BC=8C=E4=B8=8A=E4=BC=A0launch=E6=96=87=E4=BB=B6?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../launch/CMakeLists.txt | 37 +++++++++++++++++++ .../launch/carla_perception.launch | 23 ++++++++++++ .../launch/package.xml | 24 ++++++++++++ 3 files changed, 84 insertions(+) create mode 100644 src/carla_autonomous_driving_perception/launch/CMakeLists.txt create mode 100644 src/carla_autonomous_driving_perception/launch/carla_perception.launch create mode 100644 src/carla_autonomous_driving_perception/launch/package.xml diff --git a/src/carla_autonomous_driving_perception/launch/CMakeLists.txt b/src/carla_autonomous_driving_perception/launch/CMakeLists.txt new file mode 100644 index 0000000000..51673553ab --- /dev/null +++ b/src/carla_autonomous_driving_perception/launch/CMakeLists.txt @@ -0,0 +1,37 @@ +cmake_minimum_required(VERSION 3.0.2) +# 功能包名称(必须与package.xml中的name一致) +project(mmap_test) + +# -------------------------- 适配Python3.7.5 -------------------------- +# 指定你的虚拟环境Python解释器路径(关键!) +set(PYTHON_EXECUTABLE /home/pan-j-l/my_ros_project/venv_py37/bin/python3) +# 系统Python3.7的头文件路径(Ubuntu20.04默认路径,一般无需修改) +set(PYTHON_INCLUDE_DIR /usr/include/python3.7m) +# 系统Python3.7的库文件路径(Ubuntu20.04默认路径,一般无需修改) +set(PYTHON_LIBRARY /usr/lib/x86_64-linux-gnu/libpython3.7m.so) + +# -------------------------- 查找ROS依赖包 -------------------------- +find_package(catkin REQUIRED COMPONENTS + rospy + std_msgs + sensor_msgs + cv_bridge +) + +# -------------------------- 声明Catkin包 -------------------------- +catkin_package( + # 声明该包依赖的其他ROS包,供其他包引用 + CATKIN_DEPENDS rospy std_msgs sensor_msgs cv_bridge +) + +# -------------------------- 安装Python脚本 -------------------------- +# 将scripts目录下的Python脚本安装到ROS的devel目录,实现全局调用 +catkin_install_python(PROGRAMS + scripts/ros_test_node.py + DESTINATION ${CATKIN_PACKAGE_BIN_DESTINATION} +) + +# -------------------------- 包含目录 -------------------------- +include_directories( + ${catkin_INCLUDE_DIRS} +) \ No newline at end of file diff --git a/src/carla_autonomous_driving_perception/launch/carla_perception.launch b/src/carla_autonomous_driving_perception/launch/carla_perception.launch new file mode 100644 index 0000000000..f176b67d96 --- /dev/null +++ b/src/carla_autonomous_driving_perception/launch/carla_perception.launch @@ -0,0 +1,23 @@ + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/carla_autonomous_driving_perception/launch/package.xml b/src/carla_autonomous_driving_perception/launch/package.xml new file mode 100644 index 0000000000..2be4bc3fea --- /dev/null +++ b/src/carla_autonomous_driving_perception/launch/package.xml @@ -0,0 +1,24 @@ + + + + mmap_test + 0.0.1 + ROS Noetic功能包:集成感知模块与决策模块的测试节点 + + pan-j-l + MIT + + + catkin + + + rospy + std_msgs + sensor_msgs + cv_bridge + + + + catkin + + \ No newline at end of file From 2940f589e275dc272df1dc933e09bf73c4f12f9c Mon Sep 17 00:00:00 2001 From: Xu-z-y <2067231714@qq.com> Date: Sat, 27 Dec 2025 18:29:06 +0800 Subject: [PATCH 24/24] =?UTF-8?q?feat(evaluation):=20=E6=96=B0=E5=A2=9E?= =?UTF-8?q?=E8=AF=AD=E4=B9=89=E5=88=86=E5=89=B2=E5=AE=9E=E6=97=B6=E9=87=8F?= =?UTF-8?q?=E5=8C=96=E8=AF=84=E4=BC=B0=EF=BC=88mIoU/PA/=E7=B1=BB=E5=88=ABI?= =?UTF-8?q?oU=EF=BC=89=EF=BC=8C=E6=96=B0=E5=A2=9E=E6=A8=A1=E5=BC=8F5+E?= =?UTF-8?q?=E9=94=AE=E5=BC=80=E5=85=B3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../carla_model3_spawn_with_spectator.py | 505 +++++++----------- 1 file changed, 190 insertions(+), 315 deletions(-) diff --git a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py index eb0da7f253..b7223bf206 100644 --- a/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py +++ b/src/carla_autonomous_driving_perception/carla_model3_spawn_with_spectator.py @@ -38,6 +38,19 @@ def lerp(a, b, t): (145, 170, 100) # 22: RoadMarking ] +# ==================== 语义分割核心类别(用于量化评估,过滤无意义类别) ==================== +EVAL_CLASSES = { + "Pedestrian": 4, + "Vehicle": 10, + "Road": 7, + "Sidewalk": 8, + "Building": 1, + "Vegetation": 9, + "TrafficLight": 12, + "TrafficSign": 13 +} +# ================================================================= + # ==================== 新增:语义密度热力图生成函数 ==================== def generate_density_heatmap(sem_data, target_classes=[4, 10], width=1024, height=720): """ @@ -47,159 +60,156 @@ def generate_density_heatmap(sem_data, target_classes=[4, 10], width=1024, heigh :param width/height: 图像分辨率 :return: 彩色密度热力图(RGB格式) """ - # 1. 生成目标类别掩码(仅保留行人和车辆) mask = np.zeros((height, width), dtype=np.uint8) for cls in target_classes: - mask[sem_data == cls] = 255 # 目标类别像素设为255,背景0 - - # 2. 高斯模糊平滑(模拟密度分布,核越大越平滑) + mask[sem_data == cls] = 255 blurred_mask = cv2.GaussianBlur(mask, (21, 21), 0) - - # 3. 转换为彩色热力图(JET色板:蓝→青→黄→红,代表密度从低到高) heatmap = cv2.applyColorMap(blurred_mask, cv2.COLORMAP_JET) - - # 4. 优化视觉效果:降低背景透明度,突出目标区域 heatmap = cv2.addWeighted(heatmap, 0.9, np.zeros_like(heatmap), 0.1, 0) - - # 5. 添加热力图标注(右下角说明) cv2.putText(heatmap, "Density: Pedestrian(Red) + Vehicle(Blue)", (10, height - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1) - return heatmap # ================================================================= -# ==================== 第11次提交新增:语义类别实时计数函数 ==================== +# ==================== 第11次提交:语义类别实时计数函数 ==================== def semantic_class_count(sem_data, class_mapping): - """ - 统计指定语义类别的像素数量,并估算画面内目标数量(按单目标像素阈值) - :param sem_data: 语义分割原始数据(H,W),int32类型 - :param class_mapping: 字典 {类别名: 类别ID} - :return: 计数结果字典 {类别名: 近似目标数} - """ count_dict = {} - # 单目标像素阈值(经验值:行人≈200像素,车辆≈500像素,交通灯≈50像素) - pixel_thresholds = { - "Pedestrian": 200, - "Vehicle": 500, - "TrafficLight": 50 - } - + pixel_thresholds = {"Pedestrian": 200, "Vehicle": 500, "TrafficLight": 50} for cls_name, cls_id in class_mapping.items(): - # 统计该类别像素总数 pixel_count = np.sum(sem_data == cls_id) - # 估算近似目标数(避免0除,最少计为0) threshold = pixel_thresholds.get(cls_name, 200) approx_count = pixel_count // threshold if pixel_count >= threshold else 0 count_dict[cls_name] = approx_count return count_dict # ================================================================= -# ==================== 第12次提交新增:关键语义目标高亮标注函数 ==================== +# ==================== 第12次提交:关键语义目标高亮标注函数 ==================== def semantic_target_highlight(rgb_img, sem_data, highlight_classes={4:(0,0,255), 10:(255,0,0)}, contour_thickness=2): - """ - 对指定语义类别进行边缘检测并绘制轮廓,高亮关键目标 - :param rgb_img: 原始RGB图像(H,W,3) - :param sem_data: 语义分割原始数据(H,W),int32类型 - :param highlight_classes: 字典 {类别ID: 轮廓颜色},默认4=行人(红)、10=车辆(蓝) - :param contour_thickness: 轮廓线宽度 - :return: 叠加高亮轮廓的RGB图像 - """ - # 复制原始图像,避免修改原数据 highlighted_img = rgb_img.copy() - for cls_id, color in highlight_classes.items(): - # 1. 生成该类别的二值掩码 cls_mask = np.uint8(sem_data == cls_id) * 255 - # 2. Canny边缘检测(调整阈值控制边缘灵敏度) edges = cv2.Canny(cls_mask, 50, 150) - # 3. 查找轮廓(仅保留外部轮廓,减少计算量) contours, _ = cv2.findContours(edges, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) - # 4. 绘制轮廓(过滤小轮廓,避免噪声) - min_contour_area = 50 # 过滤面积小于50像素的噪声轮廓 + min_contour_area = 50 for cnt in contours: if cv2.contourArea(cnt) > min_contour_area: cv2.drawContours(highlighted_img, [cnt], -1, color, contour_thickness) - - # 5. 添加高亮说明文字(画面左下角) - highlight_tips = "Highlight: Pedestrian(Red) | Vehicle(Blue)" - cv2.putText(highlighted_img, highlight_tips, - (10, rgb_img.shape[0] - 10), - cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2) - + cv2.putText(highlighted_img, "Highlight: Pedestrian(Red) | Vehicle(Blue)", + (10, rgb_img.shape[0] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (255, 255, 255), 2) return highlighted_img # ================================================================= -# ==================== 第14次提交核心:语义分割与RGB融合叠加函数 ==================== +# ==================== 第14次提交:语义分割与RGB融合叠加函数 ==================== def semantic_rgb_fusion(rgb_img, sem_data, palette=CITYSCAPES_PALETTE, alpha=0.3): - """ - 实现RGB图像与语义分割图像的融合叠加显示 - :param rgb_img: 原始RGB图像(H,W,3) - :param sem_data: 语义分割原始数据(H,W),int32类型 - :param palette: 语义分割调色板 - :param alpha: 语义层透明度(0~1,0=仅RGB,1=仅语义) - :return: 融合后的图像(H,W,3) - """ - # 1. 生成语义分割彩色图 sem_rgb = np.zeros_like(rgb_img) for i in range(len(palette)): sem_rgb[sem_data == i] = palette[i] - - # 2. 融合RGB与语义分割图(alpha=语义层权重,beta=RGB层权重) fused_img = cv2.addWeighted(sem_rgb, alpha, rgb_img, 1 - alpha, 0) - - # 3. 添加融合说明文字(左上角) - fusion_tips = f"Semantic-RGB Fusion (Alpha={alpha:.1f})" - cv2.putText(fused_img, fusion_tips, + cv2.putText(fused_img, f"Semantic-RGB Fusion (Alpha={alpha:.1f})", (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 255), 2) - - # 4. 添加关键类别颜色说明(右下角) - class_tips = "Pedestrian(Red) | Vehicle(Blue) | Road(Purple)" - cv2.putText(fused_img, class_tips, - (10, rgb_img.shape[0] - 10), - cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1) - + cv2.putText(fused_img, "Pedestrian(Red) | Vehicle(Blue) | Road(Purple)", + (10, rgb_img.shape[0] - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.5, (255, 255, 255), 1) return fused_img # ================================================================= -# ==================== 第15次提交新增:可视化模式提示生成函数 ==================== -def generate_mode_hint(current_mode, fusion_alpha): +# ==================== 第16次提交核心:语义分割量化评估函数 ==================== +def semantic_quantitative_evaluation(pred_sem_data, gt_sem_data, eval_classes): + """ + 实时计算语义分割量化指标(学术核心指标) + :param pred_sem_data: 预测语义数据(可替换为实际模型输出,此处用CARLA语义模拟) + :param gt_sem_data: 真实语义数据(CARLA语义摄像头输出,作为ground truth) + :param eval_classes: 待评估类别字典 {类别名: 类别ID} + :return: 评估结果字典(mIoU、PA、各类别IoU) + """ + height, width = pred_sem_data.shape + total_pixels = height * width + class_iou = {} + correct_pixels = 0 # 全局正确像素数(PA计算用) + + for cls_name, cls_id in eval_classes.items(): + # 计算TP(真阳性)、FP(假阳性)、FN(假阴性) + tp = np.sum((pred_sem_data == cls_id) & (gt_sem_data == cls_id)) + fp = np.sum((pred_sem_data == cls_id) & (gt_sem_data != cls_id)) + fn = np.sum((pred_sem_data != cls_id) & (gt_sem_data == cls_id)) + + # 计算IoU(避免0除) + iou = tp / (tp + fp + fn + 1e-8) + class_iou[cls_name] = round(iou, 3) + + # 累计全局正确像素 + correct_pixels += tp + + # 计算核心指标 + pa = correct_pixels / total_pixels # 像素准确率(Pixel Accuracy) + miou = np.mean(list(class_iou.values())) # 平均交并比(mean IoU) + + return { + "mIoU": round(miou, 3), + "PA": round(pa, 3), + "class_IoU": class_iou + } + +def generate_evaluation_visualization(eval_result, width=1024, height=720): """ - 生成当前可视化模式的提示文字 - :param current_mode: 当前模式编号 - :param fusion_alpha: 融合透明度 - :return: 提示文字列表 + 生成量化评估可视化面板(用于画面显示) + :param eval_result: 评估结果字典 + :param width/height: 面板分辨率 + :return: 评估可视化图像(RGB格式) """ + eval_vis = np.zeros((height, width, 3), dtype=np.uint8) + # 标题 + cv2.putText(eval_vis, "Semantic Segmentation Quantitative Evaluation", + (50, 80), cv2.FONT_HERSHEY_SIMPLEX, 1.1, (0, 255, 255), 3) + # 核心指标(mIoU、PA) + core_metrics = [ + f"mIoU (mean IoU): {eval_result['mIoU']:.3f}", + f"PA (Pixel Accuracy): {eval_result['PA']:.3f}" + ] + for idx, metric in enumerate(core_metrics): + cv2.putText(eval_vis, metric, (50, 180 + idx * 60), + cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 255, 0), 2) + # 各类别IoU(分行显示) + cv2.putText(eval_vis, "Class-wise IoU:", (50, 350), + cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 255, 0), 2) + class_iou_items = list(eval_result["class_IoU"].items()) + for idx, (cls_name, iou) in enumerate(class_iou_items): + y_pos = 420 + (idx // 2) * 50 + x_pos = 50 if idx % 2 == 0 else 550 + text = f"{cls_name}: {iou:.3f}" + cv2.putText(eval_vis, text, (x_pos, y_pos), + cv2.FONT_HERSHEY_SIMPLEX, 0.8, (255, 255, 255), 2) + return eval_vis +# ================================================================= + +# ==================== 第15次提交:可视化模式提示生成函数 ==================== +def generate_mode_hint(current_mode, fusion_alpha, eval_enabled): mode_names = { 1: "Basic Mode (RGB+Sem / Top+Heatmap)", 2: "Fusion Mode (RGB+Fusion / Sem+Heatmap)", 3: "Simplified Mode (RGB+Heatmap / Top+Count)", - 4: "Full Sem Mode (Sem+Fusion / Heatmap+Top)" + 4: "Full Sem Mode (Sem+Fusion / Heatmap+Top)", + 5: "Evaluation Mode (RGB+Fusion / Eval+Heatmap)" # 新增模式5 } control_hints = [ - "Controls: 1/2/3/4=Switch Mode | ↑↓=Adjust Fusion Alpha | R=Reset | Q=Quit", + "Controls: 1-5=Switch Mode | ↑↓=Adjust Fusion Alpha | E=Toggle Evaluation | R=Reset | Q=Quit", f"Current Mode: {mode_names.get(current_mode, 'Basic Mode')}", - f"Fusion Alpha: {fusion_alpha:.1f} (0=RGB Only, 1=Sem Only)" + f"Fusion Alpha: {fusion_alpha:.1f} | Evaluation: {'Enabled' if eval_enabled else 'Disabled'}" ] return control_hints # ================================================================= -# 1. 连接CARLA服务器并配置强同步模式 +# 1. CARLA服务器连接与配置 client = carla.Client('localhost', 2000) client.set_timeout(15.0) world = client.load_world('Town05') - -# 启用严格同步模式 settings = world.get_settings() settings.synchronous_mode = True settings.fixed_delta_seconds = 1/30 -settings.no_rendering_mode = False world.apply_settings(settings) -# 2. 初始化同步锁与帧数据缓存 +# 2. 同步锁与帧缓存 frame_lock = Lock() latest_snapshot = None - -# 绑定帧同步回调 def on_world_tick(snapshot): global latest_snapshot with frame_lock: @@ -209,7 +219,7 @@ def on_world_tick(snapshot): bp_lib = world.get_blueprint_library() spawn_points = world.get_map().get_spawn_points() -# 3. 生成主角车辆(Tesla Model3) +# 3. 生成主角车辆 model3_bp = bp_lib.find('vehicle.tesla.model3') vehicle = None for _ in range(5): @@ -222,61 +232,38 @@ def on_world_tick(snapshot): if not vehicle: raise Exception("主角车辆生成失败,请重启CARLA服务器") -# 4. 初始化摄像头通用函数(复用代码,修复shutter_speed属性问题) +# 4. 摄像头初始化函数 def init_camera(vehicle, camera_type, transform, width=1024, height=720, fov=90): - """ - 初始化摄像头(RGB/语义分割) - :param vehicle: 挂载的车辆 - :param camera_type: 摄像头类型('rgb'/'semantic') - :param transform: 摄像头位姿 - :param width/height: 图像分辨率 - :param fov: 视场角 - :return: 摄像头actor + 数据队列 - """ if camera_type == 'rgb': camera_bp = bp_lib.find('sensor.camera.rgb') elif camera_type == 'semantic': camera_bp = bp_lib.find('sensor.camera.semantic_segmentation') else: raise ValueError("camera_type must be 'rgb' or 'semantic'") - - # 通用属性(所有摄像头都支持) camera_bp.set_attribute('image_size_x', str(width)) camera_bp.set_attribute('image_size_y', str(height)) camera_bp.set_attribute('fov', str(fov)) - - # 仅RGB摄像头设置shutter_speed(语义分割摄像头不支持) if camera_type == 'rgb': camera_bp.set_attribute('shutter_speed', '100') - camera = world.spawn_actor(camera_bp, transform, attach_to=vehicle) image_queue = queue.Queue() camera.listen(image_queue.put) print(f"{camera_type.upper()}摄像头初始化完成({transform.location})") return camera, image_queue -# 4.1 初始化前视RGB摄像头(原有) -front_rgb_transform = carla.Transform( - carla.Location(x=2.0, z=1.5), - carla.Rotation(pitch=-5) -) +# 4.1 前视RGB摄像头 +front_rgb_transform = carla.Transform(carla.Location(x=2.0, z=1.5), carla.Rotation(pitch=-5)) front_rgb_camera, front_rgb_queue = init_camera(vehicle, 'rgb', front_rgb_transform) -# 4.2 初始化前视语义分割摄像头(修复shutter_speed问题) -front_sem_transform = carla.Transform( - carla.Location(x=2.0, z=1.5), - carla.Rotation(pitch=-5) -) +# 4.2 前视语义分割摄像头(同时作为GT和预测模拟) +front_sem_transform = carla.Transform(carla.Location(x=2.0, z=1.5), carla.Rotation(pitch=-5)) front_sem_camera, front_sem_queue = init_camera(vehicle, 'semantic', front_sem_transform) -# 4.3 新增:初始化俯视RGB摄像头(鸟瞰视角) -top_rgb_transform = carla.Transform( - carla.Location(x=0.0, z=8.0), # 车辆正上方8米 - carla.Rotation(pitch=-90) # 垂直向下俯视 -) -top_rgb_camera, top_rgb_queue = init_camera(vehicle, 'rgb', top_rgb_transform, fov=120) # 广角120°覆盖更多区域 +# 4.3 俯视RGB摄像头 +top_rgb_transform = carla.Transform(carla.Location(x=0.0, z=8.0), carla.Rotation(pitch=-90)) +top_rgb_camera, top_rgb_queue = init_camera(vehicle, 'rgb', top_rgb_transform, fov=120) -# 6. 生成NPC车辆 +# 5. 生成NPC车辆 npc_count = 100 print(f"开始生成{npc_count}辆NPC车辆...") for i in range(npc_count): @@ -290,73 +277,49 @@ def init_camera(vehicle, camera_type, transform, width=1024, height=720, fov=90) if i % 20 == 0: world.tick() time.sleep(0.1) - -# 统计实际生成数量 all_vehicles = world.get_actors().filter('*vehicle*') actual_npc_count = len(all_vehicles) - 1 -print(f"NPC生成完成 | 实际数量: {actual_npc_count}辆(总车辆: {len(all_vehicles)})") +print(f"NPC生成完成 | 实际数量: {actual_npc_count}辆") -# ==================== 行人生成核心逻辑 ==================== -# 6.1 生成行人(walker) -walker_count = 50 # 生成50个行人(可调整) -walkers = [] # 存储行人actor -walker_controllers = [] # 存储行人控制器(用于移动) +# 6. 生成行人 +walker_count = 50 +walkers = [] +walker_controllers = [] print(f"\n开始生成{walker_count}个行人...") - -# 获取行人蓝图(随机选择不同行人模型) walker_bps = bp_lib.filter('walker.pedestrian.*') - -# 获取行人生成点(使用地图的行人专用生成点,或随机点) walker_spawn_points = [] -for _ in range(walker_count * 2): # 生成双倍候选点,避免重叠 +for _ in range(walker_count * 2): spawn_point = carla.Transform() - # 随机位置(围绕主角车,半径50-200米,避免太近) spawn_point.location = world.get_random_location_from_navigation() - if spawn_point.location is not None: - # 确保行人不在车辆正前方(避免生成失败) - if spawn_point.location.distance(vehicle.get_location()) > 20: - walker_spawn_points.append(spawn_point) - -# 生成行人 + if spawn_point.location is not None and spawn_point.location.distance(vehicle.get_location()) > 20: + walker_spawn_points.append(spawn_point) for i in range(walker_count): if i >= len(walker_spawn_points): - break # 候选点用完则停止 + break walker_bp = random.choice(walker_bps) - # 设置行人为不可碰撞(避免卡死) walker_bp.set_attribute('is_invincible', 'false') try: walker = world.spawn_actor(walker_bp, walker_spawn_points[i]) walkers.append(walker) - # 每生成10个行人同步一次,避免服务器卡顿 if i % 10 == 0: world.tick() time.sleep(0.05) except: continue - -# 6.2 生成行人控制器并启动自主移动 if walkers: - # 获取行人控制器蓝图 controller_bp = bp_lib.find('controller.ai.walker') - # 启动交通管理器(行人也需要同步) tm = client.get_trafficmanager(8000) tm.set_synchronous_mode(True) - for walker in walkers: - # 生成控制器并绑定到行人 controller = world.spawn_actor(controller_bp, carla.Transform(), walker) walker_controllers.append(controller) - # 启动行人自主行走(随机目标点,速度1-3 m/s) controller.start() controller.go_to_location(world.get_random_location_from_navigation()) controller.set_max_speed(random.uniform(1.0, 3.0)) - -# 统计实际生成的行人数量 actual_walker_count = len(walkers) print(f"行人生成完成 | 实际数量: {actual_walker_count}个") -# ================================================================= -# 7. 启动所有车辆自动驾驶 +# 7. 启动车辆自动驾驶 tm = client.get_trafficmanager(8000) tm.set_synchronous_mode(True) for v in all_vehicles: @@ -372,16 +335,13 @@ def set_spectator_smooth(last_transform=None): if not vehicle_snapshot: return last_transform vehicle_tf = vehicle_snapshot.get_transform() - target_tf = carla.Transform( vehicle_tf.transform(carla.Location(x=-8, z=3, y=0.5)), vehicle_tf.rotation ) - if last_transform is None: spectator.set_transform(target_tf) return target_tf - smooth_loc = carla.Location( x=lerp(last_transform.location.x, target_tf.location.x, 0.15), y=lerp(last_transform.location.y, target_tf.location.y, 0.15), @@ -396,32 +356,22 @@ def set_spectator_smooth(last_transform=None): spectator.set_transform(smooth_tf) return smooth_tf -# 9. 主循环(核心:多视角+热力图+计数+高亮+融合+键盘交互可视化模式) +# 9. 主循环(集成量化评估功能) print("\n程序运行中,按以下按键操作:") -print("1/2/3/4 = 切换可视化模式 | ↑/↓ = 调整融合透明度 | R = 重置模式 | Q = 退出") -print(f"功能:多模式切换 + 语义计数 + 目标高亮 + 语义-RGB融合 + {actual_npc_count}辆车辆 + {actual_walker_count}个行人 + 性能监控") +print("1-5=切换可视化模式 | ↑/↓=调整融合透明度 | E=开启/关闭量化评估 | R=重置 | Q=退出") +print(f"功能:多模式切换+量化评估+语义融合+高亮计数+{actual_npc_count}辆车辆+{actual_walker_count}个行人") last_spectator_tf = None clock = pygame.time.Clock() -# ==================== 性能监控初始化 ==================== +# 初始化参数 start_time = time.time() frame_counter = 0 current_fps = 0.0 -# ==================== 第11次提交新增:定义需要计数的语义类别 ==================== -count_class_mapping = { - "Pedestrian": 4, # 行人 - "Vehicle": 10, # 车辆 - "TrafficLight": 12 # 交通灯 -} -# ==================== 第12次提交新增:定义需要高亮的语义类别 ==================== -highlight_class_mapping = { - 4: (0, 0, 255), # 行人 - 红色轮廓 - 10: (255, 0, 0) # 车辆 - 蓝色轮廓 -} -# ==================== 第15次提交:可视化模式配置 ==================== -current_mode = 1 # 默认模式1(基础模式) -fusion_alpha = 0.3 # 融合透明度(0~1) -mode_reset_flag = False # 模式重置标记 +count_class_mapping = {"Pedestrian": 4, "Vehicle": 10, "TrafficLight": 12} +highlight_class_mapping = {4: (0, 0, 255), 10: (255, 0, 0)} +current_mode = 1 +fusion_alpha = 0.3 +eval_enabled = True # 默认开启量化评估 # ================================================================= try: @@ -432,232 +382,157 @@ def set_spectator_smooth(last_transform=None): world.tick() last_spectator_tf = set_spectator_smooth(last_spectator_tf) - # ==================== 实时FPS计算 ==================== + # 实时FPS计算 frame_counter += 1 if frame_counter % 30 == 0: elapsed_time = time.time() - start_time current_fps = 30.0 / elapsed_time if elapsed_time > 0 else 0.0 start_time = time.time() frame_counter = 0 - # ================================================================= - # 同时获取三个摄像头数据(帧同步:前视RGB + 前视语义 + 俯视RGB) + # 获取摄像头数据 if not front_rgb_queue.empty() and not front_sem_queue.empty() and not top_rgb_queue.empty(): - # 1. 处理前视RGB图像 + # 处理图像数据 front_rgb_image = front_rgb_queue.get() - front_rgb_img = np.reshape(np.copy(front_rgb_image.raw_data), - (720, 1024, 4))[:, :, :3] + front_rgb_img = np.reshape(np.copy(front_rgb_image.raw_data), (720, 1024, 4))[:, :, :3] - # 2. 处理前视语义分割图像 front_sem_image = front_sem_queue.get() - front_sem_data = np.reshape(np.copy(front_sem_image.raw_data), - (720, 1024, 4))[:, :, 2].astype(np.int32) + front_sem_data = np.reshape(np.copy(front_sem_image.raw_data), (720, 1024, 4))[:, :, 2].astype(np.int32) front_sem_rgb = np.zeros((720, 1024, 3), dtype=np.uint8) for i in range(len(CITYSCAPES_PALETTE)): front_sem_rgb[front_sem_data == i] = CITYSCAPES_PALETTE[i] - # 3. 处理俯视RGB图像 top_rgb_image = top_rgb_queue.get() - top_rgb_img = np.reshape(np.copy(top_rgb_image.raw_data), - (720, 1024, 4))[:, :, :3] - - # ==================== 生成语义密度热力图 ==================== - density_heatmap = generate_density_heatmap(front_sem_data, target_classes=[4, 10]) - # ================================================================= + top_rgb_img = np.reshape(np.copy(top_rgb_image.raw_data), (720, 1024, 4))[:, :, :3] - # ==================== 计算语义类别计数 ==================== + # 生成辅助图像 + density_heatmap = generate_density_heatmap(front_sem_data) class_count_result = semantic_class_count(front_sem_data, count_class_mapping) - # ================================================================= - - # ==================== 生成高亮RGB图像 ==================== front_rgb_img_highlight = semantic_target_highlight(front_rgb_img.copy(), front_sem_data, highlight_class_mapping) - # ================================================================= - - # ==================== 生成语义-RGB融合图像 ==================== fused_img = semantic_rgb_fusion(front_rgb_img, front_sem_data, alpha=fusion_alpha) + + # ==================== 第16次提交:量化评估计算与可视化 ==================== + # 模拟预测数据(实际项目中替换为模型输出) + pred_sem_data = front_sem_data # 此处用CARLA语义模拟预测(无噪声) + eval_result = semantic_quantitative_evaluation(pred_sem_data, front_sem_data, EVAL_CLASSES) + eval_vis = generate_evaluation_visualization(eval_result) # ================================================================= - # ==================== 第15次提交核心:根据当前模式动态拼接图像 ==================== + # 多模式图像拼接(新增模式5:评估模式) if current_mode == 1: - # 模式1:基础模式(原有布局) - # 上=RGB高亮 + 语义分割 | 下=俯视RGB + 热力图 upper_part = cv2.hconcat([front_rgb_img_highlight, front_sem_rgb]) lower_part = cv2.hconcat([top_rgb_img, density_heatmap]) elif current_mode == 2: - # 模式2:融合模式 - # 上=RGB高亮 + 语义融合 | 下=语义分割 + 热力图 upper_part = cv2.hconcat([front_rgb_img_highlight, fused_img]) lower_part = cv2.hconcat([front_sem_rgb, density_heatmap]) elif current_mode == 3: - # 模式3:精简模式 - # 上=RGB高亮 + 热力图 | 下=俯视RGB + 计数可视化(生成纯黑背景+计数文字) count_vis = np.zeros((720, 1024, 3), dtype=np.uint8) - count_title = "Semantic Count (Frame)" - cv2.putText(count_vis, count_title, (50, 100), cv2.FONT_HERSHEY_SIMPLEX, 1.2, (255, 255, 0), 3) - count_items = [ - f"Pedestrian: {class_count_result['Pedestrian']}", - f"Vehicle: {class_count_result['Vehicle']}", - f"TrafficLight: {class_count_result['TrafficLight']}" - ] + cv2.putText(count_vis, "Semantic Count (Frame)", (50, 100), cv2.FONT_HERSHEY_SIMPLEX, 1.2, (255, 255, 0), 3) + count_items = [f"Pedestrian: {class_count_result['Pedestrian']}", f"Vehicle: {class_count_result['Vehicle']}", f"TrafficLight: {class_count_result['TrafficLight']}"] for idx, item in enumerate(count_items): - cv2.putText(count_vis, item, (50, 200 + idx * 80), - cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 255, 255), 2) + cv2.putText(count_vis, item, (50, 200 + idx * 80), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (255, 255, 255), 2) upper_part = cv2.hconcat([front_rgb_img_highlight, density_heatmap]) lower_part = cv2.hconcat([top_rgb_img, count_vis]) elif current_mode == 4: - # 模式4:全语义模式 - # 上=语义分割 + 融合图 | 下=热力图 + 俯视RGB upper_part = cv2.hconcat([front_sem_rgb, fused_img]) lower_part = cv2.hconcat([density_heatmap, top_rgb_img]) + elif current_mode == 5: # 模式5:评估模式 + upper_part = cv2.hconcat([front_rgb_img_highlight, fused_img]) + lower_part = cv2.hconcat([eval_vis, density_heatmap]) # 新增评估面板 else: - # 默认回退到模式1 upper_part = cv2.hconcat([front_rgb_img_highlight, front_sem_rgb]) lower_part = cv2.hconcat([top_rgb_img, density_heatmap]) combined_img = cv2.vconcat([upper_part, lower_part]) - # ================================================================= - # 5. 添加视角标题(根据模式动态调整) + # 模式标题(新增模式5标题) mode_titles = { - 1: ["Front View (RGB + Target Highlight)", "Front View (Semantic Segmentation)", - "Top View (RGB / Bird's Eye)", "Density Heatmap (Pedestrian + Vehicle)"], - 2: ["Front View (RGB + Target Highlight)", "Front View (Semantic-RGB Fusion)", - "Front View (Semantic Segmentation)", "Density Heatmap (Pedestrian + Vehicle)"], - 3: ["Front View (RGB + Target Highlight)", "Density Heatmap (Pedestrian + Vehicle)", - "Top View (RGB / Bird's Eye)", "Semantic Count Visualization"], - 4: ["Front View (Semantic Segmentation)", "Front View (Semantic-RGB Fusion)", - "Density Heatmap (Pedestrian + Vehicle)", "Top View (RGB / Bird's Eye)"] + 1: ["Front View (RGB + Highlight)", "Semantic Segmentation", "Top View (Bird's Eye)", "Density Heatmap"], + 2: ["Front View (RGB + Highlight)", "Semantic-RGB Fusion", "Semantic Segmentation", "Density Heatmap"], + 3: ["Front View (RGB + Highlight)", "Density Heatmap", "Top View (Bird's Eye)", "Semantic Count"], + 4: ["Semantic Segmentation", "Semantic-RGB Fusion", "Density Heatmap", "Top View (Bird's Eye)"], + 5: ["Front View (RGB + Highlight)", "Semantic-RGB Fusion", "Quantitative Evaluation", "Density Heatmap"] } titles = mode_titles.get(current_mode, mode_titles[1]) - # 上半部分左标题 cv2.putText(combined_img, titles[0], (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) - # 上半部分右标题 cv2.putText(combined_img, titles[1], (1024 + 10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) - # 下半部分左标题 cv2.putText(combined_img, titles[2], (10, 720 + 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) - # 下半部分右标题 cv2.putText(combined_img, titles[3], (1024 + 10, 720 + 30), cv2.FONT_HERSHEY_SIMPLEX, 1.0, (0, 255, 0), 2) - # 6. 绘制性能监控 + 模式控制提示(左上角) + # 性能监控+模式提示 perf_info = [ f"FPS: {current_fps:.1f}", f"Sync Frame: {world.get_snapshot().frame}", - f"Vehicles: {actual_npc_count} | Pedestrians: {actual_walker_count}" + f"Vehicles: {actual_npc_count} | Pedestrians: {actual_walker_count}", + f"mIoU: {eval_result['mIoU']:.3f} | PA: {eval_result['PA']:.3f}" # 新增量化指标显示 ] - # 生成模式控制提示 - mode_hints = generate_mode_hint(current_mode, fusion_alpha) + mode_hints = generate_mode_hint(current_mode, fusion_alpha, eval_enabled) all_info = perf_info + mode_hints perf_x = 10 perf_y = 60 perf_line_height = 25 - perf_color = (0, 255, 255) # 黄色 + perf_color = (0, 255, 255) for idx, info in enumerate(all_info): y_pos = perf_y + idx * perf_line_height - # 半透明背景 - cv2.rectangle(combined_img, - (perf_x - 5, y_pos - 15), - (perf_x + 600, y_pos + 5), - (0, 0, 0), -1) - cv2.putText(combined_img, info, (perf_x, y_pos), - cv2.FONT_HERSHEY_SIMPLEX, 0.6, perf_color, 2) + cv2.rectangle(combined_img, (perf_x - 5, y_pos - 15), (perf_x + 600, y_pos + 5), (0, 0, 0), -1) + cv2.putText(combined_img, info, (perf_x, y_pos), cv2.FONT_HERSHEY_SIMPLEX, 0.6, perf_color, 2) - # 7. 绘制语义计数面板(仅模式1/2/4显示,模式3已集成到布局) + # 语义计数面板(模式1/2/4显示) if current_mode in [1, 2, 4]: count_x = combined_img.shape[1] - 320 count_y = 30 - count_color = (255, 255, 0) - count_bg_color = (0, 0, 0) - # 绘制计数面板背景 - cv2.rectangle(combined_img, - (count_x - 10, count_y - 10), - (combined_img.shape[1] - 10, count_y + 100), - count_bg_color, -1) - # 绘制计数标题和内容 - cv2.putText(combined_img, "Semantic Count (Frame)", - (count_x, count_y), cv2.FONT_HERSHEY_SIMPLEX, 0.7, count_color, 2) - count_items = [ - f"Pedestrian: {class_count_result['Pedestrian']}", - f"Vehicle: {class_count_result['Vehicle']}", - f"TrafficLight: {class_count_result['TrafficLight']}" - ] + cv2.rectangle(combined_img, (count_x - 10, count_y - 10), (combined_img.shape[1] - 10, count_y + 100), (0, 0, 0), -1) + cv2.putText(combined_img, "Semantic Count (Frame)", (count_x, count_y), cv2.FONT_HERSHEY_SIMPLEX, 0.7, (255, 255, 0), 2) + count_items = [f"Pedestrian: {class_count_result['Pedestrian']}", f"Vehicle: {class_count_result['Vehicle']}", f"TrafficLight: {class_count_result['TrafficLight']}"] for idx, item in enumerate(count_items): y_pos = count_y + (idx + 1) * 28 - cv2.putText(combined_img, item, (count_x, y_pos), - cv2.FONT_HERSHEY_SIMPLEX, 0.65, count_color, 2) + cv2.putText(combined_img, item, (count_x, y_pos), cv2.FONT_HERSHEY_SIMPLEX, 0.65, (255, 255, 0), 2) - # 8. 显示最终图像 - cv2.namedWindow('CARLA Multi-Mode Visualization (Keyboard Interactive)', cv2.WINDOW_NORMAL) - cv2.resizeWindow('CARLA Multi-Mode Visualization (Keyboard Interactive)', 1920, 1080) - cv2.imshow('CARLA Multi-Mode Visualization (Keyboard Interactive)', combined_img) + # 显示图像 + cv2.namedWindow('CARLA Multi-Mode + Quantitative Evaluation', cv2.WINDOW_NORMAL) + cv2.resizeWindow('CARLA Multi-Mode + Quantitative Evaluation', 1920, 1080) + cv2.imshow('CARLA Multi-Mode + Quantitative Evaluation', combined_img) - # ==================== 第15次提交核心:键盘事件处理 ==================== + # 键盘事件处理(新增E键控制评估开关) key = cv2.waitKey(1) & 0xFF if key == ord('q'): break - elif key == ord('1'): - current_mode = 1 - print(f"切换到模式1:基础模式") - elif key == ord('2'): - current_mode = 2 - print(f"切换到模式2:融合模式(当前Alpha={fusion_alpha:.1f})") - elif key == ord('3'): - current_mode = 3 - print(f"切换到模式3:精简模式") - elif key == ord('4'): - current_mode = 4 - print(f"切换到模式4:全语义模式") + elif key == ord('1'): current_mode = 1; print(f"切换到模式1:基础模式") + elif key == ord('2'): current_mode = 2; print(f"切换到模式2:融合模式") + elif key == ord('3'): current_mode = 3; print(f"切换到模式3:精简模式") + elif key == ord('4'): current_mode = 4; print(f"切换到模式4:全语义模式") + elif key == ord('5'): current_mode = 5; print(f"切换到模式5:量化评估模式") + elif key == ord('e') or key == ord('E'): + eval_enabled = not eval_enabled + print(f"量化评估{'开启' if eval_enabled else '关闭'}") elif key == ord('r') or key == ord('R'): - # 重置模式和透明度 - current_mode = 1 - fusion_alpha = 0.3 - mode_reset_flag = True - print(f"已重置:模式1 + 融合Alpha=0.3") - elif key == 2490368: # 上方向键(增加Alpha) - fusion_alpha = min(fusion_alpha + 0.1, 1.0) - print(f"融合Alpha调整为:{fusion_alpha:.1f}") - elif key == 2621440: # 下方向键(减少Alpha) - fusion_alpha = max(fusion_alpha - 0.1, 0.0) - print(f"融合Alpha调整为:{fusion_alpha:.1f}") - # ================================================================= + current_mode = 1; fusion_alpha = 0.3; eval_enabled = True + print(f"已重置:模式1+融合Alpha=0.3+量化评估开启") + elif key == 2490368: fusion_alpha = min(fusion_alpha + 0.1, 1.0); print(f"融合Alpha调整为:{fusion_alpha:.1f}") + elif key == 2621440: fusion_alpha = max(fusion_alpha - 0.1, 0.0); print(f"融合Alpha调整为:{fusion_alpha:.1f}") clock.tick(30) except KeyboardInterrupt: print("\n用户中断,清理资源...") finally: - # ==================== 清理所有摄像头资源 ==================== - # 前视RGB - front_rgb_camera.stop() - front_rgb_camera.destroy() - # 前视语义 - front_sem_camera.stop() - front_sem_camera.destroy() - # 俯视RGB - top_rgb_camera.stop() - top_rgb_camera.destroy() - # ================================================================= - - # ==================== 清理行人资源 ==================== + # 清理资源 + front_rgb_camera.stop(); front_rgb_camera.destroy() + front_sem_camera.stop(); front_sem_camera.destroy() + top_rgb_camera.stop(); top_rgb_camera.destroy() for controller in walker_controllers: if controller.is_alive: - controller.stop() - controller.destroy() + controller.stop(); controller.destroy() for walker in walkers: if walker.is_alive: walker.destroy() print(f"已销毁{len(walker_controllers)}个行人控制器 + {len(walkers)}个行人") - # ================================================================= - - # 恢复CARLA设置 settings.synchronous_mode = False tm.set_synchronous_mode(False) world.apply_settings(settings) - - # 销毁所有车辆 for v in all_vehicles: if v.is_alive: v.destroy() - cv2.destroyAllWindows() - print(f"资源清理完成,同步模式已关闭(销毁{len(all_vehicles)}辆车辆)") \ No newline at end of file + print(f"资源清理完成,销毁{len(all_vehicles)}辆车辆") \ No newline at end of file