利用SVD进行坐标系转换
我的项目遇到了一些问题,这个问题伴随了我好长时间一直没有解决,这几天询问了老师后终于有了新的思路,接下来我说明一下我的问题,以及解决方法
问题原因
很普通的问题,我在利用双目测出深度之后,会形成以左相机光心为原点,图片的水平方向为X轴(左小右大),垂直方向为Y轴(上小下大),垂直于相机成像平面为Z轴(远小近大),类型为右手坐标系。但这个坐标系并不能满足于我的项目,我需要强制转换一个坐标系。
一开始我想到的是制作旋转平移矩阵,也就是:
但我忽略了秩的问题,总之直接去求并不能求出来。
解决方法
根据老师的提醒,我还是找到了解决的具体方法,直接采用SVD(奇异值分解)可以求出自己想要的具体矩阵。
奇异值分解
又捡起了线性代数方面的知识,简单回顾了一下奇异值分解具体原理。
奇异值分解是把矩阵分解成了:
其中,U和V是两个方阵,Sigma 矩阵是一个对角线是奇异值、其他位置是0的矩阵。
numpy 提供了奇异值分解,直接调用即可。
1 | import numpy as np |
SVD法坐标系转换
其实我并没有看懂具体原理是什么,我就是随便找到了公式,但这样也就足够了。
我并没有去构造完整的旋转平移矩阵,我把它拆开了:
简单讲一下:
- P是新的坐标,P_0是旧坐标,两者的形状都是
(N, 3)
,第0维度是点的个数,第1维度坐标(三个数字为一个坐标) - R是旋转矩阵,T是平移向量
既然使用了奇异值分解,那么就必须去制作被分解的矩阵,这里被分解的矩阵用M表示:
比较麻烦,按上面公式的步骤来讲就是:
- 求出转换前和转换后的平均坐标。
- 用转换前和转换后的坐标减去自己的平均坐标。
- 进行内积操作
- 累计求和
当然写程序的时候可以使用并行化的原理,这样不仅节省时间,还方便处理。
有了需要被分解的矩阵就可以奇异值分解了:
但我们并不需要奇异值,所以 Sigma 可以不要。
接下来就是合成旋转矩阵:
很简单,就直接矩阵相乘。
注意:我们需要计算一下旋转矩阵的行列式,因为很有可能计算出来一个镜像旋转矩阵,这样是永远不额能旋转成功的。如果旋转矩阵的行列式为正数就正确,为负数就需要让旋转矩阵取反变成正数
所以在
平移矩阵就更好求了,但需要两个点的平均值:
程序
1 | def points3D_transform(points1, points2): |
我随便做了一个矩阵,简单测试一下:
1 | # 转换前坐标 |