【3D视觉】PointNet解析

news/2024/5/21 10:40:26/文章来源:https://blog.csdn.net/qq_43076930/article/details/126967832

在这里插入图片描述
您好,各位!今天就基于3D点云数据的分类以及分割模型 : PointNet与PointNet++做一个简单的解析,解析部分将结合论文与代码,加上一些我个人微不足道(也不一定对)的见解在里面。

在看PointNet与PointNet++之前,我潜意识中将这两个模型与3D卷积联系(可能是点云数据的空间性让我产生了这种错觉),但是事实上并没有任何联系,反而比3D卷积要简单很多。
两篇论文的链接如下:

PointNet:https://arxiv.org/abs/1612.00593

PointNet++:https://arxiv.org/abs/1706.0241

本文参考的代码如下(基于Pytorch的,包含了PointNet与PointNet++):
代码

1 PointNet

这里我们直接给出PointNet的网络结构,如下图所示。大致的运算流程如下
1、输入为一帧的全部点云数据的集合,表示为一个nx3的2d tensor,其中n代表点云数量,3对应xyz坐标。
2、输入数据先通过和一个T-Net学习到的转换矩阵相乘来对齐,保证了模型的对特定空间转换的不变性。
3、通过多次mlp对各点云数据进行特征提取后,再用一个T-Net对特征进行对齐。
4、在特征的各个维度上执行maxpooling操作来得到最终的全局特征。
5、对分类任务,将全局特征通过mlp来预测最后的分类分数;对分割任务,将全局特征和之前学习到的各点云的局部特征进行串联,再通过mlp得到每个数据点的分类结果。
在这里插入图片描述
该网络根据任务的不用(分类还是分割)可以看成两个网络,一是做分类任务的蓝色区域,二是做分割任务的浅黄色区域,这在图上已经很明显了。
问:那么网络的输入是什么呢?

可以看出来,网络的输入是一个 n*3 的张量,其中n是点云数据包含的点的个数,3就是空间位置坐标(x,y,z)。为什么可以这么简单粗暴?但是作者的确就是这么做的,而且实际中效果也是相当的好呀。

问:那么图中的input transform和feature transform是什么?

这要从点云数据的不变性说出,也就是说点云数据所代表的目标对某些空间转换应该具有不变性,如旋转和平移等刚体变换,这应该很好理解,就和对图片做上下左右翻转后,我还是我,总不可能变成在看这篇文章的你们吧。
在这里插入图片描述
为了保证输入点云的不变性,作者在进行特征提取前先对点云数据进行对齐操作(也就是input transform),对齐操作是通过训练一个小型的网络(也就是上图中的T-Net)来得到转换矩阵,并将之和输入点云数据相乘来实现。

获取该 3*3 的input transform矩阵的python代码实现如下,我做了一些注释,便于大家理解:

class STN3d(nn.Module):def __init__(self, channel):super(STN3d, self).__init__()self.conv1 = torch.nn.Conv1d(channel, 64, 1)self.conv2 = torch.nn.Conv1d(64, 128, 1)self.conv3 = torch.nn.Conv1d(128, 1024, 1)self.fc1 = nn.Linear(1024, 512)self.fc2 = nn.Linear(512, 256)self.fc3 = nn.Linear(256, 9)self.relu = nn.ReLU()self.bn1 = nn.BatchNorm1d(64)self.bn2 = nn.BatchNorm1d(128)self.bn3 = nn.BatchNorm1d(1024)self.bn4 = nn.BatchNorm1d(512)self.bn5 = nn.BatchNorm1d(256)def forward(self, x):batchsize = x.size()[0] # shape (batch_size,3,point_nums)x = F.relu(self.bn1(self.conv1(x))) # shape (batch_size,64,point_nums)x = F.relu(self.bn2(self.conv2(x))) # shape (batch_size,128,point_nums)x = F.relu(self.bn3(self.conv3(x))) # shape (batch_size,1024,point_nums)x = torch.max(x, 2, keepdim=True)[0] # shape (batch_size,1024,1)x = x.view(-1, 1024) # shape (batch_size,1024)x = F.relu(self.bn4(self.fc1(x))) # shape (batch_size,512)x = F.relu(self.bn5(self.fc2(x))) # shape (batch_size,256)x = self.fc3(x) # shape (batch_size,9)iden = Variable(torch.from_numpy(np.array([1, 0, 0, 0, 1, 0, 0, 0, 1]).astype(np.float32))).view(1, 9).repeat(batchsize, 1) # # shape (batch_size,9)if x.is_cuda:iden = iden.cuda()# that's the same thing as adding a diagonal matrix(full 1)x = x + iden # iden means that add the input-selfx = x.view(-1, 3, 3) # shape (batch_size,3,3)return x

