Pointnet/Pointnet++点云数据集处理并训练

一、三维数据的表示方法
三维数据的表述形式一般分为四种:

① 点云:由N 个D 维的点组成,当这个D = 3 的时候一般代表着( x , y , z ) 的坐标,当然也可以包括一些法向量、强度等别的特征。这是今天主要讲述的数据类型。

在这里插入图片描述
② Mesh:由三角面片和正方形面片组成。
在这里插入图片描述
③ 体素:由三维栅格将物体用0和1表征。
在这里插入图片描述
④ 多角度的RGB图像或者RGB-D图像
在这里插入图片描述
而又由于点云更接近于设备的原始表征(即雷达扫描物体直接产生点云)同时它的表达方式更加简单,一个物体仅用一个N × D 的矩阵表示,所以点云成为了众多三维数据表示方法中最重要的一种。在测绘、建筑、电力、工业甚至如今最热门的自动驾驶等领域均有广泛的应用。

二、点云分割数据集处理

我们的点云数据可能与模型需要的数据不符,所以需要自己编写脚本进行数据的规范化。标准的点云数据处理的格式如下:
在这里插入图片描述
其只包含了点云的(x,y,z)坐标以及每个点对应的标签。而可能我们从CloudCompare中导出的数据有四列数据还有一列点云的强度信息:

在这里插入图片描述
所以编写如下的脚本对多余的第四列数据进行去除(文件的具体路径自己设置):

# -*- coding:utf-8 -*-
import os
filePath = 'D:\\点云数据处理小组\\pointnet-my\\data\\shapenetcore_partanno_segmentation_benchmark_v0_normal\\03797390'
for i,j,k in os.walk(filePath):
    for name in  k:
        print(name)
        f = open(filePath+name)  # 打开txt文件
        line = f.readline()  # 以行的形式进行读取文件
        list1 = []
        while line:
            a = line.split()
            b = a[0:3]
            c = float(a[-1])
            print(c)
            if(float(a[-1])==36.0):
                c=2
            if(float(a[-1])==37.0):
                c=3
            b.append(c)
            list1.append(b)  # 将其添加在列表之中
            line = f.readline()
        f.close()
        print(list1)
        with open(filePath+name, 'w+') as file:
            for i in list1:
                file.write(str(i[0]))
                file.write(' '+str(i[1]))
                file.write(' ' + str(i[2]))
                file.write(' ' + str(i[3]))
                if(i!=list[-1]):
                    file.write('\n')
        file.close()
# path_out = 'test.txt'   # 新的txt文件
# with open(path_out, 'w+') as f_out:
#     for i in list1:
#         fir = '9443_' + i[0]       # 第一列加前缀'9443_'
#         sec = 9443 + int(i[1])     # 第二列数值都加9443
#         # print(fir)
#         # print(str(sec))
#         f_out.write(fir + ' ' + str(sec) + '\n')    # 把前两列写入新的txt文件

接着我们需要对划分训练集、测试集、验证集的json文件进行处理,由于我们采用的是自己的数据集,每一个txt的文件名与之前官方数据集中的文件名一定不一样,所以需要编写脚本对控制训练集、测试集、验证集读入的三个json文件进行修改。具体代码如下(路径名同样需要修改为自己的路径名):

import os
filePath = 'D:\\点云数据处理小组\\pointnet-my\\data\\shapenetcore_partanno_segmentation_benchmark_v0_normal\\03797390'
#####最后一行会出现一个, 报错!!!!!!!!!
######手动删除或改进程序
#####
file = '1.txt'
with open(file,'a') as f:
    f.write("[")
    for i,j,k in os.walk(filePath):
         for name in k:
              base_name=os.path.splitext(name)[0]  #去掉后缀 .txt
              f.write(" \"")
              f.write(os.path.join("shape_data/03797390/",base_name))
              f.write("\"")
              f.write(",")
    f.write("]")
f.close()

最后在实际程序运行时发现会由于含0的数据过多而导致模型分类不准确,如下:
在这里插入图片描述
而根据具体项目的实际物理意义(这里的全0即表示未被激光探测到的位置,x,y,z坐标均标注为0),所以编写脚本程序对全0的部分进行去除:

