将针孔模型相机 应用到3DGS

Motivation

3DGS 的 投影采用的是 CG系的投影矩阵 P P P, 默认相机的 principal point (相机光心) 位于图像的中点处。但是 实际应用的 绝大多数的 相机 并不满足这样一个设定, 因此我们 需要根据 f , c x , c y {f,c_x, c_y} f,cx,cy 这几个参数重新构建3D GS 的 投影矩阵。

3DGS 的相机模型的构建

原理:

目的: 将一个 相机View 坐标系的一个3D 点 变换到 NDC 坐标系

维基百科:https://www.songho.ca/opengl/gl_projectionmatrix.html

一共有如下3个坐标系

Eye 坐标系(View 坐标系) : ( x e , y e , z e ) (x_e,y_e,z_e) (xe,ye,ze)

View 坐标系 通过转化 矩阵 M p r o j M_{proj} Mproj 转化到Clip 坐标系。**先进行 缩放变换,**缩放之后的坐标是 ( x p , y p , z p ) (x_p,y_p,z_p) (xp,yp,zp), 缩放之后继续做正交投影 【 就是把 (l,r)映射到 (-1,1)】,最后才可以变换到Clip坐标系下面的坐标 ( x c , y c , z c ) (x_c,y_c,z_c) (xc,yc,zc)

Clip坐标系 : ( x c , y c , z c ) (x_c,y_c,z_c) (xc,yc,zc)

Clip 坐标系通过除以 齐次坐标系的 最后一个分量转换到 NDC 坐标系

NDC坐标系 : ( x n , y n , z n ) (x_n,y_n,z_n) (xn,yn,zn)

在这里插入sd图片描述
n为视锥体近面z坐标,f为远面z坐标,
t为视锥体top面z坐标,b为 bottom面y坐标,
r为视锥体right x坐标,left为左面x坐标,

1. 从 View 坐标系转化到 Clip 坐标系

主要是通过相似三角形的 原理去列方程:
x p = − n ⋅ x e z e = n ⋅ x e − z e x_p=\frac{-n \cdot x_e}{z_e}=\frac{n \cdot x_e}{-z_e} xp=zenxe=zenxe
y p = − n ⋅ y e z e = n ⋅ y e − z e y_p=\frac{-n \cdot y_e}{z_e}=\frac{n \cdot y_e}{-z_e} yp=zenye=zenye
z p z_p zp 坐标的求解,可以观看 闫令琪 的计算机图像学:有两个基本假设:

  • Near 的平面的所有点 Z 缩放之后的 Z值不会发生变化;
  • Far 平面的所有点 Z 缩放之后的 Z值不会发生变化;

得到了 缩放之后的 ( x p , y p , z p ) (x_p,y_p, z_p) (xp,yp,zp), 然后我们再通过线性变换做正交投影将Cuboid 的长和宽分别缩放到 一个 单位立方体, 即将 [l, r] ⇒ [-1, 1] and [b, t] ⇒ [-1, 1]。
Eq2:
x c = α x x p + β x x_c=\alpha_x x_p+\beta_x xc=αxxp+βx
y c = α y y p + β y y_c=\alpha_y y_p+\beta_y yc=αyyp+βy

x p x_p xp x e x_e xe 的关系带入上面Eq2式子当中。以 x 坐标为例,由于l对应-1,r对应1,求解出 α \alpha α β \beta β我们有:

