首页 > 编程问答 >cv2.stereoCalibrate 是否提供了合并初始估计的方法

cv2.stereoCalibrate 是否提供了合并初始估计的方法

时间:2024-07-24 08:19:00浏览次数:11  
标签:python numpy opencv camera-calibration stereo-3d

这是我的代码:

def stereo_calibrate(img, correspondences_left, correspondences_right, camera_matrix_L, camera_matrix_R, dist_coeffs=None):
    if dist_coeffs is None:
        dist_coeffs = np.zeros((4, 1))

    # Extract image points and object points from correspondences
    image_points_left = correspondences_left[:, :2].astype(np.float32)
    image_points_right = correspondences_right[:, :2].astype(np.float32)
    object_points = correspondences_left[:, 2:].astype(np.float32)  # Assuming object points are the same for both sets

    # Stereo calibration to find the extrinsic parameters
    ret, camera_matrix_L, dist_coeffs_L, camera_matrix_R, dist_coeffs_R, R, T, E, F = cv2.stereoCalibrate(
        [object_points], [image_points_left], [image_points_right],
        camera_matrix_L, dist_coeffs, camera_matrix_R, dist_coeffs,
        imageSize=(img.shape[1], image_points_left.shape[0]),
        criteria=(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 1e-6),
        flags=cv2.CALIB_FIX_INTRINSIC
    )

    if ret:
        print("Stereo Calibration Successful")
        print("Rotation Matrix between the cameras:")
        print(R)
        print("Translation Vector between the cameras:")
        print(T)
    else:
        raise ValueError("stereoCalibrate failed to find a solution")

    # Reproject object points to both cameras
    rvec_L, tvec_L = np.zeros((3, 1)), np.zeros((3, 1))  # Left camera is at origin
    reprojected_points_left, _ = cv2.projectPoints(object_points, rvec_L, tvec_L, camera_matrix_L, dist_coeffs_L)
    reprojected_points_right, _ = cv2.projectPoints(object_points, R, T, camera_matrix_R, dist_coeffs_R)

    return R, T, reprojected_points_left, reprojected_points_right


def visualize_reprojection(original_points, reprojected_points, title, img):
    total_residual = [0.0, 0.0]
    for i in range(len(original_points)):
        dx = original_points[i][0] - reprojected_points[i][0][0]
        dy = original_points[i][1] - reprojected_points[i][0][1]
        residual_x = dx * dx
        residual_y = dy * dy
        total_residual[0] += residual_x
        total_residual[1] += residual_y

        cv2.circle(img, (int(original_points[i][0]), int(original_points[i][1])), 3, (0, 0, 255), -1)  # Red for original
        cv2.circle(img, (int(reprojected_points[i][0][0]), int(reprojected_points[i][0][1])), 3, (255, 0, 0), -1)  # Blue for reprojected

    print("Total residual x: {:.4f}, y: {:.4f}".format(total_residual[0], total_residual[1]))

    cv2.imwrite(title + "output.png", img)

correspondences_left = np.array([
    [671.0889955686854, 193.80354505169868, 0, -4.0, 11],
    [776.4436176302232, 915.4922724670864, 1.4031329107584791, 3.7458267491631854, 11],

    # points along 3 point projected circle
    [929.34693878, 231.39735894, 3.0701740089441083, -2.5639874326533003, 11],
    [539.25672372, 254.15158924, -1.6947050288157524, -3.6232547337037455, 11],
    [449.60294118, 345.16666667, -3.070174008944108, -2.5639874326533008, 11],
    [393.13690476, 466.13095238, -3.867306226784721, -1.021735067555247, 11],
    [388.53170732, 601.62926829, -3.9359437874957477, 0.7129842225979681, 11],
    [434.3463035, 728.29961089, -3.263157253033188, 2.3133967973473335, 11],
    [517.17673049, 832.67746686, -1.975681194440357, 3.4780287258639375, 11],
    [904.77595628, 871.08306011, 2.8579948474501466, 2.7985470251450866, 11],
], dtype=np.float32)

