超详细分析S3DIS数据集的构建

这篇具有很好参考价值的文章主要介绍了超详细分析S3DIS数据集的构建。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

         本博文先介绍S3DIS的基本情况和路径结构,从而对该数据集有一个整体的了解,然后会在第三节中了解一下pointnet++中如何对该数据集转换,以及转换的原因,同时在第三节中会介绍pointnet++中如何构建语义分割数据集,最后会接受如何对S3DIS数据集进行预测。

1.S3DIS数据集简介

        S3DIS是室内的大型数据集,共有6个区域,13个类别,第一反应是只有6个区域吗,这么少,训练2D目标检测的数据随随便便就上千了。虽说只有6个区域,但是每个区域划分了很多的场景呀,这6个区域一共拆分了271个数据,每个数据都有上百万个点,而最终送进去网络中训练的也不是这271个数据,而是从这217个区域中划分的更小的区域,只要你想,训练集的数据能多大就有多大(图片参考自链接)。

        先区分一下Arearoom的概念,Area就是指这6个区域,room是指6个区域划分出来的271个房间,这些房间可能是办公室,会议室,走廊等。

        然后S3DIS这个数据集是包含RGB颜色信息的,加上XYZ坐标信息,一共就6维。

        数据集的结构在将下一节进行介绍。

    s3dis,点云深度学习,深度学习,3d,pytorch,numpy

2.数据路径结构

        以PointNet++中的S3DIS为例,s3dis/Stanford3dDataset_v1.2_Aligned_Version路径下有6个区域,如下所示:

s3dis,点云深度学习,深度学习,3d,pytorch,numpy

         每一个Area下面是一些区域,比如Area_1下有两个会议室(ConferenceRoom),八个走廊(hallway),若干个办公室(office)等。

s3dis,点云深度学习,深度学习,3d,pytorch,numpy

        将会议室1展开,发现有一个Annotations文件夹,一个conferenceRoom_1.txt文件,其中Annotations里保存的是会议室1中所有物品的xyzrgb坐标,均为n行6列的数据,而文件名则表示该物品的标签。比如chair_1.txt中共6729行6列,表示该物品由6729个点组成,且包含xyzrgb六个参数,标签为chair,可视化结果如下所示。 

s3dis,点云深度学习,深度学习,3d,pytorch,numpy

        下图为Annotations展开后的路径结构。

s3dis,点云深度学习,深度学习,3d,pytorch,numpy

        下图为chair_1.txt里的内容以及使用CloudCompare可视化的结果

s3dis,点云深度学习,深度学习,3d,pytorch,numpy

s3dis,点云深度学习,深度学习,3d,pytorch,numpy

         而另外一个ConferenceRoom_1.txt保存的是这个会议室中所有的点,有1136677个点,可见一个会议室的房间的点都这么多,那么一个Area的点不得上千万呀,可视化如下所示,当然,放大去看也能找到刚刚可视化的那张椅子。

s3dis,点云深度学习,深度学习,3d,pytorch,numpy

s3dis,点云深度学习,深度学习,3d,pytorch,numpy

3.collect_indoor3d_data数据转换

        在pointnet++中,往往需要对原始的S3DIS进行转换,那么为什么需要转换?因为S3DIS数据集只是存储一些点,并没有标签(标签是存储在文件名上的),而collect_indoor3d_data脚本所做的事情就是将每一个Area下的每一个场景的点和标签进行合并,并且保存为.npy格式,加速读取的速度。转换后的数据集如下所示,也可以参考我的另一篇博文如何使用S3DIS训练pointent++语义分割模型,Win10系统下复现Pointnet++(pytorch)_吃鱼不卡次的博客-CSDN博客:

s3dis,点云深度学习,深度学习,3d,pytorch,numpy

        可以使用numpy.load()打开,查看其形状,可以看到一共有七列,最后一列表示的是类别,如下所示:

s3dis,点云深度学习,深度学习,3d,pytorch,numpy

4.构建数据集S3DISDataset

        训练的时候使用的S3DISDataset来构建数据集(如下所示),测试的时候使ScannetDatasetWholeScene来构造数据集,两者是有区别的,测试的会放在下一节来介绍。

