点云数据瓦片化和体素化探讨及python实现

点云数据体素化(Voxelization):        

        简单说明定义:体素化是一种将连续空间划分为有限数量的离散立方体(体素)的过程。

        在点云处理中,体素化通常指将点云数据转换为体素网格,每个体素代表空间中的一个小块,并包含一组点或点的特征。从效果上看,体素化可以降低数据复杂度,减少点的数量,并且简化后续处理步骤,如数据过滤、特征提取或分类,为进一步的三维重建或建模做准备。

三维瓦片化(3D Tiling):

        笔者这样理解:三维瓦片化是将三维空间分割成多个小块(瓦片),每个瓦片包含一部分三维数据,并可以独立处理和可视化。

        三维瓦片化通常涉及空间层次结构的构建,如四叉树或八叉树;可以根据视点和分辨率动态加载和卸载,且瓦片的大小和层次可以根据应用需求进行调整。因此被应用于实现数据的分层和层次化表示,便于高效管理和传输。用于Web地图服务和三维GIS应用,支持大规模三维场景的快速加载和渲染。优化数据访问,提高渲染性能。

Python代码实现及分析:

        点云数据体素化实现的代码如下:

import open3d as o3d
import numpy as np
import laspy

# LAS文件路径
las_file_path = "path_to_las_file.las"  # 替换为你的LAS文件路径

# 使用laspy读取LAS文件
in_file = laspy.read(las_file_path)

# 将laspy读取的点云转换为numpy数组
points = np.vstack([in_file.x, in_file.y, in_file.z]).T

# 创建Open3D的PointCloud对象
open3d_pcd = o3d.geometry.PointCloud()
open3d_pcd.points = o3d.utility.Vector3dVector(points)

# 可视化原始点云,这一步是可选的
o3d.visualization.draw_geometries([open3d_pcd])

# 体素化参数
voxel_size = 0.1  # 体素的大小,根据实际需要调整

# 体素化点云
voxelized_pcd = open3d_pcd.voxel_down_sample(voxel_size)

# 可视化体素化后的点云,这一步是可选的
o3d.visualization.draw_geometries([voxelized_pcd])

# 如果需要,可以对体素化后的点云进行进一步处理,如构建网格等
# mesh = voxelized_pcd.estimate_normals()
# mesh = mesh.simplify_quadric_decimation()
# o3d.io.write_triangle_mesh("mesh_tile.ply", mesh)

        体素化后的点云是通过将原始点云中的点分配到不同体素中来创建的,每个体素内的点将被一个代表性的点(通常是体素内点的平均位置)所替代。因此,上述代码中的voxel_size参数决定了体素的尺寸,从而影响体素化后点云的分辨率。较小的voxel_size将产生更细致的网格,但会增加处理时间和内存使用。选择voxel_size时需要在处理时间和精度之间做出权衡。

        值得一提的是,笔者采用python处理点云数据,在于python有丰富的点云处理的函数库:如laspy,open3d等等。

        点云瓦片化的python逻辑可以理解为:将点云数据分割成多个三维空间中的小块,这些小块(瓦片)可以独立地存储、传输和渲染,从而优化了大规模三维场景的处理和可视化。在Web地图服务和三维可视化应用中,这是一种常见的技术。

        因此,笔者的点云瓦片化的基本代码如下:

import open3d as o3d

# 加载点云数据
pcd = o3d.io.read_point_cloud("test.pcd")

# 体素化
voxel_size = 0.1
downpcd = pcd.voxel_down_sample(voxel_size)

# 估计法线
downpcd.estimate_normals()
downpcd.orient_normals_towards_camera_location([0, 0, -1])

# 网格重建
mesh, _ = downpcd.triangles
mesh = downpcd.simplify_quadric_decimation()

# 导出网格
o3d.io.write_triangle_mesh("mesh. Ply", mesh)

        当然,笔者的上述代码只是一个简化的网格重建过程,实际的三维瓦片化需要更复杂的逻辑,包括空间分割、层次化和优化等,需要使用专门的库或工具,如Cesium的3D Tiles规范,来生成和发布三维瓦片服务。

        笔者利用上述基本代码,有如下运用:处理和可视化点云数据(但是笔者开始的目的是实现点云数据的表面重构,在实验过程中发现重构存在困难,逐渐跑题):

import open3d as o3d
import numpy as np
import laspy


# LAS文件路径
las_file_path = r"path_to_las_data"(修改成自己的地址再借用哦)
# 使用laspy读取LAS文件
in_file = laspy.read(las_file_path)