correspondences_right = np.array([
    [436.2245592329106, 193.79399938137954, 0, -4.0, 11.0],
    [536.1735742118314, 916.4208289054197, 1.4031329107584791, 3.7458267491631854, 11.0],

    # points along 3 pt projected circle
    [698.08370044, 233.78414097, 3.0701740089441083, -2.5639874326533003, 11.0],
    [309.2157969, 251.30324401, -1.694705028815752, -3.623254733703746, 11.0],
    [213.93006993, 346.26923077, -3.070174008944108, -2.5639874326533008, 11.0],
    [160, 468, -3.867306226784721, -1.021735067555247, 11.0],
    [152.14662447, 602.2943038, -3.9359437874957477, 0.7129842225979681, 11.0],
    [198.33038348, 728.98328417, -3.263157253033188, 2.3133967973473335, 11.0],
    [285.64635473, 833.48966268, -1.975681194440357, 3.4780287258639375, 11.0],
    [667.77506775, 870.36856369, 2.8579948474501466, 2.7985470251450866, 11.0],
], dtype=np.float32)

# Camera intrinsic parameters, replace with your actual camera matrix
camera_matrix_L = np.array([
    [1018.9, 0, 601.447],
    [0, 1018.9, 517.462],
    [0, 0, 1]
], dtype=np.float32)

camera_matrix_R = np.array([
    [1018.9, 0, 690.392],
    [0, 1018.9, 517.462],
    [0, 0, 1]
], dtype=np.float32)

# cv2.stereoCalibrate example usage
img_left, img_right = cv2.imread("a1_capture_6_26_L.png"), cv2.imread("a1_capture_6_26_R.png")
R, T, reprojected_points_left, reprojected_points_right = stereo_calibrate(img_left, correspondences_left, correspondences_right, camera_matrix_L, camera_matrix_R)

# Print out the results
print("Stereo Calibration - Rotation Matrix (R):")
print(R)
print("Stereo Calibration - Translation Vector (T):")
print(T)

# Visualize the reprojection
visualize_reprojection(correspondences_left[:, :2], reprojected_points_left, "Left_Side_Reprojection", img_left)
visualize_reprojection(correspondences_right[:, :2], reprojected_points_right, "Right_Side_Reprojection", img_right)

立体右图(红色是特征检测算法检测到的原始点,类似于findChessboardCorners): enter image description here

立体左图: enter image description here

如您所见,蓝色点相差很远。总残留量也非常高。数千个(尽管这些是高分辨率图像)。

编辑:我已经确认我的 3d 点是正确的。我通过基于 Ceres-solver 的程序和 cv2.solvePnP 运行了我的立体问题,它产生了更好的结果(为简洁起见,仅显示右图像。左图像输出相同): enter image description here


是正确的,的代码中存在一些可能导致立体校准不佳的问题:

  1. cv2.stereoCalibrate 的使用不正确: stereoCalibrate 函数中传递内参和畸变系数,但是使用的是 cv2.CALIB_FIX_INTRINSIC 标志,这告诉函数在校准过程中保持内参不变。这意味着传递的内参和畸变系数将被忽略,并且不会在校准过程中更新。

  2. 初始估计不足: cv2.stereoCalibrate 函数受益于外参(旋转和平移)的良好初始估计。当前正在传递零矩阵作为旋转和平移的初始估计,这可能会导致陷入局部最小值并产生较差的校准结果。

可以尝试以下操作来改进代码:

1. 从 stereoCalibrate 调用中删除 cv2.CALIB_FIX_INTRINSIC 标志:

ret, camera_matrix_L, dist_coeffs_L, camera_matrix_R, dist_coeffs_R, R, T, E, F = cv2.stereoCalibrate(
    [object_points], [image_points_left], [image_points_right],
    camera_matrix_L, dist_coeffs, camera_matrix_R, dist_coeffs,
    imageSize=(img.shape[1], image_points_left.shape[0]),
    criteria=(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 1e-6)
)

这将允许 stereoCalibrate 函数优化内参和畸变系数以及外参。

2. 提供外参的初始估计:

可以使用 cv2.solvePnP cv2.stereoCalibrate (不使用 cv2.CALIB_FIX_INTRINSIC 标志)的先前结果来获取旋转和平移的初始估计。

例如,可以首先使用 cv2.solvePnP 获取旋转和平移的初始估计,如下所示:

# Assume object_points, image_points_left, camera_matrix_L, dist_coeffs are defined

# Find the rotation and translation vectors.
_, rvec, tvec = cv2.solvePnP(object_points, image_points_left, camera_matrix_L, dist_coeffs)

# Convert rotation vector to rotation matrix
R, _ = cv2.Rodrigues(rvec)

然后,可以将 R tvec 作为初始估计值传递给 stereoCalibrate 函数:

ret, camera_matrix_L, dist_coeffs_L, camera_matrix_R, dist_coeffs_R, R, T, E, F = cv2.stereoCalibrate(
    [object_points], [image_points_left], [image_points_right],
    camera_matrix_L, dist_coeffs, camera_matrix_R, dist_coeffs,
    imageSize=(img.shape[1], image_points_left.shape[0]),
    criteria=(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 1e-6),
    flags=cv2.CALIB_USE_INTRINSIC_GUESS,
    R=R, T=tvec 
)

