『OPEN3D』1.6 Voxelization体素化
目錄
1 從triangle meshes中創建體素
2 從點云中創建體素
3 體素包含測試(Inclusion test)
4 Voxel carving
? ? ? ? 在點云處理的內容中,簡單介紹了open3d中對點云下采樣使用了體素的操作,這里對體素化進行詳細的介紹。
點云和三角面片(triangle meshes)表達的數據是無序的幾何結構;而體素則是另一種表達三維數據的幾何結構,體素類似于圖片中的像素,具有規則性。因此,open3d中提供了VoxelGrid幾何類型用于對體素的表達。
1 從triangle meshes中創建體素
? ? ? ? 方法create_from_triangle_mesh可以從mesh中創建體素,任何一個mesh與體素相交,則該體素置為1(存在);否則置為0(不存在)。該方法包含一個參數voxel_size用于設置體素的分辨率。
import copyimport open3d as o3d import numpy as npif __name__ == "__main__":# bunny = o3d.data.BunnyMesh()armadillo_data = o3d.data.ArmadilloMesh()mesh = o3d.io.read_triangle_mesh(armadillo_data.path)# 計算頂點的法向量mesh.compute_vertex_normals()# Fit to unit cube.mesh.scale(1 / np.max(mesh.get_max_bound() - mesh.get_min_bound()),center=mesh.get_center())print('Displaying input mesh ...')# o3d.visualization.draw_geometries([mesh])"""create_from_triangle_mesh param:voxel_size:設置每個體素的長寬高為0.5返回值類型為o3d.geometry.VoxelGrid"""mesh_for_voxelGrid: o3d.geometry.TriangleMesh = copy.deepcopy(mesh)mesh_for_voxelGrid.translate([1, 0, 0])voxel_grid: o3d.geometry.VoxelGrid = o3d.geometry.VoxelGrid.create_from_triangle_mesh(mesh_for_voxelGrid, voxel_size=0.05)print('Displaying voxel grid ...')o3d.visualization.draw_geometries([mesh,voxel_grid])?
?
?
2 從點云中創建體素
? ? ? ? 使用方法create_from_point_cloud可以實現從點云中創建voxelgrid,一個voxel被占用的話,則至少該voxel中存在一個點云。voxel的顏色則是對該voxel中所有點云的顏色做平均;參數voxel_size設置voxelgrid的分辨率。
????????
import open3d as o3d import numpy as npif __name__ == "__main__":N = 3000armadillo_data = o3d.data.ArmadilloMesh()pcd = o3d.io.read_triangle_mesh(armadillo_data.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('Displaying input point cloud ...')o3d.visualization.draw_geometries([pcd])print('Displaying voxel grid ...')voxel_grid = o3d.geometry.VoxelGrid.create_from_point_cloud(pcd,voxel_size=0.05)o3d.visualization.draw_geometries([voxel_grid])????????
?
3 體素包含測試(Inclusion test)
? ? ? ? voxel grid可以用于測試一個點云是否被體素所包含;方法check_if_included接受一個(n,3)的array;并返回array中每個點是否在voxelgrid中。
import copyimport open3d as o3d import numpy as npif __name__ == "__main__":N = 3000armadillo_data = o3d.data.ArmadilloMesh()pcd = o3d.io.read_triangle_mesh(armadillo_data.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('Displaying input point cloud ...')# o3d.visualization.draw_geometries([pcd])pcd_for_voxelgrid = copy.deepcopy(pcd)pcd_for_voxelgrid.translate([1, 0, 0])print('Displaying voxel grid ...')voxel_grid = o3d.geometry.VoxelGrid.create_from_point_cloud(pcd_for_voxelgrid,voxel_size=0.05)# o3d.visualization.draw_geometries([pcd, voxel_grid])queries = np.asarray(pcd.points)output = voxel_grid.check_if_included(o3d.utility.Vector3dVector(queries))print(output[:10])queries = np.asarray(pcd_for_voxelgrid.points)output = voxel_grid.check_if_included(o3d.utility.Vector3dVector(queries))print(output[:10])"""輸出結果Displaying voxel grid ...[False, False, False, False, False, False, False, False, False, False][True, True, True, True, True, True, True, True, True, True]"""4 Voxel carving
? ? ? ? 上述兩種方法創建的voxelGrid只在點云或mesh占用該voxel時,才會將該voxel設置為被占用的狀態;因此會出現物體的中心在voxelGrid為空洞的情況,只有表面的voxelGrid被占據;但是也可以從多個深度圖(depth maps)或者輪廓圖(silhouettes)中雕刻出體素網格;在open3d中提供了該實現分別為carve_depth_map和carve_silhouette。
下面已depth map為示例進行展示
# ---------------------------------------------------------------------------- # - Open3D: www.open3d.org - # ---------------------------------------------------------------------------- # The MIT License (MIT) # # Copyright (c) 2018-2021 www.open3d.org # # Permission is hereby granted, free of charge, to any person obtaining a copy # of this software and associated documentation files (the "Software"), to deal # in the Software without restriction, including without limitation the rights # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell # copies of the Software, and to permit persons to whom the Software is # furnished to do so, subject to the following conditions: # # The above copyright notice and this permission notice shall be included in # all copies or substantial portions of the Software. # # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING # FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS # IN THE SOFTWARE. # ----------------------------------------------------------------------------import open3d as o3d import numpy as npdef xyz_spherical(xyz):x = xyz[0]y = xyz[1]z = xyz[2]# 計算得到球體的半徑r = np.sqrt(x * x + y * y + z * z)# 半徑與x軸的夾角r_x = np.arccos(y / r)# 半徑在y軸的夾角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)# 計算該相機位姿下的旋轉矩陣和平移向量并拼接成T矩陣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, cubic_size, voxel_resolution, w=300, h=300):# 計算mesh的頂點法向量mesh.compute_vertex_normals()# 創建球體camera_sphere = o3d.geometry.TriangleMesh.create_sphere(radius=1.0,resolution=10)# o3d.visualization.draw_geometries([camera_sphere], mesh_show_back_face=True)# Setup dense voxel grid.voxel_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],color=[1.0, 0.7, 0.0])# Rescale geometry.camera_sphere = preprocess(camera_sphere)mesh = preprocess(mesh)# Setup visualizer to render depthmaps.vis = 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 grid.centers_pts = np.zeros((len(camera_sphere.vertices), 3))for cid, xyz in enumerate(camera_sphere.vertices):# Get new camera pose.trans = get_extrinsic(xyz)param.extrinsic = transc = np.linalg.inv(trans).dot(np.asarray([0, 0, 0, 1]).transpose())centers_pts[cid, :] = c[:3]# 轉換相機的參數到成open3d中的相機內外參ctr.convert_from_pinhole_camera_parameters(param)# Capture depth image and make a point cloud.vis.poll_events()vis.update_renderer()# 根據當前的位姿來進行渲染拍攝得到深度圖depth = vis.capture_depth_float_buffer(False)# Depth map carving method.voxel_carving.carve_depth_map(o3d.geometry.Image(depth), param)print("Carve view %03d/%03d" % (cid + 1, len(camera_sphere.vertices)))vis.destroy_window()return voxel_carving""" 流程: 1 先創建一個固定大小的稠密(dense)voxleGrid對象 2 創建一個球形用于虛擬相機的位姿來拍攝拍攝深度圖 3 根據拍攝得到的深度圖與相機位姿使用carve_depth_map融合到dense voxelGrid中 """ if __name__ == "__main__":armadillo_data = o3d.data.ArmadilloMesh()mesh = o3d.io.read_triangle_mesh(armadillo_data.path)cubic_size = 2.0voxel_resolution = 128.0carved_voxels = voxel_carving(mesh, cubic_size, voxel_resolution)print("Carved voxels ...")print(carved_voxels)o3d.visualization.draw_geometries([carved_voxels])生成的voxelGird內部也是被填充的,可以自行方法查看
?
總結
以上是生活随笔為你收集整理的『OPEN3D』1.6 Voxelization体素化的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: python lackey
- 下一篇: 今明Focatek相机