我是李慢慢。
最近机缘巧合,又基于Carla做了个驾驶员视角的效果。
这里简单记录下。
1、先看效果:
2、方法原理
a、创建仿真世界的客户端client
b、通过client创建主车
c、通过主车创建6个camera
d、获得每个camera的输出图像
e、将所有图像部署在一个pygame窗口里
f、仿真世界每次tick,camera的图像都会更新一次
记录下完整代码如下:
# client_to_show_ego_6_views.py
# 2022-11-27
# by limanman
# 多窗口显示驾驶员视角的demo程序
import carla
import argparse
import random
import time
import numpy as np
try:
import pygame
from pygame.locals import K_ESCAPE
from pygame.locals import K_q
except ImportError:
raise RuntimeError('cannot import pygame, make sure pygame package is installed')
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, reverse):
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)
self.reverse = reverse
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()
print("===size:", str(disp_size[0]), str(disp_size[1]))
camera_bp.set_attribute('image_size_x', str(disp_size[0]))
camera_bp.set_attribute('image_size_y', str(disp_size[1]))
camera_bp.set_attribute('fov', str(40))
#
for key in sensor_options:
camera_bp.set_attribute(key, sensor_options[key])
camera = self.world.spawn_actor(camera_bp, transform, attach_to=attached)
print("camera_attributes:", camera.attributes)
for i in camera.attributes:
print("camera_attributes:", i, camera.attributes[i])
camera.listen(self.save_rgb_image)
return camera
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.reverse == True:
array = np.flip(array, axis=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 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()
class WindowCameraRear(object):
def __init__(self):
# === 1, 创建pygame窗口 ===
pygame.init() # 内部各功能模块进行初始化创建及变量设置,默认调用
self.size = width, height = 1024, 600 # 设置游戏窗口大小,分别是宽度和高度
self.screen = pygame.display.set_mode(self.size) # 初始化显示窗口
pygame.display.set_caption("我的小游戏程序") # 设置显示窗口的标题内容
self.my_display = pygame.display.set_mode(self.size, pygame.HWSURFACE | pygame.DOUBLEBUF)
# pygame_clock = pygame.time.Clock()
def sensor_image(self, image):
print("self:", self)
print("image:", image)
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]
array = np.flip(array, axis=1) # 将画面左右翻转
self.surface = pygame.surfarray.make_surface(array.swapaxes(0, 1))
self.my_display.blit(self.surface, (0, 0))
def run_simulation(args, client):
"""This function performed one test run using the args parameters
and connecting to the carla client passed.
"""
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)
# Instanciating the vehicle to which we attached the sensors
bp = world.get_blueprint_library().filter('charger_2020')[0]
vehicle = world.spawn_actor(bp, random.choice(world.get_map().get_spawn_points()))
vehicle_list.append(vehicle)
vehicle.set_autopilot(True)
# Display Manager organize all the sensors an its display in a window
# If can easily configure the grid and the total window size
display_manager = DisplayManager(grid_size=[2, 3], window_size=[args.width, args.height])
SensorManager(world, display_manager, 'RGBCamera',
carla.Transform(carla.Location(x=3.5, y=0, z=1.5), carla.Rotation(yaw=-40)),
vehicle, {}, display_pos=[0, 0], reverse=False)
SensorManager(world, display_manager, 'RGBCamera',
carla.Transform(carla.Location(x=3.5, y=0, z=1.5), carla.Rotation(yaw=+00)),
vehicle, {}, display_pos=[0, 1], reverse=False)
SensorManager(world, display_manager, 'RGBCamera',
carla.Transform(carla.Location(x=3.5, y=0, z=1.5), carla.Rotation(yaw=+40)),
vehicle, {}, display_pos=[0, 2], reverse=False)
SensorManager(world, display_manager, 'RGBCamera',
carla.Transform(carla.Location(x=0.7, y=-1.0, z=1.1), carla.Rotation(yaw=-170)),
vehicle, {}, display_pos=[1, 0], reverse=True)
SensorManager(world, display_manager, 'RGBCamera',
carla.Transform(carla.Location(x=0.7, y=0, z=1.3), carla.Rotation(yaw=-180)),
vehicle, {}, display_pos=[1, 1], reverse=True)
SensorManager(world, display_manager, 'RGBCamera',
carla.Transform(carla.Location(x=0.7, y=+1.0, z=1.1), carla.Rotation(yaw=+170)),
vehicle, {}, display_pos=[1, 2], reverse=True)
# #######################################################
# 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 == K_ESCAPE or event.key == 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='CARLA Sensor tutorial')
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('\nCancelled by user. Bye!')
if __name__ == '__main__':
main()
真实又臭又长。
古德拜。