如有错误,恳请指出。


从这一篇博客开始,开始利用Open3d来处理点云数据。之后将围绕点云数据的多种处理方式来记录笔记。本篇博客的内容包括点云的文件格式介绍,点云数据的读取,以及点云的配准与点云的法向量计算。

文章目录

  • 1. 点云格式介绍
    • 1.1 pcd文件
    • 1.2 ply文件
    • 1.3 txt文件
    • 1.4 bin文件
  • 2. Open3d读写点云数据
    • 2.1 open3d处理pcd格式数据
    • 2.2 Open3d处理ply格式数据
    • 2.3 点云格式的转换
  • 3. Open3d配准点云数据
    • 3.1 点云配准原理
    • 3.2 Open3d配准实现
    • 3.3 Numpy拼接实现
  • 4. Open3d点云法向量计算

1. 点云格式介绍

常见点云存储方式有pcd、ply、txt、bin文件,下面分别对其进行介绍。

1.1 pcd文件

pcd点云格式是pcl库种常常使用的点云文件格式。一个pcd文件中通常由两部分组成:分别是文件说明和点云数据。 文件说明由11行组成,如下所示。

.PCD v0.7 - Point Cloud Data file format #点云文件说明
VERSION 0.7 #版本说明
FIELDS x y z #每个点组成,参考第一部分点云组成
SIZE 4 4 4 #Fileds种每个数据占用的字节数
TYPE F F F #Fileds数据对应的类型,F表示浮点类型,U表示无符号整型,I表示整型
COUNT 1 1 1 #Fields数据对应的维度
WIDTH 35947 #对于无序点云为点的数量,对于有序点云为一圈点的数量。
HEIGHT 1 #对于无序点云取值默认为1,对于有序点云为垂直方向上的点数,比如多少线雷达
VIEWPOINT 0 0 0 1 0 0 0 #点云获取的视点,用于坐标变换
POINTS 35947 #点的数量
DATA ascii #点云数据的存储类型,0.7版本支持两种存储方式:ascii和binary。

从第12行开始为点云数据,每个点与上面的FIELDS相对应。一般来说,就的点云的x,y,z坐标。pcd格式的点云可视化由于其组成就是xyz坐标,所以可以使用mayavi.mlab来直接显示:mlab.points3d(x, y, z,y, mode="point")

ps:pcd文件的读取方式如下所示

def pcd_read(file_path):lines = []with open(file_path, 'r') as f:lines = f.readlines()return lines
points = pcd_read(file_path)

1.2 ply文件

一个ply文件中通常由两部分组成:分别是文件说明和点云数据。这与pcd文件很像。 文件说明如下组成,如下所示。前3行与最后1行是描述性语句,中间部分主要说明每一行存储的是什么样的数据、数据的数量、属性等。定义元素的组成需要用到element和property两部分,第一部分element定义元素名称和数量,第二部分property逐一列举元素组成和类型。

下面的示例中定义了点的存储名称为vertex,共35947个。后面存储每一个点含5个属性,即每一行由5个数组成;然后定义了面的存储名称是face,共69451个。后面存储每一个面含1个属性,这个属性是一个列表,存储的是每一个点的索引。

文件从end_header结束后为点云数据,每一行存储的数据与element对应,描述结束。随后开始逐一按行列举上述两种元素,第一种元素是35947个点,每行有5个属性,共35947行。第二中元素是69451个面,每行1个属性,共69451行。

ply#声明是ply文件format ascii 1.0 #存储方式comment zipper output#备注说明,解释性描述element vertex 35947 #表示第一种元素构成是顶点,共35947个,下面的property对应点的组成。property float x #点的第一个元素,x,浮点型property float y #点的第二个元素,y,浮点型property float z #点的第三个元素,z,浮点型property float confidence #点的第四个元素,置信度,浮点型property float intensity #点的第五个元素,强度,浮点型element face 69451 #表示第二种元素构成是面,共69451个,下面的property对应面的组成property list uchar int vertex_indices #list uchar 表示面类型,int vertex_indices面中对应上述点的索引end_header #描述结束,下面开始逐一按行列举上述两种元素,第一种元素是35947个点,每行有5个属性,共35947行。同样地,然后开始按行列举上述第二种元素。-0.0378297 0.12794 0.00447467 0.850855 0.5 -0.0447794 0.128887 0.00190497 0.900159 0.5 -0.0680095 0.151244 0.0371953 0.398443 0.5 -0.00228741 0.13015 0.0232201 0.85268 0.5