from data_utils.S3DISDataLoader import S3DISDataset

    print("start loading training data ...")
    TRAIN_DATASET = S3DISDataset(split='train', data_root=root, num_point=NUM_POINT, test_area=args.test_area, block_size=1.0, sample_rate=1.0, transform=None)
    
    print("start loading test data ...")
    TEST_DATASET = S3DISDataset(split='test', data_root=root, num_point=NUM_POINT, test_area=args.test_area, block_size=1.0, sample_rate=1.0, transform=None)

        众所周知,dataset一定要包括三个函数,初始化函数__init_(),依次返回数据的函数__getitem__(),获取数据长度的函数__len__(),下面我以下面这4个.npy文件作为例子,分别来介绍一下这三个函数。

s3dis,点云深度学习,深度学习,3d,pytorch,numpy

4.1__init__()函数

        首先,先看一下函数的参数:

        split表示构建数据集的类型,有train和test两种,分别表示训练集和测试集;如果是测试集,那么会使用test_area参数,比如test_area=5这个参数将指定Area5作为测试集,第一节已经介绍过了,一共六个区域,每个区域的点的数量很庞大,选择其中一个区域作为测试集(验证集)也是合理的,而且也可以当成是5:1划分数据集了。

        data_root表示数据的路径,调用的就是第二节中转换而来得到的全是.npy文件的路径,即s3dis\Stanford3dDataset_v1.2_Aligned_Version。num_point表示经过预处理后输入网络的点的数量,比如默认设置为4096,则表示输入网络的点数为4096。sample_rate是用来控制用作训练数据的数量的。block_size为随机选择区域的宽高。

        一口气说完那么多,是否觉得很迷糊,没关系,后面都会详细去讲的。

        其次,看一下后面的代码:

        rooms比较简单,存储的是npy的文件名,该例子中为['Area_1_conferenceRoom_1.npy', 'Area_1_conferenceRoom_2.npy', 'Area_1_copyRoom_1.npy', 'Area_5_office_12.npy'];

        rooms_split为划分训练集和验证集,如果该数据集为训练集,将把包含Area_5的数据排除在外,则rooms_split=['Area_1_conferenceRoom_1.npy', 'Area_1_conferenceRoom_2.npy', 'Area_1_copyRoom_1.npy'];如果该数据集为测试集,则rooms_split=['Area_5_office_12.npy']。

def __init__(self, split='train', data_root='trainval_fullarea', num_point=4096, test_area=5, block_size=1.0, sample_rate=1.0, transform=None):
        super().__init__()
        self.num_point = num_point
        self.block_size = block_size
        self.transform = transform
        rooms = sorted(os.listdir(data_root))
        rooms = [room for room in rooms if 'Area_' in room]
        if split == 'train':
            rooms_split = [room for room in rooms if not 'Area_{}'.format(test_area) in room]
        else:
            rooms_split = [room for room in rooms if 'Area_{}'.format(test_area) in room]

        这几个参数主要是保存各项参数的,后面再说。

    self.room_points, self.room_labels = [], []
    self.room_coord_min, self.room_coord_max = [], []
    num_point_all = []
    labelweights = np.zeros(13)

        再次,这段代码是逐个读取rooms_split中的数据,通过points保存每个文件的xyzrgb共n行6列信息,labels保存对应点的标签信息(n行1列);通过np.histogram()来统计每个类别出现的次数,以rooms_split[0]为例子,返回的tmp为array([213074, 190384, 354422,  61528, 0, 0,  41345,  31049,77761, 0,  20437,  86833,  59784], dtype=int64),代表着rooms_split[0]的这个点云,统计的13个类别的数量,比如,第一个类别出现了213074个,这些所有值相加就是这个点云的点的数量,那么为什么要统计这个呢,是为了后面做损失的时候设置一个类别权重,遍历完所有数据之后labelweights += tmp 中的labelweights就会统计完所有数据的所有类别数量。

        coord_min, coord_max分别代表的是xyz中最小的点以及最大的点,举个例子,如下所示:points为一个3行3列的数组,np.amin()得到的值[1,2,-1]是每一列中的最小值,然后说一下对于axis参数的理解:axis=0是指第零个维度发生变化,即由3行3列变为1行3列,那么也就是说在每一列中找最小值。