这其实在原论文中也提到

The mininetwork itself resembles the big network and is composed by basic modules of point independent feature extraction, max pooling and fully connected layers

3*3的input transform矩阵的获取还是比较简单,这么一套操作下来,这个 input transform矩阵就不是固定的了,它会根据网络的输入动态调整矩阵的权重。

和上面的input transform矩阵的获取方式类似,feature transform的 64*64矩阵获取代码实现如下:

class STNkd(nn.Module):def __init__(self, k=64):super(STNkd, self).__init__()self.conv1 = torch.nn.Conv1d(k, 64, 1)self.conv2 = torch.nn.Conv1d(64, 128, 1)self.conv3 = torch.nn.Conv1d(128, 1024, 1)self.fc1 = nn.Linear(1024, 512)self.fc2 = nn.Linear(512, 256)self.fc3 = nn.Linear(256, k * k)self.relu = nn.ReLU()self.bn1 = nn.BatchNorm1d(64)self.bn2 = nn.BatchNorm1d(128)self.bn3 = nn.BatchNorm1d(1024)self.bn4 = nn.BatchNorm1d(512)self.bn5 = nn.BatchNorm1d(256)self.k = kdef forward(self, x):batchsize = x.size()[0]x = F.relu(self.bn1(self.conv1(x)))x = F.relu(self.bn2(self.conv2(x)))x = F.relu(self.bn3(self.conv3(x)))x = torch.max(x, 2, keepdim=True)[0]x = x.view(-1, 1024)x = F.relu(self.bn4(self.fc1(x)))x = F.relu(self.bn5(self.fc2(x)))x = self.fc3(x)iden = Variable(torch.from_numpy(np.eye(self.k).flatten().astype(np.float32))).view(1, self.k * self.k).repeat(batchsize, 1)if x.is_cuda:iden = iden.cuda()x = x + idenx = x.view(-1, self.k, self.k)return x

值得注意的是,论文中提到

However, transformation matrix in the feature space has much higher dimension than the spatial transform matrix, which greatly increases the difficulty of optimization.

也就是 64*64 的feature transform矩阵很难优化,但是作者发现如果这个矩阵约等于一个正交矩阵,那么优化就方便很多,也稳定很多。为了实现这个矩阵约等于一个正交矩阵,根据正交矩阵的性质,即正交矩阵与其转置的乘积等于单位矩阵。那么作者额外增加了一个损失函数,定义如下:
在这里插入图片描述
作者在代码中的实现如下:

def feature_transform_reguliarzer(trans):""" make the transformation matrix of input akin to orthogonal matrix"""d = trans.size()[1]I = torch.eye(d)[None, :, :]if trans.is_cuda:I = I.cuda()loss = torch.mean(torch.norm(torch.bmm(trans, trans.transpose(2, 1) - I), dim=(1, 2)))return loss

至此,有关input transform和feature transform的疑问就解答完毕。

问:为什么做分割任务的时候,输入到分割网络的特征为1088?

这里我们先放上图,如下所示
在这里插入图片描述

这个 n* 1088 的张量由两部分组成,一个是特征提取网络的输出(大小为n*64 ),另一个是通过maxpooling后的global feature(大小为1024),在进行两者融合的时候,对global feature进行了广播,那么64+1024就是1088了。为什么要这么做呢?论文中这么提到
After computing the global point cloud feature vector, we feed it back to per point features by concatenating the global feature with each of the point features. Then we extract new per point features based on the combined point features - this time the per point feature is aware of both the local and global information
答案就是作者想要融合点的特征信息(来自特征提取网络的输出)与全局特征(来自global feature)。
问:这一套下来,作者一直在做点之间特征的单独提取,除了最后一层maxpool获取全局信息外,好像并没有将点与其周围点进行融合,提取局部特征呀?

