使用 opencv - traingulatePoints 单位从两个图像中确定 3d 位置

Determining 3d locations from two images using opencv - traingulatePoints units

给定一组对应点下注两个任意(即不平行)图像(例如,由 SURF 找到),我使用以下方法尝试提取点的 3D 位置。

def triangulate(pts1,pts2):
    cameraMatrix = np.array([[1, 0,0],[0,1,0],[0,0,1]])        
    F,m1 = cv2.findFundamentalMat(pts1, pts2) # apparently not necessary

    # using the essential matrix can get you the rotation/translation bet. cameras, although there are two possible rotations: 
    E,m2 = cv2.findEssentialMat(pts1, pts2, cameraMatrix, cv2.RANSAC, 0.999, 1.0)
    Re1, Re2, t_E = cv2.decomposeEssentialMat(E)

    # recoverPose gets you an unambiguous R and t. One of the R's above does agree with the R determined here. RecoverPose can already triangulate, I check by hand below to compare results. 
    K_l = cameraMatrix
    K_r = cameraMatrix
    retval, R, t, mask2, triangulatedPoints = cv2.recoverPose(E,pts_l_norm, pts_r_norm, cameraMatrix,distanceThresh=0.5)

    # given R,t you can  explicitly find 3d locations using projection 
    M_r = np.concatenate((R,t),axis=1)
    M_l = np.concatenate((np.eye(3,3),np.zeros((3,1))),axis=1)
    proj_r = np.dot(cameraMatrix,M_r)
    proj_l = np.dot(cameraMatrix,M_l)
    points_4d_hom = cv2.triangulatePoints(proj_l, proj_r, np.expand_dims(pts1, axis=1), np.expand_dims(pts2, axis=1))
    points_4d = points_4d_hom / np.tile(point_s4d_hom[-1, :], (4, 1))
    points_3d = points_4d[:3, :].T
    return points_3d

我假设我的内在相机矩阵在上面近似于 I。由两种方法(findEssentialMat->decomposeEssentialMat vs recoverPose)确定的 R,t 一致,由两种方法(recoverPose vs triangulatePoints)确定的三角点也一致。我的问题涉及我看到的值,points_3d 通常在 x、y 的 0-50 和 z 的 0-0.03 范围内。据我所知,这些值应该以像素为单位;我选择的相机矩阵=我影响了比例吗?

您应该使用经过校准的相机。您可以在 OpenCV 中查找相机校准教程,它为您提供了代码并解释了如何校准您的相机。

校准将为您提供相机矩阵和畸变系数,您必须使用这些系数来获得未畸变的 SURF 关键点(又名特征),您将使用 triangulatePoints。

通常计算的相机平移是一个单位向量,因此您的 3D 点将使用该位移作为比例单位。假设您的两张图像是用相距 1 米的相机拍摄的,3D 点将以米为单位。 3D 比例从不以像素为单位。

最终评论:

1- 这种三角测量点不是很准确。准确性是通过多视图或slam方法实现的,其中none很简单。并且始终使用经过校准的相机。

2-如果你不校准你的相机,你可以近似你的相机矩阵(结果会变差但总比没有好)假设: - cx 和 cy 在图像的中间 - fx = fy = 水平分辨率的一半(例如 1920/2 像素),假设您的相机具有 90 度光圈。否则你必须画一个等腰三角形并做一些几何。

是的,您选择的相机矩阵直接影响比例。 OpenCV 中的相机矩阵应包含 fx 和 fy 的值,它们指的是以像素为单位表示的相机焦距(主距离)- see OpenCV Camera model.
如果您将这两个值都设置为 1,您将获得 "smaller values" 像素的 3D 点。通常,(显然取决于相机)fx、fy 的值在例如1000。 Here 您可以找到一个很好的示例,用于仅使用分辨率和近似视场 (FOV) 来估算网络摄像头的焦距。