【问题标题】:OpenCV + Python: Calculate stereo reprojection errorOpenCV + Python:计算立体重投影误差
【发布时间】:2018-04-29 23:04:53
【问题描述】:

我想做一些类似于this question 的事情,但是对于stereoCalibrate() 而不是calibrateCamera()。也就是说,计算立体相机校准的重投影误差。

我的简化示例如下所示:

import cv2
import numpy as np

def calibrate_stereo(w, h, objpoints, imgpoints_l, imgpoints_r):
    stereocalib_criteria = (cv2.TERM_CRITERIA_COUNT + cv2.TERM_CRITERIA_EPS , 1000, 1e-6)
    retval, A1, D1, A2, D2, R, T, E, F = cv2.stereoCalibrate(objpoints,imgpoints_l, imgpoints_r,None,None,None,None, (w,h), flags=0, criteria=stereocalib_criteria)

    return (retval, (A1,D1,A2,D2, R, T, E, F))

def calc_rms_stereo(objectpoints, imgpoints_l, imgpoints_r, A1, D1, A2, D2, R, T):
    tot_error = 0
    total_points = 0

    for i, objpoints in enumerate(objectpoints):
        # calculate world <-> cam1 transformation
        _, rvec_l, tvec_l,_ = cv2.solvePnPRansac(objpoints, imgpoints_l[i], A1, D1)

        # compute reprojection error for cam1
        rp_l, _ = cv2.projectPoints(objpoints, rvec_l, tvec_l, A1, D1)
        tot_error += np.sum(np.square(np.float64(imgpoints_l[i] - rp_l)))
        total_points += len(objpoints)

        # calculate world <-> cam2 transformation
        rvec_r, tvec_r  = cv2.composeRT(rvec_l,tvec_l,cv2.Rodrigues(R)[0],T)[:2]

        # compute reprojection error for cam2
        rp_r,_ = cv2.projectPoints(objpoints, rvec_r, tvec_r, A2, D2)
        tot_error += np.square(imgpoints_r[i] - rp_r).sum()
        total_points += len(objpoints)

    mean_error = np.sqrt(tot_error/total_points)

    return mean_error


if __name__ == "__main__":    
    # omitted: reading values for w,h, objectPoints, imgpoints_l, imgpoints_r from file (format as expected by the OpenCV functions)
    # [...]

    rms, (A1,D1,A2,D2,R,T,_,_) = calibrate_stereo(w, h, objectpoints, imgpoints_l, imgpoints_r)

    print("RMS (stereo calib): {}".format(rms))

    rms_2 = calc_rms_stereo(objectpoints, imgpoints_l, imgpoints_r, A1, D1, A2, D2, R, T)    
    print("RMS (custom calculation):", rms_2)

样本输出:

RMS (stereo calib): 0.14342257926694932
RMS (custom calculation): 0.356273345751

据我所知,stereoCalibrate() 源代码中的计算与我的非常相似。我错过了什么?

Ubuntu 上的 OpenCV 3.3.0

【问题讨论】:

  • 我对立体校准源代码的理解是他们将点之间的距离( norm(ab) )添加到错误中,然后他们除以得到平方根......我想你添加所有点分量差异的平方并做平方根......也许我错了
  • @api55 我也是这么想的。我假设您的意思是this line,但他们确实使用的是square norm
  • 正是那个。此外,它是有道理的。 RMSE 是均方误差的根,但它取决于您对误差的定义。据我所知,重投影误差是在 2D 中投影的点与在 2D 中用于首先生成 3D 点的点的距离......
  • 是的,我同意。但是 norm(ab)^2 (即点 a 和 b 之间的距离平方)应该等于元素差异的平方和,即 (a[0]-b[0])^2 + (a[1]- b[1])^2 没有?
  • 嗯,实际上是真的,我没有看到他们使用的是平方版本的NORM_L2SQR......然后一切看起来都一样,奇怪......我没有发现差异:(

标签: python opencv camera-calibration cv2


【解决方案1】:

我在实现了基于 OpenCV 实现的自定义立体校准算法后解决了这个问题。

cv2.stereoCalibrate() 内部计算的重投影误差与我的自定义计算之间的差异源于外部参数rvec_ltvec_l 的不同值。这些向量描述了左相机与每个图像的校准模式之间的旋转和平移。 cv2.solvePnpRansac() 仅根据左图像的重投影误差产生优化值,而在 cv2.stereoCalibrate() 中,这些值与 RT 基于每个立体对的两个图像中的重投影误差一起优化。

如果想要精确复制cv2.stereoCalibrate() 返回的 RMS 值,则必须修改 cv::stereoCalibrate() 的 C/C++ 源代码以返回优化的外部参数(cv::calibrateCamera() 已经为单目校准)。

【讨论】:

    猜你喜欢
    • 2016-05-13
    • 1970-01-01
    • 2021-03-23
    • 2017-04-28
    • 2014-07-09
    • 2015-02-27
    • 1970-01-01
    • 2015-03-29
    • 2013-05-23
    相关资源
    最近更新 更多