对于ply文件合适内容,点云的每个点由5个属性构成,前三个属性也是xyz的坐标位置。将xyz坐标提取出来,即可利用mlab进行3d绘图。而描述面属性的数据在可视化操作中是不需要使用到的,所以直接提取描述点的35947行数据即可。如下代码所示:points = pcd_read(file_path)[12:(12+35947)],这里的第12行开始,到之后的35947+12行结束,都是描述点的数据。

ply格式的文件读取方式同pcd格式,不能直接使用numpy.fromfile来读取,只可以通过open函数读取,随后进行一定的数据处理。读取方式:

def pcd_read(file_path):lines = []with open(file_path, 'r') as f:lines = f.readlines()return lines
points = pcd_read(file_path)

1.3 txt文件

txt文件可以说是最朴素简单的点云描述文件了。 txt点云文件与前两篇介绍的pcd和ply点云格式的区别在于,其通常只含点云信息,不含文件说明部分。txt格式的点云文件中的每一行代表一个点,文件中行数即为点的数量。每行数据全部是点的数据,不包含任何的描述信息。行的取值可以是以下几种形式数据的排列组合。
(1)x、y、z:点云的空间坐标。
(2)i:强度值,强度反应了点的密集成度。
(3)r、g、b:rgb色彩信息。
(4)a:a代表alpha(透明度)。
(5)nx、ny、nz:n代表Normal,点云的法向量。

以Pointnet的modelnet40为例,其点云表示方式如下所示x、y、z、normal_x、normal_y、normal_z。样例如下所示:

# 每一行代表一个点的数据
0.208700,0.221100,0.565600,0.837600,-0.019280,0.545900
0.404700,0.080140,-0.002638,0.002952,0.973500,-0.228800
-0.043890,-0.115500,-0.412900,-0.672800,0.679900,-0.291600
-0.525000,0.158200,0.303300,0.000000,-0.413200,0.910600
-0.191700,-0.160900,0.657400,0.228400,-0.071910,0.970900

同样的,由于是txt文件,所以直接使用简单的numpy即可读取txt文件,而上述的pcd,ply需要用open函数的系统操作读取。txt文件的同样只需要读取其xyz坐标信息即可。
读取方式:np.loadtxt()

txt_file = r"E:\workspace\PointCloud\Pointnet2\data\modelnet40_normal_resampled\airplane\airplane_0001.txt"
point = np.loadtxt(txt_file, delimiter=',')

1.4 bin文件

bin文件的存储方式是以二进制形式存储,这带来的好处是读写的速度快,精度不丢失。与txt文件相同,其没有文件的描述信息,只包含点云数据,没有文件的说明部分。但是,txt文件按行存储点的信息,而bin则是将全部数据合并为一个序列,也可以理解为一行。也就是说,读取一个bin文件的输出是一个长串的序列信息,一般需要将其reshape一下,每4个数据为一个点云数据,所以需要reshape成N行4列。样例如下所示:

49.52  22.668  2.051  0.    49.428 22.814  2.05   0.    48.096 22.6582.007  0.05  47.813 22.709  1.999  0.    48.079 23.021  2.012  0.48.211 23.271  2.019  0.    46.677 22.71   1.964  0.    46.437 22.7741.958  0.12  46.075 22.776  1.947  0.18  45.994 22.826  1.945  0.1845.881 22.95   1.944  0.23  45.721 23.05   1.941  0.    45.763 23.2521.945  0.12  45.617 23.358  1.942  0.12  45.667 23.565  1.947  0.1645.65  23.738  1.949  0.28  45.586 23.796  1.948  0.11  45.591 23.9811.951  0.    48.238 25.569  2.055  0.05  43.789 23.385  1.888  0.1443.779 23.556  1.89   0.    43.784 23.737  1.893  0.    43.719 23.881.894  0.    43.987 24.116  1.905  0.    43.024 23.763  1.871  0.

