首页 > Open3d学习计划—高级篇 6(体素化)

Open3d学习计划—高级篇 6(体素化)

Open3D是一个开源库,支持快速开发和处理3D数据。Open3D在c++和Python中公开了一组精心选择的数据结构和算法。后端是高度优化的,并且是为并行化而设置的。

本系列学习计划有Blue同学作为发起人,主要以Open3D官方网站的教程为主进行翻译与实践的学习计划。点云PCL公众号作为免费的3D视觉,点云交流社区,期待有使用Open3D或者感兴趣的小伙伴能够加入我们的翻译计划,贡献免费交流社区,为使用Open3D提供中文的使用教程。

点云和三角网格是一种十分灵活的,但是不规则的几何类型。体素网格是通过规则的3D网格来表示的另一种3D几何类型,并且它可以看作是2D像素在3D上的对照物。Open3d中的VoxelGrid几何类型能够被用来处理体素网格数据。

从三角网格中生成

Open3d提供了create_from_triangle_mesh函数能够从三角网格中生成体素网格。它返回一个体素网格,其中所有与三角形相交的网格被设置为1,其余的设置为0。其中voxel_zie参数是用来设置网格分辨率。

print('input')
mesh = o3dtut.get_bunny_mesh()
# fit to unit cube
mesh.scale(1 / np.max(mesh.get_max_bound() - mesh.get_min_bound()), center=mesh.get_center())
o3d.visualization.draw_geometries([mesh])
print('voxelization')
voxel_grid = o3d.geometry.VoxelGrid.create_from_triangle_mesh(mesh,voxel_size=0.05)
o3d.visualization.draw_geometries([voxel_grid])

input

voxelization

从点云中生成

也能够使用create_from_point_cloud函数从点云中生成体素网格。如果点云中至少有一个点在体素网格内,则该网格被占用。颜色表示的是该体素中点的平均值。参数voxel_size用来定义网格分辨率。

print('input')
N = 2000
pcd = o3dtut.get_armadillo_mesh().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)))
o3d.visualization.draw_geometries([pcd])print('voxelization')
voxel_grid = o3d.geometry.VoxelGrid.create_from_point_cloud(pcd,voxel_size=0.05)
o3d.visualization.draw_geometries([voxel_grid])

input

voxelization

包含测试

体素网格也能够用来测试点是否在被占用的网格内。方法check_if_included接受一个(n,3)数组作为输入,返回一个bool类型的数组。

queries = np.asarray(pcd.points)
output = voxel_grid.check_if_included(o3d.utility.Vector3dVector(queries))
print(output[:10])

体素雕刻

create_from_point_cloud和create_from_triangle_mesh方法只能够在几何体的表面创造体素网格。然而从大量的深度图或者轮廓中雕刻一个体素网格是有可能的。Open3d提供了carve_depth_map和 carve_silhouette方法用于体素雕刻。

下面的代码展示了使用方法,首先从一个几何形状中得到 depthmaps ,之后使用 depthmaps 去雕刻出稠密的体素网格。最后的结果是一个给定形状的填充的体素网格。

