当前位置: 首页 > news >正文

Open3D 点云数据处理基础(Python版)

Open3D 点云数据处理基础(Python版)

文章目录

  • 1 概述

  • 2 安装

  • 2.1 PyCharm 与 Python 安装

  • 2.3 Anaconda 安装

  • 2.4 Open3D 0.13.0 安装

  • 2.5 新建一个 Python 项目

  • 3 点云读写

  • 4 点云可视化

  • 2.1 可视化单个点云

  • 2.2 同一窗口可视化多个点云

  • 2.3 可视化的属性设置

  • 5 k-d tree 与 Octree

  • 5.1 k-d tree

  • 5.2 Octree

  • 5.2.1 从点云中构建Octree

  • 5.2.2 从体素栅格中构建Octree

  • 6 点云滤波

  • 6.1 体素下采样

  • 6.2 统计滤波

  • 6.3 半径滤波

  • 7 点云特征提取

  • 7.1 法线估计

  • 8 点云分割

  • 8.1 DBSCAN 聚类分割

  • 8.2 RANSAC 平面分割

  • 8.3 隐藏点剔除

  • 9 点云曲面重建

  • 9.1 Alpha shapes

  • 9.2 Ball pivoting

  • 9.3 Poisson surface reconstruction

  • 9.3.1 直接读取点云的方法

  • 9.3.2 mesh方法

  • 10 点云空间变换

  • 10.1 Translate 平移

  • 10.1.1 指定平移行向量,实现点云平移

  • 10.1.2 将点云质心平移到指定位置

  • 10.2 Rotation 旋转

  • 10.2.1 使用欧拉角旋转

  • 10.2.1.1 未指定旋转中心

  • 10.2.1.2 指定旋转中心

  • 10.2.2 使用轴向角旋转

  • 10.2.3 使用四元数旋转

  • 10.3 Scale 缩放

  • 10.4 General transformation 一般变换(平移+旋转)

  • 11 点云配准

  • 12 其他常用算法

  • 12.1 计算点云间的距离

  • 12.2 计算点云最小包围盒

  • 12.3 计算点云凸包

  • 12.4 点云体素化

  • 12.4.1 一种简单的方法

  • 12.1.2 复杂方法

  • 12.5 计算点云质心

  • 12.6 根据索引提取点云

  • 12.7 点云赋色

历时一个月,Open3D 点云数据处理基础(Python版) 终于初具雏形!目前主要是一些基础内容,后续会继续完善,希望互相学习!


1 概述

Open3D是一个开源库,支持快速开发处理3D数据的软件。Open3D后端是用C++实现的,经过高度优化并通过Python的前端接口公开。Open3D提供了三种数据结构:点云(point cloud)、网格(mesh)和RGB-D图像。对于每个表示,open3D都实现了一整套基本处理算法,如I/O、采样、可视化和数据转换。此外,还包括一些常用的算法,如法线估计、ICP配准等。

open3D包含了九个模块,如下表所示:

模块功能
Geometry 几何模块数据结构和基本处理算法
Camera 相机模块相机模型和相机轨迹
Odometry 里程计模块RGB-D图像的跟踪与对齐
Registration 配准模块全局和局部配准
Integration 积分模块体积积分
I/O 输入输出模块读写3维数据
Visualization 可视化模块使用OpenGL呈现3D数据的可自定义GUI
Utility 辅助功能模块辅助功能,如控制台输出、文件系统和特征包装器
Python 模块Open3D Python绑定和教程

本文旨在快速入门Python点云数据处理,原理性知识会在后续专题中给出,这里不做过多描述。

2 安装

2.1 PyCharm 与 Python 安装

PyCharm Community 2021.2 安装教程(附汉化教程!)

2.3 Anaconda 安装

Anaconda3 2021 安装教程

2.4 Open3D 0.13.0 安装

在成功安装 Anaconda3 之后,在所有应用中找到 Anaconda3,选择 Anaconda Powershell Prompt


打开之后如下所示


手动输入

pip install open3d

开始安装 open3d-0.13.0,需要漫长的等待…


安装成功!

2.5 新建一个 Python 项目

文件 > 新建项目,输入(若路径不存在,则自动创建)或选择位置路径,选择已经由Conda配置好的解释器


新建Python文件


输入新建的Python文件名,按回车完成新建


测试代码

import open3d as o3d import numpy as np print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("test.pcd") print(pcd) print("->正在保存点云") o3d.io.write_point_cloud("write.pcd", pcd, True) # 默认false,保存为Binarty;True 保存为ASICC形式 print(pcd)

3 点云读写

代码:

import open3d as o3d import numpy as np print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("test.pcd") print(pcd) print("->正在保存点云") o3d.io.write_point_cloud("write.pcd", pcd, True) # 默认false,保存为Binarty;True 保存为ASICC形式 print(pcd)

输出结果:

->正在加载点云... 
PointCloud with 356478 points.
->正在保存点云
PointCloud with 356478 points.

默认情况下,Open3D尝试通过文件扩展名推断文件类型。支持以下点云文件类型:

格式描述
xyz每一行包含 [x, y, z], 其中的x, y, z 是三维坐标
xyzn每一行包含 [x, y, z, nx, ny, nz], 其中的 nx, ny, nz 是法线向量
xyzrgb每一行包含 [x, y, z, r, g, b], 其中的 r, g, b 是范围在 [0, 1]的float类型
pts第一行是表示点数的整数。每个后续行包含[x, y, z, i, r, g, b], 其中的 r, g, buint8类型
ply查看 Polygon File Format, ply文件能够同时包含点云和网格数据
pcd查看 Point Cloud Data

也可以显式地指定文件类型。在这种情况下,文件扩展名将被忽略。

pcd = o3d.io.read_point_cloud("../../test_data/my_points.txt", format='xyz')

4 点云可视化

2.1 可视化单个点云

代码:

import open3d as o3d import numpy as np print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("test.pcd") print(pcd) print("->正在可视化点云") o3d.visualization.draw_geometries([pcd])

输出结果:

->正在加载点云... 
PointCloud with 356478 points.
->正在可视化点云

可视化结果展示:

可以通过键盘上的 +-,实时调整点的大小。

2.2 同一窗口可视化多个点云

函数描述:

o3d.visualization.draw_geometries([pcd1, pcd2, ... ,pcdn])

代码:

import open3d as o3d import numpy as np print("->正在加载点云1... ") pcd1 = o3d.io.read_point_cloud("bunny.pcd") print(pcd1) print("->正在加载点云2...") pcd2 = o3d.io.read_point_cloud("bunny0.pcd") print(pcd2) print("->正在同时可视化两个点云...") o3d.visualization.draw_geometries([pcd1, pcd2])

输出结果:

->正在加载点云1... 
PointCloud with 35947 points.
->正在加载点云2...
PointCloud with 35947 points.
->正在同时可视化两个点云...

可视化结果:

2.3 可视化的属性设置

函数原型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)

参数说明

参数名描述
geometry_list要可视化的几何体列表
window_name(str, optional, default='Open3D'),可视化窗口的显示标题
width(int, optional, default=1920),可视化窗口的宽度
height(int, optional, default=1080),可视化窗口的高度
left(int, optional, default=50),可视化窗口的左边距
top(int, optional, default=50),可视化窗口的顶部边距
point_show_normal(bool, optional, default=False),如果设置为true,则可视化点法线,需要事先计算点云法线
mesh_show_wireframe(bool, optional, default=False),如果设置为true,则可视化网格线框
mesh_show_back_face(bool, optional, default=False),可视化网格三角形的背面

函数原型2:

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)

参数说明

参数名描述
geometry_list要可视化的几何体列表
window_name(str, optional, default='Open3D'),可视化窗口的显示标题
width(int, optional, default=1920),可视化窗口的宽度
height(int, optional, default=1080),可视化窗口的高度
left(int, optional, default=50),可视化窗口的左边距
top(int, optional, default=50),可视化窗口的顶部边距
point_show_normal(bool, optional, default=False),如果设置为true,则可视化点法线
mesh_show_wireframe(bool, optional, default=False),如果设置为true,则可视化网格线框
mesh_show_back_face(bool, optional, default=False),可视化网格三角形的背面
lookat(numpy.ndarray[float64[3, 1]]),相机的注视向量
up(numpy.ndarray[float64[3, 1]]),相机的上方向向量
front(numpy.ndarray[float64[3, 1]]),相机的前矢量
zoom(float),相机的缩放倍数

代码:

import open3d as o3d print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("bunny.pcd") print(pcd) # 法线估计 radius = 0.01 # 搜索半径 max_nn = 30 # 邻域内用于估算法线的最大点数 pcd.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius, max_nn)) # 执行法线估计 # 可视化 o3d.visualization.draw_geometries([pcd], window_name = "可视化参数设置", width = 600, height = 450, left = 30, top = 30, point_show_normal = True)

可视化结果:

5 k-d tree 与 Octree

5.1 k-d tree

  • o3d.geometry.KDTreeFlann(pcd):建立 KDTree
  • search_knn_vector_3d(search_Pt, k):K 近邻搜索
  • search_radius_vector_3d(search_Pt, radius):半径 R 近邻搜索
  • search_hybrid_vector_3d(search_pt, radius, max_nn):混合邻域搜索,返回半径 radius 内不超过 max_nn 个近邻点

代码:

import open3d as o3d import numpy as np print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("bunny.pcd") print(pcd) # 将点云设置为灰色 pcd.paint_uniform_color([0.5, 0.5, 0.5]) # 建立KDTree pcd_tree = o3d.geometry.KDTreeFlann(pcd) # 将第1500个点设置为紫色 pcd.colors[1500] = [0.5, 0, 0.5] # 使用K近邻,将第1500个点最近的5000个点设置为蓝色 print("使用K近邻,将第1500个点最近的5000个点设置为蓝色") k = 5000 # 设置K的大小 [num_k, idx_k, _] = pcd_tree.search_knn_vector_3d(pcd.points[1500], k) # 返回邻域点的个数和索引 np.asarray(pcd.colors)[idx_k[1:], :] = [0, 0, 1] # 跳过最近邻点(查询点本身)进行赋色 print("k邻域内的点数为:", num_k) # 使用半径R近邻,将第1500个点半径(0.02)范围内的点设置为红色 print("使用半径R近邻,将第1500个点半径(0.02)范围内的点设置为红色") radius = 0.02 # 设置半径大小 [num_radius, idx_radius, _] = pcd_tree.search_radius_vector_3d(pcd.points[1500], radius) # 返回邻域点的个数和索引 np.asarray(pcd.colors)[idx_radius[1:], :] = [1, 0, 0] # 跳过最近邻点(查询点本身)进行赋色 print("半径r邻域内的点数为:", num_radius) # 使用混合邻域,将半径R邻域内不超过max_num个点设置为绿色 print("使用混合邻域,将第1500个点半径R邻域内不超过max_num个点设置为绿色") max_nn = 200 # 半径R邻域内最大点数 [num_hybrid, idx_hybrid, _] = pcd_tree.search_hybrid_vector_3d(pcd.points[1500], radius, max_nn) np.asarray(pcd.colors)[idx_hybrid[1:], :] = [0, 1, 0] # 跳过最近邻点(查询点本身)进行赋色 print("混合邻域内的点数为:", num_hybrid) print("->正在可视化点云...") o3d.visualization.draw_geometries([pcd])

输出结果:

->正在加载点云... 
PointCloud with 35947 points.
使用K近邻,将第1500个点最近的5000个点设置为蓝色
k邻域内的点数为: 5000
使用半径R近邻,将第1500个点半径(0.02)范围内的点设置为红色
半径r邻域内的点数为: 751
使用混合邻域,将第1500个点半径R邻域内不超过max_num个点设置为绿色
混合邻域内的点数为: 200
->正在可视化点云...

结果展示:

5.2 Octree

八叉树(Octree)是一种树数据结构,其中每个内部节点有八个子节点。八叉树通常用于三维点云的空间划分。八叉树的非空叶节点包含属于同一空间细分的一个或多个点。八叉树是三维空间的有用描述,可用于快速查找附近的点。Open3D具有几何体类型的八叉树,可用于创建、搜索和遍历具有用户指定的最大树深度的八叉树max_depth

5.2.1 从点云中构建Octree

可以使用convert_from_point_cloud方法从点云构造八叉树。通过遵循从根节点到“最大深度”(depth max_depth)处的相应叶节点的路径,将每个点插入到树中。随着树深度的增加,内部(最终是叶子)节点表示三维空间的较小分区。

如果点云具有颜色,则对应的叶节点将采用上次插入点的颜色。size_expand参数会增加根八叉树节点的大小,使其略大于原始点云边界以容纳所有点。

代码:

import open3d as o3d import numpy as np # --------------------------- 加载点云 --------------------------- print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("tree.pcd") print("原始点云:", pcd) # ============================================================== # ------------------------- 构建Octree -------------------------- print('octree 分割') octree = o3d.geometry.Octree(max_depth=4) octree.convert_from_point_cloud(pcd, size_expand=0.01) print("->正在可视化Octree...") o3d.visualization.draw_geometries([octree]) # ==============================================================

输出结果:

->正在加载点云... 
原始点云: PointCloud with 5746 points.
octree 分割
->正在可视化Octree...

结果展示:

5.2.2 从体素栅格中构建Octree

还可以使用create_from_voxel_grid的方法,从Open3D体素网格VoxelGrid几何体构建八叉树。每个体素被视为三维空间中的一个点,坐标对应于体素的原点。每个叶节点采用其相应体素的颜色。

代码:

import open3d as o3d import numpy as np # --------------------------- 加载点云 --------------------------- print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("tree.pcd") print("原始点云:", pcd) # ============================================================== # ------------------------- 构建Octree -------------------------- print('体素化') voxel_grid = o3d.geometry.VoxelGrid.create_from_point_cloud(pcd, voxel_size=0.2) print("体素:", voxel_grid) print("正在可视化体素...") o3d.visualization.draw_geometries([voxel_grid]) print('Octree 分割') octree = o3d.geometry.Octree(max_depth=4) octree.create_from_voxel_grid(voxel_grid) print("Octree:", octree) print("正在可视化Octree...") o3d.visualization.draw_geometries([octree]) # ==============================================================

输出结果:

->正在加载点云... 
原始点云: PointCloud with 5746 points.
体素化
体素: VoxelGrid with 861 voxels.
正在可视化体素...
Octree 分割
Octree: Octree with origin: [64.647, -54.2659, -20.2166], size: 7, max_depth: 4
正在可视化Octree...

可视化结果:

6 点云滤波

6.1 体素下采样

体素下采样使用规则体素栅格从输入点云创建均匀下采样点云。该算法分两步操作:

  • 将点云进行进行体素划分
  • 对所有非空体素,取体素内点云的质心作为该体素的点的位置。

代码:

import open3d as o3d import numpy as np print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("test.pcd") print(pcd) print("->正在可视化原始点云") o3d.visualization.draw_geometries([pcd]) print("->正在体素下采样...") voxel_size = 0.5 downpcd = pcd.voxel_down_sample(voxel_size) print(downpcd) print("->正在可视化下采样点云") o3d.visualization.draw_geometries([downpcd])

输出结果:

->正在加载点云... 
PointCloud with 356478 points.
->正在可视化原始点云
->正在体素下采样...
PointCloud with 11141 points.
->正在可视化下采样点云

可视化展示:

6.2 统计滤波

statistical_outlier_removal 会移除距离相邻点更远的点。它需要两个输入参数:

  • num_neighbors,指定为了计算给定点的平均距离,需要考虑多少个邻居。即K邻域的点数
  • std_ratio,允许根据点云平均距离的标准偏差设置阈值水平。该数值越低,滤除的点数就越多

代码:

import open3d as o3d import numpy as np print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("desk.pcd") print("原始点云:", pcd) # ------------------------- 统计滤波 -------------------------- print("->正在进行统计滤波...") num_neighbors = 20 # K邻域点的个数 std_ratio = 2.0 # 标准差乘数 # 执行统计滤波,返回滤波后的点云sor_pcd和对应的索引ind sor_pcd, ind = pcd.remove_statistical_outlier(num_neighbors, std_ratio) sor_pcd.paint_uniform_color([0, 0, 1]) print("统计滤波后的点云:", sor_pcd) sor_pcd.paint_uniform_color([0, 0, 1]) # 提取噪声点云 sor_noise_pcd = pcd.select_by_index(ind,invert = True) print("噪声点云:", sor_noise_pcd) sor_noise_pcd.paint_uniform_color([1, 0, 0]) # =========================================================== # 可视化统计滤波后的点云和噪声点云 o3d.visualization.draw_geometries([sor_pcd, sor_noise_pcd])

输出结果:

->正在加载点云... 
原始点云: PointCloud with 41049 points.
->正在进行统计滤波...
统计滤波后的点云: PointCloud with 40061 points.
噪声点云: PointCloud with 988 points.

可视化结果:

6.3 半径滤波

radius_outlier_removal 移除给定球体中几乎没有邻居的点。需要两个参数:

num_points,邻域球内的最少点数,低于该值的点为噪声点

radius ,邻域半径的大小

代码:

import open3d as o3d import numpy as np print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("desk.pcd") print("原始点云:", pcd) # ------------------------- 半径滤波 -------------------------- print("->正在进行半径滤波...") num_points = 20 # 邻域球内的最少点数,低于该值的点为噪声点 radius = 0.05 # 邻域半径大小 # 执行半径滤波,返回滤波后的点云sor_pcd和对应的索引ind sor_pcd, ind = pcd.remove_radius_outlier(num_points, radius) sor_pcd.paint_uniform_color([0, 0, 1]) print("半径滤波后的点云:", sor_pcd) sor_pcd.paint_uniform_color([0, 0, 1]) # 提取噪声点云 sor_noise_pcd = pcd.select_by_index(ind,invert = True) print("噪声点云:", sor_noise_pcd) sor_noise_pcd.paint_uniform_color([1, 0, 0]) # =========================================================== # 可视化半径滤波后的点云和噪声点云 o3d.visualization.draw_geometries([sor_pcd, sor_noise_pcd])

输出结果:

->正在加载点云... 
原始点云: PointCloud with 41049 points.
->正在进行半径滤波...
半径滤波后的点云: PointCloud with 40146 points.
噪声点云: PointCloud with 903 points.

可视化结果:

7 点云特征提取

7.1 法线估计

代码:

import open3d as o3d import numpy as np print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("bunny.pcd") print(pcd) print("->正在估计法线并可视化...") radius = 0.01 # 搜索半径 max_nn = 30 # 邻域内用于估算法线的最大点数 pcd.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius, max_nn)) # 执行法线估计 o3d.visualization.draw_geometries([pcd], point_show_normal=True) print("->正在打印前10个点的法向量...") print(np.asarray(pcd.normals)[:10, :])

输出结果:

->正在加载点云... 
PointCloud with 35947 points.
->正在估计法线并可视化...
->正在打印前10个点的法向量...
[[-0.22344398 -0.96962557  0.09949394][-0.30282456 -0.91827757  0.25507564][-0.0930339  -0.77633579 -0.62341594][ 0.06452443 -0.96881599 -0.23923249][ 0.24771039 -0.96349484  0.10157387][ 0.1890532  -0.97541781  0.11322096][-0.26920394 -0.95010988  0.15754506][ 0.72941317  0.51298568  0.45255067][ 0.83949302  0.5402317   0.05831961][-0.32325253  0.62920765  0.7068278 ]]

可视化结果:

8 点云分割

8.1 DBSCAN 聚类分割

Open3D实现了DBSCAN[1996],这是一种基于密度的聚类算法。该算法在cluster_dbscan中实现,需要两个参数:eps 为同一簇内的最大点间距,min_points 定义有效聚类的最小点数。函数返回标签 label,其中label = -1表示噪声。

代码:

import open3d as o3d import numpy as np import matplotlib.pyplot as plt print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("test.pcd") print(pcd) print("->正在DBSCAN聚类...") eps = 0.5 # 同一聚类中最大点间距 min_points = 50 # 有效聚类的最小点数 with o3d.utility.VerbosityContextManager(o3d.utility.VerbosityLevel.Debug) as cm: labels = np.array(pcd.cluster_dbscan(eps, min_points, print_progress=True)) max_label = labels.max() # 获取聚类标签的最大值 [-1,0,1,2,...,max_label],label = -1 为噪声,因此总聚类个数为 max_label + 1 print(f"point cloud has {max_label + 1} clusters") colors = plt.get_cmap("tab20")(labels / (max_label if max_label > 0 else 1)) colors[labels < 0] = 0 # labels = -1 的簇为噪声,以黑色显示 pcd.colors = o3d.utility.Vector3dVector(colors[:, :3]) o3d.visualization.draw_geometries([pcd])

输出结果:

-&gt;正在加载点云... 
PointCloud with 356478 points.
-&gt;正在DBSCAN聚类...
[Open3D DEBUG] Precompute neighbors.
[Open3D DEBUG] Done Precompute neighbors.
[Open3D DEBUG] Compute Clusters
Precompute neighbors.[========================================] 100%
[Open3D DEBUG] Done Compute Clusters: 49
point cloud has 49 clusters

可视化结果:

8.2 RANSAC 平面分割

代码:

import open3d as o3d print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("test.pcd") print(pcd) print("->正在RANSAC平面分割...") distance_threshold = 0.2 # 内点到平面模型的最大距离 ransac_n = 3 # 用于拟合平面的采样点数 num_iterations = 1000 # 最大迭代次数 # 返回模型系数plane_model和内点索引inliers,并赋值 plane_model, inliers = pcd.segment_plane(distance_threshold, ransac_n, num_iterations) # 输出平面方程 [a, b, c, d] = plane_model print(f"Plane equation: {a:.2f}x + {b:.2f}y + {c:.2f}z + {d:.2f} = 0") # 平面内点点云 inlier_cloud = pcd.select_by_index(inliers) inlier_cloud.paint_uniform_color([0, 0, 1.0]) print(inlier_cloud) # 平面外点点云 outlier_cloud = pcd.select_by_index(inliers, invert=True) outlier_cloud.paint_uniform_color([1.0, 0, 0]) print(outlier_cloud) # 可视化平面分割结果 o3d.visualization.draw_geometries([inlier_cloud, outlier_cloud])

输出结果:

-&gt;正在加载点云... 
PointCloud with 356478 points.
-&gt;正在RANSAC平面分割...
Plane equation: -0.00x + -0.00y + 1.00z + -0.27 = 0
PointCloud with 241099 points.
PointCloud with 115379 points.

可视化结果:

8.3 隐藏点剔除

假设您希望从给定的视点渲染点云,但背景中的点会泄漏到前景中,因为它们不会被其他点遮挡。为此,我们可以应用隐藏点移除算法。在Open3D中,实现了[Katz2007] 的方法,该方法从给定视图近似点云的可见性,无需曲面重建或法线估计。

代码:

import open3d as o3d import numpy as np print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("bunny.pcd") print(pcd) print("->正在剔除隐藏点...") diameter = np.linalg.norm(np.asarray(pcd.get_max_bound()) - np.asarray(pcd.get_min_bound())) print("定义隐藏点去除的参数") camera = [0, 0, diameter] # 视点位置 radius = diameter * 100 # 噪声点云半径,The radius of the sperical projection _, pt_map = pcd.hidden_point_removal(camera, radius) # 获取视点位置能看到的所有点的索引 pt_map # 可视点点云 pcd_visible = pcd.select_by_index(pt_map) pcd_visible.paint_uniform_color([0, 0, 1]) # 可视点为蓝色 print("->可视点个数为:", pcd_visible) # 隐藏点点云 pcd_hidden = pcd.select_by_index(pt_map, invert = True) pcd_hidden.paint_uniform_color([1, 0, 0]) # 隐藏点为红色 print("->隐藏点个数为:", pcd_hidden) print("->正在可视化可视点和隐藏点点云...") o3d.visualization.draw_geometries([pcd_visible, pcd_hidden])

输出结果:

-&gt;正在加载点云... 
PointCloud with 35947 points.
-&gt;正在剔除隐藏点...
定义隐藏点去除的参数
-&gt;可视点个数为: PointCloud with 11490 points.
-&gt;正在可视化可视点和隐藏点点云...

可视化结果:

函数原型:

def hidden_point_removal(self, camera_location, radius): # real signature unknown; restored from __doc__ """ hidden_point_removal(self, camera_location, radius) Removes hidden points from a point cloud and returns a mesh of the remaining points. Based on Katz et al. 'Direct Visibility of Point Sets', 2007. Additional information about the choice of radius for noisy point clouds can be found in Mehra et. al. 'Visibility of Noisy Point Cloud Data', 2010. Args: camera_location (numpy.ndarray[float64[3, 1]]): All points not visible from that location will be reomved radius (float): The radius of the sperical projection Returns: Tuple[open3d.geometry.TriangleMesh, List[int]] """ pass

9 点云曲面重建

在许多情况下,我们希望生成密集的三维几何体,即三角形网格。然而,从多视图立体方法或深度传感器中,我们只能获得非结构化点云。要从非结构化输入中获得三角形网格,我们需要执行曲面重建。文献中有几种方法,Open3D目前实现了以下功能:

  • Alpha shapes [Edelsbrunner1983]
  • Ball pivoting [Bernardini1999]
  • Poisson surface reconstruction [Kazhdan2006]

9.1 Alpha shapes

Alpha shapes 是凸壳的推广。正如这里所描述的,我们可以直观地认为Alpha shapes如下:想象一个巨大的冰淇淋,其中包含点S作为硬巧克力块。使用其中一个球形冰淇淋勺,我们可以在不撞到巧克力块的情况下雕刻出冰淇淋块的所有部分,从而甚至在内部雕刻出孔(例如,仅从外部移动勺子无法触及的部分)。我们最终将得到一个(不一定是凸的)对象,该对象以帽、弧和点为边界。如果我们现在把所有的面拉直成三角形和线段,我们就可以直观地描述SAlpha shapes

Open3D实现了 create_from_point_cloud_alpha_shape 方法

代码:

import open3d as o3d import numpy as np # --------------------------- 加载点云 --------------------------- print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("bunny.pcd") print("原始点云:", pcd) # ============================================================== # ------------------------- Alpha shapes ----------------------- alpha = 0.03 print(f"alpha={alpha:.3f}") mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_alpha_shape(pcd, alpha) mesh.compute_vertex_normals() o3d.visualization.draw_geometries([mesh], mesh_show_back_face=True) # ==============================================================

可视化结果:

9.2 Ball pivoting

Ball pivoting(BPA)[Bernardini1999]是一种与Alpha shapes相关的曲面重建方法。直观地说,想象一个具有给定半径的3D球,我们将其落在点云上。如果它击中任何3个点(并且没有穿过这3个点),它将创建一个三角形。然后,该算法从现有三角形的边开始旋转,每当它击中球未落下的3个点时,我们创建另一个三角形。

open3D 对应的函数为 create_from_point_cloud_ball_pivoting

代码:

import open3d as o3d import numpy as np # ---------------------- 定义点云体素化函数 ---------------------- def get_mesh(_relative_path): mesh = o3d.io.read_triangle_mesh(_relative_path) mesh.compute_vertex_normals() return mesh # ============================================================= # ------------------------- Ball pivoting -------------------------- print("->Ball pivoting...") _relative_path = "bunny.ply" # 设置相对路径 N = 2000 # 将点划分为N个体素 pcd = get_mesh(_relative_path).sample_points_poisson_disk(N) o3d.visualization.draw_geometries([pcd]) radii = [0.005, 0.01, 0.02, 0.04] rec_mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_ball_pivoting(pcd, o3d.utility.DoubleVector(radii)) o3d.visualization.draw_geometries([pcd, rec_mesh]) # ==============================================================

可视化结果:

9.3 Poisson surface reconstruction

泊松曲面重建方法[Kazhdan2006]解决了一个正则化优化问题,以获得光滑曲面。因此,泊松曲面重建比上述方法更可取,因为它们会产生非平滑结果,因为点云的点也是生成的三角形网格的顶点,无需任何修改。

Open3D对应的方法为 create_from_point_cloud_poisson,这基本上是Kazhdan代码的包装。该函数的一个重要参数是depth,它定义了用于曲面重建的八叉树的深度,因此表示生成的三角形网格的分辨率。depth值越高,网格的细节就越多。

9.3.1 直接读取点云的方法

代码:

