在给定2个图像的坐标点和相机的外部值的情况下,如何对3D空间中的点进行三角测量

时间:2019-04-18 06:31:12

标签: python numpy triangulation vision

我正在尝试编写一个函数,当给定两个摄像头时,它们的旋转,平移矩阵,焦点以及每个摄像头的点坐标将能够将该点三角剖分到3D空间中。基本上,给出所有需要的外部/内部值

我熟悉一般的想法:以某种方式创建两条射线并找到满足最小二乘问题的最接近点,但是,我不知道如何将给定信息转化为一系列方程式。 3D中的坐标点。

2 个答案:

答案 0 :(得分:1)

我的旅程迟到了几年。我遇到了完全相同的问题,发现有几个人在问同样的问题,但从未找到足够简单的答案让我理解在这里为未来的人。

最后我还会给你一些代码示例,让你在 python 中做你想做的事情,所以坚持下去。

我的手写笔记的一些屏幕截图,其中解释了整个过程。 Page 1. Page 2. Page 3.

这是我开头的等式,可以在 https://docs.opencv.org/master/d9/d0c/group__calib3d.html

中找到

Starting formula

一旦您在现实世界中为两个相机选择了相同的原点,您将拥有其中两个具有相同 X、Y、Z 值的方程。

抱歉,下一部分您已经有了,但其他人可能还没有做到这一点:

首先,您需要校准您的相机,这将为您提供每台相机的相机矩阵和失真(内在属性)。 https://docs.opencv.org/master/dc/dbb/tutorial_py_calibration.html

您只需要这两个并且可以转储 rvecs 和 tvecs,因为这会在您设置相机时发生变化。

一旦你选择了你的真实世界坐标系,你就可以使用 cv2.solvePnP 来获得旋转和平移向量。为此,您需要一组真实世界的点以及它们在每个相机的相机中的相应坐标。我的诀窍是我编写了一些代码来显示该领域的图像,然后我会传入点数。然后我会点击图像上的位置并创建一个映射。这个位的代码有点长,所以除非有要求,否则我不会在这里分享。

cv2.solvePnP 将为您提供旋转矩阵的向量,因此您需要使用以下行将其转换为 3x3 矩阵:

`R, jac = cv2.Rodrigues(rvec)`

现在回到最初的问题: 每个相机都有 3x3 相机矩阵。每个相机都有 3x3 旋转矩阵。每个相机都有 3x1 的平移向量。您有一些 (u, v) 坐标,用于确定每个相机中感兴趣对象的位置。数学在笔记的图像中有更多的解释。

import numpy as np

def get_xyz(camera1_coords, camera1_M, camera1_R, camera1_T, camera2_coords, camera2_M, camera2_R, camera2_T):
    # Get the two key equations from camera1
    camera1_u, camera1_v = camera1_coords
    # Put the rotation and translation side by side and then multiply with camera matrix
    camera1_P = camera1_M.dot(np.column_stack((camera1_R,camera1_T)))
    # Get the two linearly independent equation referenced in the notes
    camera1_vect1 = camera1_v*camera1_P[2,:]-camera1_P[1,:]
    camera1_vect2 = camera1_P[0,:] - camera1_u*camera1_P[2,:]
    
    # Get the two key equations from camera2
    camera2_u, camera2_v = camera2_coords
    # Put the rotation and translation side by side and then multiply with camera matrix
    camera2_P = right_M.dot(np.column_stack((camera2_R,camera2_T)))
    # Get the two linearly independent equation referenced in the notes
    camera2_vect1 = camera2_v*camera2_P[2,:]-camera2_P[1,:]
    camera2_vect2 = camera2_P[0,:] - camera2_u*camera2_P[2,:]
    
    # Stack the 4 rows to create one 4x3 matrix
    full_matrix = np.row_stack((camera1_vect1, camera1_vect2, camera2_vect1, camera2_vect2))
    # The first three columns make up A and the last column is b
    A = full_matrix[:, :3]
    b = full_matrix[:, 3].reshape((4, 1))
    # Solve overdetermined system. Note b in the wikipedia article is -b here.
    # https://en.wikipedia.org/wiki/Overdetermined_system
    soln = np.linalg.inv(A.T.dot(A)).dot(A.T).dot(-b)
    return soln

答案 1 :(得分:0)

假设您有两个摄像机-摄像机1和摄像机2。

对于每个摄像机j = ​​1、2,您将得到:

  1. 中心hj之间的距离Oj,(“焦点”是正确的术语吗?基本上是相机从其观看屏幕的点Oj)和相机的屏幕。相机的坐标系以Oj为中心,Oj--->xOj--->y轴与屏幕平行,而Oj--->z轴与屏幕垂直。

  2. 3 x 3旋转矩阵Uj和3 x 1平移矢量Tj将相对于相机j(请参见点1)的系统的笛卡尔3D坐标转换为世界坐标,即相对于描述3D世界中所有点的第三坐标系的坐标。

  3. 在摄像机j的屏幕上,该屏幕是平行于平面Oj-x-y且与原点hj相距Oj的平面,您具有2D坐标(假设仅点pj的x,y坐标,其中两个点p1p2实际上是同一点P的投影图像,位于3D,分别到摄像机1和2的屏幕上。通过在点Oj和点P之间绘制3D线并将点pj定义为该线与相机j的屏幕的唯一交点,可以得到投影。相机j的3D坐标系中的屏幕方程为z = hj,因此点pj相对于相机j的3D坐标系的坐标看起来像pj = (xj, yj, hj),因此2D屏幕坐标只是pj = (xj, yj)

输入:为您提供2D点p1 = (x1, y1), p2 = (x2, y2),twp摄像机的焦距h1, h2,两个3 x 3旋转矩阵U1和{{ 1}},两个转换3 x 1矢量列U2T1

输出:世界坐标系中P点的坐标T2

一种避免这种情况的简单方法是避免以下情况的算法:避免同质坐标和投影矩阵(也可以或多或少地等效):

  1. 表格P = (x0, y0, z0)Q1 = [x1; y1; h1],它们被解释为3 x 1矢量列;

  2. 变换Q2 = [x2; y2; h2]P1 = U1*Q1 + T1,其中P2 = U1*Q2 + T1是矩阵乘法,这里是3 x 3矩阵乘以3 x 1列,给定3 x 1列;

  3. 形成*X = T1 + t1*(P1 - T1)行;

  4. 来自前面步骤3的两条线在一个公共点(即点X = T2 + t2*(P2 - T2))处相交,或者它们是斜线,即它们不相交但不平行(不共面)。

  5. 如果线是斜线,请在第一行上找到唯一点P,在第二行上找到唯一点X1,以使向量X2垂直两条线都垂直,即X2 - X1垂直于矢量X2 - X1P1 - T1。这两个点X1和X2是两条线上的最接近点。然后,可以将点P2 - T2作为线段P = (X1 + X2)/2的中点。

通常,两条线应该彼此非常靠近,因此两个点X1和X2应该彼此非常靠近。