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)

提取流程

  1. 特征点提取 feature_extractor
    生成每一帧的特征点
  2. 特征匹配 exhaustive_matcher
    图像间匹配的特征点对, 建立2D-2D几何约束
  3. 稀疏三维重建 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.dbcameras.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: 稀疏三维点云(坐标、颜色、关联的图像特征)

二进制文件不能直接查看, 如果要查看需要先导出为文本形式

模型导出为文本

界面方式

  1. File -> Open Project, 选择 distorted/sparse/0/project.ini
    project.ini 里面有结果数据集 database_path, image_path 对应的路径
  2. Import Model
    弹出窗口会显示 cameras.bin, frames.bin, images.bin, points3D.bin 这些文件所在的目录, 直接点Open
  3. 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, 单相机时为 1
  • RIG_FROM_WORLD: 此相机相对于世界坐标系的位姿(旋转 + 平移)
    • [QW, QX, QY, QZ]: 四元数(Quaternion)表示从世界坐标系 到 相机坐标系 的旋转
    • [TX, TY, TZ]: 平移向量, 表示相机在世界坐标系中的位置
  • NUM_DATA_IDS: 关联的数据条目数量(1 表示单相机)
  • DATA_IDS[]
    • SENSOR_TYPE: 传感器类型
    • SENSOR_ID: 传感器ID
    • DATA_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=RPworld+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: 帧ID
  • QW, 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 点, 可能是由于匹配失败或三角化置信度低

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.pswp.cn/pingmian/83109.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

每日c/c++题 备战蓝桥杯(P1204 [USACO1.2] 挤牛奶 Milking Cows)

P1204 [USACO1.2] 挤牛奶 Milking Cows - 详解与代码实现 一、题目背景 三个农民每天清晨[……](简要介绍题目背景,与官网描述类似) 二、问题分析 输入要求 :读取 N 个农民的挤奶时间区间,计算两个值:最…

保持本地 Git 项目副本与远程仓库完全同步

核心目标: 保持本地 Git 项目副本与 GitHub 远程仓库完全同步。 关键方法: 定期执行 git pull 命令。 操作步骤: 进入项目目录: 在终端/命令行中,使用 cd 命令切换到你的项目文件夹。执行拉取命令: 运行…

Flutter 4.x 版本 webview_flutter 嵌套H5

