上一回,讲到针对FireEyes火眼双目相机,如何使用opencv快速读取压缩格式的双目摄像头,以及如何使用软件方便的保存截图和录制双目视频。本期文章,继续带大家实现完整的标定流程。双目标定网上资料很多,但大都语焉不详或经验不充分,无法给出科学的指导。
实际上,双目标定是一个非常复杂的过程。本文且不去从理论公式去进行推导,后面有时间再详细叙述,而是从代码角度去考虑如何做一次合格的标定。首先打开老板配套的标定文件,查看双目标定参数应该是什么样子的。
<?xml version="1.0"?>
<opencv_storage>
<Camera_Matrix_Left type_id="opencv-matrix">
<rows>3</rows>
<cols>3</cols>
<dt>d</dt>
<data>
1.5102575076556511e+03 0. 5.7050825703054056e+02 0.
1.5131519293597491e+03 4.2155950604941597e+02 0. 0. 1.</data></Camera_Matrix_Left>
<Distortion_Coeffs_Left type_id="opencv-matrix">
<rows>1</rows>
<cols>14</cols>
<dt>d</dt>
<data>
-1.3128679058980449e+01 4.0862925866371192e+01 0. 0.
1.4583347052559756e+02 -1.3191469679503978e+01
4.1873896305351899e+01 1.4086762713689984e+02 0. 0. 0. 0. 0. 0.</data></Distortion_Coeffs_Left>
<Camera_Matrix_Right type_id="opencv-matrix">
<rows>3</rows>
<cols>3</cols>
<dt>d</dt>
<data>
1.5060488762224657e+03 0. 5.8851182947326470e+02 0.
1.5081464609407883e+03 3.4116061588680532e+02 0. 0. 1.</data></Camera_Matrix_Right>
<Distortion_Coeffs_Right type_id="opencv-matrix">
<rows>1</rows>
<cols>14</cols>
<dt>d</dt>
<data>
3.4286887938153086e+01 -1.2017552811473685e+01 0. 0.
-1.0681449825891393e+02 3.4429671708623260e+01
-1.6462504185104354e+01 -1.0354548661383124e+02 0. 0. 0. 0. 0. 0.</data></Distortion_Coeffs_Right>
<Rotation_Matrix_Stereo type_id="opencv-matrix">
<rows>3</rows>
<cols>3</cols>
<dt>d</dt>
<data>
9.9950379179889370e-01 -1.0206938069847095e-04
-3.1498567609896992e-02 8.2326232746755107e-04
9.9973778948213443e-01 2.2883935861554218e-02 3.1487972605010649e-02
-2.2898512248988541e-02 9.9924179542191338e-01</data></Rotation_Matrix_Stereo>
<Translation_Matrix_Stereo type_id="opencv-matrix">
<rows>3</rows>
<cols>1</cols>
<dt>d</dt>
<data>
-2.4591255054712686e+00 2.5114034736998098e-02
-3.5916004400515719e-02</data></Translation_Matrix_Stereo>
<Essential_Matrix type_id="opencv-matrix">
<rows>3</rows>
<cols>3</cols>
<dt>d</dt>
<data>
8.2035833117598527e-04 3.5331512814355523e-02 2.5916892701990980e-02
4.1534693963981066e-02 -5.6306649584507658e-02
2.4583922879478179e+00 -2.7126078334167827e-02
-2.4584781335250101e+00 -5.5483414221595966e-02</data></Essential_Matrix>
<Fundamental_Matrix type_id="opencv-matrix">
<rows>3</rows>
<cols>3</cols>
<dt>d</dt>
<data>
4.6591706670341746e-09 2.0027914415472244e-07 1.3521207036972270e-04
2.3556544703483535e-07 -3.1873424503415368e-07
2.1057277146899138e-02 -3.1513066545476264e-04
-2.0997506649126866e-02 1.</data></Fundamental_Matrix>
</opencv_storage>
需要清楚,M1,d1,M2,d2,R,T是做双目校正时的必需量,M1--Camera1的内参,d1--C1的畸变,M2--C2的内参,d2--C2的畸变。R--旋转矩阵,T--平移矩阵。E和F可选。
为了方便后续使用opencv进行视差计算,标定最简易的方法是采用opencv来做。虽然matlab也有很多工具箱,但转换起来着实费力且容易出错。opencv的代码如下所示:
class StereoCalibration(object):
def __init__(self, filepath, w, h,left_dir,right_dir):
self.criteria = (cv2.TERM_CRITERIA_EPS +
cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
self.criteria_cal = (cv2.TERM_CRITERIA_EPS +
cv2.TERM_CRITERIA_MAX_ITER, 100, 1e-5)
# prepare object points, like (0,0,0), (1,0,0), (2,0,0) ....,(6,5,0)
self.objp = np.zeros((w*h, 3), np.float32)
self.objp[:, :2] = np.mgrid[0:w, 0:h].T.reshape(-1, 2)
# Arrays to store object points and image points from all the images.
self.objpoints = [] # 3d point in real world space
self.imgpoints_l = [] # 2d points in image plane.
self.imgpoints_r = [] # 2d points in image plane.
self.img_shape = None
self.cal_path = filepath
self.camera_model = None
self.read_images(self.cal_path,w,h,left_dir,right_dir)
def read_images(self, cal_path,w,h,left_dir,right_dir):
images_right = glob.glob(right_dir + '/*.png')
images_left = glob.glob(left_dir + '/*.png')
images_left.sort()
images_right.sort()
for i, fname in enumerate(images_right):
img_l = cv2.imread(images_left[i])
img_r = cv2.imread(images_right[i])
gray_l = cv2.cvtColor(img_l, cv2.COLOR_BGR2GRAY)
gray_r = cv2.cvtColor(img_r, cv2.COLOR_BGR2GRAY)
# Find the chess board corners
ret_l, corners_l = cv2.findChessboardCorners(gray_l, (w, h), None)
ret_r, corners_r = cv2.findChessboardCorners(gray_r, (w, h), None)
# If found, add object points, image points (after refining them)
self.objpoints.append(self.objp)
if ret_l is True:
rt = cv2.cornerSubPix(gray_l, corners_l, (11, 11),
(-1, -1), self.criteria)
self.imgpoints_l.append(corners_l)
if ret_r is True:
rt = cv2.cornerSubPix(gray_r, corners_r, (11, 11),
(-1, -1), self.criteria)
self.imgpoints_r.append(corners_r)
self.img_shape = gray_l.shape[::-1]
rt, self.M1, self.d1, self.r1, self.t1 = cv2.calibrateCamera(
self.objpoints, self.imgpoints_l, self.img_shape, None, None)
rt, self.M2, self.d2, self.r2, self.t2 = cv2.calibrateCamera(
self.objpoints, self.imgpoints_r, self.img_shape, None, None)
self.camera_model = self.stereo_calibrate(self.img_shape)
def stereo_calibrate(self, dims):
flags = 0
flags |= cv2.CALIB_USE_INTRINSIC_GUESS
stereocalib_criteria = (cv2.TERM_CRITERIA_MAX_ITER +
cv2.TERM_CRITERIA_EPS, 100, 1e-5)
ret, M1, d1, M2, d2, R, T, E, F = cv2.stereoCalibrate(
self.objpoints, self.imgpoints_l,
self.imgpoints_r, self.M1, self.d1, self.M2,
self.d2, dims,
criteria=stereocalib_criteria, flags=flags)
print('Intrinsic_mtx_1', M1)
print('dist_1', d1)
print('Intrinsic_mtx_2', M2)
print('dist_2', d2)
print('R', R)
print('T', T)
print('E', E)
print('F', F)
self.camera_model = dict([('M1', M1), ('M2', M2), ('dist1', d1),
('dist2', d2), ('rvecs1', self.r1),
('rvecs2', self.r2), ('R', R), ('T', T),
('E', E), ('F', F)])
return self.camera_model
c++的代码还要更复杂一些,操作也不方便。在实操上,我们借用FireEyes火眼双目标定的软件,虽然该软件是为火眼双目研发,但并没有限制其使用范围(👍)。
注意看这张图片,标定板内角点是11*8,如果填错了,opencv是不会正确响应的,c++和python都一样。要点是需要去掉最边上的角点,数横竖内角点的个数!!!切记。另外,标定时,一般简易多拍一些标定板在图像里占1/3大小的图片(重要!),如果失败了,补充少量大的图片,像这张图里面一样。①1/3的图片要上下左右中五个方位全覆盖。②补充不同距离的图片,如几张更远的和几张更近的,也尽量覆盖全方位,但是个数少一些。③ 如果依然失败,那么尝试删除一些倾斜角度大的,更容易成功。
点击多次采集图片,在标定配置里面选择文件夹:Documents\fire_eyes\2024-05-09\left和Documents\fire_eyes\2024-05-09\right。点击确定后,就开始自动标定了。
之后,点击校正切换,软件会自动执行校正并在软件中显示,查看效果非常直观。鉴于各种未知因素,标定结果可能不尽如人意,请尽量使用随相机发放的标定文件(更专业)。本次标定实验非常成功,可以看到,在执行“校正切换”后,将双目进行了对齐(因校正后存在弧度和留黑,导致肉眼不太容易查看效果,可以通过SGBM算法来验证)!同时期待软件中添加画线查看功能。
下一期,我们将基于这个标定参数,查看视差生成的效果了!
FireEyes 火眼 双目相机 USB摄像头模组 立体视觉 工业 U90/U140-淘宝网 (taobao.com)
软件及代码地址:
FireEyesGit/FireEyesUsbSoftware: stereo calibrate and match tools for FireEyes U90/140 (github.com)