PointNet++详解(一):数据增强方法


如有错误,恳请指出。


下面是pointnet++项目实现的点云数据增强方法,主要包括随机旋转、随机缩放、随机丢弃、随机平移、随机扰动等等。

github项目链接:https://github.com/yanx27/Pointnet_Pointnet2_pytorch

1. 随机顺序

# 作用: 随机打乱Batch中点云及其label的顺序
def shuffle_data(data, labels):
    """ Shuffle data and labels.
        Input:
          data: B,N,... numpy array
          label: B,... numpy array
        Return:
          shuffled data, label and shuffle indices
    """
    idx = np.arange(len(labels))
    np.random.shuffle(idx)
    return data[idx, ...], labels[idx], idx

# 作用: 随机打乱一个点云中点的顺序
def shuffle_points(batch_data):
    """ Shuffle orders of points in each point cloud -- changes FPS behavior.
        Use the same shuffling idx for the entire batch.
        Input:
            BxNxC array
        Output:
            BxNxC array
    """
    idx = np.arange(batch_data.shape[1])    # 根据索引随机点顺序
    np.random.shuffle(idx)
    return batch_data[:,idx,:]

2. 随机旋转

这里贴上的是沿3个轴随机旋转

# 作用: 对每个点云与法向量均进行沿xyz三个轴随机(小幅度)旋转
def rotate_perturbation_point_cloud_with_normal(batch_data, angle_sigma=0.06, angle_clip=0.18):
    """ Randomly perturb the point clouds by small rotations
        Input:
          BxNx6 array, original batch of point clouds and point normals
          angle_sigma: 权重系数, 控制随机角度的大小
          angle_clip:  确定随机角度的上下限(-0.18~0.18)
        Return:
          BxNx3 array, rotated batch of point clouds
    """
    rotated_data = np.zeros(batch_data.shape, dtype=np.float32)
    for k in range(batch_data.shape[0]):
        # 对xyz三个轴方向随机生成一个旋转角度
        angles = np.clip(angle_sigma*np.random.randn(3), -angle_clip, angle_clip)
        # 根据公式构建三个轴方向的旋转矩阵
        Rx = np.array([[1,0,0],
                       [0,np.cos(angles[0]),-np.sin(angles[0])],
                       [0,np.sin(angles[0]),np.cos(angles[0])]])
        Ry = np.array([[np.cos(angles[1]),0,np.sin(angles[1])],
                       [0,1,0],
                       [-np.sin(angles[1]),0,np.cos(angles[1])]])
        Rz = np.array([[np.cos(angles[2]),-np.sin(angles[2]),0],
                       [np.sin(angles[2]),np.cos(angles[2]),0],
                       [0,0,1]])
        # 按照内旋方式:Z-Y-X旋转顺序获得整体的旋转矩阵
        R = np.dot(Rz, np.dot(Ry,Rx))
        shape_pc = batch_data[k,:,0:3]
        shape_normal = batch_data[k,:,3:6]
        # 分别对坐标与法向量进行旋转,整体公式应该为: Pt = (Rz * Ry * Rx) * P
        rotated_data[k,:,0:3] = np.dot(shape_pc.reshape((-1, 3)), R)
        rotated_data[k,:,3:6] = np.dot(shape_normal.reshape((-1, 3)), R)
    return rotated_data

3. 随机噪声

# 作用: 对点云数据添加噪声, 进行小范围扰动
def jitter_point_cloud(batch_data, sigma=0.01, clip=0.05):
    """ Randomly jitter points. jittering is per point.
        Input:
          BxNx3 array, original batch of point clouds
          angle_sigma: 权重系数, 控制随机噪声幅度
          angle_clip:  确定随机噪声的上下限(-0.05~0.05)
        Return:
          BxNx3 array, jittered batch of point clouds
    """
    B, N, C = batch_data.shape
    assert(clip > 0)
    jittered_data = np.clip(sigma * np.random.randn(B, N, C), -1*clip, clip)
    jittered_data += batch_data    # 添加噪声
    return jittered_data

4. 随机平移

# 作用: 对每个点云进行随机平移, 对点云中的每个点添加一个随机的移动距离
def shift_point_cloud(batch_data, shift_range=0.1):
    """ Randomly shift point cloud. Shift is per point cloud.
        Input:
          BxNx3 array, original batch of point clouds
        Return:
          BxNx3 array, shifted batch of point clouds
    """
    B, N, C = batch_data.shape
    shifts = np.random.uniform(-shift_range, shift_range, (B,3))    # 对每个batch的点云设置一个随机的移动偏差
    for batch_index in range(B):
        batch_data[batch_index,:,:] += shifts[batch_index,:]    # 每个点都进行移动
    return batch_data

5. 随机缩放

# 作用: 对每个点云进行随机缩放, 实现方法是乘积因子直接与点云数据相乘即可
def random_scale_point_cloud(batch_data, scale_low=0.8, scale_high=1.25):
    """ Randomly scale the point cloud. Scale is per point cloud.
        Input:
            BxNx3 array, original batch of point clouds
        Return:
            BxNx3 array, scaled batch of point clouds
    """
    B, N, C = batch_data.shape
    scales = np.random.uniform(scale_low, scale_high, B)    # 0.8~1.25间的随机缩放
    for batch_index in range(B):
        batch_data[batch_index,:,:] *= scales[batch_index]  # 每个点都进行缩放
    return batch_data

6. 随机丢弃

# 作用: 随机丢弃点云中的点, 操作是将丢弃点全部赋予first point的值, 也就是是一个伪丢弃(shape是没有改变的)
def random_point_dropout(batch_pc, max_dropout_ratio=0.875):
    ''' batch_pc: BxNx3 '''
    for b in range(batch_pc.shape[0]):
        dropout_ratio = np.random.random()*max_dropout_ratio  # 设置随机丢弃的概率,区间是0~0.875
        drop_idx = np.where(np.random.random((batch_pc.shape[1])) <= dropout_ratio)[0]  # 找到那些比概率低的索引值来丢弃
        if len(drop_idx) > 0:
            batch_pc[b,drop_idx,:] = batch_pc[b,0,:]   # 这里所谓的丢弃就是将值设置与第一个点相同
    return batch_pc

ps:在PointNet++分组采样k个邻域点时,如果符合距离的点不足k个,也是使用第一个点来对其他不满足距离的点进行替换,达到了一种单点重复多次的效果。和这里的随机丢弃使用的一样的方法。


参考资料:

https://github.com/yanx27/Pointnet_Pointnet2_pytorch

猜你喜欢

转载自blog.csdn.net/weixin_44751294/article/details/128483380