众希网站建设,杭州 网站建设公司排名,wordpress系统选择,公司微网站怎么做的好一、前言
在三维点云处理与可视化中#xff0c;固定视角批量生成点云渲染截图是一个常见的需求。例如#xff0c;想要将同一系列的点云#xff08;PCD 文件#xff09;在同样的视角下生成序列图片#xff0c;以便后续合成为视频或进行其他可视化演示。本文将介绍如何使用…一、前言
在三维点云处理与可视化中固定视角批量生成点云渲染截图是一个常见的需求。例如想要将同一系列的点云PCD 文件在同样的视角下生成序列图片以便后续合成为视频或进行其他可视化演示。本文将介绍如何使用 Python Open3D 实现批量加载 PCD 文件、设置统一的相机视角并导出渲染截图。
二、环境准备
Python 环境建议使用 Python 3.7。Open3D 库本文使用的是 open3d 和 open3d.visualization.gui。安装方式如下pip install open3d其他依赖库 numpypickleglobtimeos 如果缺少对应的库使用 pip install 库名 即可。
三、代码解析
下面的代码分为几个主要部分
相机矩阵转换将 Open3D 的模型矩阵转换为外参矩阵。相机内参生成根据视口大小与视场角FOV生成相机内参。保存与加载相机视角使用 pickle 将当前相机的内外参持久化保存方便在下次使用时快速恢复相机位置。批量处理函数遍历指定文件夹下所有 .pcd 文件加载点云、应用相机视角、并自动保存渲染截图。主函数在 if __name__ __main__: 中调用批处理函数或先进行单独的相机视角设置保存操作。
完整代码如下可直接复制使用
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# 用于将坐标系转换为OpenGL风格
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转换为外参矩阵return np.linalg.inv(model_matrix FromGLGamera)def create_camera_intrinsic_from_size(width1024, height768, hfov60.0, vfov60.0):根据视口大小与水平/垂直FOV生成相机内参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, fnamesaved_view.pkl):保存当前可视化窗口的相机视角内参、外参、图像尺寸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(extrinsicextrinsic, intrinsicintrinsic, widthwidth, heightheight)with open(fname, wb) as pickle_file:dump(saved_view, pickle_file)print(fCamera view saved to {fname})except Exception as e:print(Error saving view:, e)def load_view(vis, fnamesaved_view.pkl):加载已保存的相机视角内参、外参、图像尺寸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(fCamera view loaded from {fname})except Exception as e:print(Cant load view file:, e)def process_pcd_folder(input_folder, output_folder, view_filesaved_view.pkl):批量处理文件夹中的所有 PCD 文件应用指定视角并保存截图os.makedirs(output_folder, exist_okTrue)pcd_files sorted(glob.glob(os.path.join(input_folder, *.pcd)))if not pcd_files:print(fNo PCD files found in {input_folder})returnprint(fFound {len(pcd_files)} PCD files)# 初始化GUIgui.Application.instance.initialize()vis o3d.visualization.O3DVisualizer(PCD Batch Renderer, 1920, 1080)gui.Application.instance.add_window(vis)# 设置渲染参数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(fProcessing {idx1}/{len(pcd_files)}: {os.path.basename(pcd_file)})try:# 加载点云文件pcd o3d.io.read_point_cloud(pcd_file)geom_name fPointCloud_{idx}# 清除之前所有几何体确保内存资源不会累积if idx 0:vis.remove_geometry(fPointCloud_{idx-1})vis.add_geometry(geom_name, pcd)# 加载预先保存的视角load_view(vis, view_file)# 构建输出路径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(fScreenshot saved to {output_path})# 处理完当前文件后处理下一个process_next(idx 1)# 使用post_to_main_thread确保截图任务在GUI线程执行gui.Application.instance.post_to_main_thread(vis, take_screenshot)except Exception as e:print(fError processing {pcd_file}: {e})# 出错时跳过当前文件继续下一个process_next(idx 1)# 开始处理第一个文件process_next(0)gui.Application.instance.run()def batch_process():主函数指定输入、输出文件夹以及相机视角文件然后进行批量处理input_folder ./inputoutput_folder ./screenshotsos.makedirs(output_folder, exist_okTrue)view_file saved_view.pklprocess_pcd_folder(input_folder, output_folder, view_file)if __name__ __main__:# 若需要先设置视角运行 save_view 所在的逻辑# 若已设置好视角运行 batch_process()批量处理batch_process()1. 代码主要流程
读取文件列表通过 glob.glob 获取指定文件夹下的所有 .pcd 文件并排序。初始化 Open3D GUI使用 O3DVisualizer 进行可视化。循环处理每个 PCD 读取点云数据 pcd o3d.io.read_point_cloud(...)加载之前保存的视角参数 load_view(vis, view_file)设置几何体到渲染窗口通过 vis.export_current_image(...) 将当前视图截图保存 处理结束后退出当全部 .pcd 文件处理完毕自动退出 GUI。
2. 视角保存与加载
save_view(vis, fnamesaved_view.pkl)从当前的 vis.scene.camera 获取 model_matrix然后计算外参矩阵、内参矩阵并存储到一个字典中通过 pickle 持久化到 saved_view.pkl 文件。load_view(vis, fnamesaved_view.pkl)从文件中读取上述字典调用 vis.setup_camera(...) 将相机恢复到保存时的视角。
这样做的好处是我们可以先交互式地在 Open3D 中调整一个理想的点云视角然后保存该视角。后续就可以用同样的参数去渲染其他点云实现“统一视角”输出。
3. 视角设置的两种方式
先在单个点云上用脚本交互式设置并保存 先运行一个类似的脚本只加载一个点云不做批处理。在界面中使用鼠标旋转/平移点云至理想位置然后调用 save_view(vis)。 直接修改代码中的相机参数如果你对内参、外参很熟悉也可以直接硬编码想要的矩阵。
四、使用说明
准备 PCD 文件将所有需要处理的 .pcd 文件放在同一个文件夹中。保存视角可选 若你已知道要使用的视角参数可以跳过这一步否则先写个简单脚本加载一两个 PCD 文件后通过交互操作找到满意的视角执行 save_view(vis)。此时会生成一个 saved_view.pkl 文件里面记录了相机的内外参。 运行批处理 修改 batch_process() 中的 input_folder 和 output_folder 为你的输入、输出路径。运行脚本后Open3D 窗口会依次加载每个 .pcd应用保存好的视角然后自动截图并存储到 output_folder 中。
在所有点云都处理完后你就能在输出文件夹下看到对应的 .png 文件序列。
五、结果展示
下面是一张示例截图展示了点云在固定视角下的渲染效果仅做示意非实际数据
六、后续扩展
生成视频如果想将渲染好的序列图片合成为视频可使用 ffmpeg示例命令如下ffmpeg -framerate 10 -i labeled_sync_frame_%03d.png -c:v libx264 -pix_fmt yuv420p output.mp4其中 -framerate 10 表示每秒 10 帧可根据需要调整。更多可视化选项如改变 point_size、背景颜色、或添加坐标轴等可参考 Open3D 文档或修改 O3DVisualizer 的属性。其他文件格式如果想批量处理 .ply 或 .xyz只需要在代码中修改对应的读取方式以及 glob.glob 匹配模式即可。
七、总结
通过上述方法可以轻松地在同一视角下对多份点云进行批量渲染和截图适用于制作点云动画、对比分析等场景。核心思想是事先保存好相机参数并在批处理过程中为每个点云恢复相同的内外参保证输出图像的视角一致。希望对你的三维可视化工作有所帮助欢迎交流讨论