图神经网络(处理点云)PPFNet的实现

news2024/11/24 17:07:06

文章说明:
1)参考资料:PYG官方文档。超链。
2)博主水平不高,如有错误还望批评指正。
3)我在百度网盘上传了这篇文章的jupyter notebook和有关文献。超链。提取码8848。

文章目录

    • 前言
    • 文献阅读
    • 代码实操
    • 历史遗留问题

前言

本篇文章接上一篇文章,超链,PointNet++无法解决旋转变化,所以我们使用PPFNet解决问题。

文献阅读

重要!重要!重要!我的理解不一定对!水平低请见谅!谨慎食用!
参考文献: PPFNet: Global Context Aware Local Features for Robust 3D Point Matching
文章概述: 参考文献提出Point Pair Feature NETwork模型,模型在点云中能够感知全局并且能够描述局部。模型受到PointNet的启发(PointNet++也是受到PointNet启发),采用新颖的N-tuple损失以及框架将全局信息嵌入于局部,具有置换不变性质,高召回率高鲁棒性。乃是3D点云提取特征重要工作文献。
理论概述:
11. 考虑两个点的集合 X X X以及 Y Y Y x i , y i x_{i},y_{i} xi,yi分别表示第 i i i个点坐标。假设它们存在某种关系并且是双射的,按照这篇The 3d-3d registration problem revisited的方法并且假定是刚性的。它们之间的关系可以分别表示为排列矩阵刚性变换。所以点集配准的L2可表示为: d ( X , Y ∣ R , t , P ) = 1 n ∑ i = 1 n ∣ ∣ x i − R y i ( P ) − t ∣ ∣ 2 d(X,Y|R,t,P)=\frac{1}{n}\sum_{i=1}^n||x_i-Ry_{i(P)}-t||^2 d(X,YR,t,P)=n1i=1n∣∣xiRyi(P)t2。符号说明: P P P指排列矩阵, T T T指刚性变换, T = { R ∈ S O ( 3 ) , t ∈ R 3 } T=\{{R\in SO(3)},t \in R^3\} T={RSO(3),tR3}。这里还是把L2理解为距离吧。
1). 排列矩阵是什么呢?如下一个矩阵便是一个44排列矩阵。表示集合{2,1,4,3}。第n行第m列为1,n在第m个的位置。
[ 0 1 0 0 1 0 0 0 0 0 0 1 0 0 1 0 ] \begin{bmatrix}0&1&0&0\\1&0&0&0\\0&0&0&1\\0&0&1&0\end{bmatrix} 0100100000010010
2). 刚性变换是什么呢?在几何学之中表示,使物体的大小形状不变变换。例如,平移,旋转,镜像。
12. 如果两个点集是数量相同的上述公式简化为 d ( X , Y ∣ T , P ) = 1 n ∣ ∣ X − P Y T T ∣ ∣ 2 d(X,Y|T,P)=\frac{1}{n}||X-PYT^\mathcal{T}||^2 d(X,YT,P)=n1∣∣XPYTT2。符号说明: T \mathcal{T} T是转置。如果两个点集匹配,那么有 d ( X , Y ∣ T , P ) ≈ 0 d(X,Y|T,P)\approx0 d(X,YT,P)0。得出结论:模型进行有效学习应该保持嵌入空间相似距离并且让 d ( X , Y ∣ T , P ) d(X,Y|T,P) d(X,YT,P)尽量为0。 d f ( X , Y ∣ T , P ) = 1 n ∣ ∣ f ( X ) − f ( P Y T T ) ∣ ∣ 2 d_f(X,Y|T,P)=\frac{1}{n}||f(X)-f(PYT^\mathcal{T})||^2 df(X,YT,P)=n1∣∣f(X)f(PYTT)2为保持不变性(即让它约为0), f f f应该对排列矩阵刚性变换极不敏感。但原文却说对刚性变换敏感。原文是“Ideally we would like to learn f being invariant to permutations P and as intolerant as possible to rigid transformations T”。还请大佬能够确认。
2. PPF stands for Point Pair Feature。我们对Point Pair Feature进行描述,它是一个4维的描述子。 ( ∥ p j − p i ∥ 2 , ∠ ( n i , p j − p i ) , ∠ ( n j , p j − p i ) , ∠ ( n i , n j ) ) (∥p_j−p_i∥^2,∠(n_i,p_j−p_i),∠(n_j,p_j−p_i),∠(n_i,n_j)) (pjpi2,(ni,pjpi),(nj,pjpi),(ni,nj))符号说明: P i P_i Pi是点集 X 1 X_1 X1 i i i个点的特征向量, P j P_j Pj是点集 X 2 X_2 X2 j j j个点的特征向量。 n n n指法线。 ∣ ∣ ⋅ ∣ ∣ ||\cdot|| ∣∣∣∣维欧几里得空间。 ∠ ( v 1 , v 2 ) = a t a n 2 ( ∣ ∣ v 1 × v 2 ∣ ∣ , v 1 ⋅ v 2 ) ∠(v_1,v_2) = atan2(||v_1\times v_2||,v_1 \cdot v_2) (v1,v2)=atan2(∣∣v1×v2∣∣,v1v2)
3. 这篇文章受到PointNet启发,鉴于篇幅假定你已经彻底搞懂了PointNet并且知道PointNet能够有效聚合全局信息但是同时难以捕捉局部信息。
流程概述:
1.局部区域点云编码。 先看看图因为图很好理解的。 F r F_r Fr为输入PPFNet的数据。
在这里插入图片描述
2.PPFNet的结构。 不难理解不再赘述。
在这里插入图片描述
3.N-tuple loss。 这是一个损失函数。如有兴趣建议自行阅读论文这一部分。博主没看因为我受不了。好了给我速速结束这一部分。