通过提供初始估计值,将帮助 stereoCalibrate 函数更快、更准确地收敛到解决方案。

3. 使用更多对应点:

通常,用于校准的对应点越多,结果越好。尝试增加用于校准的对应点的数量。

通过进行这些更改,应该能够改进立体校准的结果并减少重投影误差。

标签:python,numpy,opencv,camera-calibration,stereo-3d
From: 78785990

相关文章

  • 在Python多处理中执行二进制信号量或互斥体以进行上下文切换操作
    我正在尝试自动化win应用程序和java应用程序之间的同步关系。我的标准是:启动win和jav应用程序在jav应用程序中执行命令等待jav应用程序的响应使用jav应用程序的响应到Windows应用程序作为输入。在jav应用程序中执行命令win应用程序......
  • 在spyder-python上随机出现的这些奇怪的亮点是什么
    在此处输入图像描述每次我单击此按钮或进行任何更改时,都会创建奇怪的突出显示,当我最小化功能时更是如此。有什么建议如何摆脱这些或可能的原因是什么?谢谢!我尝试更改外观首选项中的设置,但无法影响问题。很抱歉,我无法直接查看或与Spyder界面交互。我是一个AI......
  • 比较Python字典并找到缺失的元素
    我遇到了一个问题,我已经尝试了几天但没有得到任何结果。我想比较两个字典,在一个字典中有“赛前”足球比赛,在第二个字典中有“现场”足球比赛。我想将它们相互比较并打印它们(如果有)没有赛前比赛直播。示例1pre=[{"Home":"Genoa","Away":"In......
  • Python使用Visual Studio打印功能不显示输出
    任务:检查一个整数是正数还是负数。检查整数是否能被2整除。当输入0时,我需要退出循环并报告每个计数和总和。print函数没有显示任何输出。这是我从defmain()开始使用的代码defmain():countpositive=0countnegative=0count_divisible_by_2=0sump......
  • Python 中的像素最小二乘法
    我有一个非线性前向模型,它计算每个像素参数w的灰度图像。我还可以使用scipys优化函数来反转模型。我目前遇到的唯一问题是图像的大小使得这个解决方案非常慢...比如7%的像素在40分钟内计算得很慢。我使用for循环遍历所有像素并按像素应用模型。我尝试过......
  • 无法正确使用“comm.Gatherv()”来收集大小不均匀的 numpy 数组
    我正在学习MPI4Py,我想实现一个简单的程序。解释这里,每个等级都有一个send_array大小rank+1和值分别等于rank+1rank0=[1]rank1=[22]rank2=[333]rank3=[4444]我想收集值rank=0到缓冲区rbuf它的大......
  • SQL 命令在手动运行时工作正常(SQL Developer),但在 Python 的 oracledb 模块中给出 ORA-
    我正在使用OracleSQL数据库,并且我想运行该命令ALTERSESSIONSETNLS_DATE_FORMAT='YYYY-MM-DD';当我从SQLDeveloper应用程序手动运行它时,它工作正常。但是,当我使用oracledb模块从Python运行它时,出现以下错误:ErrorrunningSQLscript:ORA-00922:mi......
  • 在pip包中分发pythonnet dll类型信息
    我已经能够使用C#通过以下方式加载pythonnetdll:fromimportlib.resourcesimportpathimportsys#Assuming'my_package.lib'isthesub-packagecontainingtheDLLswithpath('pyrp.lib','')aslib_path:sys.path.append......
  • 尝试使用 pyinstaller 将 python 文件转换为可执行文件时出现 TypeError
    稍后的目的是通过命令行向GPT4all发送问题并将答案存储在文本文档中。我想将阻止代码转换为exe,但它产生了TypeError。这是到目前为止的代码:fromgpt4allimportGPT4Allmodel=GPT4All("Meta-Llama-3-8B-Instruct.Q4_0.gguf",device='cpu')#downloads/loads......
  • 使用 Python-PlexAPI 获取 plex 上所有好友的关注列表
    有关如何接收我的plex服务器上所有用户的监视列表的任何提示。我正在根据一些规则创建自动删除,其中一个规则是,如果电影位于用户观看列表中,则不应删除该电影。我遇到了麻烦,因为所有与观看列表相关的内容都在MyPlexAccount上。lexapi.myplex.MyPlexAccount具有我的用......