def xyz_spherical(xyz):x = xyz[0]y = xyz[1]z = xyz[2]r = np.sqrt(x * x + y * y + z * z)r_x = np.arccos(y / r)r_y = np.arctan2(z, x)return [r, r_x, r_y]def get_rotation_matrix(r_x, r_y):rot_x = np.asarray([[1, 0, 0], [0, np.cos(r_x), -np.sin(r_x)],[0, np.sin(r_x), np.cos(r_x)]])rot_y = np.asarray([[np.cos(r_y), 0, np.sin(r_y)], [0, 1, 0],[-np.sin(r_y), 0, np.cos(r_y)]])return rot_y.dot(rot_x)def get_extrinsic(xyz):rvec = xyz_spherical(xyz)r = get_rotation_matrix(rvec[1], rvec[2])t = np.asarray([0, 0, 2]).transpose()trans = np.eye(4)trans[:3, :3] = rtrans[:3, 3] = treturn transdef preprocess(model):min_bound = model.get_min_bound()max_bound = model.get_max_bound()center = min_bound + (max_bound - min_bound) / 2.0scale = np.linalg.norm(max_bound - min_bound) / 2.0vertices = np.asarray(model.vertices)vertices -= centermodel.vertices = o3d.utility.Vector3dVector(vertices / scale)return modeldef voxel_carving(mesh,output_filename,camera_path,cubic_size,voxel_resolution,w=300,h=300,use_depth=True,surface_method='pointcloud'):mesh.compute_vertex_normals()camera_sphere = o3d.io.read_triangle_mesh(camera_path)# setup dense voxel gridvoxel_carving = o3d.geometry.VoxelGrid.create_dense(width=cubic_size,height=cubic_size,depth=cubic_size,voxel_size=cubic_size / voxel_resolution,origin=[-cubic_size / 2.0, -cubic_size / 2.0, -cubic_size / 2.0])# rescale geometrycamera_sphere = preprocess(camera_sphere)mesh = preprocess(mesh)# setup visualizer to render depthmapsvis = o3d.visualization.Visualizer()vis.create_window(width=w, height=h, visible=False)vis.add_geometry(mesh)vis.get_render_option().mesh_show_back_face = Truectr = vis.get_view_control()param = ctr.convert_to_pinhole_camera_parameters()# carve voxel gridpcd_agg = o3d.geometry.PointCloud()centers_pts = np.zeros((len(camera_sphere.vertices), 3))for cid, xyz in enumerate(camera_sphere.vertices):# get new camera posetrans = get_extrinsic(xyz)param.extrinsic = transc = np.linalg.inv(trans).dot(np.asarray([0, 0, 0, 1]).transpose())centers_pts[cid, :] = c[:3]ctr.convert_from_pinhole_camera_parameters(param)# capture depth image and make a point cloudvis.poll_events()vis.update_renderer()depth = vis.capture_depth_float_buffer(False)pcd_agg += o3d.geometry.PointCloud.create_from_depth_image(o3d.geometry.Image(depth),param.intrinsic,param.extrinsic,depth_scale=1)# depth map carving methodif use_depth:voxel_carving.carve_depth_map(o3d.geometry.Image(depth), param)else:voxel_carving.carve_silhouette(o3d.geometry.Image(depth), param)print("Carve view %03d/%03d" % (cid + 1, len(camera_sphere.vertices)))vis.destroy_window()# add voxel grid survaceprint('Surface voxel grid from %s' % surface_method)if surface_method == 'pointcloud':voxel_surface = o3d.geometry.VoxelGrid.create_from_point_cloud_within_bounds(pcd_agg,voxel_size=cubic_size / voxel_resolution,min_bound=(-cubic_size / 2, -cubic_size / 2, -cubic_size / 2),max_bound=(cubic_size / 2, cubic_size / 2, cubic_size / 2))elif surface_method == 'mesh':voxel_surface = o3d.geometry.VoxelGrid.create_from_triangle_mesh_within_bounds(mesh,voxel_size=cubic_size / voxel_resolution,min_bound=(-cubic_size / 2, -cubic_size / 2, -cubic_size / 2),max_bound=(cubic_size / 2, cubic_size / 2, cubic_size / 2))else:raise Exception('invalid surface method')voxel_carving_surface = voxel_surface + voxel_carvingreturn voxel_carving_surface, voxel_carving, voxel_surface
mesh = o3dtut.get_armadillo_mesh()output_filename = os.path.abspath("../../TestData/voxelized.ply")
camera_path = os.path.abspath("../../TestData/sphere.ply")
visualization = True
cubic_size = 2.0
voxel_resolution = 128.0voxel_grid, voxel_carving, voxel_surface = voxel_carving(mesh, output_filename, camera_path,cubic_size, voxel_resolution)

Carve view 001/642

Carve view 002/642

Carve view 003/642

Carve view 004/642



Carve view 642/642

Surface voxel grid from pointcloud

print("surface voxels")
print(voxel_surface)
o3d.visualization.draw_geometries([voxel_surface])print("carved voxels")
print(voxel_carving)
o3d.visualization.draw_geometries([voxel_carving])print("combined voxels (carved + surface)")
print(voxel_grid)
o3d.visualization.draw_geometries([voxel_grid])

surface voxels

geometry::VoxelGrid with 17215 voxels.

carved voxels

geometry::VoxelGrid with 48370 voxels.

combined voxels (carved + surface)

geometry::VoxelGrid with 50786 voxels.

资源

三维点云论文及相关应用分享

【点云论文速读】基于激光雷达的里程计及3D点云地图中的定位方法

3D目标检测:MV3D-Net

三维点云分割综述(上)

