坐标变换及视图变换和透视变换(相机透视模型)
文章目录
- 2D transformation
- Scale
- Reflection
- Shear(切变)
- Rotation around origin
- Translation
- Reverse
- 变换顺序
- 复杂变换的分解
- 齐次坐标(Homogenous Coordinates)
- 3D transformation
- Scale&Translation
- Rotation
- Viewing / Camera transformation
- Projection transformation
- 视口变换
- 相机内参和相机外参
- 参考链接
2D transformation
Scale
- Uniform

- Non-Uniform

Reflection

Shear(切变)

Rotation around origin
假设旋转矩阵的4个未知数,取特殊点列方程可推导

如果旋转 − θ -\theta −θ角度,那么经过推导很容易得出旋转矩阵为原来旋转 θ \theta θ角度的矩阵的转置:

又考虑到实际上如果一个图形旋转 θ \theta θ角度再旋转 − θ -\theta −θ角度会变回原来的形状,也就是 R − θ R θ X = E X R_{-\theta}R_\theta X=EX R−θRθX=EX,即 R − θ R θ = E R_{-\theta}R_\theta=E R−θRθ=E两个矩阵是互逆的。

补充:如果一个矩阵的逆等于它的转置,那么这个矩阵是正交矩阵。
以上变换都属于线性变换,都可以写成矩阵相乘的形式:

Translation
需要注意平移(Translation)变换不属于Linear Transformation:

但以上变换可以统称为仿射变换(Affine Transformations)

Reverse
做逆变换相当于把变换后的图形又变回去,假如对 X X X做了变换 M M M,变为 X ′ = M X X'=MX X′=MX,再对 X ′ X' X′做逆变换 M − 1 M^{-1} M−1, M − 1 M X = X M^{-1}MX=X M−1MX=X,即变回 X X X

变换顺序
由于矩阵乘法是不可交换的,所以变换的顺序是很重要的,不同的变换顺序得到的结果也不一样,顺序是先线性变换后平移:

复杂变换的分解

齐次坐标(Homogenous Coordinates)
将一个 n n n维空间中的点或向量,表示为 n + 1 n+1 n+1维空间中的向量,能够达到合并矩阵运算中乘法和加法操作的目的,简化计算

这样可以定义至少3种有效操作:

Point+Point由于没有什么实质性意义,所以给出一个定义, ( x y w ) \begin{pmatrix}x \\ y \\ w\end{pmatrix} xyw 这个点实际上定义为 ( x / w y / w 1 ) \begin{pmatrix}x/w \\ y/w \\ 1\end{pmatrix} x/wy/w1 这个点,那么这时,两个点相加就被赋予了两个点中点这一意义
那么通过使用齐次坐标,可以将仿射变换改写为:

缩放、旋转、平移可以表示成:

3D transformation
和2D变换中的相似,齐次坐标在3维空间中变成了4维,仿射变换矩阵如下:

注意是先应用线性变换,再应用平移变换!
Scale&Translation

Rotation
三维空间中的旋转和2维相似,绕某个轴旋转就固定哪个轴的坐标不变,其他两个轴应用2维旋转矩阵即可,但我们发现绕y轴旋转的矩阵中 sin α \sin α sinα的符号有点不同,这是因为图中y的方向是 z × x z×x z×x得到的,如果y轴是向下的,即由 x × z x×z x×z得到,那么 sin α \sin α sinα会刚好相反

留下几个知识点:欧拉角、四元数、罗德里格兹旋转公式
旋转矩阵不适合做插值,而四元数是可以的

Viewing / Camera transformation
考虑我们现实场景重拍摄一张图片的步骤:
- 找一个好地方并摆出姿势(model transformation)
- 找一个好的拍摄角度并放置相机(view transformation)
- 在相机上投影出相片(projection transformation)
这三部就是图形学中的MVP变换。
我们首先考虑视角变换,也即相机变换。通常,相机可以通过三个方向向量来确定一个唯一的视图/相机位置(可以注意到 g ^ \hat g g^和 t ^ \hat t t^总是垂直的):
- Position e ⃗ \vec e e (决定相机的物理位置)
- Gaze direction g ^ \hat g g^ (决定俯视仰视平视方向)
- Up direction t ^ \hat t t^ (相机的角度,决定拍出的图像是什么角度,相机旋转,则拍出的照片也会旋转)
由于如果我们保持相机和物体的相对位置不变,同时移动二者,可能会得到相同的拍摄图像,因此不妨将相机固定到一个位置,即:
- 原点
- up at Y Y Y
- gaze at − Z -Z −Z
对于这样的位置,可以采取如下仿射变换:
- 将 e e e平移到原点
- 将 g g g旋转到 − Z -Z −Z
- 将 t t t旋转到 Y Y Y
- 将 ( g × t ) (g×t) (g×t)旋转到 X X X
这个变换实际上也就是世界坐标系转换到相机坐标系的过程。
但实际上,上面这些变换是不好表示的,由于前面提到旋转矩阵是正交的,所以我们可以考虑上述旋转变换的逆变换:

这样我们对所有的物体都事先运用这种变换就相当于我们的相机在一个固定位置去拍摄,并且相机位置是原点。这种变换也被称为ModelView Transformation。这实际上是世界坐标系到相机坐标系的一个变换。
Projection transformation
投影变换就是从3D物体投影到2D图像的变换,可以分为:
- 正交投影(Orthographic Projection)
- 透视投影(Perspective Projection)
二者本质的区别是是否具有近大远小的性质,透视投影具有近大远小的性质而正交投影没有。透视投影中,原本平行的线投影后可能不再平行。如下图所示,正交投影相当于把相机拉到无限远的位置。下图中,Near clip plane是近平面,也相当于相机的成像平面。

正交投影
当按照前面的方式进行视图变换后,正交投影其实就相当于丢弃掉Z轴坐标,然后将物体的中心平移到相机位置,并且将物体缩放到一个小的矩型中(归一化)。如下图,但这里还有一个问题是物体的正反我们无法分辨。

在实际操作中,我们通常是将一个长方体通过平移和缩放映射一个中心位于原点,边长为1的一个立方体中:

变换矩阵就是(先平移后缩放):

在这个过程中,实际上物体是被拉伸了,后面会提到在做完MVP变换后还要进行视口变换。
透视投影
首先需要明确齐次坐标中的一个知识点:就是 ( x , y , z , 1 ) (x,y,z,1) (x,y,z,1)和 ( k x , k y , k z , k ) (kx,ky,kz,k) (kx,ky,kz,k)表示的是同一个点。
透视投影实际上可以拆分为两步:
- 将远平面到近平面内的frustum(截锥体)挤压变换成一个长方体。变换需要满足:近平面的所有点坐标不变。远平面只有xy变换而z不变。该变换表示为 M p e r s o − > o r t h o M_{perso->ortho} Mperso−>ortho。注意近平面和远平面的中心连线是和z轴平行的。相机位置在中心连线上。
- 对长方体进行正交投影。

实际上,远平面(右)要挤压成与近平面(左)一样的大小,实际上是一个相似变换。

