首先说明的是,零件分割(part segmentation)和第一个分类(classification)完全不是同一层次的应用,
虽然点云的分割实际上也是对每个点进行分类,但其难度要高于对整个点云物体的分类。
以下先提供Part Segmentation所需要的数据集
shapenetcore_partanno_v0.zip
HDF5_data
ShapeNetPart数据集解压后格式为pointnet-master/part_seg/PartAnnotation。
HDF5文件解压放在pointnet-master/part_seg/hdf5_data。
一、分割实现原理
首先介绍零件分割的神经网络构建,先贴流程图
分割网络前半部分和分类网络一样,都是利用两次T-Net网络生成的特征变换矩阵第一次对输入点云数据进行矩阵相乘,使得点云数据对旋转不敏感,使其满足旋转不变性。第二次对特征进行旋转,得到另一组高维特征。我认为的加上T-net网络实际上是增加了点云特征,为后面的concat等操作提供了更多的学习特征。
其中代码中最重要的,也是分割中最核心的代码就是将局部特征与全局特征进行拼接。正如原作者所说的,是将每个
点的特征与全局特征拼接,相当于单个点在全局特征中进行了一次检索,检索到在哪个位置就是哪个类别,对连接起
来的特征进行MLP的变换,最后输出m类相当于m个score:(将单个点和总体的特征连接到一起,判定在总体中的位
置,来决定是哪个分类)
关键代码如下:
out_max = tf_util.max_pool2d(out5, [num_point,1], padding='VALID', scope='maxpool')
expand = tf.tile(out_max, [1, num_point, 1, 1])#复制2048次
concat = tf.concat(axis=3, values=[expand, out1, out2, out3, out4, out5])
out_max是经过maxpooling后得到的全局特征 ,维度(32,1,1,3)
tf.tile(),将第二维复制2048次,得到相当于2048个全局特征集合,维度(32,2048,1,3)
concat()将先前的得到out1~5的每个点的局部特征分别与全局特征进行串联拼接。
维度(32,2048,1,(3 + out1~5的通道数))
经过以上操作,就完成了全局特征和每个点的局部特征的拼接,后进行全连接层,对每个点进行分
类,返回(32,2048,50),2048个点,每个点对应50类的分数,取分数最高的为点的类别。
二、数据集处理
相对于神经网络的设计,我认为这部分是相对简单的,对数据进行预处理以及理解才是核心部分。
我一度看不懂数据集中的编号是什么意思,直到将代码看了两遍,才逐渐理解
以下为hdf5_data中作者已制作好的数据集以及编号文本,
如果要自己制作数据集,又需要费一番功夫了
-
all_object_categories.txt
shapenet数据集总共提供了16种物体,并分别给定对应编号,这个编号是自己设定的,并无特殊含义。
利用split()[0]、split()[1]将以上数据分别划分为
编号列表objcats :[02691156,02773838,…]
objnames类名列表: [Airplane,Bag,…] -
catid_partid_to_overallid.json (物品的零件编号分类)
将16个物体的零件类别分为50类,用1~50分别对应。例如03642806_2和03642806_1说明这个编号的物体的零件分为2类,并分别对应29,28编号。神经网络最后对每个点的分类,也就是判断每个点对应每个物体零件的分类,再分配color。 -
color_partid_catid_map.txt
物体零件对应的颜色,共有50类,该文本起解释说明作用,在代码中没用上,也或许是在制作数据集的时候用于生成part_color_mapping.json文件 -
part_color_mapping.json
这个文件中颜色的顺序,依次对应上一文件中的顺序,用于对每一个点分类后进行对应类的颜色选取。 -
overallid_to_catid_partid.json
每一个物体对应零件编号的列表
用于生成object2setofoid() 字典形式{‘03691156‘ : [0,1,2]…}
三、成果展示
预测结果
将分割信息写入log日志:
Total Point :point_num(该实例点云数量)
Ground Truth :objnames[cur_gt_label] (实例类别)
Predict :objnames[label_pred_val] (预测类别)
Accuracy :seg_acc = np.mean(seg_pred_val == seg) (分割正确点数占总点云数的百分比,正确率)
IoU :avg_iou (每个零件算IOU相加,求平均IOU) avg_iou = total_iou / len(iou_oids)
IoU details :’’ + n_pred + '’ + n_gt + ‘’ + n_intersect + '’ + n_union + ‘’’’ + (n_intersect / n_union) +\n
2874个实例的总的 Accuary = total_acc / total_seen 总的正确点云数 / 总的点云数量
IoU = (total_acc_iou += avg_iou) / total_seen