# -*- coding:utf-8 -*-
import os
filePath = 'D:\\点云数据处理小组\\pointnet-my\\data\\shapenetcore_partanno_segmentation_benchmark_v0_normal\\03797390'
for i,j,k in os.walk(filePath):
    for name in  k:
        list1 = []
        for line in open(filePath+name):
            a = line.split()
            #print(a)
            b = a[0:6]
            #print(b)
            a1 =float(a[0])
            a2 =float(a[1])
            a3 =float(a[2])
            #print(a1)
            if(a1==0 and a2==0 and a3==0):
                continue
            list1.append(b[0:6])
        with open(filePath+name, 'w+') as file:
            for i in list1:
                file.write(str(i[0]))
                file.write(' '+str(i[1]))
                file.write(' ' + str(i[2]))
                file.write(' ' + str(i[3]))
                file.write(' ' + str(i[4]))
                if(i!=list[-1]):
                    file.write('\n')
        file.close()

三、 模型训练
我们打开项目文件夹下的model文件夹,选择以pointnet2_part_seg_msg为名的python文件,双击进入:
在这里插入图片描述
接下来我们需要修改的地方为PointNetFeaturePropagation的in_channel,具体方法为128+4分割的总类个数,比如这里我们的分割采用的是两个物体,每个物体均为2分类,所以通道数为128+42=136:

在这里插入图片描述
接着我们需要修改独热编码部分,将view方法中的第二个参数修改为需要被分割的物体的种类数:
在这里插入图片描述
2.2.5 训练模型部分的修改
在训练模型的时候,我们需要修改要分类的对象seg_classes为我们自己的数据集对应的类别,如例子中的分类两个类别,每个类别有两个部件。(为了方便,我们保留了原来的’Airplane’: [0, 1], ‘Mug’: [2, 3]这两个名字,同时应该注意,编号应该从0开始依次编号,若不是这样则会报错),同时应该注意自己的电脑是否支持cuda加速,如果没有GPU,则可以把代码后面所有的".cuda()"删去,程序才能正确运行。
在这里插入图片描述
接下来我们需要修改分割的物体总数num_classes为自己的类别个数,总共的部件数为自己的总个数:num_part。
在这里插入图片描述
最后,右键运行程序,如果出现进度条则表明模型已经成功改进,可以跑通自己的数据集啦!
在这里插入图片描述
四、打印模型预测数据
我们在用自己的数据集训练完模型后,将利用名为test_partseg的python文件进行模型的测试,为了更好的理解模型以及测试模型效果,我们有时需要打印出模型预测后的点云坐标。这里给出test_partseg文件的修改方法以及运行结果。

4.1 测试模型代码修改
首先我们需要找到该python文件,接着与上面同样的修改如下图的两个地方:
在这里插入图片描述
在这里插入图片描述

接着我们需要编写代码打印出分类后的具有不同标签的坐标,本例子中要打印两个物体的四个类别的坐标点,代码如下(部分代码):

                for j in aaa:
                    #print(points1[i,j])
 
                    res1= open(r'E:\03797390_0_'+str(i)+'.txt', 'a')
                    res1.write('\n' + str(points1[i,j]).strip('[]'))
                    res1.close()
                    xxxxxx=xxxxxx+1
 
                bbb = numpy.argwhere(cur_pred_val[i] == 1)
                for j in bbb:
                    #print(points1[i, j])
 
                    res2 = open(r'E:\03797390_1_' + str(i) + '.txt', 'a')
                    res2.write('\n' + str(points1[i,j]).strip('[]'))
                    res2.close()
                    xxxxxx = xxxxxx + 1
 
                ccc = numpy.argwhere(cur_pred_val[i] == 2)
                for j in ccc:
                    #print(points1[i, j])
 
                    res3 = open(r'E:\02691156_2_' + str(i) + '.txt', 'a')
                    res3.write('\n' + str(points1[i,j]).strip('[]'))
                    res3.close()
                    xxxxxx = xxxxxx + 1
 
                ddd = numpy.argwhere(cur_pred_val[i] == 3)
                for j in ddd:
                    #print(points1[i, j])
 
                    res4 = open(r'E:\02691156_3_' + str(i) + '.txt', 'a')
                    res4.write('\n' + str(points1[i,j]).strip('[]'))
                    res4.close()
                    xxxxxx = xxxxxx + 1

修改完成后运行程序发现可以显示结果,表明修改成功!
在这里插入图片描述
打印出的点云坐标格式如下:
在这里插入图片描述

在这里插入图片描述
参考文献:https://blog.csdn.net/weixin_44603934/article/details/123589948

猜你喜欢

转载自blog.csdn.net/qq_27353621/article/details/125594871