使用CaralaUE4采集仿真世界车辆图像,并使用neural_renderer渲染位置与采集图像相同的图像

导语:Carla在自动驾驶领域中是一个很重要的仿真器,它和UE4的结合可以生成非常精细的仿真世界;常被用于自动驾驶等研究任务中。神经渲染器是将传统的渲染过程参数化,使其整个过程变得可以微分。

1 CarlaUE4的安装和使用

1.1 下载

首先,进入Carla的官方页面,然后点击Get Started,然后进入到Quick start package installation找到Package installation,并进入到Carla repository。选择Carla 0.9.10,进入到详细页面。看到Release 0.9.10中有两个Window版本zip文件,都下载下来。

1.2 使用

  1. 激活要使用Carla的虚拟环境;

  2. 下载完成后,还需要安装一个python库

pip install --user pygame numpy

  1. 安装完成以后,解压下载的Carla0.9.10.ZIP文件,得到以下的目录文件
-Carla_0.9.10
	-WindowsNoEditor
		- CarlaUE4
		- Co-Simulation
		- PythonAPI
			- carla
			- examples
				- manual_control.py
			- util
		- CarlaUE4.exe
		- ...
  1. 运行上面的CarlaUE4.exe文件,会得到一个初始场景,是一个街道画面。
  2. 然后,将目录切换到PythonAPI/examples/下,运行python manual_control.py会弹出另外一个界面,在该界面中车辆是Actor,我们可以通过相关的命令控制车辆。

1.3 仿真数据集的收集

2 神经渲染器neural_renderer

通过第一步采集得到的数据,使用相机的位置和旋转信息来计算神经渲染器的相机位置(eye变量),使用以下代码进行计算

def get_params(carlaTcam, carlaTveh):  # carlaTcam: tuple of 2*3
    # scale = 0.41 整个scale是代表渲染的尺寸与原始尺寸的比值吗?
    scale = 0.35
    # calc eye
    eye = [0, 0, 0]
    for i in range(0, 3):
        # eye[i] = (carlaTcam[0][i] - carlaTveh[0][i]) * scale 使用这个计算方式会导致相机渲染不出任何东西
        eye[i] = carlaTcam[0][i] * scale # 因为相机使用的是相对位置。在神经渲染器中,由于目标的位置是空间原点,所以应该直接使用相机的位置来渲染(上面提到相机的位置信息是相对于目标车辆的,所以无论车辆怎么变,相机与车辆的位置都是固定的)

    # calc camera_direction and camera_up
    pitch = math.radians(carlaTcam[1][0])
    yaw = math.radians(carlaTcam[1][1])
    roll = math.radians(carlaTcam[1][2])
    # 需不需要确定下范围???
    cam_direct = [math.cos(pitch) * math.cos(yaw), math.cos(pitch) * math.sin(yaw), math.sin(pitch)]
    cam_up = [math.cos(math.pi/2+pitch) * math.cos(yaw), math.cos(math.pi/2+pitch) * math.sin(yaw), math.sin(math.pi/2+pitch)]
    
    # 如果物体也有旋转,则需要调整相机位置和角度,和物体旋转方式一致
    # 先实现最简单的绕Z轴旋转
    p_cam = eye
    p_dir = [eye[0] + cam_direct[0], eye[1] + cam_direct[1], eye[2] + cam_direct[2]]
    p_up = [eye[0] + cam_up[0], eye[1] + cam_up[1], eye[2] + cam_up[2]]
    p_l = [p_cam, p_dir, p_up]
    trans_p = []
    for p in p_l:
        if math.sqrt(p[0]**2 + p[1]**2) == 0:
            cosfi = 0
            sinfi = 0
        else:
            cosfi = p[0] / math.sqrt(p[0]**2 + p[1]**2)
            sinfi = p[1] / math.sqrt(p[0]**2 + p[1]**2)        
        cossum = cosfi * math.cos(math.radians(carlaTveh[1][1])) + sinfi * math.sin(math.radians(carlaTveh[1][1]))
        sinsum = math.cos(math.radians(carlaTveh[1][1])) * sinfi - math.sin(math.radians(carlaTveh[1][1])) * cosfi
        trans_p.append([math.sqrt(p[0]**2 + p[1]**2) * cossum, math.sqrt(p[0]**2 + p[1]**2) * sinsum, p[2]])
    
    
    return trans_p[0], \
        [trans_p[1][0] - trans_p[0][0], trans_p[1][1] - trans_p[0][1], trans_p[1][2] - trans_p[0][2]], \
        [trans_p[2][0] - trans_p[0][0], trans_p[2][1] - trans_p[0][1], trans_p[2][2] - trans_p[0][2]]


eye, camera_direction, camera_up = get_params(((-25, 16, 20), (-45, 180, 0)), ((-45, 3, 0.8), (0, 0, 0)))  # test example
self.renderer.renderer.eye = eye
# 以下两个参数在实际渲染过程中不起作用
self.renderer.renderer.camera_direction = camera_direction
self.renderer.renderer.camera_up = camera_up 

# 渲染
```渲染参数
vertices_-var: 顶点参数 [113449 3]
faces_var: 渲染的表面 ([1, 23145, 3])
texture: 纹理信息  ([1, 23145, 6,6,6,3])
```
imgs_pred = self.mask_renderer.forward(self.vertices_var, self.faces_var, self.textures)

# 将渲染图与原图相加
img = img[:, :, ::-1]
img = cv2.resize(img, (self.img_size, self.img_size))
img = np.transpose(img, (2, 0, 1))
img = np.resize(img, (1, img.shape[0], img.shape[1], img.shape[2]))
img = torch.from_numpy(img).cuda(device=0)
imgs_pred = imgs_pred / torch.max(imgs_pred)
total2show = img
total_img = img + 255 * imgs_pred

3 相机知识

  1. OPEGL学习笔记:https://www.zhihu.com/column/c_1213149364098600960
  2. Carmera旋转:https://learnopengl-cn.github.io/01%20Getting%20started/09%20Camera/
  3. 相机旋转:https://www.zhihu.com/search?type=content&q=opengl%20%E7%9B%B8%E6%9C%BA%20%E6%97%8B%E8%BD%AC
Table of Contents