细化操作
鉴于视口内的四边形ABCD,我认为存在唯一的(?)变换将其映射回矩形。如下图所示:视口中的四边形ABCD充当物理“窗口”,如果将其映射回矩形,它将显示为扭曲。
(右边的方框代表NDC,我稍后再讨论)
目标是快速获得右边的图像。我们可以用光线跟踪每个点来获取图像(我已经完成了),但是我更喜欢使用OpenGL或其他投影技术,因为我想利用诸如混合,基元等功能。
第一次尝试
我相信我可以解决找到3x4相机矩阵的问题,该矩阵可以在3空间(在左侧)中使3 + 1维均匀坐标并将其投影到2空间(在2维上)具有2 + 1维均匀坐标(在左侧)正确的)。可以使用直接线性变换来解决此问题,以获得相机矩阵的未知项
Ba=0
的方程组a
,并使用奇异值分解(SVD)求解该系统。我将向量EA,EB,EC,ED(其中E是您的肉眼或世界空间中的相机)作为原像中的点,并将(0,0),(1,0),(1 ,1),(0,1)之类的东西作为后图像中的点,并且每对点都会给出一些线性方程式以插入SVD。生成的矩阵将映射EA->(0,0)等。(假设有足够的自由度,即,如果解决方案是唯一的,我不确定,请参见注释[a]。) br />但令我烦恼的是,这不是OpenGL的工作方式。 OpenGL不会直接使用3x4矩阵将3d投影到2d。 OpenGL需要“归一化的设备坐标”(NDC),它们是三维点。投影到NDC之后,将绘制从(-1,-1,-1,1)到(1,1,1,1)的“单位”框中的所有内容;外部的所有内容都会被裁剪(因为我们正在处理同质坐标:仅当(x / w,y / w,z / w的前三个坐标)时,任何点(x,y,z,w)才会显示在屏幕上,1)在-1到1)的单位框中。左侧,带有ABCD(前端)和A'B'C'D'(后端,隐藏在前端后面))到单位立方体,例如使用4x4矩阵?它是怎么做到的?我尝试了什么
我已经尝试了一些更强大的方法:我使ABCD和A'B'C'D'看起来像是普通的锥体平截头体(例如gl平截头体)(即,在这种假设的设置中,左侧的图像只是在其上叠加了一个黑色矩形)而不是四边形),然后使用DLT /直接线性变换来求解所谓的4x4矩阵。但是,当我尝试它时,似乎没有足够的自由度...生成的4x4矩阵并未将每个输入向量映射到每个输出向量。在使用A,B,C,D,A'(5对转换前和转换后向量)时,我/几乎/得到了我想要的结果...这些向量已正确映射,但是例如B', C',D'映射到(3,3,1,1)而不是(-1,-1,1,1),并被OpenGL裁剪掉。如果我尝试添加第六个点(要投影的4x4矩阵有6对点),则我的解决方案似乎退化了(零,无穷大)。我在这里要处理多少自由度,而使用4x4矩阵映射我们知道并喜欢的普通4向量(3 + 1维齐次坐标向量)是否有可能?想法
我想不可能将任意长方体映射到具有4x4矩阵的任意长方体,尽管我很困惑,因为我认为可以将任何凸四边形映射到任何其他凸的四边形在2d中具有某些矩阵,例如在Photoshop中?...不能/不能通过投影变换来完成吗?以及如何将其推广到3d? ......同样,由于未能找到4x4矩阵,线性代数表示,在最佳情况下,我们不应期望NxN矩阵将N个以上线性独立的点映射到N个目标点,但是我觉得某种程度上是同质的协调作弊这是因为存在一些隐藏的共线性吗?我猜不是吗?
另一种解决方案?
我猜可能还可以做以下丑事:使用典型的平截头体相机投影矩阵,找到与角对应的2d点,然后执行2d透视变形单应性,但是如果在渲染像素后发生(例如photoshop),那么分辨率就有问题了……也许假设可以找出一个矩阵在NDC空间内的XY平面上执行此转换,然后将其与基于普通视锥峰的矩阵组合起来? >
(注[a]:自由度:如果需要的话,可以将ABCD进一步约束为作用在矩形上的投影变换的后图像...即左侧的黑色矩形可以说是投影相框剪贴画模型的结果)
#1 楼
我认为解决方案正在寻找能正确转换四个点的射影变换。即
$$ y'= P \时间x'$$
其中$ x'= [x_0,x_1,1] $和$ y = [\ frac {y '_0} {y'_2},\ frac {y'_1} {y'_2}] $
$ P $是一个3x3矩阵,具有9个条目。由于最终归一化,它在缩放之前是唯一的,剩下8个自由度,这些自由度由对应关系给出的8个方程式唯一地确定(每个点对2个)。
现在您可以使用代数为此,或者只是使用OpenCV的
getPerspectiveTransform
:)。还可以查看Wikipedia上的同质坐标以熟悉该概念。
评论
$ \ begingroup $
谢谢! (我不久前解决了这个问题,并在看到您的评论时才发布了解决方案。)
$ \ endgroup $
– ninjagecko
17年9月20日在11:41
#2 楼
我通过实现直接线性变换解决了自己的问题。 Wikipedia上的示例部分就是我的用例。要获取方程式,请将矩阵(例如
[x1 x2 x3 x4; x5 x6 x7 x8; x9 x10 x11 x12]
)插入您喜欢的计算机代数系统(如SageMath),然后如图所示求解所需的矩阵方程式,复制-将变量方面的解决方案粘贴到您的代码中,并调整格式。然后可以通过适当缩放或忽略特定尺寸(例如,忽略深度/ z坐标)来使解决方案适应其用例(根据使用情况在“规范化设备坐标”矩阵中)。
您将需要使用您的语言的SVD分解函数或库。
评论
如果您用谷歌搜索角钉,则会得到此的一些实现