You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用cv2.solvePnPRansac进行位姿估计时重投影异常的原因及修正方法咨询

cv2.solvePnPRansac进行位姿估计时重投影异常的原因及修正方法咨询

我正在尝试用OpenCV的cv2.solvePnPRansac,仅用最少的4对3D-2D对应点来实现盒子正面的位姿估计(对应的效果展示图见文末)。

我的输入参数如下:

  • 2D像素点:手动选取的4个点,在图中以白色标记
  • 3D坐标设定:盒子的尺寸为3x4x6(单位任意),3D坐标系原点对应图片中左上角的像素点(坐标[1065, 602])
  • 畸变系数:设置为np.zeros((5,1)).astype('float32')
  • 相机内参:采用单目相机标定得到的标准参数(参考单图相机内参标定方案)

我的验证过程:

得到位姿估计输出的rvec(旋转向量)和tvec(平移向量)后,我用cv2.projectPoints将3D点重新投影到2D图像上,重投影的点在图中以红色标记。

出现的问题:

从图中可以看到,有3个点的重投影结果几乎完全和原2D点重合(白红标记叠加),但第4个点的重投影误差非常大,偏离很明显。

我现在有几个疑问:

  1. 这种“3个点准、1个点偏差大”的表现是正常的吗?
  2. 我尝试使用多于4对的3D-2D对应点来做估计,但结果反而变得更差!这是不是说明我的方法(或者代码)存在问题?
  3. 要得到更准确的位姿结果,是否需要做一些迭代优化的工作?

以下是我使用的代码:

import os
import numpy as np
import matplotlib.pyplot as plt
import cv2

# 绘图工具函数
def plot_points(ax, pts_list, c):
    for pt in pts_list:
        pt_x = pt[0]
        pt_y = pt[1]
        pt_label = (str(int(pt_x)) + ' , ' + str(int(pt_y)))
        ax.scatter(pt_x, pt_y, s=80, facecolors='none', edgecolors=c)
        ax.text(pt_x+5, pt_y+5, pt_label, fontsize=15, color=c)

def project_planes(ax, src, c):
    x_src = [val[0] for val in src] + [src[0][0]]
    y_src = [val[1] for val in src] + [src[0][1]]
    ax.plot(x_src, y_src, '--', c=c)

# 读取图像
image1 = cv2.imread('image1.jpg') # 图像与相机内参标定方案配套
image1 = cv2.cvtColor(image1, cv2.COLOR_BGR2RGB)

# 相机内参矩阵
mtx = np.array([
    [2448.0, 0, 1253.0], 
    [0, 2438.0, 986.0], 
    [0, 0, 1.0]
]).astype('float32')

# 畸变系数
dst = np.zeros((5,1)).astype('float32')

# 盒子的可见面3D坐标(仅正面4个点)
box3D_visible = np.array([
    [0, 0, 0],
    [0, 4, 0],
    [3, 4, 0],
    [3, 0, 0],
])

# 对应的2D像素坐标
box2D_visible = np.array([
    [1065, 602],
    [1074, 1342],
    [1774,1086], 
    [1840,478],
])

# 位姿估计
_, rvec, tvec, _ = cv2.solvePnPRansac(
    box3D_visible[:,:,np.newaxis].astype('float32'),
    box2D_visible[:,:,np.newaxis].astype('float32'),
    mtx, 
    dst
)

# 重投影验证
box2D_reproj = cv2.projectPoints(
    box3D_visible[:,:,np.newaxis].astype('float32'),
    rvec, 
    tvec,
    mtx,
    dst
)[0][:,0,:]

# 绘图展示
fig, ax = plt.subplots()
plt.imshow(image1)
# 绘制原始2D点和边框
box_face1 = box2D_visible[:4]
project_planes(ax, box_face1, 'w')
plot_points(ax, box_face1, 'w')
# 绘制重投影的2D点和边框
project_planes(ax, box2D_reproj, 'r')
plot_points(ax, box2D_reproj, 'r')
plt.show()

我的最终目标是能在这张图上重投影出完整的盒子骨架(平行六面体)。

盒子位姿估计重投影结果

备注:内容来源于stack exchange,提问作者aRedDish

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.14 17:43:00