3D-MiniNet: 从点云中学习2D表示以实现快速有效的3D LIDAR语义分割(2020)

win下使用QT添加VTK插件实现点云可视化GUI

JSNet:3D点云的联合实例和语义分割

大场景三维点云的语义分割综述

PCL中outofcore模块---基于核外八叉树的大规模点云的显示

基于局部凹凸性进行目标分割

基于三维卷积神经网络的点云标记

点云的超体素(SuperVoxel)

基于超点图的大规模点云分割

更多文章可查看:点云学习历史文章大汇总

SLAM及AR相关分享

【开源方案共享】ORB-SLAM3开源啦!

【论文速读】AVP-SLAM:自动泊车系统中的语义SLAM

【点云论文速读】StructSLAM:结构化线特征SLAM

SLAM和AR综述

常用的3D深度相机

AR设备单目视觉惯导SLAM算法综述与评价

SLAM综述(4)激光与视觉融合SLAM

Kimera实时重建的语义SLAM系统

SLAM综述(3)-视觉与惯导,视觉与深度学习SLAM

易扩展的SLAM框架-OpenVSLAM

高翔:非结构化道路激光SLAM中的挑战

SLAM综述之Lidar SLAM

基于鱼眼相机的SLAM方法介绍

往期线上分享录播汇总

第一期B站录播之三维模型检索技术

第二期B站录播之深度学习在3D场景中的应用

第三期B站录播之CMake进阶学习

第四期B站录播之点云物体及六自由度姿态估计

第五期B站录播之点云深度学习语义分割拓展

第六期B站录播之Pointnetlk解读

[线上分享录播]点云配准概述及其在激光SLAM中的应用

[线上分享录播]cloudcompare插件开发

[线上分享录播]基于点云数据的 Mesh重建与处理

[线上分享录播]机器人力反馈遥操作技术及机器人视觉分享

[线上分享录播]地面点云配准与机载点云航带平差

点云PCL更多活动请查看:点云PCL活动之应届生校招群

扫描下方微信视频号二维码可查看最新研究成果及相关开源方案的演示:

如果你对Open3D感兴趣,或者正在使用该开源方案,就请加入我们,一起翻译,一起学习,贡献自己的力量,目前阶段主要以微信群为主,有意者发送“Open3D学习计划”到公众号后台,和更多热爱分享的小伙伴一起交流吧!如果翻译的有什么问题或者您有更好的意见,请评论交流!!!!

以上内容如有错误请留言评论,欢迎指正交流。如有侵权,请联系删除

扫描二维码

                   关注我们

让我们一起分享一起学习吧!期待有想法,乐于分享的小伙伴加入免费星球注入爱分享的新鲜活力。分享的主题包含但不限于三维视觉,点云,高精地图,自动驾驶,以及机器人等相关的领域。

分享及合作:微信“920177957”(需要按要求备注) 联系邮箱:[email protected],欢迎企业来联系公众号展开合作。

点一下“在看”你会更好看耶

更多相关:

  • 1. 定义网络的基本参数 定义输入网络的是什么: input = Input(shape=(240, 640, 3)) 反向传播时梯度下降算法 SGD一定会收敛,但是速度慢 Adam速度快但是可能不收敛 [link](https://blog.csdn.net/wydbyxr/article/details/84822806...

  • size_t和int       size_t是一些C/C++标准在stddef.h中定义的。这个类型足以用来表示对象的大小。size_t的真实类型与操作系统有关。 在32位架构中被普遍定义为: typedef   unsigned int size_t; 而在64位架构中被定义为: typedef  unsigned lo...

  • 我在 https://blog.csdn.net/wowricky/article/details/83218126 介绍了一种内存池,它的实现类似于linux 中打开slub_debug (1. make menuconfig: Kenel hacking -> Memory Debugging, 2. comand line中传入...

  • 项目开发中需要从引擎 获取一定范围的数据大小,用作打点上报,测试过程中竟然发现写入了一部分数据之后通过GetApproximateSizes 获取写入的key的范围时取出来的数据大小竟然为0。。。难道发现了一个bug?(欣喜) 因为写入的数据是小于一个sst的data-block(默认是4K),会不会因为GetApproximate...

  • CAD是基于实体的(solid-based) 计算机图形学是基于表面的(surface-based)   凸多边形是指多边形任何两个顶点连接总是在多边形内。   网格化算法: 拓扑结构: 如何简化网格? 细分 网格化简:  ...