【问题标题】:cv2 triangulatePoints always returns same Z valuecv2 triangulatePoints 总是返回相同的 Z 值
【发布时间】:2021-01-23 09:39:08
【问题描述】:

我正在尝试使用 cv2.triangulatePoints 获取 3D 点,但它总是返回几乎相同的 Z 值。我的输出如下所示: 正如它所看到的,所有点的 Z 值几乎相同。没有深度。

这是我的三角测量:

    def triangulate(self, proj_mat1, pts0, pts1):
        proj_mat0 = np.zeros((3,4))
        proj_mat0[:, :3] = np.eye(3)
        pts0, pts1 = self.normalize(pts0), self.normalize(pts1) 
        pts4d = cv2.triangulatePoints(proj_mat0, proj_mat1, pts0.T, pts1.T).T
        pts4d /= pts4d[:, 3:]
        out = np.delete(pts4d, 3, 1)
        print(out)
        return out

这是我的投影矩阵计算:

    def getP(self, rmat, tvec):
       P = np.concatenate([rmat, tvec.reshape(3, 1)], axis = 1)
       return P

这是我得到 rmat、tvec 和调用 triangulation 的部分:

    E, mask = cv2.findEssentialMat(np.array(aa), np.array(bb), self.K)
    _, R, t, mask = cv2.recoverPose(E, np.array(aa), np.array(bb), self.K)
    proj_mat1 = self.getP(R, t)
    out = self.triangulate(proj_mat1, np.array(aa, dtype = np.float32), np.array(bb, dtype = np.float32))

我的相机矩阵:

array([[787.8113353 ,   0.        , 318.49905794],
       [  0.        , 786.9638204 , 245.98673477],
       [  0.        ,   0.        ,   1.        ]])

我的投影矩阵1:

array([[1., 0., 0., 0.],
       [0., 1., 0., 0.],
       [0., 0., 1., 0.]])

解释:

  • aa 和 bb 是来自 2 帧的匹配点。
  • self.K 是我的相机矩阵
  • 从基本矩阵中提取旋转和平移矩阵
  • 根据匹配的关键点计算的基本矩阵。它每帧都会改变。
  • 投影矩阵 2 每帧都会发生变化。

更改第一个投影矩阵后的输出(我从 matplotlib 切换到 pangolin 作为 3D 可视化工具):

使用我在cmets中提到的P1和P2后的输出:

我的错误在哪里?如果需要任何进一步的信息,请告诉我。我会更新我的问题。

【问题讨论】:

  • Ciao!我认为,为了帮助人们理解代码背后的数学,如果您可以在问题的末尾添加所有计算矩阵会很好:相机矩阵、旋转矩阵、平移向量、投影矩阵 1 和 2、投影点数组 aa 和 bb 以及在这个意义上的其他任何东西......祝你好运!
  • 感谢您的评论@Antonino。我编辑了我的问题。

标签: python opencv computer-vision camera-calibration triangulation


【解决方案1】:

不幸的是,我无法直接仔细检查,但我的直觉是,您面临的问题本质上是由于您选择了第一个投影矩阵

我做了一些研究,发现this great paper 既有理论又有实践。尽管与您的方法有些不同,但有一点值得说

如果您仔细检查,第一个投影矩阵正是相机矩阵,最后一列为零。其实第一个摄像头的旋转矩阵归约到单位矩阵,对应的平移向量是空向量,所以用this general formula

P = KT

其中P 是投影矩阵,K 是相机矩阵,T 是旋转矩阵R 旁边是平移向量t 得到的矩阵,根据:

T = [R|t]

然后你会得到:

回到你的情况,首先我建议像刚才所说的那样改变你的第一个投影矩阵

另外,我知道您计划在每一帧都使用不同的东西,但是如果在建议的更改之后仍然不匹配,那么在您的鞋子中,我会开始只使用 2 张图像 [我认为您隐含已经创建了aabb] 之间的对应关系,首先使用您的算法计算矩阵,然后检查根据上述文章获得的矩阵

通过这种方式,您将能够了解/调试哪些矩阵正在给您带来麻烦

祝你有美好的一天,
安东尼诺

【讨论】:

  • 我尝试按照您的建议将第一个投影矩阵更改为 K * [R|t]。我最终得到了一条直线。我在问题的末尾添加了输出。
  • @MertcanKarık 对不起,我的解释不好!对于您的代码,我将替换 proj_mat0,而不是 proj_mat1 [我正在使用投影矩阵 1 和投影矩阵 2,如链接的文章和 OpenCV 文档中所示]
  • “第一”是指 [proj_mat0]。我将它们标准化以在 3D 可视化中看到靠近原点的位置。如果我不规范化,我会在另一个位置看到完全相同的东西。 [.T] 表示转置。我转置 [pts0] 和 [pts1] 因为 [cv2.triangulatePoints] 接受 [2xN] 数组作为点。对于您的最后一个问题,我只更改了 [proj_mat0]。
  • 另外,我也试过这个:我使用 [cv2.calibrateCamera] 获得相机矩阵和失真系数,然后使用它们,我找到了 [cv2.stereoCalibrate] 的旋转矩阵和平移向量。最后使用相机矩阵、失真系数、旋转矩阵和平移向量,我发现 [P1]、[P2] 矩阵和 [cv2.stereoRectify]。然后,我在三角测量中使用了 P1 和 P2 而不是 [proj_mat0] 和 [proj_mat1],但输出再次变差。我在问题的末尾添加了输出。
  • @MertcanKarık 很有趣!检查this project,尤其是components.py 中的triangulate_points 方法:这里的程序员使用相同的样式调用opencv triangulatePoints 方法,因此您可以检查他如何构建要传递给该函数的值。一旦你仔细检查了输入值的正确性,也许你可以使用该代码来构建输出并与你的交叉检查
【解决方案2】:

非常感谢@Antonino 的所有努力。我的网络摄像头很糟糕。在更改了我的代码的每一部分并进行了多次试验后,我决定更换我的网络摄像头并购买了好的网络摄像头。它起作用了:D这是结果:

【讨论】:

  • 这是个好消息,我为你感到高兴!只是出于好奇:您是否必须更改您发布的初始代码中的任何内容[例如proj_mat0 值] 还是像最初发布的那样开箱即用?
  • 我只发现了带有棋盘技术的新相机矩阵。除此之外,我没有改变任何东西。如果你想看看,我可以分享我的完整代码。
  • 非常感谢您的回复!不,我只是想了解您是否必须从理论/数学的角度进行更改...祝您的项目伙伴好运!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-10-22
  • 2019-10-31
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多