首页 > 编程语言 >基于三维点云数据的主成分分析方法(PCA)的python实现

基于三维点云数据的主成分分析方法(PCA)的python实现

时间:2023-11-08 15:00:33浏览次数:32  
标签:python 维度 points 点云 np PCA data 节点

https://github.com/mengxingshifen1218/learning-pointcloud/blob/master/%E6%B7%B1%E8%93%9D/CH1/PointCloudHomework1/pca_normal.py

 

 

KD-Tree原理详解

https://zhuanlan.zhihu.com/p/112246942

构建算法:

Input:  无序化的点云,维度k
Output:点云对应的kd-tree
Algorithm:
1、初始化分割轴:对每个维度的数据进行方差的计算,取最大方差的维度作为分割轴,标记为r;
2、确定节点:对当前数据按分割轴维度进行检索,找到中位数数据,并将其放入到当前节点上;
3、划分双支:
    划分左支:在当前分割轴维度,所有小于中位数的值划分到左支中;
    划分右支:在当前分割轴维度,所有大于等于中位数的值划分到右支中。
4、更新分割轴:r = (r + 1) % k;
5、确定子节点:
    确定左节点:在左支的数据中进行步骤2;
    确定右节点:在右支的数据中进行步骤2;

拿个例子说明为:

二维样例:{(2,3),(5,4),(9,6),(4,7),(8,1),(7,2)}

构建步骤:

1、初始化分割轴:

发现x轴的方差较大,所以,最开始的分割轴为x轴。

2、确定当前节点:

对{2,5,9,4,8,7}找中位数,发现{5,7}都可以,这里我们选择7,也就是(7,2);

3、划分双支数据:

在x轴维度上,比较和7的大小,进行划分:

左支:{(2,3),(5,4),(4,7)}

右支:{(9,6),(8,1)}

4、更新分割轴:

一共就两个维度,所以,下一个维度是y轴。

5、确定子节点:

左节点:在左支中找到y轴的中位数(5,4),左支数据更新为{(2,3)},右支数据更新为{(4,7)}

右节点:在右支中找到y轴的中位数(9,6),左支数据更新为{(8,1)},右支数据为null。

6、更新分割轴:

下一个维度为x轴。

7、确定(5,4)的子节点:

左节点:由于只有一个数据,所以,左节点为(2,3)

右节点:由于只有一个数据,所以,右节点为(4,7)

8、确定(9,6)的子节点:

左节点:由于只有一个数据,所以,左节点为(8,1)

右节点:右节点为空。

最终,就可以构建整个的kd-tree了。

示意图如下所示 [1] :

二维空间表示:

二维坐标系下的分割示意图

kd-tree表示:

2.3、最近邻检索

在构建了完整的kd-tree之后,我们想要使用他来进行高维空间的检索。所以,这里讲解一下比较常用的最近邻检索,其中范围检索也是同样的道理。

最近邻搜索,其实和之前我们曾经学习过的KNN很像。不过,在激光点云章,如果使用常规的KNN算法的话,时间复杂度会空前高涨。因此,为了减少时间消耗,在工程上,一般使用kd-tree进行最近邻检索。

由于kd-tree已经按照维度进行划分了,所以,我们在进行比较的时候,也可以通过维度进行比较,来快速定位到与其最接近的点。由于可能会进行多个最近邻点的检索,所以,算法也可能会发生变化。因此,我将从最简单的一个最近邻开始说起。

 

 

整体求解

 实现PCA分析和法向量计算,并加载数据集中的文件进行验证

import open3d as o3d 
# import os
import numpy as np
from scipy.spatial import KDTree

# from pyntcloud import PyntCloud

# 功能:计算PCA的函数
# 输入:
#     data:点云,NX3的矩阵
#     correlation:区分np的cov和corrcoef,不输入时默认为False
#     sort: 特征值排序,排序是为了其他功能方便使用,不输入时默认为True
# 输出:
#     eigenvalues:特征值
#     eigenvectors:特征向量
def PCA(data, correlation=False, sort=True):
    # normalize 归一化
    mean_data = np.mean(data, axis=0)
    normal_data = data - mean_data
    # 计算对称的协方差矩阵
    H = np.dot(normal_data.T, normal_data)
    # SVD奇异值分解,得到H矩阵的特征值和特征向量
    eigenvectors, eigenvalues, _ = np.linalg.svd(H)

    if sort:
        sort = eigenvalues.argsort()[::-1]
        eigenvalues = eigenvalues[sort]
        eigenvectors = eigenvectors[:, sort]

    return eigenvalues, eigenvectors

