一个高精度的标定板对我们的标定结果是至关重要的,最好的方案应该是去购买一款高精度的实物板子。不过从学习的角度出发,我们这里用一张白纸加一块纸板的方式凑活凑活。
首先你需要找一个这样的图(当然你可以考虑自己画一个,
标定板生成网站: https://calib.io/pages/camera-calibration-pattern-generator)
我们把它打印出来,然后贴在一块较为平整的纸板上(纸板你可以从快递纸箱上裁取)。
这一步就完成了,我们现在有一块炫酷的板子!
1.Ubuntu先打开终端,执行代码,我们看到我的笔记本现在有video 2-5 四个摄像头
ls /dev/video*
ls /dev/video*
我们看到多出来的video1和video6就是我们双目摄像头的设备号了
from cv2 import cv2
# 按设备号读取视频
# 记得我们之前查看的设备号吗,我们的摄像头编号是video1和video6
# 因为厂家对摄像头频率做了同步,和视频帧拼接,所以实际上只有设备号为1的能正常打开
cameraCapture = cv2.VideoCapture(1)
# cameraCapture = cv2.VideoCapture(6) # 运行代码发现6这个摄像头并不能打开
# 摄像头厂家告诉我,我这款摄像头是2560*720的,我们调整一下大小
cameraCapture.set(cv2.CAP_PROP_FRAME_WIDTH,2560)
cameraCapture.set(cv2.CAP_PROP_FRAME_HEIGHT,720)
#读取帧P
ret,frame = cameraCapture.read()
while cv2.waitKey(1) :
cv2.imshow('window',frame)
ret,frame = cameraCapture.read()
cv2.destroyAllWindows()
cameraCapture.release()
import os
import cv2
id_image = 0 # 图片的ID
cameraCapture = cv2.VideoCapture(1)
# cameraCapture = cv2.VideoCapture(6)
# #迭代停止模式选择(type, max_iter, epsilon)
# #cv2.TERM_CRITERIA_EPS :精确度(误差)满足epsilon,则停止。
# #cv2.TERM_CRITERIA_MAX_ITER:迭代次数超过max_iter,则停止。
# #两者结合,满足任意一个结束。
criteria = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.001)
# 设置高宽
cameraCapture.set(cv2.CAP_PROP_FRAME_WIDTH, 2560)
cameraCapture.set(cv2.CAP_PROP_FRAME_HEIGHT, 720)
while True:
ret, frame = cameraCapture.read()
# 这里的左右两个摄像头的图像是连在一起的,所以进行一下分割
# 如果你的摄像头本来就是双设备号,直接获取两个摄像头做为frame1,frame2就好
frame2 = frame[0:720, 0:1280]
frame1 = frame[0:720, 1280:2560]
# 转换成灰度图 棋盘格识别需要时灰度图
grayR = cv2.cvtColor(frame1, cv2.COLOR_BGR2GRAY)
grayL = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY)
# 查找棋盘格这个 注意到我们用的棋盘格 内角数是8*6的 用其他的要修改一下
retR, cornersR = cv2.findChessboardCorners(grayR , (8, 6) , None)
retL, cornersL = cv2.findChessboardCorners(grayL , (8, 6) , None)
# cv2.imshow('imgR', frame1)
# cv2.imshow('imgL', frame2)
cv2.imshow('imgR', grayR)
cv2.imshow('imgL', grayL)
# 如果找到了棋盘格就显示内角点
if (retR == True) & (retL == True):
corners2R = cv2.cornerSubPix(grayR, cornersR, (11, 11), (-1, -1), criteria)
corners2L = cv2.cornerSubPix(grayL, cornersL, (11, 11), (-1, -1), criteria)
# 画出角点
cv2.drawChessboardCorners(grayR, (8, 6), corners2R, retR)
cv2.drawChessboardCorners(grayL, (8, 6), corners2L, retL)
cv2.imshow('VideoR', grayR)
cv2.imshow('VideoL', grayL)
# 第一次运行需要创建路径
os.makedirs('calibration/left/chessboard-L')
os.makedirs('calibration/right/chessboard-R')
if cv2.waitKey(0) & 0xFF == ord('s'): # S 存储 C取消存储
print('S PRESSESED')
str_id_image = str(id_image)
print('Images ' + str_id_image + ' saved for right and left cameras')
# 需要提前创建好路径
cv2.imwrite('calibration/right/chessboard-R' + str_id_image + '.png', frame1)
cv2.imwrite('calibration/left/chessboard-L' + str_id_image + '.png', frame2)
id_image = id_image + 1
else:
print('Images not saved')
if cv2.waitKey(1) & 0xFF == ord('q'): # q 结束当前程序
break
# Release the Cameras
cameraCapture.release()
cv2.destroyAllWindows()
按S保存多张图片到本地, 30张左右吧。因为后续还会剔除一些效果不好的照片。
1.打开Matlab 执行指令stereoCameraCalibrator
2.点击Add Images(添加图像),选择刚才左右摄像头保存照片的路径;用直尺量得单个棋盘格长度并输入(我这里是29.5mm)
3.点击确定,等待分析结果
5.进行校准
勾选【2 Coefficients】【Skew值】【Tangential Distortion】,(标定时选择各参数的意义可参考这篇博客)然后点击Calibrate进行校准
得到结果,然后我们需要把误差大的图像删掉
6.选中删除,(弹出提示是否要删除图像并重新校准,点击是)
7.然后重复若干次,理想情况下,你应该让误差降到0.5以下。
8.完成后导出参数
9.我们的结果就在这里面
10.把结果取出来
我们可以通过逐个查看变量, 或者在命令行执行相应的指令调取参数,但是这样有点呆呆的。
我们可以把我们想要的数据都抽出来写进一个xls文件里。因为我的环境是Ubuntu,不能优雅地使用xlswrite()函数,这里我们用writetable()函数来实现我们想要的效果。输出到’out.xls’文件。
这个xls文件在你的安装目录/bin下面,你应该改成一个你用起来舒服的路径。
T3=array2table(stereoParams.CameraParameters1.IntrinsicMatrix')
writetable(T3,'out.xls','Sheet',1,'range','B1:D3','WriteVariableNames',false)
T4=array2table(stereoParams.CameraParameters1.RadialDistortion)
writetable(T4,'out.xls','Sheet',1,'range','B4:D4','WriteVariableNames',false)
T5=array2table(stereoParams.CameraParameters1.TangentialDistortion)
writetable(T5,'out.xls','Sheet',1,'range','B5:D5','WriteVariableNames',false)
T11=array2table([stereoParams.CameraParameters1.RadialDistortion(1:2), stereoParams.CameraParameters1.TangentialDistortion,0])
% 如果你选的是3coefficient 要用这句 T11=array2table([stereoParams.CameraParameters1.RadialDistortion(1:2), stereoParams.CameraParameters1.TangentialDistortion,stereoParams.CameraParameters1.RadialDistortion(3)])
writetable(T11,'out.xls','Sheet',1,'range','B6:F6','WriteVariableNames',false)
T7=array2table(stereoParams.CameraParameters2.IntrinsicMatrix')
writetable(T7,'out.xls','Sheet',1,'range','B7:D9','WriteVariableNames',false)
T8=array2table(stereoParams.CameraParameters1.RadialDistortion)
writetable(T8,'out.xls','Sheet',1,'range','B10:D10','WriteVariableNames',false)
T9=array2table(stereoParams.CameraParameters1.TangentialDistortion)
writetable(T9,'out.xls','Sheet',1,'range','B11:D11','WriteVariableNames',false)
T12=array2table([stereoParams.CameraParameters2.RadialDistortion(1:2), stereoParams.CameraParameters2.TangentialDistortion,0])
% 如果你选的是3coefficient 要用这句 T12=array2table([stereoParams.CameraParameters2.RadialDistortion(1:2), stereoParams.CameraParameters2.TangentialDistortion,stereoParams.CameraParameters2.RadialDistortion(3)])
writetable(T12,'out.xls','Sheet',1,'range','B12:F12','WriteVariableNames',false)
T1=array2table(stereoParams.TranslationOfCamera2)
writetable(T1,'out.xls','Sheet',1,'range','B13:D13','WriteVariableNames',false)
T2=array2table(stereoParams.RotationOfCamera2')
writetable(T2,'out.xls','Sheet',1,'range','B14:D16','WriteVariableNames',false)
TT={'平移矩阵';' ';'旋转矩阵';' ';' ';' ';'相机1内参';' ';' ';' ';'相机1径向';' ';'相机1切向';' ';'相机2内参';' ';' ';' ';'相机2径向';' ';'相机2切向';' ';'相机1畸变';' ';'相机2畸变'}
writecell(TT,'out.xls','Sheet',1,'range','A1:A25')
把代码贴到命令行执行
好的!没有返回消息就是最好的消息!我们接下来看看我们的结果
打开它
好的我们已经获取了我们想要的结果!
11.写入摄像头配置文件
import cv2
import numpy as np
# 相机1内参
left_camera_matrix = np.array([[840.3242628,11.98349443,720.9895252],
[ 0,836.7533204,467.2355637],
[0., 0, 1.0000]])
# 相机1畸变参数
left_distortion = np.array([[-0.036908075,0.136760373,-0.005282581,0.022916452,0]])
# 相机2内参
right_camera_matrix = np.array([[849.7778635,6.943897179,727.9328227],
[ 0 ,842.8092963,477.808017],
[0., 0,1.0000]])
# 相机2畸变参数
right_distortion = np.array([[-0.025533065,0.054401825,-0.003324632,0.017924097,0]])
# 平移矩阵
T = np.array([-115.8938089,0.071100061,-0.404734693])
# 旋转矩阵
R = np.matrix([
[0.999914262,0.002400323,0.012872745],
[-0.002236823,0.999916842,-0.012700606],
[-0.01290216,0.012670723,0.99983648],
])
size = (1280, 720) # 图像尺寸
# 进行立体更正
R1, R2, P1, P2, Q, validPixROI1, validPixROI2 = cv2.stereoRectify(left_camera_matrix, left_distortion,
right_camera_matrix, right_distortion, size, R,
T)
# 计算更正map
left_map1, left_map2 = cv2.initUndistortRectifyMap(left_camera_matrix, left_distortion, R1, P1, size, cv2.CV_16SC2)
right_map1, right_map2 = cv2.initUndistortRectifyMap(right_camera_matrix, right_distortion, R2, P2, size, cv2.CV_16SC2)
12完成啦!