3D Gaussian splatting 04: 代码阅读-提取相机位姿和稀疏点云
目录
- 3D Gaussian splatting 01: 环境搭建
- 3D Gaussian splatting 02: 快速评估
- 3D Gaussian splatting 03: 用户数据训练和结果查看
- 3D Gaussian splatting 04: 代码阅读-提取相机位姿和稀疏点云
- 3D Gaussian splatting 05: 代码阅读-训练整体流程
- 3D Gaussian splatting 06: 代码阅读-训练参数
- 3D Gaussian splatting 07: 代码阅读-训练载入数据和保存结果
- 3D Gaussian splatting 08: 代码阅读-渲染
代码阅读: 预处理阶段
convert.py 用于从帧系列中提取相机参数, 相机位姿和对象特征点的稀疏点云, 从 convert.py 的代码可以看到转换阶段的处理流程:
1. 3D稀疏点云重建
## Feature extraction
feat_extracton_cmd = colmap_command + " feature_extractor "\"--database_path " + args.source_path + "/distorted/database.db \--image_path " + args.source_path + "/input \--ImageReader.single_camera 1 \--ImageReader.camera_model " + args.camera + " \--SiftExtraction.use_gpu " + str(use_gpu)
exit_code = os.system(feat_extracton_cmd)
if exit_code != 0:logging.error(f"Feature extraction failed with code {exit_code}. Exiting.")exit(exit_code)## Feature matching
feat_matching_cmd = colmap_command + " exhaustive_matcher \--database_path " + args.source_path + "/distorted/database.db \--SiftMatching.use_gpu " + str(use_gpu)
exit_code = os.system(feat_matching_cmd)
if exit_code != 0:logging.error(f"Feature matching failed with code {exit_code}. Exiting.")exit(exit_code)### Bundle adjustment
# The default Mapper tolerance is unnecessarily large,
# decreasing it speeds up bundle adjustment steps.
mapper_cmd = (colmap_command + " mapper \--database_path " + args.source_path + "/distorted/database.db \--image_path " + args.source_path + "/input \--output_path " + args.source_path + "/distorted/sparse \--Mapper.ba_global_function_tolerance=0.000001")
exit_code = os.system(mapper_cmd)
if exit_code != 0:logging.error(f"Mapper failed with code {exit_code}. Exiting.")exit(exit_code)
提取流程
- 特征点提取 feature_extractor
生成每一帧的特征点 - 特征匹配 exhaustive_matcher
图像间匹配的特征点对, 建立2D-2D几何约束 - 稀疏三维重建 mapper
生成相机位姿 + 稀疏3D点云, 通过SfM恢复3D结构和相机运动
说明
- 相机模型参数
camera_model
, 默认使用的是OPENCV
- 用
skip_matching
参数可以跳过这个步骤, 这个阶段生成的数据会保存在 distorted 目录下, 这是用 colmap 直接处理产生的结果
2. 图像去畸变
### Image undistortion
## We need to undistort our images into ideal pinhole intrinsics.
img_undist_cmd = (colmap_command + " image_undistorter \--image_path " + args.source_path + "/input \--input_path " + args.source_path + "/distorted/sparse/0 \--output_path " + args.source_path + "\--output_type COLMAP")
exit_code = os.system(img_undist_cmd)
if exit_code != 0:logging.error(f"Mapper failed with code {exit_code}. Exiting.")exit(exit_code)
将上一步生成的文件, 使用colmap image_undistorter
处理后输出到 sparse 目录, 最后移动到 sparse/0 目录下.
image_undistorter 涉及的处理包含
- 去畸变 Undistortion: 根据相机的内参和畸变系数(通常来自
database.db
或cameras.txt
), 对原始图像进行去畸变处理, 在images目录下生成无畸变的图像 - 图像重投影: 将原始图像重新投影到新的虚拟相机坐标系下, 确保去畸变后的图像尽可能保持直线性和几何一致性, 新产生的稀疏重建数据输出到 sparse 目录下.
output/
├── images/ # 去畸变后的图像, 文件名与原始图像一致, 但内容已去除畸变
├── sparse/ # 稀疏重建数据(适配去畸变后的图像)
│ ├── cameras.bin # 更新后的相机内参(去除了畸变参数, 通常为 `SIMPLE_PINHOLE` 或 `PINHOLE` 模型)
│ ├── images.bin # 更新后的图像位姿
│ └── points3D.bin # 3D点云数据(与原始稀疏模型一致)
3. 生成小尺寸图片
source_file = os.path.join(args.source_path, "images", file)destination_file = os.path.join(args.source_path, "images_2", file)
shutil.copy2(source_file, destination_file)
exit_code = os.system(magick_command + " mogrify -resize 50% " + destination_file)
如果指定了resize参数, 则将images中的图片序列按 1/2, 1/4, 1/8 大小压缩后放到对应的 images_2, images_4, images_8 目录下.
提取结果数据结构
在Convert阶段, 使用Colmap处理输入帧序列, 在3D场景的稀疏重建完成后, model 默认会被导出到 bin 文件中, 因为这样比较紧凑, 节省空间, 在结果目录中生成以下文件
- cameras.bin: 相机内参(焦距、畸变系数等)
- images.bin: 每张图像的外参(旋转矩阵、平移向量)
- points3D.bin: 稀疏三维点云(坐标、颜色、关联的图像特征)
二进制文件不能直接查看, 如果要查看需要先导出为文本形式
模型导出为文本
界面方式
- File -> Open Project, 选择 distorted/sparse/0/project.ini
project.ini 里面有结果数据集 database_path, image_path 对应的路径 - Import Model
弹出窗口会显示 cameras.bin, frames.bin, images.bin, points3D.bin 这些文件所在的目录, 直接点Open - Export Model as Text
选择目录导出
界面方式需要先有个 project.ini 才能打开然后才能导出, 对于 image_undistorter 之后的数据, 可以直接用命令行
colmap model_converter --input_path ./sparse/0 --output_path ./export --output_type TXT
相机参数 cameras.txt
分别将 distorted/sparse/0 和 sparse/0 下面的文件导出对比一下,
这个是 distorted 的
# Camera list with one line of data per camera:
# CAMERA_ID, MODEL, WIDTH, HEIGHT, PARAMS[]
# Number of cameras: 1
1 OPENCV 1366 768 1293.8711353466817 1286.2774515116257 683 384 0.061212269737348043 -0.0680218 70521804764 0.0027510647480376441 -0.00096792591781855999
从参数可以看到, 只有1个相机, 类型为 OPENCV, 宽1366, 高768, 后面的对应OPENCV的参数为fx, fy, cx, cy, k1, k2, p1, p2
, 参数说明在这里 sensor models opencv camera_calibration_and_3d_reconstruction
这个是 sparse 的,
# Camera list with one line of data per camera:
# CAMERA_ID, MODEL, WIDTH, HEIGHT, PARAMS[]
# Number of cameras: 1
1 PINHOLE 1342 753 1293.8711353466817 1286.2774515116257 671 376.5
可以看到 image_undistorter 处理后, 将相机类型简化为 PINHOLE 了. 宽1342, 高753, 后面对应PINHOLE参数fx, fy, cx, cy
.
稀疏三维点云 points3D.txt
每一行代表3D世界坐标系中的一个点, 每一行的数据记录的是每个特征点的编号, 在世界坐标系中的三轴坐标, 颜色, 误差, 对应的帧ID(有多个)等
# 3D point list with one line of data per point:
# POINT3D_ID, X, Y, Z, R, G, B, ERROR, TRACK[] as (IMAGE_ID, POINT2D_IDX)
# Number of points: 95681, mean track length: 6.0265674480826918
1 -4.6429054040200315 -0.12682166809568018 5.4170983660932128 163 177 139 0.36651172613355359 91 228 97 1097 1 1084 2 1041 3 1098
2 -2.8858762120805075 -0.14464560656096839 9.1629341058577598 151 128 96 0.39002500983496419 91 963 97 1371 94 6903 93 6795 92 1260 1 1467 98 7488 90 847 89 938 86 1686
3 -2.0084821657841556 -0.081920789643777775 8.8585159154051105 138 105 91 0.41792357452137563 91 1080 97 1389 95 1376 94 1289 93 1292 92 1327 99 1553 100 1585 103 935 104 972 106 1279105 1269
帧位姿信息信息 frames.txt
每行记录对应一帧, 用于描述每一帧图像的相机姿态, 即相机在世界坐标系下的位置和旋转.
# Frame list with one line of data per frame:
# FRAME_ID, RIG_ID, RIG_FROM_WORLD[QW, QX, QY, QZ, TX, TY, TZ], NUM_DATA_IDS, DATA_IDS[] as (SENSOR_TYPE, SENSOR_ID, DATA_ID)
# Number of frames: 106
1 1 0.99836533904705349 0.04193352296417753 0.038821862334836317 0.0010452014780679608 -0.25128396315431845 -1.2152713376026862 3.0253864464155615 1 CAMERA 1 1
2 1 0.99835087534385147 0.042428195611485663 0.038620024616921315 -0.00196764222042955 -0.13775248425073805 -1.2180580685699627 3.0103416379580277 1 CAMERA 1 2
3 1 0.99855111805603081 0.043597372641527229 0.024544817561746674 -0.019811250810262224 -0.040750492657603658 -1.2271622331366634 3.0046993738476142 1 CAMERA 1 3
其中
FRAME_ID
: 帧ID,RIG_ID
: 相机系统ID, 单相机时为 1RIG_FROM_WORLD
: 此相机相对于世界坐标系的位姿(旋转 + 平移)[QW, QX, QY, QZ]
: 四元数(Quaternion)表示从世界坐标系 到 相机坐标系 的旋转
[TX, TY, TZ]
: 平移向量, 表示相机在世界坐标系中的位置
NUM_DATA_IDS
: 关联的数据条目数量(1 表示单相机)DATA_IDS[]
SENSOR_TYPE
: 传感器类型SENSOR_ID
: 传感器IDDATA_ID
: 数据ID, 与FRAME_ID
一致
如果要将世界坐标系中的点转换到相机坐标系, 公式为如下, 其中 R R R 是四元数对应的旋转矩阵, T T T 是平移向量
P c a m e r a = R ∗ P w o r l d + T P_camera = R * P_world + T Pcamera=R∗Pworld+T
帧位姿和 2D 到 3D 的点对应关系 images.txt
从一开始的注释可以看到, 总共有106帧, 平均每帧有 5439.9 个特征点. 每一帧对应两行数据, 因为第二行数据特别长, 这里只选了第一帧, 且第二行只复制了一部分
# Image list with two lines of data per image:
# IMAGE_ID, QW, QX, QY, QZ, TX, TY, TZ, CAMERA_ID, NAME
# POINTS2D[] as (X, Y, POINT3D_ID)
# Number of images: 106, mean observations per image: 5439.8867924528304
1 0.99836533904705349 0.04193352296417753 0.038821862334836317 0.0010452014780679608 -0.25128396315431845 -1.2152713376026862 3.0253864464155615 1 00001.png
825.15373304728928 -5.6413415027986957 -1 164.01311518616183 -3.143878378690431 -1 234.84114206197438 -3.2774780931266605 -1 410.44616170102927 -4.4760000788289176 -1 410.44616170102927 -4.4760000788289176 -1 498.88078573599353 -4.4877569648373878 -1 569.35841783248441 -5.1971020964857075 -1 100.7993779156044 -2.2199628505093756 -1 356.56707555817059 -3.3454093456278997 -1 448.63533653913873 -3.8738229730629996 -1 448.63533653913873 -3.8738229730629996 -1 3.8371802816758418 -1.3898702174245159 -1 14.528644520511875 -1.3897672966739947 -1 14.528644520511875 -1.3897672966739947 -1 58.303840482829514 -1.6884535247444319 -1 183.3108855651688 -2.0632513592141777 -1 225.6034102754262 -2.3950756662687809 -1 225.6034102754262 -2.3950756662687809 -1 379.73286273610427 -3.4805414725628907 -1 379.73286273610427 -3.4805414725628907 -1 19.916327860588694 -1.2292769819643468 -1 19.916327860588694 -1.2292769819643468 10907 79.77255155967282 -1.4162716901826116 -1 238.963680618659 -2.0952003476307937 -1 247.31417122505815 -1.9649340021943544 -1 284.2464937295465 -2.3623328654380202 -1 306.65943761573396 -2.2745898954538575 -1 542.61914847275943 -3.5028586005029183 -1 581.95785661473622 -3.3856713839217605 -1 581.95785661473622 -3.3856713839217605 -1 815.63607208237715 -3.4239040200370709 -1 288.53829875350897 -1.9195248965336305 -1 1166.9736271841496 -1.7695890660907594 ...
第一行是图像位姿和元信息, 和 frames.txt 中的数据是一致的
IMAGE_ID
: 帧IDQW, QX, QY, QZ
,TX, TY, TZ
: 四元数旋转向量和平移向量, 参考上面 frames.txt 的说明CAMERA_ID
**:相机ID, 对应cameras.txt
中的相机数据NAME
: 帧对应的文件名, 00001.png
第二行是 2D 特征点与 3D 点的对应关系
POINTS2D[] as (X, Y, POINT3D_ID)
X, Y
: 特征点在图像中的 归一化坐标, 通常以相机光心为原点, 可能与像素坐标不同POINT3D_ID
: 关联的 3D 点 ID, 对应points3D.txt
中的点,-1
表示该 2D 点未关联到任何 3D 点, 可能是由于匹配失败或三角化置信度低
相关文章:
3D Gaussian splatting 04: 代码阅读-提取相机位姿和稀疏点云
目录 3D Gaussian splatting 01: 环境搭建3D Gaussian splatting 02: 快速评估3D Gaussian splatting 03: 用户数据训练和结果查看3D Gaussian splatting 04: 代码阅读-提取相机位姿和稀疏点云3D Gaussian splatting 05: 代码阅读-训练整体流程3D Gaussian splatting 06: 代码…...