利用相似变换的性质,可以求出 ( x , y , z ) (x,y,z) (x,y,z)到 ( x ′ , y ′ , z ′ ) (x',y',z') (x′,y′,z′)的变换。
y ′ = n z y x ′ = n z x y^{\prime}=\frac{n}{z} y \quad x^{\prime}=\frac{n}{z} x y′=znyx′=znx
对于截锥体内的所有平面,xy变换都满足上述关系,但z的关系目前还不知道,只知道远平面和近平面的z不变。表示成齐次坐标为:

M p e r s o − > o r t h o M_{perso->ortho} Mperso−>ortho的目标就是:

至此我们可以推导出 M p e r s o − > o r t h o M_{perso->ortho} Mperso−>ortho矩阵的一部分:

至于第三行,我们利用近平面的任意一点和远平面的任意一点z都不会改变可以推导出第三行,最终的 M p e r s o − > o r t h o M_{perso->ortho} Mperso−>ortho矩阵就是:
M p e r s o − > o r t h o = ( n 0 0 0 0 n 0 0 0 0 n + f − n f 0 0 1 0 ) M_{perso->ortho}=\begin{pmatrix} n & 0 & 0 & 0\\ 0 & n & 0 & 0 \\ 0 & 0 & n+f & -nf\\ 0 & 0 & 1 & 0 \end{pmatrix} Mperso−>ortho= n0000n0000n+f100−nf0
n n n是近平面的z值, f f f是远平面的z值。
然后就是用正交变换矩阵再去做一次变换即得到最终的投影变换矩阵。
M persp = M ortho M persp → ortho M_{\text {persp }}=M_{\text {ortho }} M_{\text {persp } \rightarrow \text { ortho }} Mpersp =Mortho Mpersp → ortho
这也是相机坐标系到图像坐标系的过程。
透视投影中还涉及到两个概念,视锥的长宽比(aspect ratio)和垂直可视角度(vertical field-of-view,fovY)。实际含义可以从下图看出:

我们假设前面经过矩型块是对称的,即 l = − r ( x 方向 ) , b = − t ( y 方向 ) l=-r(x 方向),b=-t(y方向) l=−r(x方向),b=−t(y方向)。那么可以从 t , r t,r t,r推出两个概念的表达式:
tan f o v Y 2 = t ∣ n ∣ aspect = r t \begin{aligned} \tan \frac{f o v Y}{2} & =\frac{t}{|n|} \\ \text { aspect } & =\frac{r}{t} \end{aligned} tan2fovY aspect =∣n∣t=tr

视口变换
在MVP变换过后,我们的目标就是将前述的小立方块投影到一个图片上,这实际上也是图像坐标系到像素坐标系的变换。
首先我们假设像素坐标系是如下形式:坐标原点在左下角,每个像素是有单位宽度和高度的小颜色块,像素内部每一点颜色都一样,像素坐标系放的是像素的索引。如下图。

设定y轴方向的长度为高度(height),x轴方向的长度是宽度(width),整个屏幕的范围就是上图灰色区域。
视口变换的目标是:
- 保持相机坐标系的z不变
- xy平面要从原来小立方体 [ − 1 , 1 ] 2 [-1,1]^2 [−1,1]2的范围变换到 [ 0 , w i d t h ] × [ 0 , h e i g h t ] [0,width]\times[0,height] [0,width]×[0,height]的范围
变换矩阵很容易写出,就是缩放+平移操作。视口变换矩阵 M v i e w p o r t M_{viewport} Mviewport为
M viewport = ( width 2 0 0 width 2 0 height 2 0 height 2 0 0 1 0 0 0 0 1 ) M_{\text {viewport }}=\left(\begin{array}{cccc} \frac{\text { width }}{2} & 0 & 0 & \frac{\text { width }}{2} \\ 0 & \frac{\text { height }}{2} & 0 & \frac{\text { height }}{2} \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{array}\right) Mviewport = 2 width 00002 height 0000102 width 2 height 01
经过视口变换后,下一步就是光栅化(Rasterization)的过程。
相机内参和相机外参
外参就是上面从世界坐标系到相机坐标系的变换矩阵,可以简单理解为相机的位置、角度。
内参是上面另外两个变换矩阵的叠加,简单理解就是相机的内部特性,如焦距,畸变系数等。
参考链接
[1] https://www.bilibili.com/video/BV1X7411F744?spm_id_from=333.788.videopod.episodes&vd_source=bac8ddf04ec0b6386d58110f67353bc7&p=4
[2] https://www.bilibili.com/video/BV1r8411f72j/?spm_id_from=333.337.search-card.all.click&vd_source=bac8ddf04ec0b6386d58110f67353bc7
[3] https://zhuanlan.zhihu.com/p/692565077
还有一些不太理解的地方以及一些概念以后再更新。
相关文章:
坐标变换及视图变换和透视变换(相机透视模型)
文章目录 2D transformationScaleReflectionShear(切变)Rotation around originTranslationReverse变换顺序复杂变换的分解 齐次坐标(Homogenous Coordinates)3D transformationScale&TranslationRotation Viewing / Camera t…...
基于反激电路的电池充放电均衡控制
基于反激电路的电池充放电均衡控制是一种高效的能量转移型主动均衡方法,适用于锂离子电池组等串联电池组的管理。以下从原理、拓扑结构、控制策略和设计要点进行详细分析: 一、基本原理 反激电路(Flyback Converter)是一种隔离型…...
Windows版FFmpeg使用及B站视频下载示例python源码
Windows版FFmpeg使用及B站视频下载示例python源码 FFmpeg介绍和下载 FFmpeg 是一个功能强大、灵活且广泛使用的多媒体处理工具,无论是在专业领域还是日常使用中,都能满足各种多媒体处理需求。FFmpeg 是一个开源项目,遵循 LGPL 或 GPL 许可。…...
leetcode_动态规划/递归 509. 斐波那契数
509. 斐波那契数 斐波那契数 (通常用 F(n) 表示)形成的序列称为 斐波那契数列 。该数列由 0 和 1 开始,后面的每一项数字都是前面两项数字的和。也就是: F(0) 0,F(1) 1F(n) F(n - 1) F(n - 2),其中 n …...
对泰坦尼克号沉没事件幸存者数据分析和预测
一、分析目的 探究决定泰坦尼克号沉没事件中什么因素决定着船上人的生死,并对实例进行判别和预测。 二、数据介绍 Titanic.csv数据中包含了891个样本,记录了泰坦尼克号遇难时的891个乘客的基本信息,其中包括以下信息: Passenger…...
算法之排序算法
排序算法 ♥常见排序算法知识体系详解♥ | Java 全栈知识体系 算法 - 排序 | CS-Notes 面试笔记 十大经典排序算法总结 | JavaGuide...
DMA发送全部历史记录数据到串口
背景 博主参与的项目中,有个读取全部历史记录的功能,如果下位机在主程序中将全部历史记录单纯地通过串口传输会比较占用cpu资源,影响主程序中别的功能。最后商量得出以下实现方案: 定义两个发送缓冲区DMATxbuf1和DMATxbuf2&…...
蓝桥杯好题推荐-----高精度减法
🌈个人主页:羽晨同学 💫个人格言:“成为自己未来的主人~” 题目链接 记录详情 - 洛谷 | 计算机科学教育新生态https://www.luogu.com.cn/record/205122671 思路讲解 这个题目的解题思路,其实是和高精度加法是非常像的。怎么说…...
SpringMVC (3)
目录 1. 传递对象 2. 后端参数重命名(后端参数映射) 3. 传递数组 4. 传递集合 5. 传递JSON数据 5.1 JSON概念 5.2 JSON语法 5.3 JSON字符串和Java对象互转 5.4 JSON优点 5.5 传递JSON对象 6. 获取URL中参数PathVariable 7. 上传文件RequestP…...
vscode使用豆包MARSCode----集成doubao1.5 DeepSeekR1 DeepseekV3模型的ai编程插件
引入扩展 打开VSCode扩展窗口,在搜索窗口搜索MarsCode,找到MarsCode 插件单击「install」,完成安装,登录即可使用MarsCode 编程助手。 主要功能 主要快捷键 / explain 解释项目代码,AI 返回的内容有结构分类&#…...
Ubuntu 下 nginx-1.24.0 源码分析 - ngx_buf_t
ngx_buf_t 定义在 src/core/ngx_buf.h typedef struct ngx_buf_s ngx_buf_t;struct ngx_buf_s {u_char *pos;u_char *last;off_t file_pos;off_t file_last;u_char *start; /* start of buffer */u_char …...
分布式开源协调服务之zookeeper
Zookeeper简介 Zookeeper是什么? Zookeeper官网中对Zookeeper的定义还是比较明确的: ZooKeeper is a centralized service for maintaining configuration information, naming, providing distributed synchronization, and providing group services…...
ubuntu系统安装playhouse三方库
ubuntu系统python3.10安装playhouse三方库 问题描述 问题描述 虚拟环境中使用pip install playhouse,返回安装成功 用pip list查看,能看到playhouse及版本号 导包时提示没有找到playhouse我那件目录,能发现 检查site-package发现问题&#x…...
【星云 Orbit-F4 开发板】04.一触即发:GPIO 外部中断
【星云 Orbit-F4 开发板】04. 一触即发:外部中断控制 摘要 本文详细介绍了如何使用STM32F407微控制器的HAL库实现外部中断功能。通过配置GPIO引脚作为外部中断源,并在中断回调函数中处理按键事件,实现了按键控制LED状态翻转的功能。本文旨在…...
笔记二:整数和浮点数在内存中存储
目录 一、数据类型介绍 二、类型的基本归类 1.整形家族: 2.浮点数家族: 3.构造类型: 4.指针类型 5.空类型: 三、整形在内存中的存储 3.1 原码,反码、补码 3.2 大小端介绍 四、浮点数在内存中的存储 编辑 4.…...
PyQT(PySide)的上下文菜单策略设置setContextMenuPolicy()
在 Qt 中,QWidget 类提供了几种不同的上下文菜单策略,这些策略通过 Qt::ContextMenuPolicy 枚举类型来定义,用于控制控件(如按钮、文本框等)在用户右键点击时如何显示上下文菜单。 以下是 Qt::ContextMenuPolicy 枚举中…...
BladeX框架接口请求跨域
前端使用代理请求接口,接口可以正常访问。如果换全路径请求就跨域。 除了后端要配置跨域 还需要修改配置文件对OPTIONS请求的限制...
如何在Apple不再支持的MacOS上安装Homebrew
手头有一台2012年产的Macbook Pro,系统版本停留在了10.15.7(2020年9月24日发布的)。MacOS 11及后续的版本都无法安装到这台老旧的电脑上。想通过pkg安装Homebrew,发现Homebrew releases里最新的pkg安装包不支持MacOS 10.15.7&…...
本地大模型编程实战(26)用langgraph实现基于SQL数据构建的问答系统(5)
本文将将扩展上一篇文章完成的 langgraph 链,继续使用基于 langgraph 链 ,对结构化数据库 SQlite 进行查询的方法。该系统建立以后,我们不需要掌握专业的 SQL 技能,可以用自然语言询问有关数据库中数据的问题并返回答案。主要完善…...
数据结构与算法:滑动窗口
前言 滑动窗口一般主要用于解决子数组或子串问题,这类的题目更看重对题目的分析和转化。 一、原理 在整个数组上,用l和r分别控制窗口的左右边界,r就扩大,l就减小。 当窗口的范围和题目中某个指标间存在单调关系时,…...
OpenClaw 太难装了?试试 LangTARS:一行命令部署 + WebUI 管理面板,还能接入 Dify/Coze/nn??悠
1. 什么是 Apache SeaTunnel? Apache SeaTunnel 是一个非常易于使用、高性能、支持实时流式和离线批处理的海量数据集成平台。它的目标是解决常见的数据集成问题,如数据源多样性、同步场景复杂性以及资源消耗高的问题。 核心特性 丰富的数据源支持&#…...
Raspberry Pi Imager 终极指南:如何轻松创建树莓派启动盘
Raspberry Pi Imager 终极指南:如何轻松创建树莓派启动盘 【免费下载链接】rpi-imager The home of Raspberry Pi Imager, a user-friendly tool for creating bootable media for Raspberry Pi devices. 项目地址: https://gitcode.com/gh_mirrors/rp/rpi-imager…...
神秘“欢乐马“空降屠榜,碾压Seedance 2.0,视频AI又变天了?
文章目录 前言榜单突变:神秘模型空降第一查无此人?这匹马到底从哪儿来的技术深扒:这马到底强在哪儿第一个就是"稳"第二个是"快"第三个是"全" 对比Seedance 2.0:神仙打架开源普惠?这可能…...
进程与线程的核心区别:一篇看懂,告别混淆
在编程学习中,尤其是接触 C 多线程、操作系统相关知识时,进程(Process)和线程(Thread)是两个绕不开的概念。很多新手会把二者混为一谈,甚至像之前我被问到的那样,疑惑“进程是不是线…...
ESXi 自动加入 vCenter:Kickstart 脚本高效部署指南
在虚拟化集群部署中,手动将 ESXi 主机加入 vCenter Server 不仅繁琐,还容易出现配置失误,尤其适用于大规模集群搭建场景。本教程将介绍一种基于 Pyvmomi 工具的优化方案,无需依赖外部复杂环境,直接通过 ESXi Kickstart…...
万字拆解 LLM 运行机制:Token、上下文与采样参数抵
springboot自动配置 自动配置了大量组件,配置信息可以在application.properties文件中修改。 当添加了特定的Starter POM后,springboot会根据类路径上的jar包来自动配置bean(比如:springboot发现类路径上的MyBatis相关类ÿ…...
英语常见插入语/固定短语总结
一、表示“据我所知/依我所见”(信息来源) 短语中文意思例句1. as far as I know据我所知As far as I know, she still works there.2. as far as I can see依我看/据我所见As far as I can see, theres no problem.3. as far as Im concerned就我而言/…...
目标检测实战:从XML到TXT标注文件的完整转换指南
1. 为什么需要XML到TXT的格式转换 做目标检测项目时,我们经常会遇到标注文件格式不兼容的问题。LabelImg生成的XML文件虽然信息完整,但YOLO系列模型训练时需要的却是TXT格式的标注。这就好比你想用微信支付,但商家只支持支付宝——虽然都是支…...
深入解析cv2.dnn.NMSBoxes()在目标检测中的双重过滤机制
1. 从目标检测的"海选"到"决赛":为什么需要双重过滤? 当你用YOLOv3这类模型做目标检测时,神经网络会输出一大堆预测框——就像选秀节目的海选现场,有实力选手也有浑水摸鱼的。我刚开始做项目时,发…...
突破限制!无需模拟器的3种Windows APK安装方案
突破限制!无需模拟器的3种Windows APK安装方案 【免费下载链接】APK-Installer An Android Application Installer for Windows 项目地址: https://gitcode.com/GitHub_Trending/ap/APK-Installer Windows APK安装一直是跨平台应用的痛点,传统模拟…...