import open3d as o3d import numpy as np # --------------------------- 加载点云 --------------------------- print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("bunny.pcd") print("原始点云:", pcd) # ============================================================== # ------------------------- Ball pivoting -------------------------- print('run Poisson surface reconstruction') radius = 0.001 # 搜索半径 max_nn = 30 # 邻域内用于估算法线的最大点数 pcd.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius, max_nn)) # 执行法线估计 with o3d.utility.VerbosityContextManager(o3d.utility.VerbosityLevel.Debug) as cm: mesh, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson(pcd, depth=12) print(mesh) o3d.visualization.draw_geometries([mesh]) # ==============================================================

可视化结果:

9.3.2 mesh方法

代码:

import open3d as o3d import numpy as np # -------------------------- 定义点云体素化函数 --------------------------- def get_mesh(_relative_path): mesh = o3d.io.read_triangle_mesh(_relative_path) mesh.compute_vertex_normals() return mesh # ===================================================================== # -------------------- Poisson surface reconstruction ------------------ # 加载点云 print("->Poisson surface reconstruction...") _relative_path = "bunny.ply" # 设置相对路径 N = 5000 # 将点划分为N个体素 pcd = get_mesh(_relative_path).sample_points_poisson_disk(N) pcd.normals = o3d.utility.Vector3dVector(np.zeros((1, 3))) # 使现有法线无效 # 法线估计 pcd.estimate_normals() o3d.visualization.draw_geometries([pcd], point_show_normal=True) pcd.orient_normals_consistent_tangent_plane(100) o3d.visualization.draw_geometries([pcd], point_show_normal=True) # 泊松重建 print('run Poisson surface reconstruction') with o3d.utility.VerbosityContextManager( o3d.utility.VerbosityLevel.Debug) as cm: mesh, densities = o3d.geometry.TriangleMesh.create_from_point_cloud_poisson( pcd, depth=9) print(mesh) o3d.visualization.draw_geometries([mesh]) # =====================================================================

可视化结果:

10 点云空间变换

Open3D的几何体类型有多种转换方法。下面将介绍如何使用taranslate平移、rotate旋转、scale缩放和transform变换(旋转+平移)。

10.1 Translate 平移

我们要研究的第一种转换方法是translate。该函数接受两个输入参数:

  • 第一个输入参数为一个三维行向量(tx,ty,tz)
  • 第二个参数为布尔值,默认relative = True,实现点云平移。若设置为relative = False,则将点云质心平移到第一个参数指定的位置
pcd.translate((tx,ty,tz),relative=True)
10.1.1 指定平移行向量,实现点云平移

只输入第一个参数,或者将第二个参数设置为relative = TrueTruerelative可以省略

代码:

import copy # 点云深拷贝 import open3d as o3d # -------------------------- 加载点云 ------------------------ print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("bunny.pcd") print(pcd) print(f'pcd质心:{pcd.get_center()}') # =========================================================== # -------------------------- 点云平移 ------------------------ print("\n->沿X轴平移0.2m") pcd_tx = copy.deepcopy(pcd).translate((0.2, 0, 0)) pcd_tx.paint_uniform_color([1, 0, 0]) print(pcd_tx) print(f'pcd_tx质心:{pcd_tx.get_center()}') print("\n->沿Y轴平移0.2m") pcd_ty = copy.deepcopy(pcd_tx).translate((0, 0.2, 0)) pcd_ty.paint_uniform_color([0, 1, 0]) print(pcd_ty) print(f'pcd_ty质心:{pcd_ty.get_center()}') print("\n->沿X轴平移-0.2m,再沿Y轴平移0.2m") pcd_txy = copy.deepcopy(pcd).translate((-0.2, 0.2, 0)) pcd_txy.paint_uniform_color([0, 0, 1]) print(pcd_txy) print('pcd_txy质心:', pcd_txy.get_center()) # =========================================================== # -------------------------- 可视化 -------------------------- o3d.visualization.draw_geometries([pcd, pcd_tx, pcd_ty, pcd_txy]) # ===========================================================

输出结果:

-&gt;正在加载点云... 
PointCloud with 35947 points.
pcd质心:[-0.02675991  0.09521606  0.00894711]-&gt;沿X轴平移0.2m
PointCloud with 35947 points.
pcd_tx质心:[0.17324009 0.09521606 0.00894711]-&gt;沿Y轴平移0.2m
PointCloud with 35947 points.
pcd_ty质心:[0.17324009 0.29521606 0.00894711]-&gt;沿X轴平移-0.2m,再沿Y轴平移0.2m
PointCloud with 35947 points.
pcd_txy质心: [-0.22675991  0.29521606  0.00894711]

结果展示:

10.1.2 将点云质心平移到指定位置

将第二个参数relative设置为False即可。

代码:

import copy # 点云深拷贝 import open3d as o3d # -------------------------- 加载点云 ------------------------ print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("bunny.pcd") print(pcd) print(f'pcd质心:{pcd.get_center()}') # =========================================================== # -------------------------- 点云平移 ------------------------ print("\n->沿X轴平移0.2m") pcd_tx = copy.deepcopy(pcd).translate((0.2, 0.2, 0.2)) pcd_tx.paint_uniform_color([1, 0, 0]) print(pcd_tx) print(f'pcd_tx质心:{pcd_tx.get_center()}') print("\n->将点云质心平移到指定位置") pcd_new = copy.deepcopy(pcd_tx).translate((0.2, 0.2, 0.2),relative=False) #pcd_new = copy.deepcopy(pcd_tx).translate((0.2, 0.2, 0.2),False) # relative 可以省略 pcd_new.paint_uniform_color([0, 1, 0]) print(pcd_new) print(f'pcd_new:{pcd_new.get_center()}') # =========================================================== # -------------------------- 可视化 -------------------------- o3d.visualization.draw_geometries([pcd, pcd_tx, pcd_new]) # ===========================================================

输出结果:

-&gt;正在加载点云... 
PointCloud with 35947 points.
pcd质心:[-0.02675991  0.09521606  0.00894711]-&gt;沿X轴平移0.2m
PointCloud with 35947 points.
pcd_tx质心:[0.17324009 0.29521606 0.20894711]-&gt;将点云质心平移到指定位置
PointCloud with 35947 points.
pcd_new:[0.2 0.2 0.2]

结果展示:

10.2 Rotation 旋转

Open3D使用rotate进行旋转,接受两个输入参数:

  1. 第一个参数是旋转矩阵R。由于3D中的旋转可以通过多种方式进行参数化,Open3D提供了方便的功能,可以将不同的参数化转换为旋转矩阵:

  2. 使用get_rotation_matrix_from_xyz从欧拉角 Euler angles 中转换(其中,xyz也可以是yzx, zxy, xzy, zyx, 和yxz的形式)

  3. 使用get_rotation_matrix_from_axis_angle从轴角表示法 Axis-angle representation 中转换

  4. 使用get_rotation_matrix_from_quaternion从四参数 Quaternions 中转换

  5. 第二个参数center,若不设置,则围绕点云质心旋转,旋转前后点云质心位置不变

pcd.rotate(R) # 不指定旋转中心

若指定center,则整个点云围绕指定的坐标中心(x,y,z)旋转。旋转前后点云质心位置发生改变

pcd.rotate(R,center=(x,y,z)) # 指定旋转中心
10.2.1 使用欧拉角旋转
10.2.1.1 未指定旋转中心

未指定旋转中心,默认以点云质心为旋转中心,旋转前后点云执行不变。

代码:

import copy # 点云深拷贝 import open3d as o3d import numpy as np # -------------------------- 加载点云 ------------------------ print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("bunny.pcd") print(pcd) pcd.paint_uniform_color([1,0,0]) print("->pcd质心:",pcd.get_center()) # =========================================================== # -------------------------- 点云旋转 ------------------------ print("\n->采用欧拉角进行点云旋转") pcd_EulerAngle = copy.deepcopy(pcd) R1 = pcd.get_rotation_matrix_from_xyz((0,np.pi/2,0)) print("旋转矩阵:\n",R1) pcd_EulerAngle.rotate(R1) # 不指定旋转中心 pcd_EulerAngle.paint_uniform_color([0,0,1]) print("\n->pcd_EulerAngle质心:",pcd_EulerAngle.get_center()) # =========================================================== # -------------------------- 可视化 -------------------------- o3d.visualization.draw_geometries([pcd, pcd_EulerAngle]) # ===========================================================

输出结果:

-&gt;正在加载点云... 
PointCloud with 35947 points.
-&gt;pcd质心: [-0.02675991  0.09521606  0.00894711]-&gt;采用欧拉角进行点云旋转
旋转矩阵:[[ 6.123234e-17  0.000000e+00  1.000000e+00][ 0.000000e+00  1.000000e+00  0.000000e+00][-1.000000e+00  0.000000e+00  6.123234e-17]]-&gt;pcd_EulerAngle质心: [-0.02675991  0.09521606  0.00894711]

结果展示:

10.2.1.2 指定旋转中心

指定旋转中心,旋转前后点云质心改变。

代码:

import copy # 点云深拷贝 import open3d as o3d import numpy as np # -------------------------- 加载点云 ------------------------ print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("bunny.pcd") print(pcd) pcd.paint_uniform_color([1,0,0]) print("->pcd质心:",pcd.get_center()) # =========================================================== # -------------------------- 点云旋转 ------------------------ print("\n->采用欧拉角进行点云旋转") pcd_EulerAngle = copy.deepcopy(pcd) R1 = pcd.get_rotation_matrix_from_xyz((0,np.pi/2,0)) print("旋转矩阵:\n",R1) pcd_EulerAngle.rotate(R1,center = (0.1,0.1,0.1)) # 指定旋转中心 pcd_EulerAngle.paint_uniform_color([0,0,1]) print("\n->pcd_EulerAngle质心:",pcd_EulerAngle.get_center()) # =========================================================== # -------------------------- 可视化 -------------------------- o3d.visualization.draw_geometries([pcd, pcd_EulerAngle]) # ===========================================================