踩坑早期版本 使用 WebView 代码如下 import package:flutter/material.dart; import package:webview_flutter/webview_flutter.dart;class HomePage extends StatelessWidget {const HomePage({super.key});overrideWidget build(BuildContext context) {return Scaffold(ap…

rtpinsertsound:语音注入攻击!全参数详细教程!Kali Linux教程!

简介 2006年8月至9月期间,我们创建了一个用于将音频插入指定音频(即RTP)流的工具。该工具名为rtpinsertsound。 该工具已在Linux Red Hat Fedora Core 4平台(奔腾IV,2.5 GHz)上进行了测试,但预…

跑步前热身动作

跑前热身的核心目标是升高体温、激活肌肉、预防损伤 ,同时通过动态动作提升运动表现。热身(步骤关节→肌肉→心肺)和针对性动作(如抱膝抬腿)能有效降低受伤风险,建议每次跑步前严格执行。 推荐跑前热身动作…

GIT命令行的一些常规操作

放弃修改 git checkout . 修改commit信息 git commit --amend 撤销上次本地commit 1、通过git log查看上次提交的哈希值 2、git reset --soft 哈希值 分支 1.创建本地分支 git branch 分支名 2.切换本地分支 git checkout mybranch; 3.创建一个新分支并…

RAGFlow从理论到实战的检索增强生成指南

目录 前言 一、RAGFlow是什么?为何需要它? 二、RAGFlow技术架构拆解 三、实战指南:从0到1搭建RAGFlow系统 步骤1:环境准备 步骤2:数据接入 步骤3:检索与生成 四、优化技巧:让RAGFlow更精…

软件工程方法论:在确定性与不确定性的永恒之舞中寻找平衡

当我们谈论“软件工程”时,“工程”二字总暗示着某种如桥梁建造般的精确与可控。然而,软件的本质却根植于人类思维的复杂性与需求的流变之中。软件工程方法论的发展史,并非线性进步的凯歌,而是一部在确定性的渴望与不确定性的现实…

Python打卡训练营Day41

DAY 41 简单CNN 知识回顾 数据增强卷积神经网络定义的写法batch归一化:调整一个批次的分布,常用与图像数据特征图:只有卷积操作输出的才叫特征图调度器:直接修改基础学习率 卷积操作常见流程如下: 1. 输入 → 卷积层 →…

开源版 PyMOL 如何绘制 Galidesivir 分子结构 ?

参阅:开源版PyMol安装保姆级教程 百度网盘下载 提取码:csub pip show pymol 简介: PyMOL是一个Python增强的分子图形工具。它擅长蛋白质、小分子、密度、表面和轨迹的3D可视化。它还包括分子编辑、射线追踪和动画。 先从 www.python.org 下载 python-…

【FPGA】Vivado 保姆级安装教程 | 从官网下载安装包开始到安装完毕 | 每步都有详细截图说明 | 支持无脑跟装

安装包下载:Xilinx_Vivado Download Link(下好后可直接安装) 目录 (有安装包后,可直接跳转至 Step5,免得去官网下了,比较麻烦) Step1:进入官网 Step2:注册…

纯html,js创建一个类似excel的表格

后台是php,表中数据可编辑,可删除,可提交到数据库 <!DOCTYPE html> <html> <head><meta charset="utf-8"><style>body {font-family: Arial, sans-serif;margin: 20px;background-color: #fff;}.toolbar {margin-bottom: 10px;disp…

密码编码器使用指南

密码编码器概述 通过第三章的学习,您应该已经对UserDetails接口及其多种实现方式有了清晰认识。如第二章所述,在认证授权流程中,不同参与者负责管理用户凭证的表示形式,其中UserDetailsService和PasswordEncoder等组件都提供了默认实现。本节将重点分析PasswordEncoder的核…

《数据结构初阶》【番外篇:二路归并的外排史诗】

【番外篇&#xff1a;多路归并的外排史诗】目录 前言&#xff1a;---------------介绍---------------一、实际情景二、外部排序什么是外部排序&#xff1f; 三、多路归并排序什么是多路归并排序&#xff1f; ---------------实现---------------四、文件归并文件二路归并排序思…

DDP与FSDP:分布式训练技术全解析

DDP与FSDP:分布式训练技术全解析 DDP(Distributed Data Parallel)和 FSDP(Fully Sharded Data Parallel)均为用于深度学习模型训练的分布式训练技术,二者借助多 GPU 或多节点来提升训练速度。 1. DDP(Distributed Data Parallel) 实现原理 数据并行:把相同的模型复…

MATLAB实战:实现数字调制解调仿真

以下是使用MATLAB实现BPSK和QPSK数字调制解调仿真的完整代码。该代码包括调制、AWGN信道、匹配滤波/相关解调、星座图绘制以及误码率计算与理论值比较。 %% 清理环境 clear all; close all; clc; %% 参数设置 numBits 100000; % 传输比特数 EbN0_dB 0:2:10; …

数据可视化的定义和类型

数据可视化是一种将数据转换为图形或视觉表示的方法。想象一下&#xff0c;你面前有一堆数字和表格&#xff0c;看着这些&#xff0c;可能会让人头大。数据可视化就像是给这些枯燥的数字画上一幅画。它用图表、地图和各种有趣的图形&#xff0c;帮我们把难懂的数字变得容易看懂…

*JavaScript中的Symbol类型:唯一标识符的艺术

JavaScript中的Symbol类型&#xff1a;唯一标识符的艺术 在JavaScript的世界中&#xff0c;数据类型一直是开发者关注的焦点。从基本的Number、String到后来的Symbol&#xff0c;每一种类型的引入都为语言本身注入了新的活力。而今天我们要聊的主角——Symbol&#xff0c;是ES…

粽叶飘香时 山水有相逢

粽叶飘香时 山水有相逢 尊敬的广大客户们&#xff1a; 五月初五&#xff0c;艾叶幽香。值此端午佳节&#xff0c;衡益科技全体同仁向您致以最诚挚的祝福&#xff01; 这一年我们如同协同竞渡的龙舟&#xff0c;在数字化转型的浪潮中默契配合。每一次技术对接、每轮方案优化&a…

一文认识并学会c++模板初阶

文章目录 泛型编程&#xff1a;概念 函数模板概念&#xff1a;&#x1f6a9;函数模板格式原理&#xff1a;&#x1f6a9;函数模板实例化与非模板函数共存 类模板类模板实例化 泛型编程&#xff1a; 概念 &#x1f6a9;编写与类型无关的通用代码&#xff0c;是代码复写一种手段…