如有錯(cuò)誤,懇請指出。
下面是pointnet++項(xiàng)目實(shí)現(xiàn)的點(diǎn)云數(shù)據(jù)增強(qiáng)方法,主要包括隨機(jī)旋轉(zhuǎn)、隨機(jī)縮放、隨機(jī)丟棄、隨機(jī)平移、隨機(jī)擾動(dòng)等等。
github項(xiàng)目鏈接:https://github.com/yanx27/Pointnet_Pointnet2_pytorch
1. 隨機(jī)順序
# 作用: 隨機(jī)打亂Batch中點(diǎn)云及其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
# 作用: 隨機(jī)打亂一個(gè)點(diǎn)云中點(diǎn)的順序
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]) # 根據(jù)索引隨機(jī)點(diǎn)順序
np.random.shuffle(idx)
return batch_data[:,idx,:]
2. 隨機(jī)旋轉(zhuǎn)
這里貼上的是沿3個(gè)軸隨機(jī)旋轉(zhuǎn)
# 作用: 對每個(gè)點(diǎn)云與法向量均進(jìn)行沿xyz三個(gè)軸隨機(jī)(小幅度)旋轉(zhuǎn)
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: 權(quán)重系數(shù), 控制隨機(jī)角度的大小
angle_clip: 確定隨機(jī)角度的上下限(-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三個(gè)軸方向隨機(jī)生成一個(gè)旋轉(zhuǎn)角度
angles = np.clip(angle_sigma*np.random.randn(3), -angle_clip, angle_clip)
# 根據(jù)公式構(gòu)建三個(gè)軸方向的旋轉(zhuǎn)矩陣
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]])
# 按照內(nèi)旋方式:Z-Y-X旋轉(zhuǎn)順序獲得整體的旋轉(zhuǎn)矩陣
R = np.dot(Rz, np.dot(Ry,Rx))
shape_pc = batch_data[k,:,0:3]
shape_normal = batch_data[k,:,3:6]
# 分別對坐標(biāo)與法向量進(jìn)行旋轉(zhuǎn),整體公式應(yīng)該為: 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. 隨機(jī)噪聲
# 作用: 對點(diǎn)云數(shù)據(jù)添加噪聲, 進(jìn)行小范圍擾動(dòng)
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: 權(quán)重系數(shù), 控制隨機(jī)噪聲幅度
angle_clip: 確定隨機(jī)噪聲的上下限(-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. 隨機(jī)平移
# 作用: 對每個(gè)點(diǎn)云進(jìn)行隨機(jī)平移, 對點(diǎn)云中的每個(gè)點(diǎn)添加一個(gè)隨機(jī)的移動(dòng)距離
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)) # 對每個(gè)batch的點(diǎn)云設(shè)置一個(gè)隨機(jī)的移動(dòng)偏差
for batch_index in range(B):
batch_data[batch_index,:,:] += shifts[batch_index,:] # 每個(gè)點(diǎn)都進(jìn)行移動(dòng)
return batch_data
5. 隨機(jī)縮放
# 作用: 對每個(gè)點(diǎn)云進(jìn)行隨機(jī)縮放, 實(shí)現(xiàn)方法是乘積因子直接與點(diǎn)云數(shù)據(jù)相乘即可
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間的隨機(jī)縮放
for batch_index in range(B):
batch_data[batch_index,:,:] *= scales[batch_index] # 每個(gè)點(diǎn)都進(jìn)行縮放
return batch_data
6. 隨機(jī)丟棄
# 作用: 隨機(jī)丟棄點(diǎn)云中的點(diǎn), 操作是將丟棄點(diǎn)全部賦予first point的值, 也就是是一個(gè)偽丟棄(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 # 設(shè)置隨機(jī)丟棄的概率,區(qū)間是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,:] # 這里所謂的丟棄就是將值設(shè)置與第一個(gè)點(diǎn)相同
return batch_pc
ps:在PointNet++分組采樣k個(gè)鄰域點(diǎn)時(shí),如果符合距離的點(diǎn)不足k個(gè),也是使用第一個(gè)點(diǎn)來對其他不滿足距離的點(diǎn)進(jìn)行替換,達(dá)到了一種單點(diǎn)重復(fù)多次的效果。和這里的隨機(jī)丟棄使用的一樣的方法。
參考資料:文章來源:http://www.zghlxwxcb.cn/news/detail-765902.html
https://github.com/yanx27/Pointnet_Pointnet2_pytorch文章來源地址http://www.zghlxwxcb.cn/news/detail-765902.html
到了這里,關(guān)于PointNet++詳解(一):數(shù)據(jù)增強(qiáng)方法的文章就介紹完了。如果您還想了解更多內(nèi)容,請?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!