输出结果:

-&gt;正在加载点云... 
PointCloud with 35947 points.
-&gt;pcd质心: [-0.02675991  0.09521606  0.00894711]-&gt;采用欧拉角进行点云旋转
旋转矩阵:[[ 6.123234e-17  0.000000e+00  1.000000e+00][ 0.000000e+00  1.000000e+00  0.000000e+00][-1.000000e+00  0.000000e+00  6.123234e-17]]-&gt;pcd_EulerAngle质心: [0.00894711 0.09521606 0.22675991]

结果展示:

10.2.2 使用轴向角旋转
10.2.3 使用四元数旋转

10.3 Scale 缩放

使用rotate函数实现点云缩放,接受两个输入参数:

  • 缩放倍数
  • 缩放后点云质心center,不可省略。
pcd_scale.rotate(2,center=pcd.get_center()) # 缩放前后质心一致
pcd_scale.rotate(2,center=(x,y,z)) # 缩放后质心为(x,y,z)

代码:

import copy # 点云深拷贝 import open3d as o3d import numpy as np # -------------------------- 加载点云 ------------------------ print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("circle.pcd") print(pcd) pcd.paint_uniform_color([1,0,0]) print("->pcd质心:",pcd.get_center()) # =========================================================== # -------------------------- 点云缩放 ------------------------ print("\n->点云缩放") pcd_scale1 = copy.deepcopy(pcd) pcd_scale1.scale(1.5,center=pcd.get_center()) pcd_scale1.paint_uniform_color([0,0,1]) print("->pcd_scale1质心:",pcd_scale1.get_center()) # 缩放前后质心不变 pcd_scale2 = copy.deepcopy(pcd) pcd_scale2.scale(0.5,center=(1,1,1)) # 自定义缩放后的质心 pcd_scale2.paint_uniform_color([0,1,0]) print("->pcd_scale2质心:",pcd_scale2.get_center()) # =========================================================== # -------------------------- 可视化 -------------------------- o3d.visualization.draw_geometries([pcd, pcd_scale1,pcd_scale2]) # ===========================================================

输出结果:

-&gt;正在加载点云... 
PointCloud with 63 points.
-&gt;pcd质心: [1.01066824 1.99955513 0.        ]-&gt;点云缩放
-&gt;pcd_scale1质心: [1.01066824 1.99955513 0.        ]
-&gt;pcd_scale2质心: [1.00533412 1.49977756 0.5       ]

结果展示:

10.4 General transformation 一般变换(平移+旋转)

使用transform实现点云的一般变换,接受1个输入参数,为4×4变换矩阵,前3行3列为旋转矩阵,第4列前3行为平移向量。

代码:

import copy # 点云深拷贝 import open3d as o3d import numpy as np # -------------------------- 加载点云 ------------------------ print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("circle.pcd") print(pcd) pcd.paint_uniform_color([1,0,0]) print("->pcd质心:",pcd.get_center()) # =========================================================== # -------------------------- transform ------------------------ print("\n->点云的一般变换") pcd_T = copy.deepcopy(pcd) T = np.eye(4) T[ :3, :3] = pcd.get_rotation_matrix_from_xyz((np.pi/6,np.pi/4,0)) # 旋转矩阵 T[0,3] = 5.0 # 平移向量的dx T[1,3] = 3.0 # 平移向量的dy print("\n->变换矩阵:\n",T) pcd_T.transform(T) pcd_T.paint_uniform_color([0,0,1]) print("\n->pcd_scale1质心:",pcd_T.get_center()) # =========================================================== # -------------------------- 可视化 -------------------------- o3d.visualization.draw_geometries([pcd, pcd_T]) # ===========================================================

输出结果:

-&gt;正在加载点云... 
PointCloud with 63 points.
-&gt;pcd质心: [1.01066824 1.99955513 0.        ]-&gt;点云的一般变换-&gt;变换矩阵:[[ 0.70710678  0.          0.70710678  5.        ][ 0.35355339  0.8660254  -0.35355339  3.        ][-0.61237244  0.5         0.61237244  0.        ][ 0.          0.          0.          1.        ]]-&gt;pcd_scale1质心: [5.71465037 5.08899072 0.38087219]

结果展示:

11 点云配准

12 其他常用算法

12.1 计算点云间的距离

函数介绍:

Open3D提供了compute_point_cloud_distance方法来计算从源点云到目标点云的距离。它为源点云中的每个点计算到目标点云中最近点的距离。

代码:

import open3d as o3d import numpy as np print("->正在加载点云1... ") pcd1 = o3d.io.read_point_cloud("bunny.pcd") print(pcd1) print("->正在加载点云2...") pcd2 = o3d.io.read_point_cloud("test.pcd") print(pcd2) print("->正在点云1每一点到点云2的最近距离...") dists = pcd1.compute_point_cloud_distance(pcd2) dists = np.asarray(dists) print("->正在打印前10个点...") print(dists[:10]) print("->正在提取距离大于3.56的点") ind = np.where(dists > 3.56)[0] pcd3 = pcd1.select_by_index(ind) print(pcd3) o3d.visualization.draw_geometries([pcd3])

输出结果:

-&gt;正在加载点云1... 
PointCloud with 35947 points.
-&gt;正在加载点云2...
PointCloud with 356478 points.
-&gt;正在点云1每一点到点云2的最近距离...
-&gt;正在打印前10个点...
[3.56774778 3.57472048 3.58922401 3.53018802 3.55273519 3.555428313.56749706 3.49795738 3.49527627 3.55416983]
-&gt;正在提取距离大于3.56的点
PointCloud with 19935 points.

可视化结果:

12.2 计算点云最小包围盒

函数介绍:

代码:

import open3d as o3d import numpy as np print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("bunny.pcd") print(pcd) print("->正在计算点云轴向最小包围盒...") aabb = pcd.get_axis_aligned_bounding_box() aabb.color = (1, 0, 0) print("->正在计算点云最小包围盒...") obb = pcd.get_oriented_bounding_box() obb.color = (0, 1, 0) o3d.visualization.draw_geometries([pcd, aabb, obb])

输出结果:

-&gt;正在加载点云... 
PointCloud with 35947 points.
-&gt;正在计算点云轴向最小包围盒...
-&gt;正在计算点云最小包围盒...

可视化结果:

12.3 计算点云凸包

点云的凸包是包含所有点的最小凸集。Open3D 包含计算点云凸包的 compute_convex_hull 方法。该实现基于Qhull。

代码:

import open3d as o3d import numpy as np print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("bunny.pcd") print(pcd) print("->正在计算点云凸包...") hull, _ = pcd.compute_convex_hull() hull_ls = o3d.geometry.LineSet.create_from_triangle_mesh(hull) hull_ls.paint_uniform_color((1, 0, 0)) o3d.visualization.draw_geometries([pcd, hull_ls])

输出结果:

-&gt;正在加载点云... 
PointCloud with 35947 points.
-&gt;正在计算点云凸包...

可视化结果:

12.4 点云体素化

12.4.1 一种简单的方法

代码:

import open3d as o3d import numpy as np # --------------------------- 加载点云 --------------------------- print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("bunny.ply") print("原始点云:", pcd) # ============================================================== # --------------------------- 体素化点云 ------------------------- print('执行体素化点云') voxel_grid = o3d.geometry.VoxelGrid.create_from_point_cloud(pcd, voxel_size=0.005) print("正在可视化体素...") o3d.visualization.draw_geometries([voxel_grid]) # ==============================================================

输出结果:

-&gt;正在加载点云... 
原始点云: PointCloud with 35947 points.
执行体素化点云
正在可视化体素...

可视化结果:

12.1.2 复杂方法

代码:

import open3d as o3d import numpy as np # ---------------------- 定义点云体素化函数 ---------------------- def get_mesh(_relative_path): mesh = o3d.io.read_triangle_mesh(_relative_path) mesh.compute_vertex_normals() return mesh # ============================================================= # ------------------------- 点云体素化 -------------------------- print("->正在进行点云体素化...") _relative_path = "bunny.ply" # 设置相对路径 N = 2000 # 将点划分为N个体素 pcd = get_mesh(_relative_path).sample_points_poisson_disk(N) # fit to unit cube pcd.scale(1 / np.max(pcd.get_max_bound() - pcd.get_min_bound()), center=pcd.get_center()) pcd.colors = o3d.utility.Vector3dVector(np.random.uniform(0, 1, size=(N, 3))) print("体素下采样点云:", pcd) print("正在可视化体素下采样点云...") o3d.visualization.draw_geometries([pcd]) print('执行体素化点云') voxel_grid = o3d.geometry.VoxelGrid.create_from_point_cloud(pcd, voxel_size=0.05) print("正在可视化体素...") o3d.visualization.draw_geometries([voxel_grid]) # ===========================================================

输出结果:

-&gt;正在进行点云体素化...
体素下采样点云: PointCloud with 2000 points.
正在可视化体素下采样点云...
执行体素化点云
正在可视化体素...

可视化结果:

get_mesh 函数参考代码*:

open3d_tutorial.py

