厦门响应式网站建设,百度不收录新网站,做电影网站能赚钱吗,网页制作网站的大作业前面我们已经学习了Open3D#xff0c;并掌握了其相关应用#xff0c;但我们也发现对于一些点云分割任务#xff0c;我们采用聚类等方法的效果似乎并不理想#xff0c;这时#xff0c;我们可以想到在深度学习领域是否有相关的算法呢#xff0c;今天#xff0c;我们便来学…前面我们已经学习了Open3D并掌握了其相关应用但我们也发现对于一些点云分割任务我们采用聚类等方法的效果似乎并不理想这时我们可以想到在深度学习领域是否有相关的算法呢今天我们便来学习一个在点云处理领域具有代表性的算法PointNet。
PointNet
在学习PointNet前我们需要学习以下它的前身PointNet。 我们知道点云数据具有以下特点
无序性点云的位置可以随意调换没有影响点与点之间可以换近密远疏扫描视角不同导致点云的稀疏性不同非结构化数据处理困难如NLP的处理就要比图像复杂 那么针对这种问题该如何解决呢其实最主要的是我们要去提取特征。
思路对于无序性的数据我们要考虑能否利用置换不变性来解决问题PointNet便是采用这个思路即对于点云数据求最值无论是max、min还是sum它都与点的位置没有关系。 同时由于点云一般只有三维xyz)其维度太少因此可以利用神经网络多层感知机、全连接网络等来升维进而再进行处理。 下图为PointNet网络结构其中里面的input_transform我们无需太过在意可以看到其输入的是所有点云随后进行维度变换最终输出分类或分割结果。 PointNet网络介绍
根据其论文中给出的介绍Point是用于点云分割与分类的深度学习模型由下图可知该模型主要分为三部分分别是点空间特征提取、分割模型以及分类模块。其中Hierarchical Point set feature learning 由一系列点集抽象层set abstraction组成而每一个set abstraction 又由三个关键层组成sampling layerGrouping layerPointNet Layer。 Sampling layerSampling layer的作用是从点云中选择很多个质点和围绕在这些质点的局部区域。作为输入通过使用FPS算法farthest point sampling最远点采样法选出一系列点作为质点与随机选取相比这样可以更好的覆盖整个点集空间。Grouping layer这一层使用Ball query方法生成N’个局部区域根据论文中的意思这里有两个变量 一个是每个区域中点的数量K另一个是球的半径。这里半径应该是占主导的会在某个半径的球内找点上限是K。球的半径和每个区域中点的数量都是人指定的。这一步也可以使用KNN来进行而且两者的对于结果的影响并不大。PointNet layer输入为N’xKx(dC)输出为N’x(dC’)这里C’为局部特征的长度应该是大于C的。这一步主要是将K个局部区域内的点的坐标转换为相对该区域中心点的坐标并作为PointNet的输入得到局部特征。
事实上PointNet相较于PointNet的创新便是在于数据的处理其采用了分簇、分组的方式进行处理这可以大幅减少计算量PointNet是将所有点云输入PointNet网络PointNet是将数据分簇分组后输入PointNet网络
分簇与分组
在这里分簇是为了采样即Sampling layer而分组则是将每个簇的数据量统一这样才能够输入卷积网络中运算具体的对于分组Grouping layer时如果簇中数量多那么就按照距离中心点距离进行排序挑选近的留下即删除远的点对于簇中数量少则将复制该簇内里离中心点最近的点缺几个则复制几次
PointNet项目部署
源码下载
了解了PointNet的基本原理后接下来我们便要部署该项目来完成我们的任务这里应领导要求博主并没有使用PointNet的官方代码官方代码是基于Tensflow框架开发的而是使用了Pytorch的版本。
源码下载地址
环境部署
将源码下载后便是部署环境PointNet所使用的包并不多且比较通用博主直接使用了先前的conda环境发现可以完美运行也就没有重新创建conda环境。
S3Dis数据集介绍
在本次实验中由于我们要做的任务是点云分割任务因此我们使用的数据集为S3Dis该数据集是一个室内点云分割数据集 共有6个区域13个类别共计217个小区域办公室、会议室等其内容如下 13个类别 6个大区域 我们以Area_1区域1为例其内有会议室、走廊等多个场所 再以office_9为例office_9.txt是整个办公室点云Annotations内的是office_9的分割点云如里面的桌子椅子等 我们使用CloudCompare打开可以看到其内容数据格式为xyzrgb格式 数据格式转换
为何要进行数据格式转换呢因为S3DIS数据集只是存储一些点并没有标签标签是存储在文件名上的而collect_indoor3d_data脚本所做的事情就是将每一个Area下的每一个场景的点和标签进行合并并且保存为.npy格式加速读取的速度。 生成的.npy格式的数据也有217个。 .npy文件的内容如下其实就是转成numpy的格式从而方便运算其相比于原本的txt多了一个维度即第7个维度用于表示所属类别。
import numpy as np
datanp.load(stanford_indoor3d/Area_1_WC_1.npy)
print(data)collect_indoor3d_data代码如下该部分主要是完成读取点云数据并设置点云数据的保存路径名称等
import os
import sys
from indoor3d_util import DATA_PATH, collect_point_labelBASE_DIR os.path.dirname(os.path.abspath(__file__))
ROOT_DIR os.path.dirname(BASE_DIR)
sys.path.append(BASE_DIR)anno_paths [line.rstrip() for line in open(os.path.join(BASE_DIR, meta/anno_paths.txt))]
anno_paths [os.path.join(DATA_PATH, p) for p in anno_paths]output_folder os.path.join(ROOT_DIR, data/stanford_indoor3d/)
if not os.path.exists(output_folder):os.mkdir(output_folder)# Note: there is an extra character in the v1.2 data in Area_5/hallway_6. Its fixed manually.
for anno_path in anno_paths:print(anno_path)try:elements anno_path.split(/)out_filename elements[-3]_elements[-2].npy # Area_1_hallway_1.npycollect_point_label(anno_path, os.path.join(output_folder, out_filename), numpy)except:print(anno_path, ERROR!!)具体的划分点云中的标签是通过collect_point_label方法实现的事实上我们并不需要读懂这部分代码要想完成数据转换只需要将我们的数据格式转换成与S3Dis数据集一样即可。
def collect_point_label(anno_path, out_filename, file_formattxt): Convert original dataset files to data_label file (each line is XYZRGBL).We aggregated all the points from each instance in the room.Args:anno_path: path to annotations. e.g. Area_1/office_2/Annotations/out_filename: path to save collected points and labels (each line is XYZRGBL)file_format: txt or numpy, determines what file format to save.Returns:NoneNote:the points are shifted before save, the most negative point is now at origin.points_list []for f in glob.glob(os.path.join(anno_path, *.txt)):cls os.path.basename(f).split(_)[0]print(f)if cls not in g_classes: # note: in some room there is staris class..cls clutterpoints np.loadtxt(f)labels np.ones((points.shape[0],1)) * g_class2label[cls]points_list.append(np.concatenate([points, labels], 1)) # Nx7data_label np.concatenate(points_list, 0)xyz_min np.amin(data_label, axis0)[0:3]data_label[:, 0:3] - xyz_minif file_formattxt:fout open(out_filename, w)for i in range(data_label.shape[0]):fout.write(%f %f %f %d %d %d %d\n % \(data_label[i,0], data_label[i,1], data_label[i,2],data_label[i,3], data_label[i,4], data_label[i,5],data_label[i,6]))fout.close()elif file_formatnumpy:np.save(out_filename, data_label)else:print(ERROR!! Unknown file format: %s, please use txt or numpy. % \(file_format))exit()训练PointNet网络
首先是模型选择我们这里可以看到model中可供我们选择的模型其中加了msg的代表使用了多尺度特征其效果要比不加的好当然其网络也会更复杂一些我们使用的是pointnet2_sem_seg_msg
parser.add_argument(--model, typestr, defaultpointnet2_sem_seg_msg, helpmodel name [default: pointnet_sem_seg])选择使用的测试集这里默认为Area_5
parser.add_argument(--test_area, typeint, default5, helpWhich area to use for test, option: 1-6 [default: 5])随后一些batch-size设置epoch设置我们就不再赘述了博主设置batch16同时需要注意的是需要修改以下num_workers的值博主设置为0这个看你服务器的性能博主由于是在本地测试因此也就设为0了否则会报错
UnpicklingError: pickle data was truncated开启训练
加载数据集训练集与验证集 开启训练输出最终的训练平均损失以及训练平均准确度 测试模型
在测试模型时我们指定加载的模型权重即可即我们在训练时保存的log文件的地址
parser.add_argument(--log_dir, typestr,defaultpointnet2_sem_seg_msg, helpexperiment root)可以看到测试数据集为Area_5 训练时的模型显卡使用情况如下 最终的评估结果如下 结语
本章主要介绍了PointNet模型的结构以及部署问题接下来便要进行模型的应用我们需要使用自己的数据集来完成相应的任务。