当前位置: 首页 > news >正文

使用 Open3D 批量渲染并导出固定视角点云截图

一、前言

在三维点云处理与可视化中,固定视角批量生成点云渲染截图是一个常见的需求。例如,想要将同一系列的点云(PCD 文件)在同样的视角下生成序列图片,以便后续合成为视频或进行其他可视化演示。本文将介绍如何使用 Python + Open3D 实现批量加载 PCD 文件、设置统一的相机视角,并导出渲染截图。

二、环境准备

  1. Python 环境:建议使用 Python 3.7+。
  2. Open3D 库:本文使用的是 open3dopen3d.visualization.gui。安装方式如下:
    pip install open3d
    
  3. 其他依赖库
    • numpy
    • pickle
    • glob
    • time
    • os
      如果缺少对应的库,使用 pip install 库名 即可。

三、代码解析

下面的代码分为几个主要部分:

  1. 相机矩阵转换:将 Open3D 的模型矩阵转换为外参矩阵。
  2. 相机内参生成:根据视口大小与视场角(FOV)生成相机内参。
  3. 保存与加载相机视角:使用 pickle 将当前相机的内外参持久化保存,方便在下次使用时快速恢复相机位置。
  4. 批量处理函数:遍历指定文件夹下所有 .pcd 文件,加载点云、应用相机视角、并自动保存渲染截图。
  5. 主函数:在 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(width=1024, height=768, hfov=60.0, vfov=60.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, fname='saved_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(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"):"""加载已保存的相机视角(内参、外参、图像尺寸)"""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 文件,应用指定视角并保存截图"""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)# 设置渲染参数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:# 加载点云文件pcd = o3d.io.read_point_cloud(pcd_file)geom_name = f"PointCloud_{idx}"# 清除之前所有几何体,确保内存资源不会累积if idx > 0:vis.remove_geometry(f"PointCloud_{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(f"Screenshot 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(f"Error processing {pcd_file}: {e}")# 出错时跳过当前文件,继续下一个process_next(idx + 1)# 开始处理第一个文件process_next(0)gui.Application.instance.run()def batch_process():"""主函数:指定输入、输出文件夹以及相机视角文件,然后进行批量处理"""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__":# 若需要先设置视角,运行 save_view 所在的逻辑# 若已设置好视角,运行 batch_process()批量处理batch_process()

1. 代码主要流程

  • 读取文件列表:通过 glob.glob 获取指定文件夹下的所有 .pcd 文件并排序。
  • 初始化 Open3D GUI:使用 O3DVisualizer 进行可视化。
  • 循环处理每个 PCD
    1. 读取点云数据 pcd = o3d.io.read_point_cloud(...)
    2. 加载之前保存的视角参数 load_view(vis, view_file)
    3. 设置几何体到渲染窗口
    4. 通过 vis.export_current_image(...) 将当前视图截图保存
  • 处理结束后退出:当全部 .pcd 文件处理完毕,自动退出 GUI。

2. 视角保存与加载

  • save_view(vis, fname='saved_view.pkl'):从当前的 vis.scene.camera 获取 model_matrix,然后计算外参矩阵、内参矩阵并存储到一个字典中,通过 pickle 持久化到 saved_view.pkl 文件。
  • load_view(vis, fname='saved_view.pkl'):从文件中读取上述字典,调用 vis.setup_camera(...) 将相机恢复到保存时的视角。

这样做的好处是,我们可以先交互式地在 Open3D 中调整一个理想的点云视角,然后保存该视角。后续就可以用同样的参数去渲染其他点云,实现“统一视角”输出。

3. 视角设置的两种方式

  1. 先在单个点云上用脚本交互式设置并保存
    • 先运行一个类似的脚本,只加载一个点云,不做批处理。
    • 在界面中使用鼠标旋转/平移点云至理想位置,然后调用 save_view(vis)
  2. 直接修改代码中的相机参数:如果你对内参、外参很熟悉,也可以直接硬编码想要的矩阵。

四、使用说明

  1. 准备 PCD 文件:将所有需要处理的 .pcd 文件放在同一个文件夹中。
  2. 保存视角(可选):
    • 若你已知道要使用的视角参数,可以跳过这一步;否则先写个简单脚本,加载一两个 PCD 文件后,通过交互操作找到满意的视角,执行 save_view(vis)
    • 此时会生成一个 saved_view.pkl 文件,里面记录了相机的内外参。
  3. 运行批处理
    • 修改 batch_process() 中的 input_folderoutput_folder 为你的输入、输出路径。
    • 运行脚本后,Open3D 窗口会依次加载每个 .pcd,应用保存好的视角,然后自动截图并存储到 output_folder 中。

在所有点云都处理完后,你就能在输出文件夹下看到对应的 .png 文件序列。

五、结果展示

下面是一张示例截图,展示了点云在固定视角下的渲染效果(仅做示意,非实际数据):
在这里插入图片描述

六、后续扩展

  1. 生成视频:如果想将渲染好的序列图片合成为视频,可使用 ffmpeg,示例命令如下:
    ffmpeg -framerate 10 -i labeled_sync_frame_%03d.png -c:v libx264 -pix_fmt yuv420p output.mp4
    
    其中 -framerate 10 表示每秒 10 帧,可根据需要调整。
  2. 更多可视化选项:如改变 point_size、背景颜色、或添加坐标轴等,可参考 Open3D 文档或修改 O3DVisualizer 的属性。
  3. 其他文件格式:如果想批量处理 .ply.xyz,只需要在代码中修改对应的读取方式,以及 glob.glob 匹配模式即可。

七、总结

通过上述方法,可以轻松地在同一视角下对多份点云进行批量渲染和截图,适用于制作点云动画、对比分析等场景。核心思想是事先保存好相机参数,并在批处理过程中为每个点云恢复相同的内外参,保证输出图像的视角一致。希望对你的三维可视化工作有所帮助,欢迎交流讨论!

相关文章:

使用 Open3D 批量渲染并导出固定视角点云截图

一、前言 在三维点云处理与可视化中,固定视角批量生成点云渲染截图是一个常见的需求。例如,想要将同一系列的点云(PCD 文件)在同样的视角下生成序列图片,以便后续合成为视频或进行其他可视化演示。本文将介绍如何使用…...

汽车无钥匙进入一键启动操作正确步骤

汽车智能无钥匙进入和一键启动的技术在近年来比较成熟,不同车型的操作步骤可能略有不同,但基本的流程应该是通用的,不会因为时间变化而有大的改变。 移动管家汽车一键启动无钥匙进入系统通常是通过携带钥匙靠近车辆,然后触摸门把…...

JMeter 的基础知识-安装部分

以下将从环境配置开始,为你详细介绍 JMeter 的基础知识,涵盖环境搭建、界面认知、测试计划创建、常用组件使用等方面内容。 1. 环境配置 1.1 安装 Java JMeter 是基于 Java 开发的,所以需要先安装 Java 开发工具包(JDK)。 下载 JDK:访问 Oracle 官方网站(https://www…...

解决后端跨域问题

目录 一、什么是跨域问题? 1、跨域问题的定义 2、举例 3、为什么会有跨域问题的存在? 二、解决跨域问题 1、新建配置类 2、编写代码 三、结语 一、什么是跨域问题? 1、跨域问题的定义 跨域问题(Cross-Origin Resource Sh…...

补题A-E Codeforces Round 953 (Div. 2)

https://codeforces.com/contest/1979 A. Guess the Maximum 原题链接&#xff1a;https://codeforces.com/contest/1979/problem/A 求相邻元素的最大值的最小值。 #include <bits/stdc.h> using namespace std; #define IOS ios::sync_with_stdio(0), cin.tie(0), cout…...

【WordPress】发布文章时自动通过机器人推送到钉钉

在您的主题下functions.php中添加如下代码&#xff1a; function wpso_dingding_publish_notify($post_ID) {// 获取文章对象$post get_post($post_ID);// 检查是否是文章首次发布&#xff08;即不是修订版&#xff09;if (get_post_status($post_ID) publish && !g…...

鸿蒙开发深入浅出04(首页数据渲染、搜索、Stack样式堆叠、Grid布局、shadow阴影)

鸿蒙开发深入浅出04&#xff08;首页数据渲染、搜索、Stack样式堆叠、Grid布局、shadow阴影&#xff09; 1、效果展示2、ets/pages/Home.ets3、ets/views/Home/SearchBar.ets4、ets/views/Home/NavList.ets5、ets/views/Home/TileList.ets6、ets/views/Home/PlanList.ets7、后端…...

管道文件(1)

1.无名管道&#xff1a;在同一主机下&#xff0c;具有亲缘关系的进程间的通信&#xff0c;如父子进程间的通信。 2.有名管道&#xff1a;在同一主机下的任意进程间的通信。 &#xff08;1&#xff09;管道的创建 &#xff08;2&#xff09;管道的打开&#xff08;open&#xff…...

什么是AI agent技术,有哪些著名案例

AI Agent技术是一种基于人工智能的智能实体&#xff0c;能够感知环境、进行决策和执行动作&#xff0c;以实现特定目标。近年来&#xff0c;随着大模型&#xff08;如GPT-4&#xff09;和生成式AI技术的发展&#xff0c;AI Agent在多个领域得到了广泛应用&#xff0c;并取得了显…...

Cursor结合Claude 3.7零基础开发愤怒的小鸟【深夜Claude 3.7系列发布,类似DeepSeek-R1和V3的合体?】

文章目录 前言介绍“市面上唯一的混合模型”卓越的编程能力、精准控制思考时间Cursor已接入Cursor结合Claude 3.7快速编写游戏完整html代码 &#x1f343;作者介绍&#xff1a;双非本科大四网络工程专业在读&#xff0c;阿里云专家博主&#xff0c;前三年专注于Java领域学习&am…...

基于 Python 的天气数据分析与可视化

基于 Python 的天气数据分析与可视化 1. 项目背景 天气数据分析与可视化项目旨在通过爬取天气数据并进行分析&#xff0c;生成可视化图表&#xff0c;帮助用户了解天气变化趋势。通过该项目&#xff0c;学生可以掌握 Python 的数据爬取、数据分析和可视化技能。该项目适用于气…...

Bybit事件技术分析

事件概述 2025年2月21日UTC时间下午02:16:11&#xff0c;Bybit的以太坊冷钱包&#xff08;0x1db92e2eebc8e0c075a02bea49a2935bcd2dfcf4&#xff09;因恶意合约升级遭到资金盗取。根据Bybit CEO Ben Zhou的声明&#xff0c;攻击者通过钓鱼攻击诱骗冷钱包签名者错误签署恶意交易…...

JavaWeb-在idea中配置Servlet项目

文章目录 在idea中进行Servlet项目的配置(较新的idea版本)创建一个空的JavaSE项目(Project)创建一个普通的JavaSE板块(module)添加Web项目的配置定义一个对象模拟实现接口在web.xml中配置路径映射配置项目到Tomcat服务器启动Tomcat服务器进行测试 在idea中进行Servlet项目的配置…...

redis小记

redis小记 下载redis sudo apt-get install redis-server redis基本命令 ubuntu16下的redis没有protected-mode属性&#xff0c;就算sudo启动&#xff0c;也不能往/var/spool/cron/crontabs写计划任务&#xff0c;感觉很安全 #连接到redis redis-cli -h 127.0.0.1 -p 6379 …...

垂类大模型微调(一):认识LLaMA-Factory

LlamaFactory 是一个专注于 高效微调大型语言模型(LLMs) 的开源工具框架,尤其以支持 LLaMA(Meta 的大型语言模型系列)及其衍生模型(如 Chinese-LLaMA、Alpaca 等)而闻名。它的目标是简化模型微调流程,降低用户使用门槛; 官方文档 一、介绍 高效微调支持 支持多种微调…...

企业为什么要选择软件测试外包公司?湖南软件测试公司有哪些?

在当今快速发展的技术背景下&#xff0c;软件测试已成为软件开发生命周期的重要一环。随着企业对软件质量要求的不断提高&#xff0c;软件测试外包公司逐渐被越来越多的企业所青睐。 软件测试外包公司通过将软件测试从内部团队外包出去&#xff0c;帮助企业减少开发成本、提升…...

数据保护API(DPAPI)深度剖析与安全实践

Windows DPAPI 安全机制解析 在当今数据泄露与网络攻击日益频繁的背景下&#xff0c;Windows 提供的 DPAPI&#xff08;Data Protection API&#xff09;成为开发者保护本地敏感数据的重要工具。本文将从 双层密钥体系、加密流程、跨上下文加密、已知攻击向量与防御措施、企业…...

java23种设计模式-桥接模式

桥接模式&#xff08;Bridge Pattern&#xff09;学习笔记 &#x1f31f; 定义 桥接模式属于结构型设计模式&#xff0c;将抽象部分与实现部分分离&#xff0c;使它们可以独立变化。通过组合代替继承的方式&#xff0c;解决多维度的扩展问题&#xff0c;防止类爆炸。 &#x…...

3D Web轻量化引擎HOOPS Communicator如何赋能航空航天制造?

在当今航空航天制造领域&#xff0c;精确度、效率和协作是推动行业发展的关键要素。随着数字化技术的飞速发展&#xff0c;3D Web可视化开发包HOOPS Communicator 为航空航天制造带来了革命性的变化。它凭借强大的功能和灵活的应用&#xff0c;助力企业在设计、生产、培训等各个…...

iOS手机App爬虫- (1) Mac安装Appium真机运行环境

iOS手机App爬虫 一、环境准备与工具安装1. 开发基础环境配置1.1 Node.js环境1.2 Xcode套件1.3 Java环境 2. 核心测试工具链2.1 Appium主程序2.2 辅助工具集 3. 可视化工具 二、设备与环境验证1. 设备信息获取2. 环境健康检查 三、WebDriverAgent编译部署1. 设备端准备2. 项目配…...

浅谈 React Hooks

React Hooks 是 React 16.8 引入的一组 API&#xff0c;用于在函数组件中使用 state 和其他 React 特性&#xff08;例如生命周期方法、context 等&#xff09;。Hooks 通过简洁的函数接口&#xff0c;解决了状态与 UI 的高度解耦&#xff0c;通过函数式编程范式实现更灵活 Rea…...

conda相比python好处

Conda 作为 Python 的环境和包管理工具&#xff0c;相比原生 Python 生态&#xff08;如 pip 虚拟环境&#xff09;有许多独特优势&#xff0c;尤其在多项目管理、依赖处理和跨平台兼容性等方面表现更优。以下是 Conda 的核心好处&#xff1a; 一、一站式环境管理&#xff1a…...

【网络】每天掌握一个Linux命令 - iftop

在Linux系统中&#xff0c;iftop是网络管理的得力助手&#xff0c;能实时监控网络流量、连接情况等&#xff0c;帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...

基于大模型的 UI 自动化系统

基于大模型的 UI 自动化系统 下面是一个完整的 Python 系统,利用大模型实现智能 UI 自动化,结合计算机视觉和自然语言处理技术,实现"看屏操作"的能力。 系统架构设计 #mermaid-svg-2gn2GRvh5WCP2ktF {font-family:"trebuchet ms",verdana,arial,sans-…...

Unity3D中Gfx.WaitForPresent优化方案

前言 在Unity中&#xff0c;Gfx.WaitForPresent占用CPU过高通常表示主线程在等待GPU完成渲染&#xff08;即CPU被阻塞&#xff09;&#xff0c;这表明存在GPU瓶颈或垂直同步/帧率设置问题。以下是系统的优化方案&#xff1a; 对惹&#xff0c;这里有一个游戏开发交流小组&…...

SCAU期末笔记 - 数据分析与数据挖掘题库解析

这门怎么题库答案不全啊日 来简单学一下子来 一、选择题&#xff08;可多选&#xff09; 将原始数据进行集成、变换、维度规约、数值规约是在以下哪个步骤的任务?(C) A. 频繁模式挖掘 B.分类和预测 C.数据预处理 D.数据流挖掘 A. 频繁模式挖掘&#xff1a;专注于发现数据中…...

(二)原型模式

原型的功能是将一个已经存在的对象作为源目标,其余对象都是通过这个源目标创建。发挥复制的作用就是原型模式的核心思想。 一、源型模式的定义 原型模式是指第二次创建对象可以通过复制已经存在的原型对象来实现,忽略对象创建过程中的其它细节。 📌 核心特点: 避免重复初…...

pikachu靶场通关笔记22-1 SQL注入05-1-insert注入(报错法)

目录 一、SQL注入 二、insert注入 三、报错型注入 四、updatexml函数 五、源码审计 六、insert渗透实战 1、渗透准备 2、获取数据库名database 3、获取表名table 4、获取列名column 5、获取字段 本系列为通过《pikachu靶场通关笔记》的SQL注入关卡(共10关&#xff0…...

CMake控制VS2022项目文件分组

我们可以通过 CMake 控制源文件的组织结构,使它们在 VS 解决方案资源管理器中以“组”(Filter)的形式进行分类展示。 🎯 目标 通过 CMake 脚本将 .cpp、.h 等源文件分组显示在 Visual Studio 2022 的解决方案资源管理器中。 ✅ 支持的方法汇总(共4种) 方法描述是否推荐…...

关键领域软件测试的突围之路:如何破解安全与效率的平衡难题

在数字化浪潮席卷全球的今天&#xff0c;软件系统已成为国家关键领域的核心战斗力。不同于普通商业软件&#xff0c;这些承载着国家安全使命的软件系统面临着前所未有的质量挑战——如何在确保绝对安全的前提下&#xff0c;实现高效测试与快速迭代&#xff1f;这一命题正考验着…...