# Helpers and monkey patches for ipynb tutorials import open3d as o3d import numpy as np import PIL.Image import IPython.display import os import urllib import tarfile import gzip import zipfile import shutil interactive = True def jupyter_draw_geometries( geoms, 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=None, up=None, front=None, zoom=None, ): vis = o3d.visualization.Visualizer() vis.create_window( window_name=window_name, width=width, height=height, left=left, top=top, visible=True, # If false, capture_screen_float_buffer() won't work. ) vis.get_render_option().point_show_normal = point_show_normal vis.get_render_option().mesh_show_wireframe = mesh_show_wireframe vis.get_render_option().mesh_show_back_face = mesh_show_back_face for geom in geoms: vis.add_geometry(geom) if lookat is not None: vis.get_view_control().set_lookat(lookat) if up is not None: vis.get_view_control().set_up(up) if front is not None: vis.get_view_control().set_front(front) if zoom is not None: vis.get_view_control().set_zoom(zoom) if interactive: vis.run() else: for geom in geoms: vis.update_geometry(geom) vis.poll_events() vis.update_renderer() im = vis.capture_screen_float_buffer() vis.destroy_window() im = (255 * np.asarray(im)).astype(np.uint8) IPython.display.display(PIL.Image.fromarray(im, "RGB")) o3d.visualization.draw_geometries = jupyter_draw_geometries def edges_to_lineset(mesh, edges, color): ls = o3d.geometry.LineSet() ls.points = mesh.vertices ls.lines = edges colors = np.empty((np.asarray(edges).shape[0], 3)) colors[:] = color ls.colors = o3d.utility.Vector3dVector(colors) return ls def _relative_path(path): script_path = os.path.realpath(__file__) script_dir = os.path.dirname(script_path) return os.path.join(script_dir, path) def download_fountain_dataset(): fountain_path = _relative_path("../TestData/fountain_small") fountain_zip_path = _relative_path("../TestData/fountain.zip") if not os.path.exists(fountain_path): print("downloading fountain dataset") url = "https://storage.googleapis.com/isl-datasets/open3d-dev/fountain.zip" urllib.request.urlretrieve(url, fountain_zip_path) print("extract fountain dataset") with zipfile.ZipFile(fountain_zip_path, "r") as zip_ref: zip_ref.extractall(os.path.dirname(fountain_path)) os.remove(fountain_zip_path) return fountain_path def get_non_manifold_edge_mesh(): verts = np.array( [[-1, 0, 0], [0, 1, 0], [1, 0, 0], [0, -1, 0], [0, 0, 1]], dtype=np.float64, ) triangles = np.array([[0, 1, 3], [1, 2, 3], [1, 3, 4]]) mesh = o3d.geometry.TriangleMesh() mesh.vertices = o3d.utility.Vector3dVector(verts) mesh.triangles = o3d.utility.Vector3iVector(triangles) mesh.compute_vertex_normals() mesh.rotate( mesh.get_rotation_matrix_from_xyz((np.pi / 4, 0, np.pi / 4)), center=mesh.get_center(), ) return mesh def get_non_manifold_vertex_mesh(): verts = np.array( [ [-1, 0, -1], [1, 0, -1], [0, 1, -1], [0, 0, 0], [-1, 0, 1], [1, 0, 1], [0, 1, 1], ], dtype=np.float64, ) triangles = np.array([ [0, 1, 2], [0, 1, 3], [1, 2, 3], [2, 0, 3], [4, 5, 6], [4, 5, 3], [5, 6, 3], [4, 6, 3], ]) mesh = o3d.geometry.TriangleMesh() mesh.vertices = o3d.utility.Vector3dVector(verts) mesh.triangles = o3d.utility.Vector3iVector(triangles) mesh.compute_vertex_normals() mesh.rotate( mesh.get_rotation_matrix_from_xyz((np.pi / 4, 0, np.pi / 4)), center=mesh.get_center(), ) return mesh def get_open_box_mesh(): mesh = o3d.geometry.TriangleMesh.create_box() mesh.triangles = o3d.utility.Vector3iVector(np.asarray(mesh.triangles)[:-2]) mesh.compute_vertex_normals() mesh.rotate( mesh.get_rotation_matrix_from_xyz((0.8 * np.pi, 0, 0.66 * np.pi)), center=mesh.get_center(), ) return mesh def get_intersecting_boxes_mesh(): mesh0 = o3d.geometry.TriangleMesh.create_box() T = np.eye(4) T[:, 3] += (0.5, 0.5, 0.5, 0) mesh1 = o3d.geometry.TriangleMesh.create_box() mesh1.transform(T) mesh = mesh0 + mesh1 mesh.compute_vertex_normals() mesh.rotate( mesh.get_rotation_matrix_from_xyz((0.7 * np.pi, 0, 0.6 * np.pi)), center=mesh.get_center(), ) return mesh def get_armadillo_mesh(): armadillo_path = _relative_path("../TestData/Armadillo.ply") if not os.path.exists(armadillo_path): print("downloading armadillo mesh") url = "http://graphics.stanford.edu/pub/3Dscanrep/armadillo/Armadillo.ply.gz" urllib.request.urlretrieve(url, armadillo_path + ".gz") print("extract armadillo mesh") with gzip.open(armadillo_path + ".gz", "rb") as fin: with open(armadillo_path, "wb") as fout: shutil.copyfileobj(fin, fout) os.remove(armadillo_path + ".gz") mesh = o3d.io.read_triangle_mesh(armadillo_path) mesh.compute_vertex_normals() return mesh def get_bunny_mesh(): bunny_path = _relative_path("../TestData/Bunny.ply") if not os.path.exists(bunny_path): print("downloading bunny mesh") url = "http://graphics.stanford.edu/pub/3Dscanrep/bunny.tar.gz" urllib.request.urlretrieve(url, bunny_path + ".tar.gz") print("extract bunny mesh") with tarfile.open(bunny_path + ".tar.gz") as tar: tar.extractall(path=os.path.dirname(bunny_path)) shutil.move( os.path.join( os.path.dirname(bunny_path), "bunny", "reconstruction", "bun_zipper.ply", ), bunny_path, ) os.remove(bunny_path + ".tar.gz") shutil.rmtree(os.path.join(os.path.dirname(bunny_path), "bunny")) mesh = o3d.io.read_triangle_mesh(bunny_path) mesh.compute_vertex_normals() return mesh def get_knot_mesh(): mesh = o3d.io.read_triangle_mesh(_relative_path("../TestData/knot.ply")) mesh.compute_vertex_normals() return mesh def get_eagle_pcd(): path = _relative_path("../TestData/eagle.ply") if not os.path.exists(path): print("downloading eagle pcl") url = "http://www.cs.jhu.edu/~misha/Code/PoissonRecon/eagle.points.ply" urllib.request.urlretrieve(url, path) pcd = o3d.io.read_point_cloud(path) return pcd

12.5 计算点云质心

使用get_center() 实现点云质心计算

代码:

import open3d as o3d print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("tree.pcd") print(pcd) print(f'pcd质心:{pcd.get_center()}')

输出结果:

-&gt;正在加载点云... 
PointCloud with 5746 points.
pcd质心:[ 66.36420378 -52.42476729 -15.28512276]

pcl点云质心计算结果:

-&gt;点云质心为:(66.3642, -52.4248, -15.2851)

12.6 根据索引提取点云

函数原型:

select_by_index(self, indices, invert=False)

代码:

import open3d as o3d import numpy as np print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("desk.pcd") print(pcd) """------------------- 根据索引提取点云 --------------------""" print("->正在根据索引提取点云...") idx = list(range(20000)) # 生成 从0到19999的列表 # 索引对应的点云(内点) inlier_pcd = pcd.select_by_index(idx) inlier_pcd.paint_uniform_color([1, 0, 0]) print("内点点云:", inlier_pcd) # 索引外的点云(外点) outlier_pcd = pcd.select_by_index(idx, invert=True) # 对索引取反 outlier_pcd.paint_uniform_color([0, 1, 0]) print("外点点云:", outlier_pcd) o3d.visualization.draw_geometries([inlier_pcd, outlier_pcd]) """========================================================"""

输出结果:

-&gt;正在加载点云... 
PointCloud with 41049 points.
-&gt;正在根据索引提取点云...
内点点云: PointCloud with 20000 points.
外点点云: PointCloud with 21049 points.

可视化结果:

源码:

def select_by_index(self, indices, invert=False): # real signature unknown; restored from __doc__ """ select_by_index(self, indices, invert=False) Function to select points from input pointcloud into output pointcloud. Args: indices (List[int]): Indices of points to be selected. invert (bool, optional, default=False): Set to ``True`` to invert the selection of indices. Returns: open3d.geometry.PointCloud """ pass

12.7 点云赋色

赋色函数:

paint_uniform_color :将点云进行单一颜色赋值,为RGB颜色空间,R、G、B分量的范围为[0,1],注意不是[0,255]

代码:

import open3d as o3d import numpy as np print("->正在加载点云... ") pcd = o3d.io.read_point_cloud("bunny.pcd") print(pcd) print("->正在点云赋色...") pcd.paint_uniform_color([1,0.706,0]) print("->正在可视化赋色后的点云...") o3d.visualization.draw_geometries([pcd]) print("->正在保存赋色后的点云") o3d.io.write_point_cloud("color.pcd", pcd, True) # 默认false,保存为Binarty;True 保存为ASICC形式

输出结果:

-&gt;正在加载点云... 
PointCloud with 35947 points.
-&gt;正在点云赋色...
-&gt;正在可视化赋色后的点云...
-&gt;正在保存赋色后的点云

可视化结果:

相关文章:

Open3D 点云数据处理基础(Python版)

