Nuscenes——环视相机下BEV时序融合:前后帧空间对齐操作

想要融合多帧的时序信息,在目前的多种BEV方法中,使用Ego motion将前一帧Align到当前帧是效果较好的方法,本文将会对Align部分进行讲解。

获取数据

获取nuscenes历史帧ego motion的方法:Nuscenes——环视相机数据准备:当前帧与前一帧所有数据的获取及操作细节

我们首先使用dataloader获取Nuscenes中的数据:

  • 获取到多帧BEV的semantic mask,并保存到label_mask_list列表中;
  • ego moiton相关的translation、rotation等信息,并保存到ego_motion_list中;
num_frame = 5 # 保留几帧时序信息
label_mask_list = []
ego_motion_list = []
for i, (gt_map, images_path, ego_motion) in enumerate(tqdm.tqdm(data_loader)):
'''
    gt_map [list(Tensor)]: a list saves gt images of All batch
    images_path list(list(str)): a list saves multi-view images dir of All batch
    '''
    for j, semantic_gt in enumerate(gt_map):
        '''
        j (int): batch size id.
        semantic_gt (tensor): gt images # get gt [3, 400, 200]
        '''
        

        label_mask_list.append(semantic_gt)
        if len(label_mask_list) > num_frame:
            label_mask_list.pop(0)
        ego_motion_list.append(ego_motion[j][-1])
        if len(ego_motion_list) > num_frame:
            ego_motion_list.pop(0)   

获得的5帧时序mask如图所示:(车辆运动方向为向下)

Nuscenes——环视相机下BEV时序融合:前后帧空间对齐操作_第1张图片

然后使用motion_align函数将其中任意两帧进行对齐:

if len(label_mask_list) is num_frame:
    prev_idx=0;  # 前一帧的idx
    curr_idx=4   # 后一帧的idx
    aligned_mask = motion_align(label_mask_list, ego_motion_list,prev_idx=prev_idx,curr_idx=curr_idx)

基于ego motion信息对齐

基于该函数即可实现使用ego_motiontranslationrotation信息将两帧空间做对齐:

def motion_align(label_mask_list, ego_motion_list, x_scale=0.15, y_scale=0.15, prev_idx=0, curr_idx=1):
    from pyquaternion import Quaternion
    # 取出两帧mask
    label_mask_prev, label_mask_curr = label_mask_list[prev_idx], label_mask_list[curr_idx]
    
    # 获得全局坐标系下的translation和rotation_θ
    translation_prev, translation_curr = ego_motion_list[prev_idx]['translation'][:2], ego_motion_list[curr_idx]['translation'][:2]
    rotation_θ_prev, rotation_θ_curr = Quaternion(ego_motion_list[prev_idx]['rotation']).yaw_pitch_roll[0], Quaternion(ego_motion_list[curr_idx]['rotation']).yaw_pitch_roll[0]
    # 在全局坐标系下,获得相对变换的平移矩阵translation和相对变换的旋转矩阵rotation
    translation_shift = (np.array(translation_curr) - np.array(translation_prev)) / np.array([x_scale, y_scale]) 
    rotation_θ_shift = np.array(rotation_θ_curr) - np.array(rotation_θ_prev)         # yaw:    rotation angle around the z-axis in radians, in the range `[-pi, pi]`
    
    # 获取当前帧车相对于全局坐标系的旋转矩阵
    rotation_θ_ego = np.array(-rotation_θ_curr)
    ego_transform_matrix = np.array([[np.cos(rotation_θ_ego),-np.sin(rotation_θ_ego)],
                                    [np.sin(rotation_θ_ego), np.cos(rotation_θ_ego)]])
    # 将基于全局坐标系的相对平移量转换到基于ego坐标系的相对平移量
    ego_translation_shift = ego_transform_matrix @ translation_shift.T
    print("ego_translation_shift:", ego_translation_shift)

    # 由于我在生成mask时,进行了顺时针旋转,因此需要将x,y调换位置
    translation = ego_translation_shift[::-1]
    # 给ego坐标系的x变换为正
    translation[0] * -1

    # 不同时序帧做空间对齐
    aligned_mask = align(label_mask_prev, -rotation_θ_shift, translation)
    
    return aligned_mask


def align(src, θ, xy):
    transform_matrix=np.array([[np.cos(θ),-np.sin(θ), -xy[0] ],
                               [np.sin(θ), np.cos(θ), xy[1] ],
                               [    0    ,     0    ,   1   ]])
    # 因为这里我的mask时H,W形式,因此需要转换成一般的W,H
    src = np.swapaxes(src, 1, 0)
    rows, cols = src.shape
    center = (int(rows/2),int(cols/2))
    dst=np.zeros((rows,cols),dtype=np.uint8)
    for i in range(rows):
        for j in range(cols):
            src_pos=np.array([i-center[0],j-center[1],1])
            [x,y,_]=np.dot(transform_matrix,src_pos)
            x=int(x)+center[0]
            y=int(y)+center[1]

            if x>=rows or y>=cols or x<0 or y<0:
                dst[i][j]=255
            else:
                dst[i][j]=src[x][y]
    # 最终转换回H,W形式
    return np.swapaxes(dst, 1, 0)

Align后的mask图:

Nuscenes——环视相机下BEV时序融合:前后帧空间对齐操作_第2张图片

参考文章:

  • Numpy平移,旋转,镜像操作
  • numpy维度交换

你可能感兴趣的:(BEV,深度学习,计算机视觉,人工智能)