CTFHub-RCE 命令注入-过滤空格
观察源代码 代码里面可以发现过滤了空格 判断是Windows还是Linux 源代码中有 ping -c 4 说明是Linux 查看有哪些文件 127.0.0.1|ls 打开flag文件 我们尝试将空格转义打开这个文件 利用 ${IFS} 127.0.0.1|cat${IFS}flag_195671031713417.php 可是发现 文本内容显示不出来&…...
卫生间改造翻新怎么选产品?我在瑞尔特找到了解决方案
在一场打掉重来的卫生间翻新改造中,最令人头疼的,从来都不是瓷砖、吊顶这类“看得见”的工序,而是那些每天都在用、但选错一次就要懊悔好多年的卫浴产品。从功能到体验,从老人适配到美学搭配,这事真不是买个贵的就够了…...
C++ list数据删除、list数据访问、list反转链表、list数据排序
list数据删除,代码见下 #include<iostream> #include<list>using namespace std;void printList(const list<int>& l) {for (list<int>::const_iterator it l.begin(); it ! l.end(); it) {cout << *it << " "…...

Express教程【002】:Express监听GET和POST请求
文章目录 2、监听post和get请求2.1 监听GET请求2.2 监听POST请求 2、监听post和get请求 创建02-app.js文件。 2.1 监听GET请求 1️⃣通过app.get()方法,可以监听客户端的GET请求,具体的语法格式如下: // 1、导入express const express req…...
mysql安装教程--笔记
一、Windows 系统安装 方法1:使用 MySQL Installer(推荐) 1. 下载安装包 访问 MySQL 官网下载页面,选择 MySQL Installer for Windows。 2. 运行安装程序 双击下载的 .msi 文件,选择安装类型: ◦ Developer…...
C++ 观察者模式:设计与实现详解
一、引言 在现代软件开发中,组件间的交互与通信是系统设计的核心挑战之一。观察者模式(Observer Pattern)作为一种行为设计模式,提供了一种优雅的解决方案,用于实现对象间的一对多依赖关系。本文将深入探讨 C++ 中观察者模式的设计理念、实现方式及其应用场景。 二、观察…...