x c = 2 x p r − l − r + l r − l ( x p = n x e − z e ) = 2 ⋅ n ⋅ x e − z e r − l − r + l r − l = 2 n ⋅ x e ( r − l ) ( − z e ) − r + l r − l = 2 n r − l ⋅ x e − z e − r + l r − l = 2 n r − l ⋅ x e − z e + r + l r − l ⋅ z e − z e = ( 2 n r − l ⋅ x e + r + l r − l ⋅ z e ⏟ x c ) / − z e \begin{aligned} x_c& =\frac{2 x_p}{r-l}-\frac{r+l}{r-l} \quad\left(x_p=\frac{n x_e}{-z_e}\right) \\ & =\frac{2 \cdot \frac{n \cdot x_e}{-z_e}}{r-l}-\frac{r+l}{r-l} \\ & =\frac{2 n \cdot x_e}{(r-l)\left(-z_e\right)}-\frac{r+l}{r-l} \\ & =\frac{\frac{2 n}{r-l} \cdot x_e}{-z_e}-\frac{r+l}{r-l} \\ & =\frac{\frac{2 n}{r-l} \cdot x_e}{-z_e}+\frac{\frac{r+l}{r-l} \cdot z_e}{-z_e} \\ & =(\underbrace{\frac{2 n}{r-l} \cdot x_e+\frac{r+l}{r-l} \cdot z_e}_{x_c}) /-z_e\end{aligned} xc=rl2xprlr+l(xp=zenxe)=rl2zenxerlr+l=(rl)(ze)2nxerlr+l=zerl2nxerlr+l=zerl2nxe+zerlr+lze=(xc rl2nxe+rlr+lze)/ze

y c = 2 y p t − b − t + b t − b ( y p = n y e − z e ) = 2 ⋅ n ⋅ y e − z e t − b − t + b t − b = 2 n ⋅ y e ( t − b ) ( − z e ) − t + b t − b = 2 n t − b ⋅ y e − z e − t + b t − b = 2 n t − b − z e ⋅ y e + t + b t − b − z e = ( 2 n t − b ⋅ y e + t + b t − b ⋅ z e ⏟ y c ) / − z e \begin{aligned} y_c & =\frac{2 y_p}{t-b}-\frac{t+b}{t-b} \quad\left(y_p=\frac{n y_e}{-z_e}\right) \\ & =\frac{2 \cdot \frac{n \cdot y_e}{-z_e}}{t-b}-\frac{t+b}{t-b} \\ & =\frac{2 n \cdot y_e}{(t-b)\left(-z_e\right)}-\frac{t+b}{t-b} \\ & =\frac{\frac{2 n}{t-b} \cdot y_e}{-z_e}-\frac{t+b}{t-b} \\ & =\frac{2 n}{\frac{t-b}{-z_e} \cdot y_e}+\frac{t+b}{\frac{t-b}{-z_e}} \\ & =(\underbrace{\frac{2 n}{t-b} \cdot y_e+\frac{t+b}{t-b} \cdot z_e}_{y_c}) /-z_e\end{aligned} yc=tb2yptbt+b(yp=zenye)=tb2zenyetbt+b=(tb)(ze)2nyetbt+b=zetb2nyetbt+b=zetbye2n+zetbt+b=(yc tb2nye+tbt+bze)/ze

上面的恰好是 Clip 坐标系的 齐次坐标系。 发现 计算的 x c , y c x_c,y_c xc,yc 恰好是 除以了 − z e -z_e ze, 因此 我们可以预先指定 齐次坐标的 第四项是: w c = − z e w_c = -z_e wc=ze earlier。 下面是 Clip 坐标系的齐次坐标:
( x c y c z c w c ) = ( 2 n r − l 0 r + l r − l 0 0 2 n t − b t + b t − b 0 ⋅ ⋅ ⋅ ⋅ 0 0 − 1 0 ) ( x e y e z e w e ) \left(\begin{array}{c}x_c \\ y_c \\ z_c \\ w_c\end{array}\right)=\left(\begin{array}{cccc}\frac{2 n}{r-l} & 0 & \frac{r+l}{r-l} & 0 \\ 0 & \frac{2 n}{t-b} & \frac{t+b}{t-b} & 0 \\ \cdot & \cdot & \cdot & \cdot \\ 0 & 0 & -1 & 0\end{array}\right)\left(\begin{array}{l}x_e \\ y_e \\ z_e \\ w_e\end{array}\right) xcyczcwc = rl2n000tb2n0rlr+ltbt+b1000 xeyezewe