的确,在PointNet这篇文章中确实没有做到像CNN那样逐层提取局部特征。我们知道在CNN中,一个点会与周围若干点进行加权求和(具体取决于卷积核大小),然后获取一个新的点,随着网络层数加深,深层网络的一个点对应原始图像的一个映射区域,这就是感受野的概念。但是本文做的特征提取都是点之间独立进行的,这势必会造成一些问题,至于具体的问题解决,作者在PointNet++展开了说明。(下一篇PointNet++)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.luyixian.cn/news_show_11660.aspx

如若内容造成侵权/违法违规/事实不符,请联系dt猫网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

第三章实验

实例一print("今有物不知其数,三三数之剩二,五五数之剩三,七七数之剩二,问几何?\n") number = int(input("请输入您认为符合条件的数:")) if number%3 == 2 and number%5 == 3 and number%7 == 2:print(number,"符合条件:三三数之剩二,五五数…

GBase 8s是如何实现库中数据安全保障的

随着计算机网络的广泛应用,网上信息的开放性与共享性日益增强,但随之而来的是信息安全问 题愈发严重。数据库是这些数据信息存储的主要场所,因此确保数据库中存储以及存取信息的安 全是确保网络安全的首要问题。为此,需要在通用的…

Nginx在Linux下的安装

✨ Nginx在Linux下的安装安装pcre安装其他的依赖安装Nginx(把压缩包放到opt目录)📃个人主页:不断前进的皮卡丘🌞博客描述:梦想也许遥不可及,但重要的是追梦的过程,用博客记录自己的成长,记录自己一步一步向上攀登的印记…

软件测试 git和gitee集成Pycharm 基于Flask的Mock Server服务器

文章目录1 Git1.1 作用1.2 工具1.3 名称解释2 安装git和注册Gitee3 使用Git(1)clone克隆命令(2)初始化(3)查看文件状态(4)文件提交暂存区(5)提交到本地版本库(6)修改文件(7)查看日志(8)跳转到提交的时间截点4 git和gitee集成Pycharm4.1 在Pycharm安装git和连接gitee(1)新建项目…

交互与前端3 前端需求简单梳理

说明 技术的终点是前端 我是从模型/算法作为起点的,顺着工作的需要和自己的兴趣,慢慢的逐步走到了前端。我想现在也是时候把前端搞好了,前端有几个作用: 1 对外可以作为广告。技术最终还是要考虑变现的。2 与外部协同。有很多工作是需要外部…

关于穿越机FPV视频果冻效应的讨论

关于穿越机FPV视频果冻效应的讨论1. 名词定义2. 摄像原理2.1 快门分类2.2 卷帘拍摄3. 产生原因4. 解决方法4.1 振动出处4.2 软件方法(辅助作用)4.3 硬件方法(直接办法)5. F450试验机遇到的问题5.1 现象5.2 测试5.3 减震改善5.4 其他改善5.5 初步结论5.6 改进方向6. 总结7. 参考…

基于ssm的远程家庭健康监测管理系统设计与实现-计算机毕业设计源码+LW文档

开发语言:Java 框架:ssm JDK版本:JDK1.8 服务器:tomcat7 数据库:mysql 5.7(一定要5.7版本) 数据库工具:Navicat11 开发软件:eclipse/myeclipse/idea Maven包:…

常用的荧光染料示踪剂 Me-tetrazine-ICG,甲基-四嗪-吲哚菁绿 有哪些特点?

甲基-四嗪-吲哚菁绿是一种荧光染料化合物,四嗪可通过TCO点击化学标记到其它大分子上。吲哚菁绿是生物学中常用的荧光染料示踪剂,波长更长。 西安凯新生物科技有限公司常规修饰性聚乙二醇常备现 货,非常规基团修饰性聚乙二醇(PEG&a…

h5(1)

H5 一、canvas标签 canvas是绘图标签&#xff0c;可以使用该标签在网页上生成一块画布&#xff0c;然后就可以在这块画布中随意的绘图。 canvas标签基本使用&#xff1a; <canvas width"500" height"500" id"cvs"></canvas> //w…

AWS聚焦数字经济与可持续发展

2022年中国国际服务贸易交易会于9月5日圆满闭幕&#xff0c;AWS在此间展示了多项领先的云计算技术和行业解决方案。围绕着本届服贸会“服务合作促发展绿色创新迎未来”的主题&#xff0c;AWS也在此次论坛中诠释和传递着其在助力数字经济及企业可持续发展的价值愿景。 9月3日与…

springboot 上传文件/图片到本地文件夹,利用nginx可以采用地址打开该文件

springboot 上传文件/图片到本地文件夹&#xff0c;利用nginx可以采用地址打开该文件 步骤&#xff1a; 一、下载nginx 打开nginx.conf 文件&#xff0c;配置nginx 启动nginx在nginx.exe文件所在的文件夹路径上直接cmd&#xff0c;输入nginx.exe即可启动nginx 注意&#xff…

企业运营管理 | 如何用「内容」取胜营销战?

全媒体时代&#xff0c;舆论生态、媒体格局、传播方式日新月异&#xff0c;但「内容为王」始终是品牌营销增长的公认规则。 除了投放渠道多、内容更新频次快、跨地域运营等挑战&#xff0c;如何规模化地输出统一的、优质的内容&#xff0c;以此驱动品牌增长&#xff0c;成为品牌…

u盘部分文件无故消失该怎么办?

u盘属于移动存储设备&#xff0c;用于备份数据&#xff0c;方便携带。可以存放各种格式的数据、文档、音频、视频、图片&#xff0c;即插即用&#xff0c;随时拔下。这给了我们极大地便利。但是我们在使用u盘的时候偶尔会出现一些意外&#xff0c;比如u盘文件没删除却消失了&am…

数据分析案例-基于sklearn随机森林算法探究影响预期寿命的因素

目录 项目目标 导入数据 查看数据基本信息 数据预处理 数据可视化 特征工程 建模 项目目标 **探索影响预期寿命的因素** 世卫组织建立了一段时间内所有国家健康状况的数据集&#xff0c;其中包括预期寿命&#xff0c;成人死亡率等方面的统计数据。使用此数据集&#xff…

Panama-FFI实现原理与移植

移植FFI 在说明如何对FFI进行移植之前需要先说明FFI的实现原理。JEP424是外部函数访问+本地内存,但是实际上需要移植的内容只有外部函数访问,对于本地内存的操作并不需要修改。 从java中调用native方法叫做downcall,而从native方法中调用java方法叫做upcall,下面通过downca…

泰克示波器知识分享-波的类型

提到泰克示波器&#xff0c;相信大多数人都知道&#xff0c;那大家对示波器基础知识了解多少呢?今天安泰测试就给大家分享一波干活——波的类型介绍&#xff1a; 您可以把大多数波分成下面几类&#xff1a; 周期信号和非周期信号 重复的信号称为周期信号,一直变化的信号则称为…

基于Android studio有声听书系统 java音乐播放器系统

1&#xff1a;注册登录&#xff1a;未注册用户首先进行账号注册&#xff0c;注册成功后进行登录&#xff0c;已注册用户直接输入账号密码进行登录&#xff0c;登录成功后进入主页面。 2&#xff1a;主页面&#xff1a;通过左右滑动可以实现对推荐界面、订阅界面、历史界面的切换…

第三章流程控制语句

一、判断输入的是不是黄蓉所说的数 二、验证瑛姑给出的答案是否正确 三、输出玫瑰花语 四、判断是否为酒后驾车 五、助力瑛姑(1):while循环版解题法 六、助力瑛姑(2):for循环版解题法七、打印九九乘法表 八、助力瑛姑(3):for循环改进版解题法 九、逢七拍腿游戏 十…

基于ssm的网上招投标系统设计与实现-计算机毕业设计源码+LW文档

开发语言&#xff1a;Java 框架&#xff1a;ssm JDK版本&#xff1a;JDK1.8 服务器&#xff1a;tomcat7 数据库&#xff1a;mysql 5.7&#xff08;一定要5.7版本&#xff09; 数据库工具&#xff1a;Navicat11 开发软件&#xff1a;eclipse/myeclipse/idea Maven包&#xff1a;…

bean的作用域、bean的生命周期、bean的后置处理器

bean的作用域 概念&#xff1a;在Spring中可以通过配置bean标签的scope属性来指定bean的作用域范围&#xff0c;取值含义如下所示&#xff1a; 如果是在WebApplicationContext环境下还会有另外两个作用域(不常用) 在resources目录下创建spring-scope.xml文件 在test的java下创…