【PostgreSQL 03】PostGIS空间数据深度实战:从地图服务到智慧城市
PostGIS空间数据深度实战:从地图服务到智慧城市 关键词 PostGIS, 空间数据库, 地理信息系统, GIS, 空间查询, 地理分析, 位置服务, 智慧城市, 空间索引, 坐标系统 摘要 PostGIS是PostgreSQL的空间数据扩展,它将普通的关系数据库转变为强大的地理信息系统…...

HIT-csapp大作业:程序人生-HELLO‘s P2P
计算机系统 大作业 题 目 程序人生-Hello’s P2P 专 业 计算学部 学 号 2023111813 班 级 23L0518 学 生 鲁永哲 指 导 教 师 史先俊 计…...

深入探讨redis:主从复制
前言 如果某个服务器程序,只部署在一个物理服务器上就可能会面临一下问题(单点问题) 可用性问题,如果这个机器挂了,那么对应的客户端服务也相继断开性能/支持的并发量有限 所以为了解决这些问题,就要引入分布式系统,…...

帕金森常见情况解读
一、身体出现的异常节奏 帕金森会让身体原本协调的 “舞步” 出现错乱。它是一种影响身体行动能力的状况,随着时间推进,就像老旧的时钟,齿轮转动不再顺畅,使得身体各个部位的配合逐渐失衡,打乱日常行动的节奏。 …...