$Z的推导 和 x,y 没有关系。因此 上面的矩阵写成下面的形式:
( x c y c z c w c ) = ( 2 n r − l 0 r + l r − l 0 0 2 n t − b t + b t − b 0 0 0 A B 0 0 − 1 0 ) ( x e y e z e w e ) \left(\begin{array}{c}x_c \\ y_c \\ z_c \\ w_c\end{array}\right)=\left(\begin{array}{cccc}\frac{2 n}{r-l} & 0 & \frac{r+l}{r-l} & 0 \\ 0 & \frac{2 n}{t-b} & \frac{t+b}{t-b} & 0 \\ 0 & 0 & A & B \\ 0 & 0 & -1 & 0\end{array}\right)\left(\begin{array}{c}x_e \\ y_e \\ z_e \\ w_e\end{array}\right) xcyczcwc = rl2n0000tb2n00rlr+ltbt+bA100B0 xeyezewe ,
其中的 Z 项 单目提出来应该等于下面的式子:
z n = z c / w c = A z e + B w e − z c z_n=z_c / w_c=\frac{A z_e+B w_e}{-z_c} zn=zc/wc=zcAze+Bwe
最后根据: Z_near 平面 和 Z_far 平面不会移动的原因,得到最后的 投影矩阵:
M p r o j = ( 2 n r − l 0 r + l r − l 0 0 2 n t − b t + b t − b 0 0 0 − ( f + n ) f − n − 2 f n f − n 0 0 − 1 0 ) M_{proj}=\left(\begin{array}{cccc}\frac{2 n}{r-l} & 0 & \frac{r+l}{r-l} & 0 \\ 0 & \frac{2 n}{t-b} & \frac{t+b}{t-b} & 0 \\ 0 & 0 & \frac{-(f+n)}{f-n} & \frac{-2 f n}{f-n} \\ 0 & 0 & -1 & 0\end{array}\right) Mproj= rl2n0000tb2n00rlr+ltbt+bfn(f+n)100fn2fn0

Code:

3DGS 设定:

self.zfar = 100.0
self.znear = 0.01

下面这个 Projection_Matrix 的构建 和上面公式推导会有一点不一样的地方,尤其是对于 Z值的计算上,Github 上也有人提出过疑问。 矩阵的P[2,2] 有误, 但是作者又说 他在 Code 中没有 使用 Z的数值。

https://github.com/graphdeco-inria/gaussian-splatting/issues/388
https://github.com/graphdeco-inria/gaussian-splatting/issues/376

def getProjectionMatrix(znear, zfar, fovX, fovY):tanHalfFovY = math.tan((fovY / 2)) ## 视场角一半的正切数值tanHalfFovX = math.tan((fovX / 2))## 得到 l,b,top,righttop = tanHalfFovY * znearbottom = -topright = tanHalfFovX * znearleft = -rightP = torch.zeros(4, 4)z_sign = 1.0P[0, 0] = 2.0 * znear / (right - left)P[1, 1] = 2.0 * znear / (top - bottom)P[0, 2] = (right + left) / (right - left)P[1, 2] = (top + bottom) / (top - bottom)P[3, 2] = z_signP[2, 2] = z_sign * zfar / (zfar - znear)P[2, 3] = -(zfar * znear) / (zfar - znear)return P
带有Cx, Cy的相机模型:

https://github.com/graphdeco-inria/gaussian-splatting/issues/144

def getProjectionMatrixShift(znear, zfar, focal_x, focal_y, cx, cy, width, height, fovX, fovY):tanHalfFovY = math.tan((fovY / 2))tanHalfFovX = math.tan((fovX / 2))# the origin at center of image planetop = tanHalfFovY * znearbottom = -topright = tanHalfFovX * znearleft = -right# shift the frame window due to the non-zero principle point offsetsoffset_x = cx - (width/2)offset_x = (offset_x/focal_x)*znearoffset_y = cy - (height/2)offset_y = (offset_y/focal_y)*zneartop = top + offset_yleft = left + offset_xright = right + offset_xbottom = bottom + offset_yP = torch.zeros(4, 4)z_sign = 1.0P[0, 0] = 2.0 * znear / (right - left)P[1, 1] = 2.0 * znear / (top - bottom)P[0, 2] = (right + left) / (right - left)P[1, 2] = (top + bottom) / (top - bottom)P[3, 2] = z_signP[2, 2] = z_sign * zfar / (zfar - znear)P[2, 3] = -(zfar * znear) / (zfar - znear)return P

