asp網(wǎng)站鏈接access廣州seo關(guān)鍵詞優(yōu)化是什么
一、前言
在三維點(diǎn)云處理與可視化中,固定視角批量生成點(diǎn)云渲染截圖是一個(gè)常見(jiàn)的需求。例如,想要將同一系列的點(diǎn)云(PCD 文件)在同樣的視角下生成序列圖片,以便后續(xù)合成為視頻或進(jìn)行其他可視化演示。本文將介紹如何使用 Python + Open3D 實(shí)現(xiàn)批量加載 PCD 文件、設(shè)置統(tǒng)一的相機(jī)視角,并導(dǎo)出渲染截圖。
二、環(huán)境準(zhǔn)備
- Python 環(huán)境:建議使用 Python 3.7+。
- Open3D 庫(kù):本文使用的是
open3d
和open3d.visualization.gui
。安裝方式如下:pip install open3d
- 其他依賴庫(kù):
numpy
pickle
glob
time
os
如果缺少對(duì)應(yīng)的庫(kù),使用pip install 庫(kù)名
即可。
三、代碼解析
下面的代碼分為幾個(gè)主要部分:
- 相機(jī)矩陣轉(zhuǎn)換:將 Open3D 的模型矩陣轉(zhuǎn)換為外參矩陣。
- 相機(jī)內(nèi)參生成:根據(jù)視口大小與視場(chǎng)角(FOV)生成相機(jī)內(nèi)參。
- 保存與加載相機(jī)視角:使用
pickle
將當(dāng)前相機(jī)的內(nèi)外參持久化保存,方便在下次使用時(shí)快速恢復(fù)相機(jī)位置。 - 批量處理函數(shù):遍歷指定文件夾下所有
.pcd
文件,加載點(diǎn)云、應(yīng)用相機(jī)視角、并自動(dòng)保存渲染截圖。 - 主函數(shù):在
if __name__ == "__main__":
中調(diào)用批處理函數(shù),或先進(jìn)行單獨(dú)的相機(jī)視角設(shè)置保存操作。
完整代碼如下(可直接復(fù)制使用):
import numpy as np
import open3d as o3d
import open3d.visualization.gui as gui
from pickle import load, dump
import os
import glob
import time# 用于將坐標(biāo)系轉(zhuǎn)換為OpenGL風(fēng)格
ToGLCamera = np.array([[1, 0, 0, 0],[0, -1, 0, 0],[0, 0, -1, 0],[0, 0, 0, 1]
])
FromGLGamera = np.linalg.inv(ToGLCamera)def model_matrix_to_extrinsic_matrix(model_matrix):"""將Open3D的model_matrix轉(zhuǎn)換為外參矩陣"""return np.linalg.inv(model_matrix @ FromGLGamera)def create_camera_intrinsic_from_size(width=1024, height=768, hfov=60.0, vfov=60.0):"""根據(jù)視口大小與水平/垂直FOV生成相機(jī)內(nèi)參"""fx = (width / 2.0) / np.tan(np.radians(hfov) / 2)fy = (height / 2.0) / np.tan(np.radians(vfov) / 2)return np.array([[fx, 0, width / 2.0],[0, fy, height / 2.0],[0, 0, 1]])def save_view(vis, fname='saved_view.pkl'):"""保存當(dāng)前可視化窗口的相機(jī)視角(內(nèi)參、外參、圖像尺寸)"""try:model_matrix = np.asarray(vis.scene.camera.get_model_matrix())extrinsic = model_matrix_to_extrinsic_matrix(model_matrix)width, height = vis.size.width, vis.size.heightintrinsic = create_camera_intrinsic_from_size(width, height)saved_view = dict(extrinsic=extrinsic, intrinsic=intrinsic, width=width, height=height)with open(fname, 'wb') as pickle_file:dump(saved_view, pickle_file)print(f"Camera view saved to {fname}")except Exception as e:print("Error saving view:", e)def load_view(vis, fname="saved_view.pkl"):"""加載已保存的相機(jī)視角(內(nèi)參、外參、圖像尺寸)"""try:with open(fname, 'rb') as pickle_file:saved_view = load(pickle_file)vis.setup_camera(saved_view['intrinsic'], saved_view['extrinsic'],saved_view['width'], saved_view['height'])print(f"Camera view loaded from {fname}")except Exception as e:print("Can't load view file:", e)def process_pcd_folder(input_folder, output_folder, view_file='saved_view.pkl'):"""批量處理文件夾中的所有 PCD 文件,應(yīng)用指定視角并保存截圖"""os.makedirs(output_folder, exist_ok=True)pcd_files = sorted(glob.glob(os.path.join(input_folder, "*.pcd")))if not pcd_files:print(f"No PCD files found in {input_folder}")returnprint(f"Found {len(pcd_files)} PCD files")# 初始化GUIgui.Application.instance.initialize()vis = o3d.visualization.O3DVisualizer("PCD Batch Renderer", 1920, 1080)gui.Application.instance.add_window(vis)# 設(shè)置渲染參數(shù)vis.point_size = 4vis.show_axes = Falsevis.show_skybox(False)def process_next(idx):if idx >= len(pcd_files):print("Batch processing completed!")gui.Application.instance.quit()returnpcd_file = pcd_files[idx]print(f"Processing {idx+1}/{len(pcd_files)}: {os.path.basename(pcd_file)}")try:# 加載點(diǎn)云文件pcd = o3d.io.read_point_cloud(pcd_file)geom_name = f"PointCloud_{idx}"# 清除之前所有幾何體,確保內(nèi)存資源不會(huì)累積if idx > 0:vis.remove_geometry(f"PointCloud_{idx-1}")vis.add_geometry(geom_name, pcd)# 加載預(yù)先保存的視角load_view(vis, view_file)# 構(gòu)建輸出路徑base_name = os.path.splitext(os.path.basename(pcd_file))[0]output_path = os.path.join(output_folder, f"{base_name}.png")def take_screenshot():# 延遲1秒以確保視角和渲染完全加載time.sleep(1)vis.export_current_image(output_path)print(f"Screenshot saved to {output_path}")# 處理完當(dāng)前文件后,處理下一個(gè)process_next(idx + 1)# 使用post_to_main_thread確保截圖任務(wù)在GUI線程執(zhí)行gui.Application.instance.post_to_main_thread(vis, take_screenshot)except Exception as e:print(f"Error processing {pcd_file}: {e}")# 出錯(cuò)時(shí)跳過(guò)當(dāng)前文件,繼續(xù)下一個(gè)process_next(idx + 1)# 開(kāi)始處理第一個(gè)文件process_next(0)gui.Application.instance.run()def batch_process():"""主函數(shù):指定輸入、輸出文件夾以及相機(jī)視角文件,然后進(jìn)行批量處理"""input_folder = './input'output_folder = './screenshots'os.makedirs(output_folder, exist_ok=True)view_file = 'saved_view.pkl'process_pcd_folder(input_folder, output_folder, view_file)if __name__ == "__main__":# 若需要先設(shè)置視角,運(yùn)行 save_view 所在的邏輯# 若已設(shè)置好視角,運(yùn)行 batch_process()批量處理batch_process()
1. 代碼主要流程
- 讀取文件列表:通過(guò)
glob.glob
獲取指定文件夾下的所有.pcd
文件并排序。 - 初始化 Open3D GUI:使用
O3DVisualizer
進(jìn)行可視化。 - 循環(huán)處理每個(gè) PCD:
- 讀取點(diǎn)云數(shù)據(jù)
pcd = o3d.io.read_point_cloud(...)
- 加載之前保存的視角參數(shù)
load_view(vis, view_file)
- 設(shè)置幾何體到渲染窗口
- 通過(guò)
vis.export_current_image(...)
將當(dāng)前視圖截圖保存
- 讀取點(diǎn)云數(shù)據(jù)
- 處理結(jié)束后退出:當(dāng)全部
.pcd
文件處理完畢,自動(dòng)退出 GUI。
2. 視角保存與加載
save_view(vis, fname='saved_view.pkl')
:從當(dāng)前的vis.scene.camera
獲取model_matrix
,然后計(jì)算外參矩陣、內(nèi)參矩陣并存儲(chǔ)到一個(gè)字典中,通過(guò)pickle
持久化到saved_view.pkl
文件。load_view(vis, fname='saved_view.pkl')
:從文件中讀取上述字典,調(diào)用vis.setup_camera(...)
將相機(jī)恢復(fù)到保存時(shí)的視角。
這樣做的好處是,我們可以先交互式地在 Open3D 中調(diào)整一個(gè)理想的點(diǎn)云視角,然后保存該視角。后續(xù)就可以用同樣的參數(shù)去渲染其他點(diǎn)云,實(shí)現(xiàn)“統(tǒng)一視角”輸出。
3. 視角設(shè)置的兩種方式
- 先在單個(gè)點(diǎn)云上用腳本交互式設(shè)置并保存:
- 先運(yùn)行一個(gè)類似的腳本,只加載一個(gè)點(diǎn)云,不做批處理。
- 在界面中使用鼠標(biāo)旋轉(zhuǎn)/平移點(diǎn)云至理想位置,然后調(diào)用
save_view(vis)
。
- 直接修改代碼中的相機(jī)參數(shù):如果你對(duì)內(nèi)參、外參很熟悉,也可以直接硬編碼想要的矩陣。
四、使用說(shuō)明
- 準(zhǔn)備 PCD 文件:將所有需要處理的
.pcd
文件放在同一個(gè)文件夾中。 - 保存視角(可選):
- 若你已知道要使用的視角參數(shù),可以跳過(guò)這一步;否則先寫(xiě)個(gè)簡(jiǎn)單腳本,加載一兩個(gè) PCD 文件后,通過(guò)交互操作找到滿意的視角,執(zhí)行
save_view(vis)
。 - 此時(shí)會(huì)生成一個(gè)
saved_view.pkl
文件,里面記錄了相機(jī)的內(nèi)外參。
- 若你已知道要使用的視角參數(shù),可以跳過(guò)這一步;否則先寫(xiě)個(gè)簡(jiǎn)單腳本,加載一兩個(gè) PCD 文件后,通過(guò)交互操作找到滿意的視角,執(zhí)行
- 運(yùn)行批處理:
- 修改
batch_process()
中的input_folder
和output_folder
為你的輸入、輸出路徑。 - 運(yùn)行腳本后,Open3D 窗口會(huì)依次加載每個(gè)
.pcd
,應(yīng)用保存好的視角,然后自動(dòng)截圖并存儲(chǔ)到output_folder
中。
- 修改
在所有點(diǎn)云都處理完后,你就能在輸出文件夾下看到對(duì)應(yīng)的 .png
文件序列。
五、結(jié)果展示
下面是一張示例截圖,展示了點(diǎn)云在固定視角下的渲染效果(僅做示意,非實(shí)際數(shù)據(jù)):
六、后續(xù)擴(kuò)展
- 生成視頻:如果想將渲染好的序列圖片合成為視頻,可使用
ffmpeg
,示例命令如下:
其中ffmpeg -framerate 10 -i labeled_sync_frame_%03d.png -c:v libx264 -pix_fmt yuv420p output.mp4
-framerate 10
表示每秒 10 幀,可根據(jù)需要調(diào)整。 - 更多可視化選項(xiàng):如改變
point_size
、背景顏色、或添加坐標(biāo)軸等,可參考 Open3D 文檔或修改O3DVisualizer
的屬性。 - 其他文件格式:如果想批量處理
.ply
或.xyz
,只需要在代碼中修改對(duì)應(yīng)的讀取方式,以及glob.glob
匹配模式即可。
七、總結(jié)
通過(guò)上述方法,可以輕松地在同一視角下對(duì)多份點(diǎn)云進(jìn)行批量渲染和截圖,適用于制作點(diǎn)云動(dòng)畫(huà)、對(duì)比分析等場(chǎng)景。核心思想是事先保存好相機(jī)參數(shù),并在批處理過(guò)程中為每個(gè)點(diǎn)云恢復(fù)相同的內(nèi)外參,保證輸出圖像的視角一致。希望對(duì)你的三維可視化工作有所幫助,歡迎交流討論!