提问人:vatbub 提问时间:9/21/2023 最后编辑:vatbub 更新时间:10/6/2023 访问量:95
OpenCV 中用于 3D 旋转的参考向量是什么?
What is the reference vector in OpenCV for 3D rotation?
问:
我正在使用 OpenCV 的模块对场景进行 3D 重建,我试图了解 OpenCV 如何处理相机的外部校准,尤其是旋转。我知道 OpenCV 使用罗德里格斯向量,即定义旋转轴通过其指向的方向的向量和旋转角度的向量通过罗德里格斯向量的长度绕轴旋转的程度(参见维基百科)。Calib3D
为了说明这一点,以下是我对这种情况的想象:
换句话说:有一些参考向量v_ref(图像中的红色)和向量v_cam(蓝色)指向相机指向的方向。在此示例中,两者之间的角度为 75.96°。因此,罗德里格斯向量v_Rodigues的计算方法是首先计算 v_Ref 和 v_cam 之间的归一化叉积,然后将其乘以角度以使其达到适当的长度。
由此,我有两个问题:
- 我的理解正确吗?
- OpenCV 用作v_Ref吗?
编辑:由于这个问题似乎引起了一些误解:
我实际上有以下情况:
我使用全站仪测量了相机的位置。
这意味着我对相机的位置和相机的前向矢量有一个很好的估计。
但是,OpenCV 需要罗德里格斯向量(如图中),而不是相机的前向向量。
因此,我试图从我的 计算,正如评论中指出的那样,只有在我知道的情况下才有效。
这就是为什么我试图找出 OpenCV 使用什么作为 .v_Cam
v_Rodrigues
v_Cam
v_Rodrigues
v_Cam
v_Ref
v_Ref
我认为我对 OpenCV 的相机和世界坐标系是如何定义的有很好的理解,我只是错过了 .v_Ref
答:
好吧,我想我终于有了一些看起来正确的东西。 我将尝试在这里总结我的发现作为答案,但在我写这篇文章时,我仍然在整理我的想法,所以如果这个答案仍然有点不清楚,请原谅我。
正如 @fana 和 @ChristophRackwitz 所指出的,有一个对象坐标系和一个相机坐标系。
对象坐标系是一个规则的右手笛卡尔坐标系,因此 X 和 Y 定义水平面,Z 指向上方。
如@ChristophRackwitz所述,相机坐标系连接到相机的投影平面。
通过相机的镜头观察时,X 指向右侧,Y 指向下方,Z 指向外部。
所以,用我自己的话来说,等于相机坐标系中的Z轴。v_Cam
这个网站有一个很好的坐标系说明。
此外,@fana如前所述,如果不应用平移和旋转(即旋转矩阵是单位矩阵或罗德里格斯向量全为零),则对象坐标系和相机坐标系的轴是相同的。
因此,如果我的理解是正确的,那么以下情况适用:
当未应用旋转时,坐标轴相同。
因此,在这种情况下,等于对象坐标系的 Z 轴,这也意味着(与对象坐标系的 Z 轴对齐)。v_cam
v_Ref = (0, 0, 1)
考虑到这一点,我开始尝试: 我为自己生成了一个 11×11 的平面对象点网格:
val objectPoints = List(11) { rowIndex ->
List(11) { columnIndex ->
Point3(columnIndex.toDouble() - 5.0, rowIndex.toDouble() - 5.0, 0.0)
}
}.flatten()
(此代码生成一个规则的点网格,从 到(-5.0, -5.0, 0.0)
(5.0, 5.0, 0.0)
然后,我希望我的相机位于这些平面物体点的上方,指向下方(上图中的c.f.),并相应地生成投影图像点:v_cam
val imagePoints = List(11) { rowIndex ->
List(11) { columnIndex ->
Point((columnIndex.toDouble() - 5.0) * imageScaleFactor, (rowIndex.toDouble() - 5.0) * imageScaleFactor)
}
}.flatten()
然后,我继续调用这些点作为输入:Calib3d.calibrateCamera()
val cameraMatrix = Mat()
val distortionCoefficients = Mat()
val rotationVectors = mutableListOf<Mat>()
val translationVectors = mutableListOf<Mat>()
val overallRms = Calib3d.calibrateCamera(
// The map and toMat-functions just convert the data into a form that OpenCV accepts
listOf(objectPoints.map { it.toOpenCVPoint() }.toMat3f()),
listOf(imagePoints.toMat2f()),
imageSize,
cameraMatrix,
distortionCoefficients,
rotationVectors,
translationVectors
)
这给了我以下内在因素:
CameraIntrinsics(
cameraMatrix = CameraMatrix(
focalLength = Point(x = 1.350310986449413E17, y = 1.3503109864494126E17),
opticalCenter = Point(x = 9.500000000000115, y = 9.500000000000115)
),
distortionCoefficients = DistortionCoefficients(
k1 = -1.2551867374857695E-26,
k2 = -3.1640690574535313E-41,
p1 = 1.4867968141433821E-6,
p2 = 1.4867967882740299E-6,
k3 = -9.212409017493725E-56,
),
overallRms = 3.7999673703527265E9
)
和外在因素:
CameraExtrinsics(
worldLocation = Point3(x = -7.905761924365692E-9, y = -7.905762033403558E-9, z = 1.123709191949999E8),
rotation = RodriguesVector(-1.110720731360427, 1.1107207365421794, -3.6640522551246774E-9)
)
起初,罗德里格斯向量看起来像我所期望的:
相机笔直地指向下方,因此相机的 z 轴(或 )与对象坐标系的 z 轴(或我认为的方向)完全相反。
因此,我希望在 X-Y 平面中,因为它必须垂直于两者,并且 .但是,我预计罗德里格斯向量的长度是 since 指向下方,而我假设等于 z 轴,因此指向上方,导致两者之间成 180° 角。v_cam
v_Ref
v_Rodrigues
v_Cam
v_Ref
3.1415 [rad] = 180°
v_cam
v_Ref
然而,事实并非如此:
如果计算上述罗德里格斯向量的长度,则结果是 ,而不是 。pi/2 [rad] = 90°
180°
由于 OpenCV 计算了一个合理的平移向量,我假设罗德里格斯向量也是正确的,只是不是我所期望的。
但是,鉴于我知道相机朝下,我可以反向应用罗德里格斯公式(即将罗德里格斯向量乘以,然后应用维基百科上提到的公式),给我真正的 .-1
v_Ref
事实证明,似乎是.v_Ref
(1.0, 1.0, 0.0)
对于为什么会这样,我还没有一个合乎逻辑的解释,但测试其他一些相机位置似乎也证实了这一点。
我现在将继续我的项目,假设并在我发现更多时更新此答案。v_Ref = (1.0, 1.0, 0.0)
谢谢你@fana和@ChristophRackwitz对我的包容:)
评论
overallRms = 3.7999673703527265E9
看起来很大。(它可能表示一些 plobles。
calibrateCamera()
imagePoints
(X,Y,Z)=(0,0,0)
(x,y)=(0,0)
t = (-6, -6, some plus value)
worldLocation
calibrateCamera()
imagePoints being outsiode of the image
评论
v_Ref
v_Rodrigues
v_Ref
v_Cam
R
v_result = R * v_src
v_src
v_Ref
(0, 0, 1)
(1, 0, 0)
v_Rodrigues
v_Ref
v_Cam
v_Rodrigues
v_Ref
v_Rodrigues
v_Cam