bin文件reshape之后的4列依次是x,y,z的坐标位置,以及反映强度s。所以,直接提取前3列即可用mlab来实现点云的可视化操作。读取方式:np.fromfile()

kitti_file = r'E:\Study\Machine Learning\Dataset3d\kitti\training\velodyne\000100.bin'
points = np.fromfile(file=kitti_file, dtype=np.float32, count=-1).reshape([-1, 4])

总结:以上既是点云数据的4中常见的数据格式,pcd和ply格式具有说明文档,txt和bin格式没有说明文档更加直观。

参考资料:

1. 点云格式介绍(一)
2. 点云格式介绍(二)
3. 点云格式介绍(三)
4. 点云格式介绍(四)


2. Open3d读写点云数据

2.1 open3d处理pcd格式数据

Open3d读取到的点云通常存储到PointCloud类中,如下图所示。下图中points存储了全部的点云坐标,可以用numpy.array转换成矩阵形式。

  • numpy转pcd格式

对于点云矩阵,通常要转换为PointCloud格式才能被Open3d处理,包括存储和点云处理等。

import numpy as np
import open3d
points = np.random.randn(35947, 3)
pcd = open3d.geometry.PointCloud()
pcd.points = open3d.utility.Vector3dVector(points)
  • pcd格式转numpy

Open3d读取pcd格式点云文件的函数为o3d.io.read_point_cloud,读取的点云存储为上图所示的PointCloud类

import open3d as o3dimport numpy as nppcd = o3d.io.read_point_cloud(path)points = np.array(pcd.points) #转为矩阵
  • 保存为pcd格式

保存点云文件的函数为o3d.io.write_point_cloud

import open3d as o3do3d.io.write_point_cloud(path, pcd)
o3d.io.write_point_cloud(path, pcd , write_ascii=True)  # 指定编码方式减少错误,也可以直接打开查看

2.2 Open3d处理ply格式数据

open3d处理ply数据与处理pcd数据是类似的,只是在open3d处理ply数据是转化为TriangleMesh格式,包括存储和点云处理等。也就是说,对于ply点云文件,Open3d读取到的点云通常存储到TriangleMesh类中,vertices存储了全部的点云坐标。一些ply测试文件的下载地址:http://graphics.stanford.edu/data/3Dscanrep/

  • numpy转ply格式
import open3d as o3d
ply = o3d.geometry.TriangleMesh()
ply.vertices = o3d.utility.Vector3dVector(points_array)
  • ply格式转numpy
import open3d
import numpy as np
ply_path = r"E:\Study\Machine Learning\Dataset3d\points_ply\lucy\lucy.ply"
ply = open3d.io.read_triangle_mesh(ply_path)
points = np.array(ply.vertices)
  • 保存为ply格式
import open3d as o3d
o3d.io.write_triangle_mesh(path, ply)
o3d.io.write_triangle_mesh (path, ply, write_ascii=True)   # 指定编码方式减少错误,也可以直接打开查看

2.3 点云格式的转换

在mmdetection3d中提供了一些点云格式转换的工具代码。

  • ply转bin格式
import numpy as np
import pandas as pd
from plyfile import PlyDatadef convert_ply(input_path, output_path):plydata = PlyData.read(input_path)  # read filedata = plydata.elements[0].data  # read datadata_pd = pd.DataFrame(data)  # convert to DataFramedata_np = np.zeros(data_pd.shape, dtype=np.float)  # initialize array to store dataproperty_names = data[0].dtype.names  # read names of propertiesfor i, name in enumerate(property_names):  # read data by propertydata_np[:, i] = data_pd[name]data_np.astype(np.float32).tofile(output_path)convert_ply('./test.ply', './test.bin')
  • off、obj转ply格式