清华大学发Nature!光学工程+神经网络创新结合
2025深度学习发论文&模型涨点之——光学工程神经网络 清华大学的一项开创性研究成果在《Nature》上发表,为光学神经网络的发展注入了强劲动力。该研究团队巧妙地提出了一种全前向模式(Fully Forward Mode,FFM)的训练方法&…...

【android bluetooth 案例分析 04】【Carplay 详解 3】【Carplay 连接之车机主动连手机】
1. 背景 在前面的文章中,我们已经介绍了 carplay 在车机中的角色划分, 并实际分析了 手机主动连接车机的案例。 感兴趣可以 查看如下文章介绍。 【android bluetooth 案例分析 04】【Carplay 详解 1】【CarPlay 在车机侧的蓝牙通信原理与角色划分详解】…...

C++学习-入门到精通【11】输入/输出流的深入剖析
C学习-入门到精通【11】输入/输出流的深入剖析 目录 C学习-入门到精通【11】输入/输出流的深入剖析一、流1.传统流和标准流2.iostream库的头文件3.输入/输出流的类的对象 二、输出流1.char* 变量的输出2.使用成员函数put进行字符输出 三、输入流1.get和getline成员函数2.istrea…...

NW969NW978美光闪存颗粒NW980NW984
NW969NW978美光闪存颗粒NW980NW984 技术解析:NW969、NW978、NW980与NW984的架构创新 美光(Micron)的闪存颗粒系列,尤其是NW969、NW978、NW980和NW984,代表了存储技术的前沿突破。这些产品均采用第九代3D TLC…...