代码实操

导库

import torch
from torch.nn import Sequential,Linear,ReLU
from torch_geometric.nn import PPFConv
from torch_cluster import knn_graph
from torch_geometric.nn import global_max_pool

定义PPFNet框架
注意!注意!注意!注意!搭建PPFConv时输入维度必须加4,为什么呢?因为上面理论已经说了。输出维度还是不管你随意吧。

class PPFNet(torch.nn.Module):
    
    def __init__(self):
        super().__init__()
        mlp1=Sequential(Linear(4,20),ReLU(),Linear(20,24))
        self.conv1=PPFConv(mlp1)
        mlp2=Sequential(Linear(28,32),ReLU(),Linear(32,32))
        self.conv2=PPFConv(mlp2)
        self.classifier=Linear(32,40)
        
    def forward(self,pos,normal,batch):
        edge_index=knn_graph(pos,k=16,batch=batch,loop=False)
        x=self.conv1(x=None,pos=pos,normal=normal,edge_index=edge_index)
        x=x.relu()
        x=self.conv2(x=x,pos=pos,normal=normal,edge_index=edge_index)
        x=x.relu()
        x=global_max_pool(x,batch)
        return self.classifier(x)
    
model = PPFNet()
print(model)
#输出如下:
#PPFNet(
#  (conv1): PPFConv(local_nn=Sequential(
#    (0): Linear(in_features=4, out_features=20, bias=True)
#    (1): ReLU()
#    (2): Linear(in_features=20, out_features=24, bias=True)
#  ), global_nn=None)
#  (conv2): PPFConv(local_nn=Sequential(
#    (0): Linear(in_features=28, out_features=32, bias=True)
#    (1): ReLU()
#    (2): Linear(in_features=32, out_features=32, bias=True)
#  ), global_nn=None)
#  (classifier): Linear(in_features=32, out_features=40, bias=True)
#)

导库

from torch_geometric.transforms import Compose, RandomRotate,SamplePoints

定义旋转操作

random_rotate = Compose([
    RandomRotate(degrees=180, axis=0),
    RandomRotate(degrees=180, axis=1),
    RandomRotate(degrees=180, axis=2),
])
test_transform = Compose([
    random_rotate,
    SamplePoints(num=128, include_normals=True),
])

导库,导入数据数据变换,训测拆分打乱顺序

from torch_geometric.datasets import GeometricShapes
from torch_geometric.loader import DataLoader
train_dataset=GeometricShapes(root='/DATA/GeometricShapes',train=False,transform=SamplePoints(128,include_normals=True))
test_dataset=GeometricShapes(root='/DATA/GeometricShapes',train=False,transform=test_transform)
train_loader=DataLoader(train_dataset,batch_size=10,shuffle=True)
test_loader=DataLoader(test_dataset,batch_size=10)

jupyter nootbook内的输出如下
在这里插入图片描述

历史遗留问题

上篇文章我们使用K最邻近算法构边建图,好像这篇文章也是K最邻近算法构边建图。PointNet++那一篇文章指出这样不好(数据不均匀效果就不好,主观很好理解)。所以使用FPS算法来寻找质心克服问题。简单来说1.开始随便找个质心2.质心张开一个固定半径邻域3.再在剩下所有点内(质心以及质心邻域内的不算)寻找到离所有质心最远的点成为下个质心4迭代直到没有点了。
开摆

import matplotlib.pyplot as plt