如果你有其他格式的点云文件 (例:off, obj), 你可以使用 trimesh 将它们转化成 ply.

import trimeshdef to_ply(input_path, output_path, original_type):mesh = trimesh.load(input_path, file_type=original_type)  # read filemesh.export(output_path, file_type='ply')  # convert to plyto_ply('./test.obj', './test.ply', 'obj')

参考资料:

1. Open3d读写pcd点云文件
2. Open3d读写ply点云文件
3. mmdetection3d官方文档


3. Open3d配准点云数据

3.1 点云配准原理

  • 配准原理

点云配准本质上是将点云从一个坐标系变换到另一个坐标系。点云配准通常会需要用到两个点云数据。第一类点云数据称为原始点云,用S(source)来表示。第二类点云数据称为目标点云,用T(Target)来表示。配准就是希望这里的原始数据可以对其目标数据的坐标系,让原始点云S在目标点云T的坐标上进行显示。以实现数据的补充。我们可以通过找到点云中具有相似特征的点云来确定坐标的变换关系。例如,同一个物体的点云同时出现在原始点云和目标点云中,并且在两个点云中有特征相似的部分点云,根据这些相似的点云信息来计算出变换关系。

假设原始点云到目标点云发生的是刚体变换,即原始点云通过旋转和平移即可得到目标点云。这里的旋转和平移过程用旋转变换矩阵R和平移变换矩阵T来表示。我们用P(S)表示原始点云中的点,P(T)表示原始点云在目标点云坐标系中的点。那么这种变换关系可以表示为:
P ( T ) = R ⋅ P ( S ) + T P(T) = R·P(S)+T P(T)=R⋅P(S)+T

因此,点云配准的主要任务是计算出旋转矩阵R和平移矩阵T。

  • 迭代最近点算法(Iterative Closest Point, ICP)

第一步:初始化R、T矩阵,根据R、T矩阵可以得到P(T),即原始点云在目标点云坐标系下的坐标。
第二步:在目标点云中寻找与P(T)最近的点,并且距离小于规定的阈值,这个阈值可以自己定义。
第三步:对第二步中匹配到的点计算欧式距离误差,并且通过最小二乘法来优化R、T矩阵。
第四步:将第三步优化后的R、T矩阵带回第一步中,重新进行迭代,直到迭代满足要求后,得到最终优化的R、T矩阵。

  • ICP方法分类

ICP方法可分为点到点(PointToPoint)和点到平面(PointToPlane)两类。

1)PointToPoint:计算P(t)和目标点云T的距离采用点到点之间的距离形式
2)PointToPlane:计算P(t)中点到目标点云T的点所在平面的距离,这里通常需要用到目标点云的法向量。

3.2 Open3d配准实现

在Open3d的open3d.pipelines.registration中,提供了几种点云配准的方法,这里给出代码的参数说明。

def registration_icp(source, target, max_correspondence_distance, init, *args, **kwargs): # real signature unknown; NOTE: unreliably restored from __doc__ """registration_icp(source, target, max_correspondence_distance, init=(with default value), estimation_method=TransformationEstimationPointToPoint without scaling., criteria=ICPConvergenceCriteria class with relative_fitness=1.000000e-06, relative_rmse=1.000000e-06, and max_iteration=30)Function for ICP registrationArgs:source (open3d.geometry.PointCloud): The source point cloud.target (open3d.geometry.PointCloud): The target point cloud.max_correspondence_distance (float): Maximum correspondence points-pair distance.init (numpy.ndarray[numpy.float64[4, 4]], optional): Initial transformation estimation Default value:array([[1., 0., 0., 0.],[0., 1., 0., 0.],[0., 0., 1., 0.],[0., 0., 0., 1.]])estimation_method (open3d.pipelines.registration.TransformationEstimation, optional, default=TransformationEstimationPointToPoint without scaling.): Estimation method. One of (``TransformationEstimationPointToPoint``, ``TransformationEstimationPointToPlane``, ``TransformationEstimationForGeneralizedICP``, ``TransformationEstimationForColoredICP``)criteria (open3d.pipelines.registration.ICPConvergenceCriteria, optional, default=ICPConvergenceCriteria class with relative_fitness=1.000000e-06, relative_rmse=1.000000e-06, and max_iteration=30): Convergence criteriaReturns:open3d.pipelines.registration.RegistrationResult"""