# 将laspy读取的点云转换为numpy数组
points = np.vstack([in_file.x, in_file.y, in_file.z]).T

# 如果LAS文件包含RGB颜色信息,可以这样获取颜色:
# colors = np.vstack([in_file.red, in_file.green, in_file.blue]).T

# 创建Open3D的PointCloud对象
open3d_pcd = o3d.geometry.PointCloud()
open3d_pcd.points = o3d.utility.Vector3dVector(points)

# 如果有颜色信息,可以这样添加到Open3D的PointCloud对象中
# 检查点云是否为空
if open3d_pcd.is_empty():
    print("Point cloud is empty.")
    exit()

# 可视化点云,这一步是可选的
o3d.visualization.draw_geometries([open3d_pcd])

# 获取点云的边界框
bounding_box = open3d_pcd.get_axis_aligned_bounding_box()
# 创建Open3D的PointCloud对象,以及进行点云处理的步骤 ...

# 创建一个Visualizer对象
vis = o3d.visualization.Visualizer()
vis.create_window(width=800, height=600)  # 设置窗口的宽度和高度

# 将点云添加到Visualizer对象中
vis.add_geometry(o3d_pcd)

# 设置视点,这里需要确保窗口尺寸已经设置
view_ctl = vis.get_view_control()
view_ctl.set_front([0.3879, -0.3879, -0.2357])
view_ctl.set_lookat([2.4925, 2.0569, 2.3537])
view_ctl.set_up([0.0, 0.0, 1.0])

# 运行
vis.run()

# 销毁视窗
vis.destroy_window()

# open3d_pcd.colors = o3d.utility.Vector3dVector(colors / 256.0)

# 可视化点云,这一步是可选的
o3d.visualization.draw_geometries([open3d_pcd])


# 打印边界框的信息以检查
print("Bounding box min bound:", bounding_box.min_bound.tolist())
print("Bounding box max bound:", bounding_box.max_bound.tolist())

# 体素化点云
voxel_size = 0.1  # 根据需要调整体素大小
voxelized_pcd = open3d_pcd.voxel_down_sample(voxel_size)

# 裁剪点云
try:
    coarse_pcd = voxelized_pcd.crop(bounding_box)
except RuntimeError as e:
    print(e)
    exit()

# 将瓦片化为网格(可选)
mesh, _ = coarse_pcd.estimate_normals()
mesh = mesh.simplify_quadric_decimation()

# 将网格保存为瓦片
o3d.io.write_triangle_mesh("mesh_tile.ply", mesh)

# 可视化瓦片化的网格,这一步也是可选的
o3d.visualization.draw_geometries([mesh])
print("OK" )

        可视化结果:

                                                                                                                署个名(作者:余心远)

  • 36
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要基于体素方法获取单株树木的主干点,您可以使用以下Python代码: ```python import numpy as np import open3d as o3d # 加载点云数据 point_cloud = o3d.io.read_point_cloud("point_cloud.pcd") points = np.asarray(point_cloud.points) # 创建VoxelGrid网格 voxel_size = 0.1 # 设置体素大小 voxel_down_pcd = point_cloud.voxel_down_sample(voxel_size) # 提取点云中心 centroids = np.asarray(voxel_down_pcd.points) # 构建KD树 kdtree = o3d.geometry.KDTreeFlann(voxel_down_pcd) # 设置搜索半径和最小邻居数 search_radius = 0.2 # 设置搜索半径 min_neighbors = 5 # 设置最小邻居数 # 存储主干点 trunk_points = [] # 寻找主干点 for i in range(len(centroids)): [_, idx, _] = kdtree.search_radius_vector_3d(centroids[i], search_radius) if len(idx) >= min_neighbors: trunk_points.append(points[idx[0]]) trunk_points = np.asarray(trunk_points) # 可视主干点 trunk_cloud = o3d.geometry.PointCloud() trunk_cloud.points = o3d.utility.Vector3dVector(trunk_points) o3d.visualization.draw_geometries([trunk_cloud]) ``` 这段代码首先加载点云数据,然后创建一个VoxelGrid网格来降采样点云,并提取体素中心作为主干点的候选点。接下来,构建KD树以便进行最近邻搜索。然后,根据搜索半径和最小邻居数,在候选点中找到满足条件的主干点,并将其存储在`trunk_points`列表中。最后,将提取的主干点可视。 请注意,这只是一个基本的示例代码,您可能需要根据您的数据和具体需求进行适当的调整和优。您还需要安装Open3D库并将点云数据存储为PCD文件(可以根据实际情况修改文件路径)。 希望这对您有所帮助!如果您有任何其他问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值