使用 ssld 提取CMS 签名并重签名
拿SpringBoard的cms签名和entitlements.xml,对tihook.dylib进行重签名 工具来源:https://github.com/eksenior/ssld...
前端基础之《Vue(17)—路由集成》
一、页面应用程序分类 1、单页面应用程序(SPA) 通过路由系统把组件串联起来的并且只有一个根index.html页面的程序,叫做单页面应用程序。 2、多页面应用程序(MPA) 整个应用程序中,有多个.html页面。每次用…...

大厂前端研发岗位PWA面试题及解析
文章目录 一、基础概念二、Service Worker 深度三、缓存策略实战四、高级能力五、性能与优化六、调试与部署七、安全与更新八、跨平台兼容九、架构设计十、综合场景十一、前沿扩展一、基础概念 什么是PWA?列举3个核心特性 解析:渐进式网页应用。核心特性:离线可用、类原生体…...

第十四章 MQTT订阅
系列文章目录 系列文章目录 第一章 总体概述 第二章 在实体机上安装ubuntu 第三章 Windows远程连接ubuntu 第四章 使用Docker安装和运行EMQX 第五章 Docker卸载EMQX 第六章 EMQX客户端MQTTX Desktop的安装与使用 第七章 EMQX客户端MQTTX CLI的安装与使用 第八章 Wireshark工具…...
element ui 表格 勾选复选框后点击分页不保存之前的数据问题
element ui 表格 勾选复选框后点击分页不保存之前的数据问题 给 el-table上加 :row-key"getRowKey"给type“selection” 上加 :reserve-selection"true"...
DataAgent产品经理(数据智能方向)
DataAgent产品经理(数据智能方向) 一、核心岗位职责 AI智能体解决方案设计 面向工业/政务场景构建「数据-模型-交互」闭环,需整合多源异构数据(如传感器数据、业务系统日志)与AI能力(如大模型微调、知识图…...

腾讯云推出云开发AI Toolkit,国内首个面向智能编程的后端服务
5月28日,腾讯云开发 CloudBase 宣布推出 AI Toolkit(CloudBase AI Toolkit),这是国内首个面向智能编程的后端服务,适配 Cursor 等主流 AI 编程工具。 云开发 AI Toolkit旨在解决 AI 辅助编程的“最后一公里”问题&…...
华为计试——刷题
判断两个IP是否属于同一子网 题目:给定一个子网掩码和两个 IP 地址,判断这两个 IP 地址是否在同一个子网中。 思路:首先,判断这个 IP 地址和子网掩码格式是否正确,不正确输出 ‘1’,进而结束;…...
【AI-安装指南】Redis Stack 的安装与使用
目录 一、Redis Stack 的介绍 二、安装方式 2.1 安装 2.2 添加依赖 2.3 设置配置信息 2.4 Redis 添加向量数据 2.5 查询向量数据 一、Redis Stack 的介绍 传统的 Redis 服务是不能存储向量的,因此我们需要首先安装 Redis Stack,而 Windows 电脑安 装 Redis Stack,官方…...
LeetCode Hot100(矩阵)
73. 矩阵置零 这边提供nm的做法以及更少的思路,对于nm的做法,我们只需要开辟标记当前行是否存在0以及当前列是否存在0即可,做法如下 class Solution {public void setZeroes(int[][] matrix) {int arr[]new int[matrix.length];int brr[]ne…...
spark在执行中如何选择shuffle策略
目录 1. SortShuffleManager与HashShuffleManager的选择2. Shuffle策略的自动选择机制3. 关键配置参数4. 版本差异(3.0+新特性)5. 异常处理与调优6. 高级Shuffle服务(CSS)1. SortShuffleManager与HashShuffleManager的选择 SortShuffleManager:默认使用,适用于大规模数据…...

前端-不对用户显示
这是steam的商店偏好设置界面,在没有被锁在国区的steam账号会有5个选项,而被锁在国区的账号只有3个选项,这里使用的技术手段仅仅在前端隐藏了这个其他两个按钮。 单击F12打开开发者模式 单击1处,找到这一行代码,可以看…...

WPF【10_2】数据库与WPF实战-示例
客户预约关联示例图 MainWindow.xaml 代码 <Window x:Class"WPF_CMS.MainWindow" xmlns"http://schemas.microsoft.com/winfx/2006/xaml/presentation" xmlns:x"http://schemas.microsoft.com/winfx/2006/xaml" xmlns:d"ht…...
Hive的数据倾斜是什么?
一、Hive数据倾斜的定义 数据倾斜指在Hive分布式计算过程中,某一个或几个Task(如Map/Reduce任务)处理的数据量远大于其他Task,导致这些Task成为整个作业的性能瓶颈,甚至因内存不足而失败。数据倾斜通常发生在Shuffle阶…...

Cursor奇技淫巧篇(经常更新ing)
Dot files protection :Cursor当开启了Agent模式之后可以自动帮我们写文件,但是一般项目中的一些配置文件(通常以.开头的)都是非常重要性,为了防止Cursor在运行的过程中自己修改这些文件,导致风险ÿ…...