def main():

    # 从txt文件获取点,只对点进行处理
    filename = "D:\pointcloud_processing\modelnet40_normal_resampled\\airplane\\airplane_0001.txt"
    points = np.loadtxt(filename, delimiter=',')[:, 0:3] # 导入txt数据到np.array,这里只需导入前3列
    print('total points number is:', points.shape[0])

    # 用PCA分析点云主方向
    w, v = PCA(points) # PCA方法得到对应的特征值和特征向量
    point_cloud_vector = v[:, 0] #点云主方向对应的向量为最大特征值对应的特征向量
    print('the main orientation of this pointcloud is: ', point_cloud_vector)
    # 三个特征向量组成了三个坐标轴
    axis = o3d.geometry.TriangleMesh.create_coordinate_frame().rotate(v, center=(0, 0, 0))

    # 循环计算每个点的法向量
    leafsize = 32   # 切换为暴力搜索的最小数量
    KDTree_radius = 0.1 # 设置邻域半径
    tree = KDTree(points, leafsize=leafsize) # 构建KDTree
    radius_neighbor_idx = tree.query_ball_point(points, KDTree_radius) # 得到每个点的邻近索引
    normals = [] # 定义一个空list

    # -------------寻找法线---------------
    # 首先寻找邻域内的点
    for i in range(len(radius_neighbor_idx)):
        neighbor_idx = radius_neighbor_idx[i] # 得到第i个点的邻近点索引,邻近点包括自己
        neighbor_data = points[neighbor_idx] # 得到邻近点,在求邻近法线时没必要归一化,在PCA函数中归一化就行了
        eigenvalues, eigenvectors = PCA(neighbor_data) # 对邻近点做PCA,得到特征值和特征向量
        normals.append(eigenvectors[:, 2]) # 最小特征值对应的方向就是法线方向
    # ------------法线查找结束---------------
    normals = np.array(normals, dtype=np.float64) # 把法线放在了normals中
    # o3d.geometry.PointCloud,返回了PointCloud类型
    pc_view = o3d.geometry.PointCloud(points=o3d.utility.Vector3dVector(points))
    # 向PointCloud对象中添加法线
    pc_view.normals = o3d.utility.Vector3dVector(normals)
    # 可视化
    o3d.visualization.draw_geometries([pc_view, axis], point_show_normal=True)

if __name__ == '__main__':
    main()

  

标签:python,维度,points,点云,np,PCA,data,节点
From: https://www.cnblogs.com/gooutlook/p/17817425.html

相关文章

  • 1.Python操控Excel之读取
    1.读取excel文件数量和创建Sheet文件: 2.生成N列N行的值: 3.取到N行N列的值: 4.取到不同的行: 5.从表单中取行和列: 6.使用循环遍历多列,再遍历每一列的每个数据: 7.先遍历2行到6行,再遍历每一行的每一个数据: 8.获取到2行2列的值: 9.rowOfCellObjects访问每一行:......
  • python123——模拟生成微软序列号
    模拟生成微软序列号描述微软产品一般都一个25位的序列号,是用来区分每份微软产品的产品序列号。产品序列号由五组被“-”分隔开,由字母数字混合编制的字符串组成,每组字符串是由五个字符串组成。如:36XJE-86JVF-MTY62-7Q97Q-6BWJ2每个字符是取自于以下24个字母及数字之中的一个:BCE......
  • python winrm 远程操作Windows服务器
    winrm:Windows远程管理先确定被控机器开启winrm服务打开powershell命令行winrmenumeratewinrm快速配置winrmwinrmquickconfig需要加域配置winrmwinrmsetwinrm/config/service/auth@{Basic="true"}winrmsetwinrm/config/service@{AllowUnencrypted="true"}pyt......
  • python入门6
    最基本内置数据类型介绍每个对象都有类型,python中最基本的内置数据类型有:1、整型整数,2345,10,502.浮点型2、小数3.14或者科学计数法314e-23、布尔型表示真假,仅包含:True、False4、字符串型由字符组成的序列。“abc”,"student”,”程序员”数字Python支持整数(如∶50,520)和......
  • python入门4
    变量和简单赋值语句变量的声明和赋值变量的声明和赋值用于将一个变量绑定到一个对象上,格式如下:变量名表达式最简单的表达式就是字面量。比如:a=123。运行过程中,解释器先运行右边的表达式,生成一个代表表达式运算结果的对象;然后,将这个对象地址赋值给左边的变量。【操作】变量在......
  • python入门5
    链式赋值链式赋值用于同一个对象赋值给多个变量。x=y=123相当于:x=123;y=123系列解包赋值系列数据赋值给对应相同个数的变量(个数必须保持一致)>>>a,b,c=4,5,6相当于:a=4;b=5;c=6【操作】使用系列解包赋值实现变量交换常量Python不支持常量,即没有语法规则限制改变一个常量的道......
  • 相关性系数及其python实现 (转)
    转自: https://www.cnblogs.com/sddai/p/10332573.html参考文献:1.python皮尔森相关系数 https://www.cnblogs.com/lxnz/p/7098954.html2.统计学之三大相关性系数(pearson、spearman、kendall) http://blog.sina.com.cn/s/blog_69e75efd0102wmd2.html 1.personcorrelatio......
  • Python 嵌入式版本安装 绿色版本
    自己封装python的代码库,用于处理log文件或者数据txt,csv文件。便于现场调试。1、下载嵌入式版本。Python嵌入版(绿色免安装版)安装教程_python绿色版免安装-CSDN博客https://www.python.org/ftp/python/3.12.0/python-3.12.0-embed-amd64.ziphttps://www.python.org/ftp/python......
  • Python 的 IDE —— `PyCharm`
    要退出解释器可以有以下两种方式:1>直接输入exitIn[1]:exit2>使用热键退出在IPython解释器中,按热键ctrl+d,IPython会询问是否退出解释器IPython的安装$sudoaptinstallipython1)集成开发环境(IDE)集成开发环境(IDE,IntegratedDevelopmentEnvironment)——集成了开发软件......
  • [-006-]-Python3+Unittest+Selenium Web UI自动化测试之悬浮窗口中的元素点击
     1.分析现状:PPT模板悬浮出现悬浮窗口悬浮窗口中分为4大类:PPT模板,PPT模板页,PPT关系图,PPT图表大类下存在小类点击可跳转但是此页面里还存在PPT模板下的总结汇报等此种情况的元素此情况如果仅用text定位是无法定位到的所以排除了text定位方式2.解决方法:首先我们看下悬浮窗......