s3dis,点云深度学习,深度学习,3d,pytorch,numpy

        self.room_points是一个列表,列表中存储的是每个点云的点,列表的大小即为点云的数量。self.room_labels也是一个列表,存储的是self.room_points中每个点云下的点的类别。同理,self.room_coord_minself.room_coord_max也是列表,存储的是每个点云的xyz的最小值以及最大值。num_point_all存储的是每个点云的数量。

        遍历完所有点云后可以看到,self.room_points(如下图所示)列表的长度为3,存储的是3个点云的xyzrgb信息,其中第3个点云的形状为(510949,6)表示的是该点云有510949个点,每个点有6个属性。self.room_labels每个元素的shape为(510949,1),self.room_coord_min和self.room_coord_max每个元素的shape为(1,3),num_point_all每个元素的shape为(1,)。

        s3dis,点云深度学习,深度学习,3d,pytorch,numpy

    for room_name in tqdm(rooms_split, total=len(rooms_split)):
            room_path = os.path.join(data_root, room_name)
            room_data = np.load(room_path)  # xyzrgbl, N*7
            points, labels = room_data[:, 0:6], room_data[:, 6]  # xyzrgb, N*6; l, N
            tmp, _ = np.histogram(labels, range(14))
            labelweights += tmp
            coord_min, coord_max = np.amin(points, axis=0)[:3], np.amax(points, axis=0)[:3]
            self.room_points.append(points), self.room_labels.append(labels)
            self.room_coord_min.append(coord_min), self.room_coord_max.append(coord_max)
            num_point_all.append(labels.size)

        接着,下面是对类别权重的处理,遍历完所有点云后,labelweights存储的是各个类别的点的数量,设置权重一般是把点数多的类别权重设置小一点,因为点数多说明这个类别相较于点数少的类别更容易学习,那么最简单的方法就是取点数的倒数,但是这个过于简单粗暴,那么我们看看pointnet++是如何设置类别权重的(这段我直接问ChatGPT了,解释得很清楚,也能理解):

        1.labelweights = labelweights.astype(np.float32):将 labelweights 数组的数据类型转换为 np.float32,以便后续的数值计算。

        2.labelweights = labelweights / np.sum(labelweights):将 labelweights 数组中的每个元素除以数组中所有元素的和,以获得每个类别的相对权重。这样做可以确保权重的总和为 1。

        3.np.power(np.amax(labelweights) / labelweights, 1 / 3.0):计算每个类别权重相对于最大权重的比例的三分之一次方。这个操作的目的是将较大的权重值进行缩放,以确保它们不会在损失计算中产生过大的影响。这有助于平衡损失在各个类别之间的影响。

        labelweights = labelweights.astype(np.float32)
        labelweights = labelweights / np.sum(labelweights)
        self.labelweights = np.power(np.amax(labelweights) / labelweights, 1 / 3.0)
        print(self.labelweights)

       最后,最重要的一个参数登场了,room_idxs,这段代码其实就是分配一下每一个点云要采多少个区域输入到网络里面去训练。

        sample_prob的值为array([0.35713406, 0.48232172, 0.16054422]),代表这每个点云中点的数量占总点数的比例,然后会按照这个比例来进行分配。

      num_iter其实就是粗略计算了一下总共要采多少个区域,np.sum(num_point_all) * sample_rate可以理解为点云下采样后还剩多少点,然后再除以num_point,意思是剩下的点可以被分成多少块区域,每个区域num_point个点,其实我觉得完全可以设定一个参数,就训练1000张图片好像也不是不行。

        room_idxs中保存的是每个点云要采样的次数,举个例子说明一下(如下所示):遍历完所有点云之后,共得到27个0,表示第一个点云我要随机裁剪27个区域,第二个点云要随机裁剪成37个区域,第三个点云同理,那么训练集一共有76个数据送去训练。那么27,37还有12是怎么得到的呢,是通过int(round(sample_prob[index] * num_iter))得到的,其实也就是按照点云的点数占总点数的比例来得到每个点云所要选择的区域的。

s3dis,点云深度学习,深度学习,3d,pytorch,numpy

        sample_prob = num_point_all / np.sum(num_point_all)
        num_iter = int(np.sum(num_point_all) * sample_rate / num_point)
        room_idxs = []
        for index in range(len(rooms_split)):
            room_idxs.extend([index] * int(round(sample_prob[index] * num_iter)))
        self.room_idxs = np.array(room_idxs)
        print("Totally {} samples in {} set.".format(len(self.room_idxs), split))

        Init()函数这部分的参数实在太多,简单举个例子见图知意吧,首先假设数据集就一共有3个点云,每个点云中的点分别有200、500和300,则一共有1000个点(num_point_all),输入网络的npoint为50,并且设置sample_rate,那么这三个点云我会生成1000*0.5/50=10个点数均为50的数据输入到网络中去训练。
        接下来要确定一下这三个点云各自贡献多少数据,如下图所示Area1分配了2个数据的名额,Area2是5个,Area3是3个,也就是按照比例分配,看图就明白了。

s3dis,点云深度学习,深度学习,3d,pytorch,numpy

