一、點雲數據
點雲數據是由大量的離散點組成的三維空間中的數據形式,例如激光雷達掃描的地形、建築物或者是攝像機捕捉的物體等三維場景都可以轉換為點雲數據。點雲數據的稀疏性、不規則性、本質上是無序的,這樣的特點造成傳統的圖像處理和計算機視覺演算法難以直接運用於點雲數據的處理分析。
二、PointNet網路結構
為了克服點雲數據的這些缺陷,作者設計了一種新型的網路結構——PointNet。PointNet網路結構可以接收任意數量的點雲數據,輸出對象的分類或者對點雲進行分割等處理。PointNet主要分為三個模塊,分別為輸入層、特徵提取層以及輸出層。
輸入層:PointNet網路的輸入層直接接收點雲數據,不需要將點雲數據轉換成體素或者多視角圖像這樣的預處理形式。輸入層將點雲數據映射到高維空間,並且為每個點生成唯一的坐標,同時把每個點看成了輸入向量。
特徵提取層:輸入層映射到高維空間後,PointNet網路首先通過一系列變換網路,對每個點進行空間上的局部特徵提取,然後通過最大池化的方式將局部特徵壓縮成全局特徵。通過這樣的處理方式,PointNet可以識別不同姿態、物體大小的點雲數據,並能夠對旋轉、平移、縮放不變。
輸出層:輸出層採用多層感知器(Multi-Layer Perceptron, MLP)來對全局特徵進行分類或分割。也就是說,PointNet不僅可以進行對象的分類,還可以實現點雲的分割,可以識別不同部位相互作用的目標。
三、代碼示例
def input_transform_net(point_cloud, is_training, reuse=None): with tf.variable_scope('input_transform_net', reuse=reuse): input_image = tf.expand_dims(point_cloud, -1) net = tf_util.conv2d(input_image, 64, [1, 3], padding='VALID', stride=[1, 1], bn=True, is_training=is_training, scope='conv1', bn_decay=bn_decay) net = tf_util.conv2d(net, 128, [1, 1], padding='VALID', stride=[1, 1], bn=True, is_training=is_training, scope='conv2', bn_decay=bn_decay) net = tf_util.conv2d(net, 1024, [1, 1], padding='VALID', stride=[1, 1], bn=True, is_training=is_training, scope='conv3', bn_decay=bn_decay) net = tf_util.max_pool2d(net, [num_point, 1], padding='VALID', scope='maxpool') net = tf.reshape(net, [batch_size, -1]) net = tf_util.fully_connected(net, 512, bn=True, is_training=is_training, scope='fc1', bn_decay=bn_decay) net = tf_util.fully_connected(net, 256, bn=True, is_training=is_training, scope='fc2', bn_decay=bn_decay) with tf.variable_scope('transform_XYZ'): assert xyz_shape[1:] == [num_points, 3] input_transform = tf_util.fully_connected(net, 3 * 3, weights_regularizer=tf.compat.v1.layers.l2_regularizer(0.0), activation_fn=None, scope='fc3') # 上述第2維應該是3*num_points而不是3,參見這個Tensorflow issue:https://github.com/tensorflow/tensorflow/issues/17947 input_transform = tf.reshape(input_transform, [batch_size, 3, 3]) # 把三個維度的下標混淆為[1, 0, 2],作用參見paper Figure 2右下方。 with tf.variable_scope('transform_XYZ'): spatial_transformed_input = tf.matmul(xyz, tf.transpose(input_transform, [0, 2, 1])) # 下面輸出的兩個變數可以作為中間結果查看。 # return spatial_transformed_input, input_transform return spatial_transformed_input def feature_transform_net(inputs, is_training, reuse=None): with tf.variable_scope('feature_transform_net', reuse=reuse): # 上述point_cloud_shape的形狀為[batch_size, num_points, 3] # 計算出PointNet的local feature的channels數目 # 看這個issue:https://github.com/charlesq34/pointnet/issues/19 batch_size, num_points, num_dims = inputs.get_shape().as_list() net = tf.expand_dims(inputs, 2) net = tf_util.conv2d(net, 64, [1, 1], padding='VALID', stride=[1, 1], bn=True, is_training=is_training, scope='conv1', bn_decay=bn_decay) net = tf_util.conv2d(net, 128, [1, 1], padding='VALID', stride=[1, 1], bn=True, is_training=is_training, scope='conv2', bn_decay=bn_decay) net = tf_util.conv2d(net, 1024, [1, 1], padding='VALID', stride=[1, 1], bn=True, is_training=is_training, scope='conv3', bn_decay=bn_decay) net = tf_util.max_pool2d(net, [num_point, 1], padding='VALID', scope='maxpool') net = tf.reshape(net, [batch_size, -1]) net = tf_util.fully_connected(net, 512, bn=True, is_training=is_training, scope='fc1', bn_decay=bn_decay) net = tf_util.fully_connected(net, 256, bn=True, is_training=is_training, scope='fc2', bn_decay=bn_decay) with tf.variable_scope('transform_feat'): # debug時,把這個命名空間改為'transform_XYZ',主要是為了便於trace。 net = tf_util.fully_connected(net, num_dims * num_dims, weights_regularizer=tf.compat.v1.layers.l2_regularizer(0.0), activation_fn=None, scope='fc3') # 把一維的向量轉換為num_dims*num_dims矩陣,(想像一個特徵是num_dims維,現在16個特徵,那麼就是一個16x16的矩陣) # 維度是(batch_size, num_dims*num_dims) net = tf.reshape(net, [batch_size, num_dims, num_dims]) return net
四、PointNet的應用領域
PointNet網路不僅在目標檢測、語義分割以及網格分割等傳統計算領域有著重要的應用,還在自動駕駛、無人飛行器和虛擬現實等領域有著廣泛的應用前景。例如在自動駕駛中,PointNet網路可以通過點雲數據對車道標線、行人、車輛等進行檢測,並進行追蹤。同樣,在無人飛行器的管理與控制中,使用PointNet網路可以對三維環境以及物體進行實時的檢測和跟蹤。
原創文章,作者:AADKE,如若轉載,請註明出處:https://www.506064.com/zh-tw/n/351552.html