相机矩阵的分解

你一直在研究一个新的计算机视觉库,并且设法校准了你的相机……现在你要用它做什么?

如果你能找到相机的位置或找出它的视野,那会更有用。你打开了你信赖的 Hartley 和 Zisserman 的副本,它告诉你如何将你的相机分解为内参和外参矩阵 --- 太棒了!

但是当你查看结果时,有些事情不太对劲。也许你的旋转矩阵有一个行列式 -1,导致你的矩阵到四元数函数出错。也许你的焦距是负的,而你不明白为什么。也许你的平移向量错误地声称世界原点在相机后面。或者最糟糕的是,一切看起来都很好,但是当你将它插入 OpenGL 时,你什么都看不到。

今天,我们将介绍将相机矩阵分解为内参矩阵和外参矩阵的过程,并尝试解决可能因不同坐标约定而出现的问题。在后面的文章中,我们将更详细地研究内在矩阵和外在矩阵,我将介绍如何将它们转换为 OpenGL 可用的形式。

NSDT工具推荐: Three.js AI纹理开发包 - YOLO合成数据生成器 - GLTF/GLB在线编辑 - 3D模型格式在线转换 - 可编程3D场景编辑器 - REVIT导出3D模型插件 - 3D模型语义搜索引擎 - Three.js虚拟轴心开发包 - 3D模型在线减面 - STL模型在线切割 

1、获取相机矩阵

我假设你已经事先获得了相机矩阵,但如果需要相机校准方面的帮助,我建议你查看 Matlab 的相机校准工具箱。OpenCV 似乎也有一些有用的例程,可以从一系列棋盘图像中自动校准相机,尽管我个人没有使用过它们。像往常一样,Hartley 和 Zisserman 对该主题进行了很好的处理。

2、相机矩阵分解

首先,我们假设你的相机矩阵为 3x4,它将齐次 3D 世界坐标转换为齐次 2D 图像坐标。按照 Hartley 和 Zisserman 的说法,我们将矩阵表示为 P,有时使用块形式会很有用:

其中 M 是可逆的 3x3 矩阵,C 是列向量,表示相机在世界坐标中的位置。一些校准软件提供了 4x4 矩阵,它增加了一行来保存 z 坐标。在这种情况下,只需删除第三行即可获得 3x4 矩阵。

相机矩阵本身可用于将 3D 点投影到 2D,但它有几个缺点:

  • 它不会告诉你相机的姿态。
  • 它不会告诉你相机的内部几何形状。
  • 镜面照明是不可能的,因为你无法在相机坐标中获得表面法线。

为了解决这些缺点,相机矩阵可以分解为两个矩阵的乘积:一个内参矩阵 K 和一个外参矩阵 [R|−RC]

矩阵 K 是一个 3x3 上三角矩阵,用于描述相机的内部参数,例如焦距。R 是一个 3x3 旋转矩阵,其列是相机参考系中世界轴的方向。向量 C 是世界坐标中的相机中心;向量 t = -RC 给出相机坐标中世界原点的位置。我们将在后续文章中更详细地研究这些矩阵中的每一个,今天我们只讨论如何从 P 中获取它们。

恢复相机中心 C 很简单。请注意,P 的最后一列是 -MC,因此只需将其左乘以 −M^−1。

3、在进行 RQ 之前...

为了恢复 R 和 K,我们注意到 R 是正交的,因为它是旋转矩阵,而 K 是上三角矩阵。任何满秩矩阵都可以通过使用 RQ 分解为上三角矩阵和正交矩阵的乘积。

不幸的是,包括 Matlab 在内的许多库都不提供 RQ 分解,但幸运的是,它的朋友 QR 分解通常可用。Solem 的视觉博客有一篇很好的文章,使用一些矩阵翻转实现了缺失的函数;这是一个 Matlab 版本(感谢 Solem 允许我转发这篇文章!):

