我有一组类似的校准图像,从中我获得了左侧图像中的图像点(棋盘角位置),“ imp1”,右侧图像中的图像点,“ imp2”和世界框架中的对象点。 ,'objp'。一系列图像中的棋盘位置至少占据了场景的80%。会仔细拍摄它们,并同时从高质量的科学相机中拍摄快照。唯一的麻烦是它们在水下,因此会有灯光波动和可能很小的振动。
首先,我分别使用cv2.calibrateCamera对每个视图进行了摄像机校准。我获得约0.3像素的重投影误差。显然失真很小。使用cv2.undistort使图像不失真会导致直线看起来直的图像。当然,直线在原始图像中也看起来是直线。相机校准代码为
flags = cv2.CALIB_FIX_PRINCIPAL_POINT | cv2.CALIB_FIX_K3 | cv2.CALIB_ZERO_TANGENT_DIST
cam1 = cv2.calibrateCamera(objp,imp1,shape,None,None,flags=flags)
cam2 = cv2.calibrateCamera(objp,imp2,shape,None,None,flags=flags)
# store the output
keys = ['retval','cameraMatrix','distCoeffs','rvecs','tvecs']
Lcam = {k:v for k,v in zip(keys,cam1)}
Rcam = {k:v for k,v in zip(keys,cam2)}
第二,我使用cv2.stereoCalibrate进行了立体校准,如下所示
# do the stereo calibration
flags = cv2.CALIB_USE_INTRINSIC_GUESS | cv2.CALIB_FIX_FOCAL_LENGTH | cv2.CALIB_FIX_PRINCIPAL_POINT | cv2.CALIB_FIX_INTRINSIC | cv2.CALIB_FIX_K1 | cv2.CALIB_FIX_K2 | cv2.CALIB_FIX_K3
stereocalib = cv2.stereoCalibrate(objp,imp1,imp2,Lcam['cameraMatrix'],Lcam['distCoeffs'],Rcam['cameraMatrix'],Rcam['distCoeffs'],shape,flags=flags)
#store the output
keys = ['retval', 'cameraMatrix1', 'distCoeffs1', 'cameraMatrix2', 'distCoeffs2', 'R', 'T', 'E', 'F']
stereo = {k:v for k,v in zip(keys,stereocalib)}
这将获得重投影误差0.8,并且当我计算对极约束x'Fx的偏差时,对于所有成对的点x和x',我发现它们始终小于1个像素,通常更像0.2个像素。
在下图中,左侧图像中指示了三个棋盘角点,右侧图像中指示了它们对应的外延线。
这两个测试,对极约束残差计算和相应的Epiline可视化使我对立体校准结果充满信心。
我的第一个问题出现在这里:我不知道如何测试旋转和平移矩阵。所获得的转换矩阵(即,立体声['T'])为
array([[-94.35664281],
[ 1.45841307],
[ 6.63416548]])
获得的旋转矢量(即,立体声['R'])为
array([[ 8.42562933e-01, 1.53811356e-02, 5.38378236e-01],
[-1.31180579e-02, 9.99881661e-01, -8.03622020e-03],
[-5.38438131e-01, -2.91455620e-04, 8.42664995e-01]])
离身份不远。在我看来,这似乎是围绕y轴的一个小旋转,这是有道理的,因为相机略微相互倾斜。
这里的单位是厘米。摄像头的安装点(略微位于镜头的上方和后面)彼此间隔约100cm,因此这似乎很合理。一个相机机身比另一个相机机身长,可能长约6厘米。一个坐骑比另一个坐骑低一点,可能约2cm。我对x坐标上的负号感到困惑。如何测试旋转和平移矩阵?
第三,现在进入第二个问题,我尝试从cv2.stereoRectify生成用于立体校正的投影矩阵,如下所示:
alpha = 1
rect = cv2.stereoRectify(stereo['cameraMatrix1'],stereo['distCoeffs1'],stereo['cameraMatrix2'],stereo['distCoeffs2'],shape,stereo['R'],stereo['T'],alpha,flags=cv2.CALIB_ZERO_DISPARITY)
# store the rectification parameters
keys = ['R1','R2','P1','P2','Q','validPixROI1','validPixROI2']
rectify = {k:v for k,v in zip(keys,rect)}
然后我将重投影图计算为
lmaps = cv2.initUndistortRectifyMap(stereo["cameraMatrix1"], stereo["distCoeffs1"], rectify['R1'], rectify['P1'], shape, cv2.CV_16SC2)
rmaps = cv2.initUndistortRectifyMap(stereo["cameraMatrix2"], stereo["distCoeffs2"], rectify['R2'], rectify['P2'], shape, cv2.CV_16SC2)
我将左图中的每个图像“ l”重新映射为
interpolate = cv2.INTER_LANCZOS4
lr = cv2.remap(l, lmaps[0], lmaps[1], interpolate)
,右视图中的每个图像'r'均为
rr = cv2.remap(r, rmaps[0], rmaps[1], interpolate)
结果是:
from matplotlib import pyplot as plt
plt.imshow(np.hstack((lr,rr)))
plt.show()
这适用于所有alpha值。重投影图具有负值,并且这些值不位于图像上,因此校正会产生废话。
我有两个问题:
首先,如何测试cv2.stereoCalibrate产生的旋转矩阵和平移矢量?
第二,有人对我有什么建议,可以对场景的两种视图进行有益的纠正?
目标是根据摄像机视图中配对的对象观测值对对象的3D世界位置进行三角剖分。纠正是前提条件。任何帮助表示赞赏!我会尽力澄清所有不清楚的地方。