4.2__getItem__()函数

        __getitem__()函数就是逐个读取__init__中构造的数据,这个函数只干一件事,就是生成可以直接喂到网络里的数据(current_points)和标签(current_labels)

        前面提到的在room1中要裁27个区域作为输入网络的数据,那么idx从0到26都将停留在room1中,按照以下的规则生成27组数据和标签。

while (True):
            center = points[np.random.choice(N_points)][:3]
            block_min = center - [self.block_size / 2.0, self.block_size / 2.0, 0]
            block_max = center + [self.block_size / 2.0, self.block_size / 2.0, 0]
            point_idxs = np.where((points[:, 0] >= block_min[0]) & (points[:, 0] <= 	block_max[0]) & (points[:, 1] >= block_min[1]) & (points[:, 1] <= block_max[1]))[0]
            if point_idxs.size > 1024:
                Break

        这段代码是为了随机找到一块宽高均为block_size大小的区域,并且要求该区域的点数要大于1024,否则就得重新选择新的区域。那么为什么要这样设置呢?是因为随机选取中心点的时候有可能找到角落上的点,第一会导致选取的这块区域不是block_size大小的正方形区域,第二是如果该区域的点太少了,即便后面可以重复取点到4096,但是网络获取到的有效点就少了,影响网络的训练。

        如下图可以比较清晰的看出来是如何根据中心点划分block的:(1)首先左图a是一个点云Room,右图b是点云Room的俯视图;(2)分别选取两个中心点AB,根据block_size在俯视图b中确定裁剪的区域,然后投影到点云Room中,如左图a所示;3)由右图b可知,裁剪的区域A所示为正常采点的情况,采集的点是左图a中立方体A里面包含的点;B是当中心点在边缘的时候,若左图a立方体B中包含的点少于1024,则需要重新选取中心点,直到满足大于1024个点的要求。

        s3dis,点云深度学习,深度学习,3d,pytorch,numpy

                        (a)Room                                                                       (b)Room俯视图

if point_idxs.size >= self.num_point:
            selected_point_idxs = np.random.choice(point_idxs, self.num_point, replace=False)
        else:
            selected_point_idxs = np.random.choice(point_idxs, self.num_point, replace=True)

        当确定好需要裁剪的区域时,则对区域内的点进行随机采样到num_point个点,即4096个点。

        最后是对这4096个点的xyz值进行归一化,去中心化操作,对rgb进行归一化操作,因此,数据的特征也从xyzrgb的三维变成了xc yc zc nx ny nz nr ng nb的九维了,其中xc yc zc指的是去中心化后的xyz坐标,nx ny nz指的是归一化后的xyz坐标 nr ng nb指的是归一化后的rgb坐标。

        selected_points = points[selected_point_idxs, :]  # num_point * 6
        current_points = np.zeros((self.num_point, 9))  # num_point * 9
        current_points[:, 6] = selected_points[:, 0] / self.room_coord_max[room_idx][0]
        current_points[:, 7] = selected_points[:, 1] / self.room_coord_max[room_idx][1]
        current_points[:, 8] = selected_points[:, 2] / self.room_coord_max[room_idx][2]
        selected_points[:, 0] = selected_points[:, 0] - center[0]
        selected_points[:, 1] = selected_points[:, 1] - center[1]
        selected_points[:, 3:6] /= 255.0
        current_points[:, 0:6] = selected_points
        current_labels = labels[selected_point_idxs]

        如下图所示,输入到网络中的数据就是9维的,最后一维是标签(我自己加上去的,可以不用管)。

s3dis,点云深度学习,深度学习,3d,pytorch,numpy

4.3__len__()函数 

        __len()__一般是指数据集有多少数据。

5.总结

        内容大概就这么多吧,其实了解了S3DIS的结构就行了,知道Area由room构成,然后在room中按照比例随机生成数据输入到网络中。然后具体每个room生成多少数据以及怎么生成数据,只要看懂4.2中的两张图就可以了。我个人认为,3D点云数据集必须要好好去了解数据集是怎么构成的,因为点云数据集真的太五花八门了,每个数据集的结构都不一样(3D目标检测KITTI这些好像更复杂),了解数据集是怎么构成后,去看dataset的代码就不会那么容易乱了。

        关于S3DIS数据集还有什么疑问或者还有什么需要补充的可以在评论区留言,大家一起学习一起进步。文章来源地址https://www.toymoban.com/news/detail-718665.html

