三维点云学习(1)上
环境安装
1.系统环境 win10 或者 ubuntu
2. Anaconda3+python3.6
使用Anaconda创建的conda虚拟环境进行python的编写 环境安装主要参考如下网址 安装Anaconda3 Anconda3 安装 open3d
3. 使用conda install 或者 pip install 下载需要的py模块
open3d numpy matplotlib pandas plyfile pyntcloud
import os
import numpy
as np
from plyfile
import PlyData
from plyfile
import PlyElement
import open3d
as o3d
import os
import numpy
as np
import matplotlib
.pyplot
as plt
import open3d
as o3d
import os
import numpy
as np
from pyntcloud
import PyntCloud
4.数据集下载
为40种物体的三维点云数据集 链接:https://pan.baidu.com/s/1LX9xeiXJ0t-Fne8BCGSjlQ 提取码:es14
5.单独读取数据集,并在open3d中显示原点云图
注意:要把对应的数据集文件 如:"sofa_0001.txt"放在对应的代码路径下
读取方法一(这个读法忽略了后三个为法向量,因而处理错误,推荐方法二)
import open3d
as o3d
import numpy
as np
import matplotlib
as plt
raw_point_cloud_matrix
= np
.genfromtxt
(r
"sofa_0001.txt", delimiter
=",").reshape
((-1,3))
pcd
= o3d
.geometry
.PointCloud
()
pcd
.points
= o3d
.utility
.Vector3dVector
(raw_point_cloud_matrix
)
print(pcd
)
o3d
.visualization
.draw_geometries
([pcd
])
原始点云数据在open3d下运行结果如下所示:
读取方法二
import open3d
as o3d
import os
import numpy
as np
import matplotlib
.pyplot
as plt
from pandas
import DataFrame
from pyntcloud
import PyntCloud
point_cloud_raw
= np
.genfromtxt
(r
"plant_0001.txt", delimiter
=",")
point_cloud_raw
= DataFrame
(point_cloud_raw
[:, 0:3])
point_cloud_raw
.columns
= ['x', 'y', 'z']
point_cloud_pynt
= PyntCloud
(point_cloud_raw
)
point_cloud_o3d
= point_cloud_pynt
.to_instance
("open3d", mesh
=False)
o3d
.visualization
.draw_geometries
([point_cloud_o3d
])
6.便捷的显示模块摘自enginelong的博客代码片
def Point_Cloud_Show(points
):
fig
= plt
.figure
(dpi
=150)
ax
= fig
.add_subplot
(111, projection
='3d')
ax
.scatter
(points
[:, 0], points
[:, 1], points
[:, 2], cmap
='spectral', s
=2, linewidths
=0, alpha
=1, marker
=".")
plt
.title
('Point Cloud')
ax
.set_xlabel
('x')
ax
.set_ylabel
('y')
ax
.set_zlabel
('z')
plt
.show
()
def Point_Show(pca_point_cloud
):
x
= []
y
= []
pca_point_cloud
= np
.asarray
(pca_point_cloud
)
for i
in range(10000):
x
.append
(pca_point_cloud
[i
][0])
y
.append
(pca_point_cloud
[i
][1])
plt
.scatter
(x
, y
)
plt
.show
()
7.PCA 主成分分析法
参考公式网址如下所示 三维点云处理学习笔记 PCA原理解释 对协方差矩阵的通俗理解 代码参考网址如下所示 点云学习(1)参考网址1 点云学习(1)参考网址2
PCA算法的优化目标
1.降维后同一纬度的方差最大 2.不同维度之间的相关性为0
PCA函数编写
主要流程
1.取均值,去中心化
average_data
= np
.mean
(data
,axis
=0)
decentration_matrix
= data
- average_data
2.求取协方差矩阵H,并用SVD奇异值分解,求解出相应的特征值、特征向量
H
= np
.dot
(decentration_matrix
.T
,decentration_matrix
)
eigenvectors
,eigenvalues
,eigenvectors_T
= np
.linalg
.svd
(H
)
3.对2步求解出的特征值特征向量进行降序排序,并存放到列表中
if sort
:
sort
= eigenvalues
.argsort
()[::-1]
eigenvalues
= eigenvalues
[sort
]
eigenvectors
= eigenvectors
[:, sort
]
PCA处理整体代码块:
def PCA(data
, correlation
=False, sort
=True):
average_data
= np
.mean
(data
,axis
=0)
decentration_matrix
= data
- average_data
H
= np
.dot
(decentration_matrix
.T
,decentration_matrix
)
eigenvectors
,eigenvalues
,eigenvectors_T
= np
.linalg
.svd
(H
)
if sort
:
sort
= eigenvalues
.argsort
()[::-1]
eigenvalues
= eigenvalues
[sort
]
eigenvectors
= eigenvectors
[:, sort
]
return eigenvalues
, eigenvectors
4.调用结果
通过调用PCA算法,并显示两个主成分方向,如下图所示黑色线为第一主成分,红色线为第二主成分
5.PCA的应用
降维(Encoder)
point_cloud_encode
= (np
.dot
(point_cloud_vector
.T
,point_cloud_raw
.T
)).T
Point_Show
(point_cloud_encode
)
效果如下所示: 降维后效果图
升维(Decoder)
point_cloud_decode
= (np
.dot
(point_cloud_vector
,point_cloud_encode
.T
)).T
Point_Cloud_Show
(point_cloud_decode
)
效果如下所示: 使用两个主方向再次升维后的结果
8.法向量估计
法向量估计 思想:选取点云中每一点,对其进行临近点的搜索,将包含该点的临近点拟合成曲面,对曲面中的点进行PCA主成分分析,查找特征值最小的对应的特征向量,该特征向量即为该拟合曲面的法向量(摘自:秦乐乐博客)
1.编码流程
2.代码展示
pcd_tree
= o3d
.geometry
.KDTreeFlann
(point_cloud_o3d
)
normals
= []
print(points
.shape
[0])
for i
in range(points
.shape
[0]):
[_
,idx
,_
] = pcd_tree
.search_knn_vector_3d
(point_cloud_o3d
.points
[i
],10)
k_nearest_point
= np
.asarray
(point_cloud_o3d
.points
)[idx
, :]
w
, v
= PCA
(k_nearest_point
)
normals
.append
(v
[:, 2])
normals
= np
.array
(normals
, dtype
=np
.float64
)
point_cloud_o3d
.normals
= o3d
.utility
.Vector3dVector
(normals
)
o3d
.visualization
.draw_geometries
([point_cloud_o3d
])
3.效果展示
如下图1所示为图2的法向量加粗展示, 法线向量显示:在显示窗口按n 可按 + - 更改点的大小(o3d)
完整代码(包含PCA算法、PCA应用(升降维)、法向量估计展示)
import open3d
as o3d
import os
import numpy
as np
import matplotlib
.pyplot
as plt
from pandas
import DataFrame
from pyntcloud
import PyntCloud
def Point_Cloud_Show(points
):
fig
= plt
.figure
(dpi
=150)
ax
= fig
.add_subplot
(111, projection
='3d')
ax
.scatter
(points
[:, 0], points
[:, 1], points
[:, 2], cmap
='spectral', s
=2, linewidths
=0, alpha
=1, marker
=".")
plt
.title
('Point Cloud')
ax
.set_xlabel
('x')
ax
.set_ylabel
('y')
ax
.set_zlabel
('z')
plt
.show
()
def Point_Show(pca_point_cloud
):
x
= []
y
= []
pca_point_cloud
= np
.asarray
(pca_point_cloud
)
for i
in range(10000):
x
.append
(pca_point_cloud
[i
][0])
y
.append
(pca_point_cloud
[i
][1])
plt
.scatter
(x
, y
)
plt
.show
()
def PCA(data
, correlation
=False, sort
=True):
average_data
= np
.mean
(data
,axis
=0)
decentration_matrix
= data
- average_data
H
= np
.dot
(decentration_matrix
.T
,decentration_matrix
)
eigenvectors
,eigenvalues
,eigenvectors_T
= np
.linalg
.svd
(H
)
if sort
:
sort
= eigenvalues
.argsort
()[::-1]
eigenvalues
= eigenvalues
[sort
]
eigenvectors
= eigenvectors
[:, sort
]
return eigenvalues
, eigenvectors
def main():
point_cloud_raw
= np
.genfromtxt
(r
"D:\三维点云学习\深蓝学院课程\第一章\作业\Homework I\数据集\modelnet40_normal_resampled\plant\plant_0001.txt", delimiter
=",")
point_cloud_raw
= DataFrame
(point_cloud_raw
[:, 0:3])
point_cloud_raw
.columns
= ['x', 'y', 'z']
point_cloud_pynt
= PyntCloud
(point_cloud_raw
)
point_cloud_o3d
= point_cloud_pynt
.to_instance
("open3d", mesh
=False)
o3d
.visualization
.draw_geometries
([point_cloud_o3d
])
print(point_cloud_o3d
)
w
, v
= PCA
(point_cloud_raw
)
point_cloud_vector1
= v
[:, 0]
point_cloud_vector2
= v
[:, 1]
point_cloud_vector
= v
[:,0:2]
print('the main orientation of this pointcloud is: ', point_cloud_vector1
)
print('the main orientation of this pointcloud is: ', point_cloud_vector2
)
point
= [[0,0,0],point_cloud_vector1
,point_cloud_vector2
]
lines
= [[0,1],[0,2]]
colors
= [[1,0,0],[0,0,0]]
line_set
= o3d
.geometry
.LineSet
(points
=o3d
.utility
.Vector3dVector
(point
),lines
=o3d
.utility
.Vector2iVector
(lines
))
line_set
.colors
= o3d
.utility
.Vector3dVector
(colors
)
o3d
.visualization
.draw_geometries
([point_cloud_o3d
,line_set
])
point_cloud_encode
= (np
.dot
(point_cloud_vector
.T
,point_cloud_raw
.T
)).T
Point_Show
(point_cloud_encode
)
point_cloud_decode
= (np
.dot
(point_cloud_vector
,point_cloud_encode
.T
)).T
Point_Cloud_Show
(point_cloud_decode
)
pcd_tree
= o3d
.geometry
.KDTreeFlann
(point_cloud_o3d
)
normals
= []
print(point_cloud_raw
.shape
[0])
for i
in range(point_cloud_raw
.shape
[0]):
[_
,idx
,_
] = pcd_tree
.search_knn_vector_3d
(point_cloud_o3d
.points
[i
],10)
k_nearest_point
= np
.asarray
(point_cloud_o3d
.points
)[idx
, :]
w
, v
= PCA
(k_nearest_point
)
normals
.append
(v
[:, 2])
normals
= np
.array
(normals
, dtype
=np
.float64
)
point_cloud_o3d
.normals
= o3d
.utility
.Vector3dVector
(normals
)
o3d
.visualization
.draw_geometries
([point_cloud_o3d
])
if __name__
== '__main__':
main
()