Open3D 点云数据处理基础&#xff08;Python版&#xff09; 文章目录 1 概述 2 安装 2.1 PyCharm 与 Python 安装 2.3 Anaconda 安装 2.4 Open3D 0.13.0 安装 2.5 新建一个 Python 项目 3 点云读写 4 点云可视化 2.1 可视化单个点云 2.2 同一窗口可视化多个点云 2.3…...

使用vue-qr,报错in ./node_modules/vue-qr/dist/vue-qr.js

找到node_modules—>vue-qr/dist/vue-qr.js文件&#xff0c;搜…e,将…去掉&#xff0c;然后重新运行项目。...

百川2大模型微调问题解决

之前用https://github.com/FlagAlpha/Llama2-Chinese微调过几个模型&#xff0c;总体来说llama2的生态还是比较好的&#xff0c;过程很顺利。微调百川2就没那么顺利了&#xff0c;所以简单做个记录 1. 数据准备&#xff0c;我的数据是单轮对话&#xff0c;之前微调llama2已经按…...

MySQL的事务-原子性

MySQL的事务处理具有ACID的特性&#xff0c;即原子性&#xff08;Atomicity)、一致性&#xff08;Consistency&#xff09;、隔离性&#xff08;Isolation&#xff09;和持久性&#xff08;Durability&#xff09;。 1. 原子性指的是事务中所有操作都是原子性的&#xff0c;要…...

D3839|完全背包

完全背包&#xff1a; 首先01背包的滚动数组中的解法是内嵌的循环是从大到小遍历&#xff0c;为了保证每个物品仅被添加一次。 for(int i 0; i < weight.size(); i) { // 遍历物品for(int j bagWeight; j > weight[i]; j--) { // 遍历背包容量dp[j] max(dp[j], dp[j…...

Java之Synchronized与锁升级

Synchronized与锁升级 一、概述 在多线程并发编程中 synchronized 一直是元老级角色&#xff0c;很多人都会称呼它为重量级锁。但是&#xff0c;随着 Java SE 1.6 对 synchronized 进行了各种优化之后&#xff0c;有些情况下它就并不那么重了。 本文详细介绍 Java SE 1.6 中为…...

kitex出现:open conf/test/conf.yaml: no such file or directory

open conf/test/conf.yaml: no such file or directory https://github.com/cloudwego/cwgo/issues/120 https://github.com/cloudwego/cwgo/issues/29 在使用Kitex生成的代码中&#xff0c;单元测试时回报错&#xff0c;如标题所示。出现该错的原因是&#xff0c;biz/servic…...

sql server多表查询

查询目标 现在有学生表和学生选课信息表&#xff0c;stu和stuSelect&#xff0c;stu中包含学生用户名、名字&#xff0c;stuSelect表中包含学生用户名&#xff0c;所选课程名 学生表&#xff1a; nameusername李明Li Ming李华Li Hua 学生选课表&#xff1a; usernameCourse…...

如何利用PPT绘图并导出清晰图片

在写论文的过程中&#xff0c;免不了需要绘图&#xff0c;但是visio等软件绘图没有在ppt上绘图比较熟练&#xff0c;尤其流程图结构图. 但是ppt导出的图片也不够清晰&#xff0c;默认分辨率是96dpi&#xff0c;而杂志投稿一般要求至300dpi。解决办法如下&#xff1a; 1.打开注…...

1.倒排索引 2.逻辑斯提回归算法

1.倒排索引 https://help.aliyun.com/zh/open-search/retrieval-engine-edition/introduction-to-inverted-indexes 倒排索引&#xff08;Inverted Index&#xff09;是一种数据结构&#xff0c;用于快速查找包含某个特定词或词语的文档。它主要用于全文搜索引擎等应用&#…...

Kafka消费者组

消费者总体工作流程 Consumer Group&#xff08;CG&#xff09;&#xff1a;消费者组&#xff0c;由多个consumer组成。形成一个消费者组的条件&#xff0c;是所有消费者的groupid相同。 • 消费者组内每个消费者负责消费不同分区的数据&#xff0c;一个分区只能由一个组内消费…...

四. 基于环视Camera的BEV感知算法-BEVDepth

目录 前言0. 简述1. 算法动机&开创性思路2. 主体结构3. 损失函数4. 性能对比总结下载链接参考 前言 自动驾驶之心推出的《国内首个BVE感知全栈系列学习教程》&#xff0c;链接。记录下个人学习笔记&#xff0c;仅供自己参考 本次课程我们来学习下课程第四章——基于环视Cam…...

CentOS系统环境搭建(二十五)——使用docker compose安装mysql

centos系统环境搭建专栏&#x1f517;点击跳转 文章目录 使用docker compose安装mysqlMySQL81.新建文件夹2.创建docker-compose.yaml3.创建my.cnf4.mysql容器的启动和关闭 MySQL5.71.新建文件夹2.创建docker-compose.yaml3.创建my.cnf4.mysql容器的启动和关闭 使用docker comp…...

协作机器人(Collaborative-Robot)安全碰撞的速度与接触力

协作机器人&#xff08;Collaborative-Robot&#xff09;的安全碰撞速度和接触力是一个非常重要的安全指标。在设计和使用协作机器人时&#xff0c;必须确保其与人类或其他物体的碰撞不会对人员造成伤害。 对于协作机器人的安全碰撞速度&#xff0c;一般会设定一个上限值&…...

第11章 GUI Page400~402 步骤二 画直线

运行效果&#xff1a; 源代码&#xff1a; /**************************************************************** Name: wxMyPainterApp.h* Purpose: Defines Application Class* Author: yanzhenxi (3065598272qq.com)* Created: 2023-12-21* Copyright: yanzhen…...

华为gre隧道全部跑静态路由

最终实现&#xff1a; 1、pc1能用nat上网ping能pc3 2、pc1能通过gre访问pc2 3、全部用静态路由做&#xff0c;没有用ospf&#xff0c;如果要用ospf&#xff0c;那么两边除了路由器上跑ospf&#xff0c;核心交换机也得用ospf r2配置&#xff1a; acl number 3000 rule 5 deny…...

【c++】入门1

c关键字 命名空间 在C/C中&#xff0c;变量、函数和后面要学到的类都是大量存在的&#xff0c;这些变量、函数和类的名称将都存在于全局作用域中&#xff0c;可能会导致很多冲突。使用命名空间的目的是对标识符的名称进行本地化&#xff0c;以避免命名冲突或名字污染&#xff…...

Python之Django项目的功能配置

1.创建Django项目 进入项目管理目录&#xff0c;比如&#xff1a;D盘 执行命令&#xff1a;diango-admin startproject demo1 创建项目 如果提示diango命令不存在&#xff0c;搜索diango-admin程序的位置&#xff0c;然后加入到环境变量path中。 进入项目&#xff0c;cd demo…...

P4 音频知识点——PCM音频原始数据

目录 前言 01 PCM音频原始数据 1.1 频率 1.2 振幅&#xff1a; 1.3 比特率 1.4 采样 1.5 量化 1.6 编码 02. PCM数据有以下重要的参数&#xff1a; 采样率&#xff1a; 采集深度 通道数 ​​​​​​​ PCM比特率 ​​​​​​​ PCM文件大小计算&#xff1a; ​…...

解决Electron中WebView加载部分HTTPS页面白屏的方法

Electron是一个开源的桌面应用程序框架&#xff0c;它允许使用Web技术构建跨平台的桌面应用。在Electron应用中&#xff0c;WebView 是一个常用的组件&#xff0c;用于嵌套加载Web内容。然而&#xff0c;有时候在加载使用 HTTPS 协议的页面时&#xff0c;可能会因为证书问题导致…...

【Java中创建对象的方式有哪些?】

✅Java中创建对象的方式有哪些&#xff1f; ✅使用New关键字✅使用反射机制✅使用clone方法✅使用反序列化✅使用方法句柄✅ 使用Unsafe分配内存 ✅使用New关键字 这是我们最常见的也是最简单的创建对象的方式&#xff0c;通过这种方式我们还可以调用任意的构造函数 (无参的和有…...

npm使用详解(好吧好吧是粗解)

目录 npm是什么&#xff1f; npm有什么用&#xff1f; npm安装 在 Windows 上 在 macOS 上 在 Linux 上&#xff08;使用 apt 包管理器为例&#xff09; 验证 npm 安装成功&#xff1a; npm使用 1. 初始化项目&#xff1a; 2. 安装和管理依赖&#xff1a; 3. 查看和…...

uniapp自定义头部导航怎么实现?

一、在pages.json文件里边写上自定义属性 "navigationStyle": "custom" 二、在对应的index页面写上以下&#xff1a; <view :style"{ height: headheight px, backgroundColor: #24B7FF, zIndex: 99, position: fixed, top: 0px, width: 100% …...

什么是 Dubbo?它有哪些核心功能?

文章目录 什么是 Dubbo&#xff1f;它有哪些核心功能&#xff1f; 什么是 Dubbo&#xff1f;它有哪些核心功能&#xff1f; Dubbo 是一款高性能、轻量级的开源 RPC 框架。由 10 层模式构成&#xff0c;整个分层依赖由上至下。 通过这张图我们也可以将 Dubbo 理解为三层模式&…...

(2021|CoRR,AugCLIP,优化)FuseDream:通过改进的 CLIP+GAN 空间优化实现免训练文本到图像生成

FuseDream: Training-Free Text-to-Image Generation with Improved CLIPGAN Space Optimization 公众&#xff1a;EDPJ&#xff08;添加 VX&#xff1a;CV_EDPJ 或直接进 Q 交流群&#xff1a;922230617 获取资料&#xff09; 目录 0. 摘要 1. 简介 2. CLIPGAN 文本到图…...