def visualize_points(pos,edge_index=None,index=None):
    fig=plt.figure(figsize=(4, 4))
    if edge_index is not None:
        for (src,dst) in edge_index.t().tolist():
            src=pos[src].tolist()
            dst=pos[dst].tolist()
            plt.plot([src[0],dst[0]],[src[1],dst[1]],linewidth=1,color='black')
    if index is None:
        plt.scatter(pos[:,0],pos[:,1],s=50,zorder=1000)
    else:
       mask=torch.zeros(pos.size(0),dtype=torch.bool)
       mask[index]=True
       plt.scatter(pos[~mask,0],pos[~mask,1],s=50,color='lightgray',zorder=1000)
       plt.scatter(pos[mask,0],pos[mask,1],s=50,zorder=1000)
    plt.axis('off')
    plt.show()

from torch_cluster import fps

dataset=GeometricShapes(root='/DATA//GeometricShapes',transform=SamplePoints(128))
data=dataset[0]
index=fps(data.pos,ratio=0.25)
visualize_points(data.pos)
visualize_points(data.pos,index=index)

jupyter notebook内的输出如下
在这里插入图片描述
唯独这篇,点个赞吧,累麻

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

今年的面试难度,我给跪了……

大家好,最近有不少小伙伴在后台留言,又得准备面试了,不知道从何下手! 不论是跳槽涨薪,还是学习提升!先给自己定一个小目标,然后再朝着目标去努力就完事儿了! 为了帮大家节约时间&a…

【STM32G431RBTx】备战蓝桥杯嵌入式→决赛试题→第七届

文章目录 前言一、题目二、模块初始化三、代码实现interrupt.h:interrupt.h:main.h:main.h: 四、完成效果五、总结 前言 无 一、题目 二、模块初始化 1.LCD这里不用配置,直接使用提供的资源包就行 2.ADC:开启ADCsingle-ended 3.LED:开启PC8-15,PD2输出模式就行了…

手撕代码——同步FIFO

手撕代码——同步FIFO 一、FIFO原理与设计二、完整代码与仿真结果三、仿真结果 一、FIFO原理与设计 查看Xilinx官方FIFO IP核,其主要的信号有时钟信号、写端口信号、读端口信号,其中,写端口信号包括写满信号full、写使能信号wr_en、写数据输入…

[元带你学: eMMC完全解读 7] eMMC 设备与系统概述

依JEDEC eMMC 5.1及经验辛苦整理,付费内容,禁止转载。 所在专栏 《元带你学: eMMC完全解读》 前言 全文3600 字, 全文介绍eMMC 内部系统框架, Bus 总线宽度, 总线Speed Mode, 了解即可。对应Bus 总线重点看 8 Bit 即可, Speed Mode 重点看 HS400。几乎所有的系统都是跑在…

Java并发编程-synchronized

目录 1. synchronized在jdk 1.6中的优化 1.1 锁消除 1.2 锁粗化 1.2 锁升级/锁膨胀 1.2.1 锁升级原理 1.2.2 自适应自旋锁 2. synchronized实现原理 3. synchronized和Lock的对比 1. synchronized在jdk 1.6中的优化 在JDK1.5的时候,Doug Lee推出了ReentrantLock,lock的…

【密码学复习】第九讲 密钥管理(一)

密钥管理简介 • 柯克霍夫斯原则(Kerckhoffs Principle) 即使密码系统的任何细节已为人悉知,只要密钥未泄漏,它也应是安全的(19世纪). 密钥安全:三分技术,七分管理 密钥管理就是在授权各方之间实现密钥关系的建立和维护…

dom4j 读取xml配置文件,根据配置文件利用反射创建对象

pom.xml <?xml version"1.0" encoding"UTF-8"?> <project xmlns"http://maven.apache.org/POM/4.0.0"xmlns:xsi"http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation"http://maven.apache.org/POM/4.0.0 …

maven打包命令打出的可执行的jar包和可依赖的jar包的区别

目录 引出问题: 介绍打包插件 下面开始打包: 解压比较这两个jar包的区别: 引出问题: 当我建了一个maven的springboot项目A写了一个工具类,我把A项目打包成jar包去给B项目用,结果 B项目报错找不到这个jar包. 百度后发现原来jar包分为可执行jar包和可被依赖的jar包 介绍打包…

二、医院设置管理

文章目录 一、医院设置管理1、项目开发流程1.1 定义路由模块1.2 定义api模块1.3 定义页面组件脚本1.4 定义页面组件模板1.5 测试数据通信1.6 跨域处理 2、分页查询2.1 定义页面组件脚本2.2 定义页面组件模板2.3 表单查询 3、删除3.1 定义api模块3.2 定义页面组件模板3.3 定义页…