或者其他人 也给了 Projection 基于 相机内参的写法:

https://github.com/graphdeco-inria/gaussian-splatting/issues/399

P[0, 0] = 2 * fx / W
P[1, 1] = 2 * fy / H
P[0, 2] = 2 * (cx / W) - 0.5
P[1, 2] = 2 * (cy / H) - 0.5
P[2, 2] = -(zfar + znear) / (zfar - znear)
P[3, 2] = 1.0
P[2, 3] = -(2 * zfar * znear) / (zfar - znear)

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

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

相关文章

centos 7 yum install -y nagios

centos 7 systemctl disable firewalld --now vi /etc/selinux/config SELINUXdisabled yum install -y epel-release httpd nagios yum install -y httpd nagios systemctl enable httpd --now systemctl enable nagios --now 浏览器 IP/nagios 用户名:…

vue学习的预备知识为学好vue打好基础

目录 Vue是什么 ?如何使用Vue ?Vue ApiVue入口apiVue实例apiVue函数api 无构建过程的渐进式增强静态HTMLVue模块化构建工具npmyarnWebpackvue-cliVite Vue是什么 ? 文章基于Vue3叙述。 Vue (发音为 /vjuː/,类似 view) 是一款用于…

十大USDT交易平台大全XEX交易所

USDT是一种基于比特币区块链网络的加密代币,主要运用于数字货币交易平台,以稳定币为主。USDT的核心价值在于其与真实货币的固定兑换比率1:1,所以被称为Tether。随着加密货币市场的不断壮大,越来越多的交易平台开始支持USDT&#x…

2024深圳杯(东北三省)数学建模C题完整论文讲解(含完整python代码及所有残骸音爆位置求解结果)

大家好呀,从发布赛题一直到现在,总算完成了2024深圳杯(东北三省数学建模联赛)A题多个火箭残骸的准确定位完整的成品论文。 本论文可以保证原创,保证高质量。绝不是随便引用一大堆模型和代码复制粘贴进来完全没有应用糊…

【vscode环境配置系列】vscode远程debug配置

VSCODE debug环境配置 插件安装配置文件debug 插件安装 安装C/C, C/C Runner 配置文件 在项目下建立.vscode文件夹,然后分别建立c_cpp_properties.json, launch.json,tasks.json,内容如下: c_cpp_properties.json:…

如何解决pycharm创建项目报错 Error occurred when installing package ‘requests‘. Details.

🐯 如何解决PyCharm创建项目时的包安装错误:‘requests’ 🛠️ 文章目录 🐯 如何解决PyCharm创建项目时的包安装错误:requests 🛠️摘要引言正文📘 **问题分析**🚀 **更换Python版本…

如何利用快解析软件搭建映射端口

端口映射,就是将内网中主机的一个端口映射到外网主机的一个端口,提供相应的服务,当用户访问外网IP的这个端口时,服务器自动将请求映射到对应局域网内部的机器上。如何才能实现端口映射?今天小编给大家介绍两种方法&…

fetch请求后端返回文件流,并下载。

前端&#xff1a; <script src"~/layui/layui.js"></script> <script src"~/Content/js/common/js/vue.min.js"></script> <script src"~/Content/js/common/js/jquery-1.10.2.min.js"></script><styl…

QT学习篇—qt软件安装

qt下载网址http://download.qt.io/new_archive/qt/ QT官网Qt | Tools for Each Stage of Software Development LifecycleAll the essential Qt tools for all stages of Software Development Lifecycle: planning, design, development, testing, and deployment.https:…

虚拟机扩容-根目录挂载sda1的空间不足

提醒&#xff01;不管成不成功&#xff0c;一定要先备份一份虚拟机&#xff01;&#xff01;&#xff01;&#xff01;&#xff01; 走过路过点个关注吧&#xff0c;想到500粉丝&#xff0c;哭。一、查看分区情况 df -h可以看到/dev/sda1已经被占满了 2.关闭虚拟机&#xff…