到了这里,关于超详细分析S3DIS数据集的构建的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 【大数据基础】基于 TMDB 数据集的电影数据分析

    https://dblab.xmu.edu.cn/blog/2400/ 环境搭建 数据预处理 本次项目使用的数据集来自知名数据网站 Kaggle 的 tmdb-movie-metadata 电影数据集,该数据集包含大约 5000 部电影的相关数据。本次实验使用数据集中有关电影的数据表 tmdb_5000_movies.csv 进行实验。数据包含以下字段: 由于数据中某

    2024年02月08日
    浏览(49)
  • 基于kaggle数据集的猫狗识别(超详细版本)

    kaggle猫狗识别数据集共包含25000张JPEG数据集照片,其中猫和狗的照片各占12500张。数据集大小经过压缩打包后占543MB。 数据集可以从kaggle官方网站下载,链接如下: 如果嫌官网下载麻烦,也可以从博主之前分享的百度网盘链接中直接获取: 网盘分享—博客链接,点击 在下载

    2024年01月21日
    浏览(80)
  • Android端恶意代码检测学习之路——(2)静态分析(apk数据集的获取)

    上次只是搞了一个apk进行测试,那必是不得行啊!那不得需要良性以及恶意数据集吗? 在网上找了很久,没有找到合适的,况且就算找到了,不能确定到底是不是良性,所以!我决定!写一个爬虫爬取豌豆荚apk(按照排行榜来顺序下载)。 可是我不会写爬虫啊!怎么办,学

    2023年04月11日
    浏览(60)
  • LLMs之dataset:大语言模型LLMs相关开源数据集的简介、下载、使用方法之详细攻略

    Dataset之NLP之LLMs:大模型核心技术—大语言模型LLMs相关开源数据集的简介(三类数据集【预训练数据/微调数据/测试数据】)、下载(国内外开源数据集平台总结)、使用方法之详细攻略 目录 相关文章

    2024年02月10日
    浏览(59)
  • 利用Re新增数据源dis实现向量相似度搜索:解决文本、图像和音频之间的相似度匹配问题

    最近工作中需要用到MongoDB的事务操作,因此参考了一些资料封装了一个小的组件,提供基础的CRUD Repository基类 和 UnitOfWork工作单元模式。今天,就来简单介绍一下这个小组件。 MongoDB在4.2版本开始全面支持了多文档事务,至今已过了四年了,虽然我们可能没有在项目中用Mon

    2024年01月23日
    浏览(44)
  • 如何构建大数据指标分析系统

    前言 :技术是为了需求服务。技术的第一性原则是解决问题,不同的技术方案都能实现同样的需求,那在公司原有技术架构上,如何设计技术架构,尽量用最少的大数据组件解决多种应用场景问题。分析分为实事状态分析和预测分析(特征工程),本文用对事实状态指标分析

    2024年01月20日
    浏览(43)
  • 大数据分析案例-基于随机森林算法构建人口普查分析模型

    🤵‍♂️ 个人主页:@艾派森的个人主页 ✍🏻作者简介:Python学习者 🐋 希望大家多多支持,我们一起进步!😄 如果文章对你有帮助的话, 欢迎评论 💬点赞👍🏻 收藏 📂加关注+ 喜欢大数据分析项目的小伙伴,希望可以多多支持该系列的其他文章 大数据分析案例合集

    2024年02月01日
    浏览(43)
  • 【机器学习】sklearn数据集的使用,数据集的获取和划分

    「作者主页」: 士别三日wyx 「作者简介」: CSDN top100、阿里云博客专家、华为云享专家、网络安全领域优质创作者 「推荐专栏」: 对网络安全感兴趣的小伙伴可以关注专栏《网络安全入门到精通》 json_decode() 可以对JSON字符串 「解码」 ,并转换为PHP变量。 语法 参数 $json

    2024年02月10日
    浏览(37)
  • (5)所有角色数据分析页面的构建-5

            所有角色数据分析页面,包括一个时间轴柱状图、六个散点图、六个柱状图(每个属性角色的生命值/防御力/攻击力的max与min的对比)。 运行结果:  

    2024年02月13日
    浏览(40)
  • 生物系统学中的进化树构建和分析R工具包V.PhyloMaker2的介绍和详细使用

    V.PhyloMaker2是一个R语言的工具包,专门用于构建和分析生物系统学中的进化树(也称为系统发育树或phylogenetic tree)。以下是对V.PhyloMaker2的一些基本介绍和使用说明: 论文介绍:V.PhyloMaker2: An updated and enlarged R package that can generate very large phylogenies for vascular plants - ScienceDirect  

    2024年02月04日
    浏览(124)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包