簡(jiǎn)介
在本文中,我提供了一個(gè)關(guān)于如何使用Python的Open3D庫(kù)(一個(gè)用于3D數(shù)據(jù)處理的開(kāi)源庫(kù))來(lái)探索、處理和可視化3D模型的快速演練。
使用Open3D可視化的3D模型(鏈接https://sketchfab.com/3d-models/tesla-model-s-plaid-9de8855fae324e6cbbb83c9b5288c961處可找到原始3D模型)
如果您正在考慮處理特定任務(wù)的3D數(shù)據(jù)/模型,例如訓(xùn)練3D模型分類和/或分割A(yù)I模型,那么您會(huì)發(fā)現(xiàn)本演練是很有幫助的?;ヂ?lián)網(wǎng)上的3D模型(在ShapeNet等數(shù)據(jù)集中)有多種格式,如.obj、.glb、.gltf等。使用Open3D等庫(kù),可以輕松處理、可視化這些模型,并將其轉(zhuǎn)換為其他格式,如點(diǎn)云,因?yàn)檫@些格式更容易理解和解釋。
注意,這篇文章也可以作為Jupyter筆記本提供給那些希望跟隨并在本地運(yùn)行代碼的人。包含Jupyter筆記本以及所有其他數(shù)據(jù)和有關(guān)資源的zip文件可以從下面的鏈接下載。
3D Data Processing with Open3D.zip。
在本教程中,我將完成以下任務(wù):
- 將三維模型加載為網(wǎng)格并將其可視化
- 通過(guò)采樣點(diǎn)將網(wǎng)格轉(zhuǎn)換為點(diǎn)云
- 從點(diǎn)云中刪除隱藏點(diǎn)
- 將點(diǎn)云轉(zhuǎn)換為數(shù)據(jù)幀
- 保存點(diǎn)云和數(shù)據(jù)幀
下面,讓我們從導(dǎo)入所有必要的庫(kù)開(kāi)始:
# 導(dǎo)入open3d和所有其他必要的庫(kù)。
import open3d as o3d
import os
import copy
import numpy as np
import pandas as pd
from PIL import Image
np.random.seed(42)
#正在檢查open3d上安裝的版本。
o3d.__version__
# Open3D version used in this exercise: 0.16.0
將三維模型加載為網(wǎng)格并將其可視化
通過(guò)運(yùn)行以下代碼行,可以將3D模型讀取為網(wǎng)格:
#定義三維模型文件的路徑。
mesh_path = "data/3d_model.obj"
# 使用open3d將三維模型文件讀取為三維網(wǎng)格。
mesh = o3d.io.read_triangle_mesh(mesh_path)
要可視化網(wǎng)格,請(qǐng)運(yùn)行以下代碼行:
#可視化網(wǎng)格。
draw_geoms_list = [mesh]
o3d.visualization.draw_geometries(draw_geoms_list)
網(wǎng)格應(yīng)該在一個(gè)新窗口中打開(kāi),看起來(lái)應(yīng)該像下面的圖像(請(qǐng)注意,網(wǎng)格打開(kāi)時(shí)是靜態(tài)圖像,而不是像這里顯示的動(dòng)畫(huà)圖像)??梢允褂檬髽?biāo)指針根據(jù)需要旋轉(zhuǎn)網(wǎng)格圖像。
可視化為網(wǎng)格的3D模型(在估計(jì)曲面法線之前)
如上所述,汽車網(wǎng)格看起來(lái)不像典型的3D模型,而是渲染成了統(tǒng)一的灰色。這是因?yàn)榫W(wǎng)格沒(méi)有任何關(guān)于三維模型中頂點(diǎn)和曲面的法線的信息。
什么是法線呢?-曲面在給定點(diǎn)處的法向量是垂直于該點(diǎn)處曲面的向量。法向量通常簡(jiǎn)稱為“法線”。要閱讀更多關(guān)于此主題的內(nèi)容,可以參考以下兩個(gè)鏈接:法線向量和估計(jì)點(diǎn)云中的曲面法線。
可以通過(guò)運(yùn)行以下代碼行來(lái)估計(jì)上面三維網(wǎng)格的法線:
# 計(jì)算網(wǎng)格的法線。
mesh.compute_vertex_normals()
#可視化網(wǎng)格。
draw_geoms_list = [mesh]
o3d.visualization.draw_geometries(draw_geoms_list)
一旦可視化,網(wǎng)格應(yīng)該如下圖所示出現(xiàn)。計(jì)算法線后,汽車將正確渲染,看起來(lái)像一個(gè)3D模型。
可視化為網(wǎng)格的3D模型(在估計(jì)表面法線之后)
現(xiàn)在,讓我們創(chuàng)建一個(gè)XYZ坐標(biāo)系,以了解這個(gè)汽車模型在歐幾里得空間中的方向。XYZ坐標(biāo)系可以覆蓋在上面的3D網(wǎng)格上,并通過(guò)運(yùn)行以下代碼行進(jìn)行可視化:
# 創(chuàng)建XYZ軸笛卡爾坐標(biāo)系的網(wǎng)格。
# 該網(wǎng)格將顯示X、Y和Z軸指向的方向,并且可以覆蓋在3D網(wǎng)格上,以可視化其在歐幾里得空間中的方向。
# X-axis : 紅色箭頭
# Y-axis : 綠色箭頭
# Z-axis : 藍(lán)色箭頭
mesh_coord_frame = o3d.geometry.TriangleMesh.create_coordinate_frame(size=5, origin=[0, 0, 0])
#使用坐標(biāo)系可視化網(wǎng)格,以了解方向。
draw_geoms_list = [mesh_coord_frame, mesh]
o3d.visualization.draw_geometries(draw_geoms_list)
使用XYZ坐標(biāo)系可視化的三維網(wǎng)格(X軸:紅色箭頭,Y軸:綠色箭頭,Z軸:藍(lán)色箭;[簡(jiǎn)記為——XYZ::RGB])
從上面的可視化中,我們可以看到這個(gè)汽車網(wǎng)格的方向如下:
- XYZ軸的原點(diǎn):在汽車模型的體積中心(在上圖中看不到,因?yàn)樗谄嚲W(wǎng)格內(nèi))。
- X軸(紅色箭頭):沿著汽車的長(zhǎng)度尺寸,正X軸指向汽車的發(fā)動(dòng)機(jī)罩(在上圖中看不到,因?yàn)樗谄嚲W(wǎng)格內(nèi))。
- Y軸(綠色箭頭):沿著汽車的高度尺寸,正Y軸指向汽車的車頂。
- Z軸(藍(lán)色箭頭):沿著汽車的寬度尺寸,正Z軸指向汽車的右側(cè)。
現(xiàn)在,讓我們來(lái)看看這個(gè)汽車模型里面有什么。為此,我們將在Z軸上裁剪網(wǎng)格,并移除汽車的右半部分(正Z軸)。
#使用其束框裁剪汽車網(wǎng)格以移除其右半部分(正Z軸)。
bbox = mesh.get_axis_aligned_bounding_box()
bbox_points = np.asarray(bbox.get_box_points())
bbox_points[:, 2] = np.clip(bbox_points[:, 2], a_min=None, a_max=0)
bbox_cropped = o3d.geometry.AxisAlignedBoundingBox.create_from_points(o3d.utility.Vector3dVector(bbox_points))
mesh_cropped = mesh.crop(bbox_cropped)
# 可視化裁剪的網(wǎng)格。
draw_geoms_list = [mesh_coord_frame, mesh_cropped]
o3d.visualization.draw_geometries(draw_geoms_list)
在移除汽車右半部分的情況下,在Z軸上裁剪三維網(wǎng)格(正Z軸)。裁剪后的網(wǎng)格顯示了此3D汽車模型中的詳細(xì)內(nèi)部
從上面的可視化中,我們可以看到這款車型有著詳細(xì)的內(nèi)飾?,F(xiàn)在我們已經(jīng)看到了這個(gè)3D網(wǎng)格內(nèi)部的內(nèi)容,我們可以在移除屬于汽車內(nèi)部的“隱藏”點(diǎn)之前將其轉(zhuǎn)換為點(diǎn)云。
通過(guò)采樣點(diǎn)將網(wǎng)格轉(zhuǎn)換為點(diǎn)云
通過(guò)定義,我們希望從網(wǎng)格中采樣的點(diǎn)的數(shù)量,可以在Open3D中輕松地將網(wǎng)格轉(zhuǎn)換為點(diǎn)云。
#從網(wǎng)格中均勻采樣100000個(gè)點(diǎn),將其轉(zhuǎn)換為點(diǎn)云。
n_pts = 100_000
pcd = mesh.sample_points_uniformly(n_pts)
#可視化點(diǎn)云。
draw_geoms_list = [mesh_coord_frame, pcd]
o3d.visualization.draw_geometries(draw_geoms_list)
通過(guò)從三維網(wǎng)格中均勻采樣100000個(gè)點(diǎn)創(chuàng)建的三維點(diǎn)云
請(qǐng)注意,上面點(diǎn)云中的顏色僅指示點(diǎn)沿Z軸的位置。
如果我們像裁剪上面的網(wǎng)格一樣裁剪點(diǎn)云,它會(huì)是這樣的:
#使用邊界框裁剪汽車點(diǎn)云以移除其右半部分(正Z軸)。
pcd_cropped = pcd.crop(bbox_cropped)
#可視化裁剪的點(diǎn)云。
draw_geoms_list = [mesh_coord_frame, pcd_cropped]
o3d.visualization.draw_geometries(draw_geoms_list)
在移除汽車右半部分的情況下在Z軸上裁剪的三維點(diǎn)云(正Z軸)。與上面裁剪的網(wǎng)格一樣,裁剪的點(diǎn)云也顯示了此3D汽車模型中的詳細(xì)內(nèi)部
我們?cè)诓眉酎c(diǎn)云的可視化中看到,它還包含屬于汽車模型內(nèi)部的點(diǎn)。這是意料之中的,因?yàn)樵擖c(diǎn)云是通過(guò)對(duì)整個(gè)網(wǎng)格中的點(diǎn)進(jìn)行均勻采樣而創(chuàng)建的。在下一節(jié)中,我們將刪除這些屬于汽車內(nèi)部且不在點(diǎn)云外表面的“隱藏”點(diǎn)。
從點(diǎn)云中刪除隱藏點(diǎn)
想象一下,你把一盞燈指向汽車模型的右側(cè)。落在三維模型右外表面上的所有點(diǎn)都將被照亮,而點(diǎn)云中的所有其他點(diǎn)則不會(huì)被照亮。
顯示Open3D的隱藏點(diǎn)移除如何從給定的視點(diǎn)處理點(diǎn)云的插圖。所有被照亮的點(diǎn)都被視為“可見(jiàn)”,而所有其他點(diǎn)都被認(rèn)為是“隱藏”
現(xiàn)在,讓我們將這些照明點(diǎn)標(biāo)記為“可見(jiàn)”,將所有未照明點(diǎn)標(biāo)記“隱藏”。這些“隱藏”點(diǎn)還將包括屬于汽車內(nèi)部的所有點(diǎn)。
此操作在Open3D中稱為“隱藏點(diǎn)刪除”。為了使用Open3D在點(diǎn)云上執(zhí)行此操作,請(qǐng)運(yùn)行以下代碼行:
# 定義隱藏點(diǎn)刪除操作的攝影機(jī)和半徑參數(shù)。
diameter = np.linalg.norm(np.asarray(pcd.get_min_bound()) - np.asarray(pcd.get_max_bound()))
camera = [0, 0, diameter]
radius = diameter * 100
# 使用上面定義的攝影機(jī)和半徑參數(shù)對(duì)點(diǎn)云執(zhí)行隱藏點(diǎn)刪除操作。
#輸出是可見(jiàn)點(diǎn)的索引列表。
_, pt_map = pcd.hidden_point_removal(camera, radius)
使用上面的可見(jiàn)點(diǎn)索引輸出列表,我們可以在可視化點(diǎn)云之前將可見(jiàn)點(diǎn)和隱藏點(diǎn)涂成不同的顏色。
# 將點(diǎn)云中的所有可見(jiàn)點(diǎn)繪制為藍(lán)色,將所有隱藏點(diǎn)繪制為紅色。
pcd_visible = pcd.select_by_index(pt_map)
pcd_visible.paint_uniform_color([0, 0, 1]) #藍(lán)色點(diǎn)是可見(jiàn)點(diǎn)(需要保留)。
print("No. of visible points : ", pcd_visible)
pcd_hidden = pcd.select_by_index(pt_map, invert=True)
pcd_hidden.paint_uniform_color([1, 0, 0]) # 紅色點(diǎn)是隱藏點(diǎn)(要?jiǎng)h除)。
print("No. of hidden points : ", pcd_hidden)
# 可視化點(diǎn)云中的可見(jiàn)(藍(lán)色)和隱藏(紅色)點(diǎn)。
draw_geoms_list = [mesh_coord_frame, pcd_visible, pcd_hidden]
o3d.visualization.draw_geometries(draw_geoms_list)
從上圖所示的攝影機(jī)視點(diǎn)移除隱藏點(diǎn)操作后的點(diǎn)云?!翱梢?jiàn)”點(diǎn)為藍(lán)色,而“隱藏”點(diǎn)為紅色
從上面的可視化中,我們可以看到隱藏點(diǎn)移除操作是如何從給定的相機(jī)視點(diǎn)工作的。該操作消除了背景中被來(lái)自給定相機(jī)視點(diǎn)的前景中的點(diǎn)遮擋的所有點(diǎn)。
為了更好地理解這一點(diǎn),我們可以再次重復(fù)相同的操作,但這次是在稍微旋轉(zhuǎn)點(diǎn)云之后。實(shí)際上,我們正在努力改變這里的觀點(diǎn)。但是,我們將旋轉(zhuǎn)點(diǎn)云本身,而不是通過(guò)重新定義相機(jī)參數(shù)來(lái)改變它。
復(fù)制
#定義將度數(shù)轉(zhuǎn)換為弧度的函數(shù)。
def deg2rad(deg):
return deg * np.pi/180
#將點(diǎn)云繞X軸旋轉(zhuǎn)90度。
x_theta = deg2rad(90)
y_theta = deg2rad(0)
z_theta = deg2rad(0)
tmp_pcd_r = copy.deepcopy(pcd)
R = tmp_pcd_r.get_rotation_matrix_from_axis_angle([x_theta, y_theta, z_theta])
tmp_pcd_r.rotate(R, center=(0, 0, 0))
#可視化旋轉(zhuǎn)的點(diǎn)云。
draw_geoms_list = [mesh_coord_frame, tmp_pcd_r]
o3d.visualization.draw_geometries(draw_geoms_list)
圍繞X軸旋轉(zhuǎn)90度的三維點(diǎn)云。請(qǐng)注意,與以前不同的是,現(xiàn)在Y軸(綠色箭頭)沿著汽車的寬度尺寸運(yùn)行,Z軸(藍(lán)色箭頭)沿著車輛的高度尺寸運(yùn)行。X軸(紅色箭頭)沒(méi)有變化,它仍然沿著汽車的長(zhǎng)度方向運(yùn)行
圖示顯示了隱藏點(diǎn)刪除操作如何從與前面相同的給定視點(diǎn)對(duì)旋轉(zhuǎn)的點(diǎn)云進(jìn)行操作。如前所述,所有照明點(diǎn)都被視為“可見(jiàn)”,而所有其他點(diǎn)都被認(rèn)為是“隱藏”。
通過(guò)對(duì)旋轉(zhuǎn)的汽車模型再次重復(fù)相同的過(guò)程,我們可以看到,這一次,落在3D模型(車頂)上外表面的所有點(diǎn)都會(huì)被照亮,而點(diǎn)云中的所有其他點(diǎn)都不會(huì)被照亮。
我們可以通過(guò)運(yùn)行以下代碼行,對(duì)旋轉(zhuǎn)的點(diǎn)云重復(fù)隱藏點(diǎn)刪除操作:
# 使用上面定義的相同攝影機(jī)和半徑參數(shù)對(duì)旋轉(zhuǎn)的點(diǎn)云執(zhí)行隱藏點(diǎn)移除操作。
#輸出是可見(jiàn)點(diǎn)的索引列表。
_, pt_map = tmp_pcd_r.hidden_point_removal(camera, radius)
# 將旋轉(zhuǎn)的點(diǎn)云中的所有可見(jiàn)點(diǎn)繪制為藍(lán)色,將所有隱藏點(diǎn)繪制為紅色。
pcd_visible = tmp_pcd_r.select_by_index(pt_map)
pcd_visible.paint_uniform_color([0, 0, 1]) # 藍(lán)色點(diǎn)是可見(jiàn)點(diǎn)(需要保留)。
print("No. of visible points : ", pcd_visible)
pcd_hidden = tmp_pcd_r.select_by_index(pt_map, invert=True)
pcd_hidden.paint_uniform_color([1, 0, 0]) #紅色點(diǎn)是隱藏點(diǎn)(要?jiǎng)h除)。
print("No. of hidden points : ", pcd_hidden)
#可視化旋轉(zhuǎn)的點(diǎn)云中的可見(jiàn)(藍(lán)色)和隱藏(紅色)點(diǎn)。
draw_geoms_list = [mesh_coord_frame, pcd_visible, pcd_hidden]
o3d.visualization.draw_geometries(draw_geoms_list)
從上圖所示的攝影機(jī)視點(diǎn)移除隱藏點(diǎn)操作后旋轉(zhuǎn)的點(diǎn)云。同樣,“可見(jiàn)”點(diǎn)為藍(lán)色,而“隱藏”點(diǎn)為紅色
上面旋轉(zhuǎn)的點(diǎn)云的可視化清楚地說(shuō)明了隱藏點(diǎn)移除操作是如何工作的。因此,現(xiàn)在,為了從這個(gè)汽車點(diǎn)云中移除所有“隱藏”點(diǎn),我們可以通過(guò)將點(diǎn)云圍繞所有三個(gè)軸從-90度到+90度稍微旋轉(zhuǎn)來(lái)依次執(zhí)行隱藏點(diǎn)移除操作。在每次刪除隱藏點(diǎn)操作之后,我們可以聚合點(diǎn)的索引的輸出列表。在所有隱藏點(diǎn)移除操作之后,點(diǎn)索引的聚合列表將包含所有未隱藏的點(diǎn)(即,位于點(diǎn)云的外表面上的點(diǎn))。以下代碼執(zhí)行此順序隱藏點(diǎn)刪除操作:
# 定義一個(gè)函數(shù)以在X、Y和Z軸上旋轉(zhuǎn)點(diǎn)云。
def get_rotated_pcd(pcd, x_theta, y_theta, z_theta):
pcd_rotated = copy.deepcopy(pcd)
R = pcd_rotated.get_rotation_matrix_from_axis_angle([x_theta, y_theta, z_theta])
pcd_rotated.rotate(R, center=(0, 0, 0))
return pcd_rotated
# 定義一個(gè)函數(shù)以獲取隱藏點(diǎn)移除操作的點(diǎn)云的相機(jī)和半徑參數(shù)。
def get_hpr_camera_radius(pcd):
diameter = np.linalg.norm(np.asarray(pcd.get_min_bound()) - np.asarray(pcd.get_max_bound()))
camera = [0, 0, diameter]
radius = diameter * 100
return camera, radius
# 定義一個(gè)函數(shù),使用前面定義的攝影機(jī)和半徑參數(shù)對(duì)點(diǎn)云執(zhí)行隱藏點(diǎn)刪除操作。
#輸出是未隱藏的點(diǎn)的索引列表。
def get_hpr_pt_map(pcd, camera, radius):
_, pt_map = pcd.hidden_point_removal(camera, radius)
return pt_map
# 通過(guò)在三個(gè)軸中的每一個(gè)軸上將點(diǎn)云從-90度略微旋轉(zhuǎn)到+90度,依次執(zhí)行隱藏點(diǎn)移除操作,并在每次操作后聚合未隱藏的點(diǎn)的索引列表。
# 定義一個(gè)列表來(lái)存儲(chǔ)每個(gè)隱藏點(diǎn)刪除操作的聚合輸出列表。
pt_map_aggregated = []
# 定義旋轉(zhuǎn)點(diǎn)云的步長(zhǎng)和角度值范圍。
theta_range = np.linspace(-90, 90, 7)
# 對(duì)順序操作的次數(shù)進(jìn)行計(jì)數(shù)。
view_counter = 1
total_views = theta_range.shape[0] ** 3
# 獲取隱藏點(diǎn)移除操作的相機(jī)和半徑參數(shù)。
camera, radius = get_hpr_camera_radius(pcd)
# 循環(huán)使用上面為每個(gè)軸定義的角度值。
for x_theta_deg in theta_range:
for y_theta_deg in theta_range:
for z_theta_deg in theta_range:
print(f"Removing hidden points - processing view {view_counter} of {total_views}.")
#按給定的角度值旋轉(zhuǎn)點(diǎn)云。
x_theta = deg2rad(x_theta_deg)
y_theta = deg2rad(y_theta_deg)
z_theta = deg2rad(z_theta_deg)
pcd_rotated = get_rotated_pcd(pcd, x_theta, y_theta, z_theta)
# 使用上面定義的攝影機(jī)和半徑參數(shù)對(duì)旋轉(zhuǎn)的點(diǎn)云執(zhí)行隱藏點(diǎn)移除操作。
pt_map = get_hpr_pt_map(pcd_rotated, camera, radius)
# 聚合未隱藏的點(diǎn)的索引的輸出列表。
pt_map_aggregated += pt_map
view_counter += 1
# 通過(guò)將聚合列表轉(zhuǎn)換為集合,從聚合列表中刪除所有重復(fù)的點(diǎn)。
pt_map_aggregated = list(set(pt_map_aggregated))
# 將點(diǎn)云中的所有可見(jiàn)點(diǎn)繪制為藍(lán)色,將所有隱藏點(diǎn)繪制為紅色。
pcd_visible = pcd.select_by_index(pt_map_aggregated)
pcd_visible.paint_uniform_color([0, 0, 1]) # 藍(lán)色點(diǎn)是可見(jiàn)點(diǎn)(需要保留)。
print("No. of visible points : ", pcd_visible)
pcd_hidden = pcd.select_by_index(pt_map_aggregated, invert=True)
pcd_hidden.paint_uniform_color([1, 0, 0]) # 紅色點(diǎn)是隱藏點(diǎn)(要?jiǎng)h除)。
print("No. of hidden points : ", pcd_hidden)
# 可視化點(diǎn)云中的可見(jiàn)(藍(lán)色)和隱藏(紅色)點(diǎn)。
draw_geoms_list = [mesh_coord_frame, pcd_visible, pcd_hidden]
# draw_geoms_list = [mesh_coord_frame, pcd_visible]
# draw_geoms_list = [mesh_coord_frame, pcd_hidden]
o3d.visualization.draw_geometries(draw_geoms_list)
從同一攝影機(jī)視點(diǎn)執(zhí)行所有順序隱藏點(diǎn)移除操作后的點(diǎn)云。聚合的“可見(jiàn)”點(diǎn)(即點(diǎn)云外表面上的點(diǎn))為藍(lán)色,而“隱藏”點(diǎn)(如不在點(diǎn)云外表面對(duì)的點(diǎn))則為紅色
讓我們?cè)俅尾眉酎c(diǎn)云,看看屬于汽車內(nèi)部的點(diǎn)。
#使用先前定義的邊界框裁剪可見(jiàn)點(diǎn)的點(diǎn)云,以移除其右半部分(正Z軸)。
pcd_visible_cropped = pcd_visible.crop(bbox_cropped)
# 使用先前定義的邊界框裁剪隱藏點(diǎn)的點(diǎn)云,以移除其右半部分(正Z軸)。
pcd_hidden_cropped = pcd_hidden.crop(bbox_cropped)
# 可視化裁剪的點(diǎn)云。
draw_geoms_list = [mesh_coord_frame, pcd_visible_cropped, pcd_hidden_cropped]
o3d.visualization.draw_geometries(draw_geoms_list)
在所有順序的隱藏點(diǎn)移除操作之后裁剪的點(diǎn)云,以紅色顯示屬于3D汽車模型內(nèi)部的所有“隱藏”點(diǎn)
從隱藏點(diǎn)移除操作后裁剪的點(diǎn)云的上述可視化中,我們可以看到,屬于汽車模型內(nèi)部的所有“隱藏”點(diǎn)(紅色)現(xiàn)在都與點(diǎn)云外表面的“可見(jiàn)”點(diǎn)(藍(lán)色)分離。
將點(diǎn)云轉(zhuǎn)換為數(shù)據(jù)幀
正如人們所期望的那樣,點(diǎn)云中每個(gè)點(diǎn)的位置可以由三個(gè)數(shù)值定義——X、Y和Z坐標(biāo)。請(qǐng)記住,在上面的部分中,我們還估計(jì)了3D網(wǎng)格中每個(gè)點(diǎn)的曲面法線。當(dāng)我們從該網(wǎng)格中采樣點(diǎn)以創(chuàng)建點(diǎn)云時(shí),點(diǎn)云中的每個(gè)點(diǎn)還包含與這些曲面法線相關(guān)的三個(gè)附加屬性——X、Y和Z方向上的法線單位向量坐標(biāo)。
因此,為了將點(diǎn)云轉(zhuǎn)換為數(shù)據(jù)幀,點(diǎn)云中的每個(gè)點(diǎn)都可以用以下七個(gè)屬性列在一行中來(lái)表示:
- X坐標(biāo)(浮動(dòng))
- Y坐標(biāo)(浮動(dòng))
- Z坐標(biāo)(浮動(dòng))
- X方向上的法向量坐標(biāo)(浮點(diǎn))
- Y方向上的法向量坐標(biāo)(浮點(diǎn))
- Z方向上的法向量坐標(biāo)(浮動(dòng))
- 可見(jiàn)點(diǎn)(布爾值True或False)
通過(guò)運(yùn)行以下代碼行,可以將點(diǎn)云轉(zhuǎn)換為數(shù)據(jù)幀:
# 為點(diǎn)云創(chuàng)建一個(gè)數(shù)據(jù)幀,其中包含所有點(diǎn)的X、Y和Z位置坐標(biāo)以及X、Y、Z方向上的法向單位向量坐標(biāo)。
pcd_df = pd.DataFrame(np.concatenate((np.asarray(pcd.points), np.asarray(pcd.normals)), axis=1),
columns=["x", "y", "z", "norm-x", "norm-y", "norm-z"]
)
# 使用上面隱藏點(diǎn)刪除操作中的點(diǎn)索引聚合列表,添加一列以指示點(diǎn)是否可見(jiàn)。
pcd_df["point_visible"] = False
pcd_df.loc[pt_map_aggregated, "point_visible"] = True
這將返回如下所示的數(shù)據(jù)幀,其中每個(gè)點(diǎn)都是由上面解釋的七個(gè)屬性列表示的行。
轉(zhuǎn)換為數(shù)據(jù)幀的三維點(diǎn)云
保存點(diǎn)云和數(shù)據(jù)幀
現(xiàn)在可以通過(guò)運(yùn)行以下代碼行來(lái)保存點(diǎn)云(刪除隱藏點(diǎn)之前和之后)和數(shù)據(jù)幀:
# 將整個(gè)點(diǎn)云保存為.pcd文件。
pcd_save_path = "data/3d_model.pcd"
o3d.io.write_point_cloud(pcd_save_path, pcd)
# 將刪除了隱藏點(diǎn)的點(diǎn)云保存為.pcd文件。
pcd_visible_save_path = "data/3d_model_hpr.pcd"
o3d.io.write_point_cloud(pcd_visible_save_path, pcd_visible)
# 將點(diǎn)云數(shù)據(jù)幀保存為.csv文件。
pcd_df_save_path = "data/3d_model.csv"
pcd_df.to_csv(pcd_df_save_path, index=False)
文章來(lái)源:http://www.zghlxwxcb.cn/news/detail-763395.html
三維模型(頂部:整體,底部:裁剪)可視化為:1——網(wǎng)格;2——一個(gè)點(diǎn)云;3——?jiǎng)h除隱藏點(diǎn)后的點(diǎn)云文章來(lái)源地址http://www.zghlxwxcb.cn/news/detail-763395.html
到了這里,關(guān)于如何使用Python的Open3D開(kāi)源庫(kù)進(jìn)行三維數(shù)據(jù)處理的文章就介紹完了。如果您還想了解更多內(nèi)容,請(qǐng)?jiān)谟疑辖撬阉鱐OY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章,希望大家以后多多支持TOY模板網(wǎng)!