在下面的参考代码中,就是使用了open3d.pipelines.registration这个函数来实现原始点云到目标点云上的配准。参考代码中的happyStandRight_0.ply作为原始点云,对应代码中的point_s1,结果中显示绿色部分点云;happyStandRight_24.ply作为目标点云,对应代码中的point_s2,结果中显示红色部分;原始点云在目标点云上的配准是显示蓝色部分。(以上的颜色是通过控制参数color来实现的)

参考代码:

import open3d
import numpy as np
import mayavi.mlab as mlab# 对两个ply格式的点云数据进行配准
def open3d_registration():ply_path = r"E:\Study\Machine Learning\Dataset3d\points_ply\happy_stand\happyStandRight_0.ply"ply = open3d.io.read_triangle_mesh(ply_path)point_s1 = np.array(ply.vertices)ply_path = r"E:\Study\Machine Learning\Dataset3d\points_ply\happy_stand\happyStandRight_24.ply"ply = open3d.io.read_triangle_mesh(ply_path)point_s2 = np.array(ply.vertices)print(point_s1.shape, point_s2.shape)source = open3d.geometry.PointCloud()source.points = open3d.utility.Vector3dVector(point_s1)target = open3d.geometry.PointCloud()target.points = open3d.utility.Vector3dVector(point_s2)icp = open3d.pipelines.registration.registration_icp(source=source,target=target,max_correspondence_distance=0.2,    # 距离阈值estimation_method=open3d.pipelines.registration.TransformationEstimationPointToPoint())print(icp)source.transform(icp.transformation)points = np.array(source.points)x = points[:, 0]y = points[:, 1]z = points[:, 2]fig = mlab.figure(bgcolor=(0, 0, 0), size=(640, 640))mlab.points3d(x, y, z, x, mode="point", color=(0, 0, 1), figure=fig)   # 蓝色x = point_s1[:, 0]y = point_s1[:, 1]z = point_s1[:, 2]mlab.points3d(x, y, z, x, mode="point", color=(0, 1, 0), figure=fig)   # 绿色x = point_s2[:, 0]y = point_s2[:, 1]z = point_s2[:, 2]mlab.points3d(x, y, z, x, mode="point", color=(1, 0, 0), figure=fig)   # 红色mlab.show()if __name__ == '__main__':open3d_registration()

ps: 这里的 print(icp) 会计算两个重要指标
1)fitness计算重叠区域(内点对应关系/目标点数),越高越好。
2)inlier_rmse计算所有内在对应关系的均方根误差RMSE,越低越好(可以作为最小二乘法的优化指标)。

结果显示:

3.3 Numpy拼接实现

点云拼接主要是把不同的点云拼接到一起。通常,为了获得一个完整物体的三维点云,我们可能会在不同的视点进行数据采集,然后把采集的点云数据拼接到一起。由于视点的不同,所采集到的多个点云的坐标系也会不一致。为了解决坐标系不一致的问题,最可能用到点云配准技术,或者提前知道视点间的坐标关系。