TinyShell后门通信模型剖析

TinyShell后门通信模型剖析 通过对TinyShell后门的外联通信函数进行剖析&#xff0c;梳理其通信过程如下&#xff1a; 调用gettimeofday函数及getpid函数获取当前时间tv及进程pid&#xff0c;将tv和pid作为SHA1算法的输入&#xff0c;生成得到20字节的IV1数据调用gettimeofda…

OpenHarmony实战开发-使用通用事件、焦点事件

基本概念 焦点 指向当前应用界面上唯一的一个可交互元素&#xff0c;当用户使用键盘、电视遥控器、车机摇杆/旋钮等非指向性输入设备与应用程序进行间接交互时&#xff0c;基于焦点的导航和交互是重要的输入手段。 默认焦点 应用打开或切换页面后&#xff0c;若当前页上存在…

工业异常检测

工业异常检测在业界和学界都一直是热门&#xff0c;近期其更是迎来了全新突破&#xff1a;与大模型相结合&#xff01;让异常检测变得更快更准更简单&#xff01; 比如模型AnomalyGPT&#xff0c;它克服了以往的局限&#xff0c;能够让大模型充分理解工业场景图像&#xff0c;判…

SpringMVC基础篇(四)

文章目录 1.视图1.基本介绍1.视图介绍2.为什么需要自定义视图 2.自定义视图实例1.思路分析2.代码实例1.view.jsp2.接口3.配置自定义视图解析器springDispatcherServlet-servlet.xml4.自定义视图MyView.java5.view_result.jsp6.结果展示 3.自定义视图执行流程4.自定义视图执行流…

比较美观即将跳转html源码

源码介绍 比较美观即将跳转html源码&#xff0c;源码由HTMLCSSJS组成&#xff0c;记事本打开源码文件可以进行内容文字之类的修改&#xff0c;双击html文件可以本地运行效果&#xff0c;也可以上传到服务器里面 源码截图 比较美观的一个跳转界面&#xff0c;修改方法如上&…

Vitis HLS 学习笔记--AXI4 主接口

目录 1. 简介 2. 认识MAXI 3. MAXI突发操作 3.1 全局/本地存储器 3.2 MAXI优势与特点 3.3 查看MAXI报告 3.3.1 HW Interfaces 3.3.2 M_AXI Burst Information 3.4 MAXI 资源消耗 4. 理解 Volatile 4.1 标准C/C中的 volatile 4.2 HLS 中的 volatile 5. 总结 1. 简介…

idea中使用GlassFish服务器启动项目

idea中使用GlassFish服务器进行测试 1.项目背景 当前在研究openMDM项目, 不过该项目不是springboot项目, 并且是使用GlassFish进行war部署的, 但是需要在idea中进行项目的二次开发,故需要进行idea启动项目并且进行开发和调试 2.GlassFish是什么 GlassFish是一个web服务器, …

ROS学习笔记(14)拉普拉斯变换和PID

0.前提 近些时间在对睿抗的ROS仿真赛进行小组安排&#xff0c;对小组成员进行了一些安排&#xff0c;也要求他们以本次比赛写下自己的比赛经历博客&#xff0c;他们的培训由我来安排和负责&#xff0c;因此我得加吧油&#xff0c;起码保证我的进度得快过他们&#xff0c;才能安…

图像处理技术与应用(三)

图像处理技术与应用入门 图像信息 切片 from skimage import io # 使用 io.imread() 函数来读取图像 img io.imread(cc.jpg) ] roi img[100:5000, 500:1780] # 显示ROI区域 io.imshow(roi) io.show() # 显示图像 红色文字段定义感兴趣的区域&#xff08;ROI&#xff09…

ArcGIS基础:便捷分享图层包和地图包

1、分享图层包&#xff1a; 首先&#xff0c;选中要分享的数据&#xff0c;右键创建图层包&#xff0c;修改保存路径。 找到项目描述那一栏&#xff0c;将摘要、标签、描述都填写分享图层包的相关内容。 一切设置好之后&#xff0c;点击右上角的【分析】按钮。 点击分析之后…