python pip安装依赖的常用软件源

目录 引言 一、什么是镜像源&#xff1f;​​​​​​​ 二、清华源 三、阿里源 四、中科大源 五、豆瓣源 六、更多资源 引言 在软件开发和使用过程中&#xff0c;我们经常需要下载和更新各种软件包和库文件。然而&#xff0c;由于网络环境的限制或者服务器的负载&#…...

避免大M取值过大引起的数值问题

在数学建模当中&#xff0c;常常会见到大M法&#xff0c;它之所以叫大M法&#xff0c;是因为它涉及到一个&#xff08;绝对值&#xff09;较大的系数M&#xff0c;这个大M的值应大于约束中的连续变量或者约束表达式可能取到的任何合理值&#xff0c;M值取过大往往会造成优化问题…...

史密斯圆图的使用

史密斯圆图的使用 简介识别史密斯圆图等反射系数圆归一化阻抗圆导纳圆图史密斯圆图的使用单支匹配双支匹配简介 史密斯图Smith Chart是电气工程,无线电,射频工程,微波工程和通信等领域常用的一种图示工具,用于分析和设计传输线和阻抗匹配网络,它由美国工程师Phillip H.Sm…...

可重复读解决了哪些问题? 对 SQL 慢查询会考虑哪些优化 ?

文章目录 可重复读解决了哪些问题&#xff1f;对 SQL 慢查询会考虑哪些优化 &#xff1f; 可重复读解决了哪些问题&#xff1f; &#xff08;1&#xff09;可重复读的核心就是一致性读(consistent read);保证多次读取同一个数据时&#xff0c;其值都和事务开始时候的内容是一致…...

从0开始python学习-35.allure报告企业定制

目录 1. 搭建allure环境 2. 生成报告 3. logo定制 4. 企业级报告内容或层级定制 5. allure局域网查看 1. 搭建allure环境 1.1 JDK&#xff0c;使用PyCharm 找到pycharm安装目录找到java.exe记下jbr目录的完整路径&#xff0c;eg: C:\Program Files\JetBrains\PyCharm Com…...

蓝桥杯2020年10月青少组Python程序设计省赛真题

1、设计一个猜字母的程序,程序随机给出26个小写字母中的一个,答题者输入猜测的字母,若输入的不是26个小写字母之一,让用户重新输入,若字母在答案之前或之后,程序给出相应正确提示,如答错5次,则答题失败并退出游戏,若回答正确,程序输出回答次数并退出游戏。 2、试编一个“口…...

【数据结构】布隆过滤器原理详解及其代码实现

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能AI、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推荐--…...

Qt中实现短信验证码功能

在Qt中实现短信验证码功能,可以使用Qt的信号槽机制和计时器来实现。 首先,在mainwindow.h头文件中添加下列代码: #include <QMainWindow> #include <QTimer>namespace Ui {class MainWindow; }class MainWindow : public...

Redis-运维

转自 极客时间 Redis 亚风 原文视频&#xff1a;https://u.geekbang.org/lesson/535?article681062 Redis 同步 Redis主从数据同步,主从第⼀次同步是全量同步 replicaof 主机 端口 #当前这个机器做Master的备份master如何判断slave是不是第⼀次来同步数据&#xff1a; Repl…...

Qt制作定时关机小程序

文章目录 完成效果图ui界面ui样图 main函数窗口文件头文件cpp文件 引言 一般定时关机采用命令行模式&#xff0c;还需要我们计算在多久后关机&#xff0c;我们可以做一个小程序来定时关机 完成效果图 ui界面 <?xml version"1.0" encoding"UTF-8"?>…...

LeetCode day30

LeetCode day30 害&#xff0c;昨天和今天在搞数据结构的报告&#xff0c;后面应该也会把哈夫曼的大作业写上来。 今天认识认识贪心算法。(&#xff61;&#xff65;∀&#xff65;)&#xff89; 2697. 字典序最小回文串 给你一个由 小写英文字母 组成的字符串 s &#xff0c;…...

数据分析基础之《numpy(5)—合并与分割》

了解即可&#xff0c;用panads 一、作用 实现数据的切分和合并&#xff0c;将数据进行切分合并处理 二、合并 1、numpy.hstack 水平拼接 # hstack 水平拼接 a np.array((1,2,3)) b np.array((2,3,4)) np.hstack((a, b))a np.array([[1], [2], [3]]) b np.array([[2], […...

centos 安装 Miniconda

在 CentOS 上安装 Miniconda 的步骤通常包括下载 Miniconda 安装脚本、运行脚本以及配置环境。以下是详细步骤&#xff1a; 1. 下载 Miniconda 安装脚本 首先&#xff0c;您需要从 Miniconda 的官方网站下载适用于 Linux 的安装脚本。您可以使用 wget 命令在 CentOS 终端中直…...

第二百二十六回

文章目录 1. 概念介绍2. 具体细节2.1 发现服务2.2 发现特征值2.3 发送数据2.4 接收数据 3. 代码与效果3.13.2 运行效果 4. 经验总结 我们在上一章回中介绍了"连接蓝牙设备的细节"相关的内容&#xff0c;本章回中将介绍通过蓝牙发送数据的细节.闲话休提&#xff0c;让…...

ubuntu常用指令

Ubuntu是一个基于Linux的操作系统&#xff0c;它使用了大量的命令行指令。这些指令对于管理系统、处理文件、监控资源和执行各种任务都非常有用。以下是一些常用的Ubuntu命令&#xff1a; 系统管理 sudo&#xff1a;提供管理员权限执行命令&#xff08;例如 sudo apt update&a…...

Quartz.NET 事件监听器

1、调度器监听器 调度器本身收到的一些事件通知&#xff0c;接口ISchedulerListener&#xff0c;如作业的添加、删除、停止、挂起等事件通知&#xff0c;调度器的启动、关闭、出错等事件通知&#xff0c;触发器的暂停、挂起等事件通知&#xff0c;接口部分定义如下&#xff1a…...

2024-AI人工智能学习-安装了pip install pydot但是还是报错

2024-AI人工智能学习-安装了pip install pydot但是还是报错 出现这样子的错误&#xff1a; /usr/local/bin/python3.11 /Users/wangyang/PycharmProjects/studyPython/tf_model.py 2023-12-24 22:59:02.238366: I tensorflow/core/platform/cpu_feature_guard.cc:182] This …...

在使用mapstruct,想忽略掉List<DTO>字段里面的,`data` 字段的映射, 如何写ignore: 使用@IterableMapping

在使用mapstruct,想忽略掉List字段里面的,data 字段的映射, 如何写ignore 代码如下: public interface AssigmentFileMapper {AssigmentFileDTO assigmentFileToAssigmentFileDTO(AssigmentFile assigmentFile);AssigmentFile assigmentFileDTOToAssigmentFile(Assigment…...

ansible-playbook的Temlates模块 tags模块 Roles模块

Temlates模块 jinja模板架构&#xff0c;通过模板可以实现向模板文件传参(python转义)把占位符参数传到配置文件中去,生产一个目标文本文件&#xff0c;传递变量到需要的配置文件当中 &#xff08;web开发&#xff09; nginx.conf.j2 早文件当中配置的是占位符&#xff08;声明…...

Canal使用详解

Canal介绍 Canal是阿里巴巴开发的MySQL binlog增量订阅&消费组件&#xff0c;Canal是基于MySQL二进制日志的高性能数据同步系统。在阿里巴巴集团中被广泛使用&#xff0c;以提供可靠的低延迟增量数据管道。Canal Server能够解析MySQL Binlog并订阅数据更改&#xff0c;而C…...

【经典LeetCode算法题目专栏分类】【第8期】滑动窗口:最小覆盖子串、字符串排列、找所有字母异位词、 最长无重复子串

《博主简介》 小伙伴们好&#xff0c;我是阿旭。专注于人工智能AI、python、计算机视觉相关分享研究。 ✌更多学习资源&#xff0c;可关注公-仲-hao:【阿旭算法与机器学习】&#xff0c;共同学习交流~ &#x1f44d;感谢小伙伴们点赞、关注&#xff01; 《------往期经典推荐--…...

C#和.Net常见问题记录

什么是.NET框架&#xff0c;.NET框架与C#(C Sharp)是什么关系&#xff1f; .NET框架是由Microsoft设计和维护的软件开发框架&#xff0c;.NET框架提供了C#(编程语言)开发的所有基础设施和支持。通过使用C#和.NET框架&#xff0c;开发者可以轻松地开发高质量、高效率的应…...

FAQ:Container Classes篇

1、Why should I use container classes rather than simple arrays?&#xff08;为什么应该使用容器类而不是简单的数组&#xff1f;&#xff09; In terms of time and space, a contiguous array of any kind is just about the optimal construct for accessing a sequen…...

每日一题(LeetCode)----栈和队列--滑动窗口最大值

每日一题(LeetCode)----栈和队列–滑动窗口最大值 1.题目&#xff08;239. 滑动窗口最大值&#xff09; 给你一个整数数组 nums&#xff0c;有一个大小为 k 的滑动窗口从数组的最左侧移动到数组的最右侧。你只可以看到在滑动窗口内的 k 个数字。滑动窗口每次只向右移动一位。 …...

13.bash shell中的if-then语句

文章目录 shell中的流控制if语句if语句if-then语句if-then-else 语句 test命令数值比较字符串比较文件比较case语句 欢迎访问个人网络日志&#x1f339;&#x1f339;知行空间&#x1f339;&#x1f339; shell中的流控制if语句 简单的脚本可以只包含顺序执行的命令&#xff0…...