Midjourney|文心一格prompt教程[进阶篇]:Midjourney Prompt 高级参数、各版本差异、官方提供常见问题

Midjourney|文心一格prompt教程[进阶篇]&#xff1a;Midjourney Prompt 高级参数、各版本差异、官方提供常见问题 1.Midjourney Prompt 高级参数 Quality 图片质量是另一个我比较常用的属性&#xff0c;首先需要注意这个参数并不影响分辨率&#xff0c;并不改变分辨率&#x…

【C++】实现一个日期计算器

&#x1f307;个人主页&#xff1a;平凡的小苏 &#x1f4da;学习格言&#xff1a;命运给你一个低的起点&#xff0c;是想看你精彩的翻盘&#xff0c;而不是让你自甘堕落&#xff0c;脚下的路虽然难走&#xff0c;但我还能走&#xff0c;比起向阳而生&#xff0c;我更想尝试逆风…

线程池学习

一、线程池的7个核心参数说明&#xff1a; corePoolSize&#xff1a;核心线程数 maximumPoolSize&#xff1a;最大线程数 keepAliveTime&#xff1a;最大空闲时间 unit&#xff1a;最大空闲时间单位 workQueue&#xff1a;任务队列 threadFactory&#xff1a;表示生成线程…

1.Hyperledger Fabric架构介绍

&#xff08;1&#xff09;Hyperledger定义&#xff1a; Hyperledger是一个开放源代码的区块链项目合作组织&#xff0c;旨在推动跨行业的企业级区块链解决方案的发展。该项目由Linux基金会于2015年发起&#xff0c;致力于建立一个可靠、安全和可扩展的区块链框架和工具集。Hy…

堆结构 - 大根堆、小根堆

在开发语言中&#xff0c;heap在使用层次的名字叫PriorityQueue&#xff08;优先级队列&#xff09;&#xff0c;PriorityQueue数据结构的名字就叫做堆&#xff0c;底层就是用堆结构实现的。 完全二叉树 空树也算是完全二叉树每一层都是满的也算是完全二叉树如果层不满&#…

魔改车钥匙实现远程控车:(番外)在macOS上安装使用MicroPython

前言 哈哈&#xff0c;各位可能会奇怪为啥上一篇文章还在说怎么在 ESP32C3 上安装 Arduino&#xff0c;现在怎么又变成了安装 MIcroPython。 其实是因为上次写 Arduino 还是我高中时候的事了&#xff0c;已经不太会了。 虽然 MIcroPython 我从来没有接触过&#xff0c;但是 …

Microsoft Office 2003的安装

哈喽&#xff0c;大家好。今天一起学习的是office2003的安装&#xff0c;这个老版本的office可是XP操作系统的老搭档了&#xff0c;有兴趣的小伙伴也可以来一起试试手。 一、测试演示参数 演示操作系统&#xff1a;Windows XP 不建议win7及以上操作系统使用 系统类型&#xff…

Springboot 搭建WebService客户端+服务端

WebService简介 Web Service技术&#xff0c; 能使得运行在不同机器上的不同应用无须借助附加的、专门的第三方软件或硬件&#xff0c; 就可相互交换数据或集成。依据Web Service规范实施的应用之间&#xff0c; 无论它们所使用的语言、 平台或内部协议是什么&#xff0c; 都可…

软件设计和架构设计

软件设计和架构设计 1.软件设计 1.1设计 设计是从架构 构件 接口以及系统其他特征定义的过程。 软件设计的结果必须描述系统的架构&#xff0c;系统如何分解和组织构件。 描述构件间的接口。 描述构件必须详细到可进一步构造的程度。 设计是把分析模型转换成设计模型的过…

三个帮助你整理信息的桌面 WiKi

如果你想在桌面上感受 wiki&#xff0c;而不用做那些复杂的工作&#xff0c;这很容易做到。这有一些轻量级 wiki&#xff0c;可以帮助你组织你的信息、跟踪你的任务、管理你的笔记等等。 这个词时&#xff0c;可能会想到 MediaWiki 或 DokuWiki 这样的例子。它们开源、好用、强…

Go 并发之channel(通道)

一、前言 作为 Go 语言最有特色的数据类型&#xff0c;通道&#xff08;channel&#xff09;完全可以与 goroutine&#xff08;也可称为 go 程&#xff09;并驾齐驱&#xff0c;共同代表 Go 语言独有的并发编程模式和编程哲学。 通道&#xff08;channel&#xff09;可以利用…