现在有许多双目相机在出厂时就已经标定好了,用户拿到手后可以直接使用,例如Intel Realsense系列。但是有些相机出厂的时候并没有完成标定工作,因而这个时候就需要我们自己来标定。由于笔者曾改装过一个双目相机,最远可以测至50m,因此有一些心得体会想给大家分享一下。本文主要介绍双目相机标定的整个过程,以及导出标定数据的方法。
相机标定主要分为手动标定和自动标定,手动标定比较繁琐,这里主要介绍基于matlab工具箱的自动标定方式来对双目相机进行标定。具体的相关标定细节也可以参照这篇博客:matlab双目标定(详细过程),里面有详细介绍。
首先需要准备一张棋盘,如下图所示。对于标定不同测距范围相机所用的棋盘方格宽度会有所不同。对于短焦双目相机(测距范围在20m以内),棋盘中方格的宽度达到20mm即可;对于长焦双目相机(测距范围在40m左右),棋盘中方格的宽度需要尽量大,否则会影响标定的精度,一般至少达到60mm。
笔者在标定长焦相机时方格长宽选择60mm。然后运行项目文件中photo.py脚本文件对棋盘进行多角度拍摄,每按下一次s键,会保存一组左右镜头的照片,照片保存的路径参数可以由用户自由设定,参数名为folder。
# !/usr/bin/python
# -*- coding: utf-8 -*-
import cv2
import time
AUTO = False # 自动拍照,或手动按s键拍照
INTERVAL = 2 # 自动拍照间隔
cap = cv2.VideoCapture(0 + cv2.CAP_DSHOW) # windows下开启摄像头是采用如下语句(微软特有):cv2.VideoCapture( camera_number + cv2.CAP_DSHOW)
cap.set(cv2.CAP_PROP_FRAME_WIDTH, 2560) # 设置双目的宽度
cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 720) # 设置双目的高度
# 显示缓存数
# print(cap.get(cv2.CAP_PROP_BUFFERSIZE))
# 设置缓存区的大小
# cap.set(cv2.CAP_PROP_BUFFERSIZE, 1)
print(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
print(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
#设置FPS
# print('setfps', cap.set(cv2.CAP_PROP_FPS, 25))
# print(cap.get(cv2.CAP_PROP_FPS))
counter = 0
utc = time.time()
folder = "images/" # 拍照文件目录
def shot(pos, frame):
global counter
path = folder + pos + "_" + str(counter) + ".jpg"
cv2.imwrite(path, frame)
print("snapshot saved into: " + path)
while True:
ret, frame = cap.read()
if not ret:
print("camera is not connected!")
break
left_frame = frame[0:720, 0:1280]
right_frame = frame[0:720, 1280:2560]
cv2.imshow("left", left_frame)
cv2.imshow("right", right_frame)
now = time.time()
if AUTO and now - utc >= INTERVAL:
shot("left", left_frame)
shot("right", right_frame)
counter += 1
utc = now
key = cv2.waitKey(1)
if key == ord("q"):
break
elif key & 0xFF == ord("s"):
shot("left", left_frame)
shot("right", right_frame)
counter += 1
cap.release()
注意尽量拍摄多组照片,这样可以提高标定效果,标定效果的好坏直接影响到测距的精度。对于短焦相机通常拍摄40组照片即可;长焦相机通常会需要更多组照片,笔者在标定长焦相机时拍摄了60组。
照片拍摄好后,进入matlab标定工具箱,如下图所示。注意:不要选择matlab2020b版本,笔者测试过该版本无法正常使用标定工具箱,可以使用matlab2020a版本。
其中Stero Camera Cailbrator为双目标定工具箱,Camera Cailbrator为单目相机标定工具箱,因此这里选择Stero Camera Cailbrator工具箱。进入工具箱以后,选择Add Images。然后选择左右相机照片的路径,Size of checkerboard square为棋盘中每一个方格的长度,单位为毫米,一定要准确测量方格的长度,如下图所示。
点击确定以后,Radial Distortion Compute选择3 Coefficients和Tangential Distortion,然后点击Calibrate进行校准。不过校准前需要剔除一些原点不一致的点,保证所有照片的原点一致。校准过程中可以可以Reprojection Errors曲线,降低误差,如下图所示。
标定好后将标定数据导入到工作空间,点击Export Camera Parameters即可。此时我们已经拿到标定数据了,为了避免手工获取数据时出错,笔者写了一个脚本可以直接获取标定数据,并保存到表格文件中,之后直接复制粘贴即可。
rowName = cell(1,10);
rowName{1,1} = '平移矩阵';
rowName{1,2} = '旋转矩阵';
rowName{1,3} = '相机1内参矩阵';
rowName{1,4} = '相机1径向畸变';
rowName{1,5} = '相机1切向畸变';
rowName{1,6} = '相机2内参矩阵';
rowName{1,7} = '相机2径向畸变';
rowName{1,8} = '相机2切向畸变';
rowName{1,9} = '相机1畸变向量';
rowName{1,10} = '相机2畸变向量';
xlswrite('out.xlsx',rowName(1,1),1,'A1');
xlswrite('out.xlsx',rowName(1,2),1,'A2');
xlswrite('out.xlsx',rowName(1,3),1,'A5');
xlswrite('out.xlsx',rowName(1,4),1,'A8');
xlswrite('out.xlsx',rowName(1,5),1,'A9');
xlswrite('out.xlsx',rowName(1,6),1,'A10');
xlswrite('out.xlsx',rowName(1,7),1,'A13');
xlswrite('out.xlsx',rowName(1,8),1,'A14');
xlswrite('out.xlsx',rowName(1,9),1,'A15');
xlswrite('out.xlsx',rowName(1,10),1,'A16');
xlswrite('out.xlsx',stereoParams.TranslationOfCamera2,1,'B1'); % 平移矩阵
xlswrite('out.xlsx',stereoParams.RotationOfCamera2.',1,'B2'); % 旋转矩阵
xlswrite('out.xlsx',stereoParams.CameraParameters1.IntrinsicMatrix.',1,'B5'); % 相机1内参矩阵
xlswrite('out.xlsx',stereoParams.CameraParameters1.RadialDistortion,1,'B8'); % 相机1径向畸变(1,2,5)
xlswrite('out.xlsx',stereoParams.CameraParameters1.TangentialDistortion,1,'B9'); % 相机1切向畸变(3,4)
xlswrite('out.xlsx',stereoParams.CameraParameters2.IntrinsicMatrix.',1,'B10'); % 相机2内参矩阵
xlswrite('out.xlsx',stereoParams.CameraParameters2.RadialDistortion,1,'B13'); % 相机2径向畸变(1,2,5)
xlswrite('out.xlsx',stereoParams.CameraParameters2.TangentialDistortion,1,'B14'); % 相机2切向畸变(3,4)
xlswrite('out.xlsx',[stereoParams.CameraParameters1.RadialDistortion(1:2), stereoParams.CameraParameters1.TangentialDistortion,...
stereoParams.CameraParameters1.RadialDistortion(3)],1,'B15'); % 相机1畸变向量
xlswrite('out.xlsx',[stereoParams.CameraParameters2.RadialDistortion(1:2), stereoParams.CameraParameters2.TangentialDistortion,...
stereoParams.CameraParameters2.RadialDistortion(3)],1,'B16'); % 相机2畸变向量
标定数据文件保存的路径即为当前程序的路径,要想保存到其他路径直接修改脚本中的路径即可,导出的参数如下图所示。
将表格中的数据复制到双目相机配置文件中,其中相机1内参复制到left_camera_matrix中,相机1畸变复制到left_distortion中,相机2内参复制到right_camera_matrix中,相机2畸变复制到right_distortion中,旋转矩阵复制到R中,转移矩阵复制到T中,如下图所示。
至此,双目标定部分就已经完成。注意:标定时照片的尺寸与测距时照片的尺寸一定要保持一致。