function [R Q] = rq(M)
    [Q,R] = qr(flipud(M)')
    R = flipud(R');
    R = fliplr(R);

    Q = Q';   
    Q = flipud(Q);

简单!

4、我看到了双重……四次分解!

只有一个问题:RQ 分解的结果不是唯一的。要看到这一点,请尝试否定 K 的任何列和 R 的相应行:得到的相机矩阵保持不变。大多数人只是强制 K 的对角线元素为正,如果两个条件成立,这是正确的方法:

  • 图像的 X/Y 轴指向与相机的 X/Y 轴相同的方向。
  • 相机朝正 z 方向看。

Solem 的博客用三行代码优雅地为我们提供了正对角线条目:

# make diagonal of K positive
T = diag(sign(diag(K)));

K = K * T;
R = T * R; # (T is its own inverse)

实际上,相机轴和图像轴不会一致,并且 K 的对角线元素不应为正。强制它们为正可能会导致严重的副作用,包括:

  • 物体出现在相机的错误一侧。
  • 旋转矩阵的行列式为 -1 而不是 1。
  • 不正确的镜面照明。
  • 由于 w 坐标为负,可见几何图形不会渲染。

Hartley 和 Zisserman 的坐标约定。请注意,从相机的 POV 观看时,相机和图像 x 轴指向左侧。

在这种情况下,你需要进行一些修复。

首先确保你的相机和世界坐标都具有相同的惯用手性。然后记下校准相机时使用的轴约定。图像 y 轴指向哪个方向,向上还是向下?x 轴?现在考虑相机的坐标轴。你的相机是否朝负 z 轴(OpenGL 风格)俯视?朝正 z 轴(如 Hartley 和 Zisserman)?x 轴指向左还是右?y 轴呢?好的,好的,你明白了。

从全正对角线开始,遵循以下四个步骤:

  • 如果图像 x 轴和相机 x 轴指向相反方向,则对 K 的第一列和 R 的第一行取反。
  • 如果图像 y 轴和相机 y 轴指向相反方向,则对 K 的第二列和 R 的第二行取反。
  • 如果相机朝负 z 轴俯视,则对 K 的第三列取反。保持 R 不变。编辑:也对 R 的第三列取反。
  • 如果 R 的行列式为 -1,则对其取反。

请注意,这些步骤中的每一步都使组合相机矩阵保持不变。最后一步相当于将整个相机矩阵 P 乘以 -1。由于 P 是在齐次坐标上操作的,因此将其乘以任何常数都没有效果。

关于步骤 3,Hartley 和 Zisserman 的相机向下看正 z 方向,但在某些现实世界系统(例如 OpenGL)中,相机向下看负 z 轴。这允许 x 和 y 轴指向右上方,从而产生一个感觉自然但仍然是右手坐标系的坐标系。上面的步骤 3 通过在 z 为负时使 w 为正来纠正这个问题。

你可能会对 K3,3为负的事实感到犹豫,但 OpenGL 需要这样做才能正确剪辑。我们将在以后的文章中进一步讨论 OpenGL。

您可以通过检查向量 t=−RC 来仔细检查结果,它是相机坐标中世界原点的位置。如果一切正确,tx,ty,tz 的符号应该反映世界原点在相机中的位置(分别是中心的左/右、中心的上方/下方、相机的前面/后面)。

5、谁翻转了我的轴?

到目前为止,我们对 2D 坐标约定的讨论都涉及校准期间使用的坐标。如果你的应用程序使用不同的 2D 坐标约定,则需要使用 2D 平移和反射来转换 K。

例如,考虑一个相机矩阵,其校准原点在左上角,y 轴向下,但您更喜欢原点在左下角,y 轴向上。要转换,你首先要对图像 y 坐标取反,然后向上平移图像高度 h。得到的固有矩阵 K' 由以下公式给出:

6、结束语

无论你使用哪种坐标约定,上述过程都应为你提供正确的相机分解。我在自己的研究中已在少数场景中对其进行了测试,到目前为止效果良好。

在下一篇文章中,我们将通过交互式演示更详细地研究外部矩阵。


原文链接:相机矩阵的分解 - BimAnt

### 图像处理中稀疏矩阵分解的应用及实现 #### 一、稀疏矩阵分解的基本概念 在图像处理领域,稀疏矩阵分解是一种重要的技术手段。它通过将复杂的图像数据分解为低秩部分和稀疏部分,从而能够有效地提取有用的信息并去除干扰项。一幅清晰的自然图像往往具有高度的相关性,因此其数据矩阵通常是低秩或近似低秩的[^2]。然而,在实际场景中,由于噪声或其他因素的影响,图像可能会变得复杂且难以分析。 为了应对这一挑战,研究者提出了基于增广拉格朗日算子的低秩稀疏矩阵分解模型。该模型的核心思想是将退化的图像视为由一个低秩成分(代表主要结构信息)和一个稀疏成分(代表异常值或噪声)组成[^1]。通过对这两个组成部分分别建模,可以有效恢复原始图像的质量。 #### 二、具体应用场景 ##### 1. 去除摩尔纹 当拍摄显示屏幕上的内容时,常常会出现令人困扰的摩尔纹现象。这种视觉伪影是由不同频率图案叠加所引起的空间干涉效应造成的。针对此问题,可以通过低秩稀疏矩阵分解结合导向滤波器来进行修复。这种方法不仅保留了原图的主要特征,还显著减少了不希望存在的条纹效果。 ##### 2. 图像去噪 对于受到高斯白噪音影响的照片来说,传统的平滑操作容易造成细节损失。而采用低秩加稀疏表示的方式,则可以在保持边缘锐利的同时清除杂点。因为真实世界的物体表面反射特性决定了大部分像素间存在较强关联性,故它们构成的部分应呈现较低维度;反之那些孤立分布的小范围突变则对应于随机产生的错误样本集合。 ##### 3. 运动模糊校正 视频监控录像经常面临因快速移动目标而导致的画面拖尾情况。借助鲁棒主成分分析(RPCA),我们可以分离出平稳背景区域以及瞬态前景对象轨迹,并进一步估计相机运动参数完成补偿调整工作。整个过程中涉及到的关键步骤之一就是执行精确可靠的SVD奇异值阈值化运算来获取最佳逼近解形式下的核心表达式。 #### 三、Python 实现示例 下面给出一段简单的 Python 脚本演示如何利用交替方向法(ADMM)框架解决上述提到的一类典型任务: ```python import numpy as np from scipy.sparse.linalg import svds def admm_lrsd(Y, mu=1e-6, rho=1.0, max_iter=100): """ 使用 ADMM 方法进行低秩+稀疏分解 参数: Y (numpy.ndarray): 输入观察到的数据矩阵. mu (float): 控制稀疏程度的超参,默认值为 1e-6. rho (float): 更新步长因子,默认设置为 1.0. max_iter (int): 最大迭代次数限制. 返回: L (numpy.ndarray): 提取出的低秩分量. S (numpy.ndarray): 计算所得的稀疏残差. """ m, n = Y.shape norm_Y = np.linalg.norm(Y) # 初始化变量 L = np.zeros((m,n)) S = np.zeros((m,n)) Z = np.zeros((m,n)) I = np.eye(m) D = np.diag(np.ones(n)) for _ in range(max_iter): U,Sigma,Vt = svds(L + Z/rho,k=min(m,n)-1) Sigma_star = np.maximum(Sigma - 1/(rho*mu),0)*np.identity(len(Sigma)) L_new = U @ Sigma_star @ Vt temp_S = Y - L_new + Z / rho S_new = np.sign(temp_S)*(abs(temp_S)>=(1/mu))*(abs(temp_S)-(1/mu)) Z += rho*(L_new+S_new-Y) if ((np.linalg.norm(L-L_new)/norm_Y)<1e-7 and \ (np.linalg.norm(S-S_new)/norm_Y)<1e-7): break L,S = L_new.copy(),S_new.copy() return L,S if __name__ == "__main__": img_data = ... # 加载待处理图片数组 low_rank_part,sparse_error = admm_lrsd(img_data) ``` 以上代码片段实现了最基本的低秩与稀疏分解功能。用户可以根据自己的需求修改相应配置选项以适应特定用途环境下的性能调优要求。 --- #### 四、总结说明 综上所述,无论是理论层面还是工程实践方面,稀疏矩阵分解都展现出了强大的潜力价值所在。特别是在现代多媒体信息系统日益普及的大背景下,此类先进技术必将发挥越来越重要的作用!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值