使用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个点的重投影误差非常大,偏离很明显。
我现在有几个疑问:
- 这种“3个点准、1个点偏差大”的表现是正常的吗?
- 我尝试使用多于4对的3D-2D对应点来做估计,但结果反而变得更差!这是不是说明我的方法(或者代码)存在问题?
- 要得到更准确的位姿结果,是否需要做一些迭代优化的工作?
以下是我使用的代码:
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
相关产品推荐
相关产品推荐