对于上述已经配准好的数据,这里就可以直接将配准好的数据与目标点云进行拼接,实现视角的补充。这里使用最普通的Numpy将两个数据矩阵进行拼接,既两个点云叠加。这会导致点云数据量显著增加。因此可以用一些下采样的方法,或者将距离相近的点合并为一个点。(点云下采样的方法可以有效的减少点云数据,又不至于影响整体效果

参考代码:

def open3d_registration():ply_path = r"E:\Study\Machine Learning\Dataset3d\points_ply\happy_stand\happyStandRight_0.ply"ply = open3d.io.read_triangle_mesh(ply_path)point_s1 = np.array(ply.vertices)ply_path = r"E:\Study\Machine Learning\Dataset3d\points_ply\happy_stand\happyStandRight_24.ply"ply = open3d.io.read_triangle_mesh(ply_path)point_s2 = np.array(ply.vertices)print(point_s1.shape, point_s2.shape)source = open3d.geometry.PointCloud()source.points = open3d.utility.Vector3dVector(point_s1)target = open3d.geometry.PointCloud()target.points = open3d.utility.Vector3dVector(point_s2)icp = open3d.pipelines.registration.registration_icp(source=source,target=target,max_correspondence_distance=0.2,    # 距离阈值estimation_method=open3d.pipelines.registration.TransformationEstimationPointToPoint())print(icp)source.transform(icp.transformation)points = np.array(source.points)# 配准可视化# x = points[:, 0]# y = points[:, 1]# z = points[:, 2]# fig = mlab.figure(bgcolor=(0, 0, 0), size=(640, 640))# mlab.points3d(x, y, z, x, mode="point", color=(0, 0, 1), figure=fig)   # 蓝色## x = point_s1[:, 0]# y = point_s1[:, 1]# z = point_s1[:, 2]# mlab.points3d(x, y, z, x, mode="point", color=(0, 1, 0), figure=fig)   # 绿色## x = point_s2[:, 0]# y = point_s2[:, 1]# z = point_s2[:, 2]# mlab.points3d(x, y, z, x, mode="point", color=(1, 0, 0), figure=fig)   # 红色# mlab.show()# 拼接可视化points = np.concatenate([points, point_s2], axis=0)print(points.shape)x = points[:, 0]y = points[:, 1]z = points[:, 2]fig = mlab.figure(bgcolor=(0, 0, 0), size=(640, 640))mlab.points3d(x, y, z, y, mode="point", figure=fig)  mlab.show()if __name__ == '__main__':open3d_registration()

结果显示:

参考资料:

1. 点云配准(一)— ICP方法
2. 点云配准(二)— python open3d ICP方法


4. Open3d点云法向量计算

上述讲到的ICP中,有一个PointToPlane的方法是计算P(t)中点到目标点云T的点所在平面的距离,就需要用到目标点云的法向量。那么法向量是针对平面而言的,即垂直于平面的向量。因此,对于点云来说,需要先拟合出一个平面,然后才能求出相应的法向量。对于一个点云数据,可以用周围邻近的点来拟合平面。

Open3d使用estimate_normals函数来计算法向量。其参数设置Open3d提供了3中参数搜索的方法(所有计算的法向量模长为1):

open3d.geometry.KDTreeSearchParamKNN(knn=20)                        # 计算近邻的20个点
open3d.geometry.KDTreeSearchParamRadius(radius=0.01)                # 计算指定半径内的点
open3d.geometry.KDTreeSearchParamHybrid(radius=0.01, max_nn=20)     # 同时考虑搜索半径和近邻点个数

Open3d绘制点云draw_geometries的参数说明:

def draw_geometries(*args, **kwargs): # real signature unknown; restored from __doc__"""draw_geometries(*args, **kwargs)Overloaded function.1. draw_geometries(geometry_list, window_name='Open3D', width=1920, height=1080, left=50, top=50, point_show_normal=False, mesh_show_wireframe=False, mesh_show_back_face=False)Function to draw a list of geometry.Geometry objectsArgs:geometry_list (List[open3d.geometry.Geometry]): List of geometries to be visualized.window_name (str, optional, default='Open3D'): The displayed title of the visualization window.width (int, optional, default=1920): The width of the visualization window.height (int, optional, default=1080): The height of the visualization window.left (int, optional, default=50): The left margin of the visualization window.top (int, optional, default=50): The top margin of the visualization window.point_show_normal (bool, optional, default=False): Visualize point normals if set to true.mesh_show_wireframe (bool, optional, default=False): Visualize mesh wireframe if set to true.mesh_show_back_face (bool, optional, default=False): Visualize also the back face of the mesh triangles.Returns:None2. draw_geometries(geometry_list, window_name='Open3D', width=1920, height=1080, left=50, top=50, point_show_normal=False, mesh_show_wireframe=False, mesh_show_back_face=False, lookat, up, front, zoom)Function to draw a list of geometry.Geometry objectsArgs:geometry_list (List[open3d.geometry.Geometry]): List of geometries to be visualized.window_name (str, optional, default='Open3D'): The displayed title of the visualization window.width (int, optional, default=1920): The width of the visualization window.height (int, optional, default=1080): The height of the visualization window.left (int, optional, default=50): The left margin of the visualization window.top (int, optional, default=50): The top margin of the visualization window.point_show_normal (bool, optional, default=False): Visualize point normals if set to true.mesh_show_wireframe (bool, optional, default=False): Visualize mesh wireframe if set to true.mesh_show_back_face (bool, optional, default=False): Visualize also the back face of the mesh triangles.lookat (numpy.ndarray[numpy.float64[3, 1]]): The lookat vector of the camera.up (numpy.ndarray[numpy.float64[3, 1]]): The up vector of the camera.front (numpy.ndarray[numpy.float64[3, 1]]): The front vector of the camera.zoom (float): The zoom of the camera.Returns:None"""pass

法向量计算与可视化代码:

import open3d
import numpy as np
import mayavi.mlab as mlab# 4. 法向量的计算
def open3d_vector_compute():pcd_path = r"E:\Study\Machine Learning\Dataset3d\points_pcd\rabbit.pcd"pcd = open3d.io.read_point_cloud(pcd_path)pcd.estimate_normals(search_param=open3d.geometry.KDTreeSearchParamHybrid(radius=0.01, max_nn=30))normals = np.array(pcd.normals)    # 法向量结果与点云维度一致(N, 3)points = np.array(pcd.points)print(normals.shape, points.shape)# 验证法向量模长为1(模长会有一定的偏差,不完全为1)normals_length = np.sum(normals**2, axis=1)flag = np.equal(np.ones(normals_length.shape, dtype=float), normals_length).all()print('all equal 1:', flag)# 法向量可视化open3d.visualization.draw_geometries([pcd],window_name="Open3d",point_show_normal=True,width=800,   # 窗口宽度height=600)  # 窗口高度if __name__ == '__main__':open3d_vector_compute()

结果展示:

ps:这里的法向量一半是向外,一半是向里的。同时, 点云格式必须设置为pcd格式才能进行法向量计算,ply格式不支持法向量计算。

参考资料:点云法向量

Open3d系列 | 1. Open3d实现点云数据读写、点云配准、点云法向量计算相关推荐

  1. 华云数据荣获“2021中国信创云年度领军企业” 联合发布2022中国“信创云”领域十大趋势

    2021年12月21日,由工信部信发司指导,中国软件网.海比研究院主办,中国软件行业协会应用软件产品云服务分会.中国总会计师协会信息化分会联合主办的"洞见2022 第五届中国企业服务年会&q ...

  2. Trimble RealWorks处理点云数据(三)之点云抽稀取样

    Trimble RealWorks处理点云数据(二)之点云切割 背景 对于点云数据来说,数据量大是常见的事,但是有些软件不能一次加载大量的数据,在某些情况下,是可以通过对点云数据进行抽稀来达到减少点云 ...

  3. Trimble RealWorks处理点云数据(五)之点云裁剪盒模式

    Trimble RealWorks处理点云数据(四)之点云外部分类 效果 背景 有时候我们会扫描室内的点云数据,而从外面是比较难看到室内的情况的,而点云又不能通过透视的方式直接进入室内观察,这时候就可 ...

  4. Open3d系列 | 2. Open3d实现点云数据增强

    如有错误,恳请指出. 在计算机视觉领域中,基于图像已经提出了一系列的数据增强方法.常见图像数据增强方式有平移.缩放.旋转等仿射变换,还有对比度变换等等.那么,对于点云来说,同样可以进行平移缩放与旋转. ...

  5. 云消防大数据_2020年刚需系列专题之智慧消防大数据平台建设方案 智慧消防云平台项目 解决方案,一查就有...

    消防产业关乎国计民生,伴随城镇化进程而逐步成长.根据中国消防协会编撰的<中国消防产业发展现状>,我国消防产业每年的总体规模约为 1000-2000 亿元.消防产业的成长伴随着我国的城镇化进 ...

  6. matlab点云数据dem,一种基于点云数据的DEM生成方法

    第38卷 第5期 2015年 5月 测绘 与空 间地理信 息 GEOMATICS& SPATIAL INFoRMATIoN TECHNOLOGY Vo1.38.No.5 May.,2015 一 ...

  7. Trimble RealWorks处理点云数据(二)之点云切割

    Trimble RealWorks处理点云数据(一)之坐标转换 背景 对于点云数据来说,数据量大是常见的事,但是有些软件不能一次加载大量的数据,所以只能通过切割的方式来减少点云数据量,分块加载,分块加 ...

  8. Trimble RealWorks处理点云数据(六)之点云数据格式转换

    背景 如果我们需要建模,有时候建模软件是不支持直接导入las格式的点云数据,这时候就需要对点云格式做转换,转换成建模软件能支持的格式 步骤 1.las导入Trimble RealWorks 2.导出 ...

  9. python 词云_python词云-数据产品岗位描述的词云

    目的: 对于数据产品岗位,需要什么样的技能才能胜任,针对这个小问题,爬取了boss直聘的岗位描述,进行词频统计,并画出词云,来看看到底数据产品需要什么样的技能.最重要用到的python的库是jieba ...

最新文章

  1. 清华医工结合项目及三创项目与天津市27家重点医院对接
  2. 编写android服务
  3. Windows四大傻X功能——那些拖慢系统性能的罪魁祸首
  4. micropython esp8266教程_(一)ESP8266/nodemcu如何使用MicroPython进行开发
  5. java jar包示例_Java包isCompatibleWith()方法与示例
  6. CentOS7种搭建FTP服务器 1
  7. 10、存储过程、while语句
  8. 树莓派连接usb手机_树莓派03 - 树莓派的VNC连接
  9. 使用TensorFlow.js进行人脸触摸检测第1部分:将实时网络摄像头数据与深度学习配合使用
  10. 今日恐慌与贪婪指数为38 恐慌程度明显上升
  11. 2008已经到来,我们怎能原地踏步!
  12. bzoj 3561: DZY Loves Math VI
  13. Django新手入门(三)——使用PyCharm创建Django项目
  14. C语言把csv文件转xls,Excel怎么批量将CSV格式转换为xlsx或xls格式?VBA、宏、软件?...
  15. TensorFlow Serving 使用 及 部署
  16. Python重试之美, 优雅的Tenacity
  17. linux修改BCD文件,关于BCDEdit 命令的使用
  18. [PPPOE]PPPD源码分析
  19. Python之第六章 内置容器 --- 字典(映射)
  20. 奥维地图怎么标注文字_如何在奥维地图上准确地告诉别人“我在哪?”

热门文章

  1. OSChina 周四乱弹 —— 上帝对我单身年限的惩罚越来越长了
  2. creo绘图属性模板_Proecreo完整制作工程图格式和模板
  3. 云计算等人才成缺口部分岗位年薪超200万元;Canva旗下图库为微信公众号提供创作用图 | 美通企业日报...
  4. 最新场库视频下载方法-最新场库视频下载工具-马赛克视频助手
  5. 2022数据合规与安全论坛
  6. 神威太湖之光是微型计算机,【单选题】国研制的神威·太湖之光计算机是‍ 。 A. 微型计算机 B. 超级计算机 C. 小型计算机 D. 中型计算机...
  7. 一场数字磁爆即将席卷而来,敬请锁定2021戴尔科技峰会!
  8. 国产充电宝品牌排行,国内最好的充电宝品牌推荐
  9. 经典网页收藏夹的实现
  10. Semantic Image Segmentation