一、前言
首先,需要声明的是,本文转载自大神dreamharding。链接见 https://blog.csdn.net/dreamharding/article/details/53700166。
也可参考https://blog.csdn.net/hyacinthkiss/article/details/41317087文章、https://blog.csdn.net/zhouqianq/article/details/78580173文章,可以互相结合印证
自动标定:https://blog.csdn.net/yanli33/article/details/60478023
https://wenku.baidu.com/view/89200f7ff90f76c660371a84.html是Matlab摄像机标定工具箱的使用说明
之前看过这样一段话,大概是说尽量matlab用手动标定,自动标定的误差较大,但是自动标定十分步骤十分简单。
二、单目标定
1、配置标定工具箱
标定工具箱的英文说明文档,里面可以下载标定的图片:http://www.vision.caltech.edu/bouguetj/calib_doc/htmls/own_calib.html
- 首先下载标定工具箱。工具箱下载:http://www.vision.caltech.edu/bouguetj/calib_doc/download/index.html
- 将下载后的标定工具箱文件解压后放到MATLAB搜索路径下,这里本人是放置toolboox这个文件夹下,
- E:\Program Files\MATLAB\R2014b\toolbox\TOOLBOX_calib
我用的是中文版,所以点添加文件夹即可。
原博主是然后打开MATLAB点击File->Set Path->Add Floder添加插件目录,在save一下,
将当前文件夹设置成待标定图片的文件夹,我这里是在桌面新建一个文件夹放置图片,所以Current Folder设置如下
2,开始进行单目标定
1、MATLAB命令行窗口输入calib_gui,弹出工具框
2、选择第一个Standard,弹出如下界面Camera Calibration Toolbox(以下简称标定界面)
3、现在开始左摄像头标定,选择第一个Images names后,MATLAB命令行窗口会提示你输入图片的basename以及各格式,这里图片保存的文件名如第二张图左侧所示为left01,left02,所以提示的basename行写left,按Enter键提示输入图片格式,这里为jpg,在按回车键读入做摄像头的棋盘图
这里读入的图片就不显示了。
4、然后点击标定界面上的Extract grid corners,MATLAB命令界面显示然后一路回车键下去最后如下
5、最后会跳出第一幅图棋盘图,然后按顺时针或逆时针旋转顺序进行点击棋盘格最外面的四个角点
6、选好角点后命令界面会提示要你输入棋盘方格的实际边长,这里网上图片的是30X30,单位mm
7、回车键后会显示角点检测结果图
8、继续命令行窗口回车键下去,弹出第二张棋盘图(同时也会弹出Figure3图片有着蓝色边框包围的角点图,这里不作显示),选择四个外围角点,如此反复下去检测完13张棋盘图。
三、下面一部分可以跳过
PS:这里插一段,这一段只是为了演示步骤不是必须的
在上述进行角点检测时有时会出现检测的角点与棋盘纸角点不是很接近,这里我选择了将其中一张图最大化窗口便于看到角点的偏差,事实上最小化窗口时这种偏差看不出来,而且偏差也是可以容忍的,以下是偏差图
如上图所示(如最外围角点),其实个人觉得这样已经可以了毕竟我是放大看的,好了不废话继续。其实在之前检测完前一张图片,准备敲回车键进行下一张检测时,如果对上一张不满意正如上图所示,我们可以在命令行窗口看到这样一句话“Need of an initial guess for distortion? ([]=no, other=yes)”这里输入1,会提示你输入一个校正系数kc
如上所示,这里填的是-0.3,注意,kc的范围是-1~1。,是畸变矫正因子,输入数值之后回车显示校正后的角点检测
如果觉得行了,在命令行窗口语句“Satisfied with distortion? ([]=no, other=yes)”后面输入1再回车进行下一张图角点检测,如果觉得不行那么在语句后面直接回车重新输入一个kc值。
检测完成后点击标定界面Calibration进行摄像头标定,命令行窗口结果如下
标定结束后可以通过标定界面按钮进行可视化的观察,这里主要说下误差图的查看,点击Analyse error
发现绿色的点误差不理想,此时可以鼠标点击其中绿色点,命令行窗口会显示如下信息
由上可知是第三幅图,如果想看第三幅的整体误差,可以点击标定界面的Reproject on images,在命令行输入3即可。
PS:这里也再插一段
接着上面所述绿色点误差较大,X和Y方向的标注差为0.52529和0.22933,此时我们可以重新计算角点,方法是点击Recomp.corners,命令行窗口会提示你输入窗口的大小语句“wintx ([] = 5) = ”还记得之前角点检测一路回车下去的步骤吗?其实那么也有这个语句不过我们回车选了默认值5,这里我们可以输入一个更大或更小的值,比如我输入9
输入两次数字9后,一直回车,然后在点击Calibration重新进行摄像头标定,结果如下
与前面相比error小了,误差也小了结果图了如下所示
PS:Recomp.corners重新计算这一步之前在一篇博文看说这一步骤并不推荐,具体原因忘了,所以在选择角点时尽量靠近,省的误差较大,这一步能不用就不用吧。
四、单目标定数据的保存。
左摄像头标定结果出来后,点击Save,这时结果文件默认保存在之前放置标定图片的新建文件夹下面,默认文件名为Calib_Results.m,将其改为Calib_Results_left.mat(双目标定用到)。至此左摄像头标定结束,右摄像头标定过程与左一样,只是将Basename改为right,格式仍为jpg,然后回车回车,最后保存为Calib_Results_right.mat。
五、双目标定
下面开始双目立体标定。
1、命令行输入stereo_gui,弹出立体标定界面,选择第一个Load
2、如果之前左右摄像头结果你是按照之前的文件名保存的,那么直接在命令行以下两行后面两次回车,否则就在后面输入你保存的文件名,注意下这里加载文件时如果出错了,那么直接重新点击Load就行了。
3、此时已经出现一个双目标定结果,不管在点击立体标定界面的Run,最后标定结果如下,下图中?为正负号
4、至此双目标定结束,下面就是讲结果写成xml文件供Opencv调用了。xml文件生成方法:先建一个txt文档,将下面语句复制进去
Intrinsics_Camera_Left.xml:
<?xml version="1.0"?>
<opencv_storage>
<Intrinsics_Camera_Left type_id="opencv-matrix">
<rows>3</rows>
<cols>3</cols>
<dt>d</dt>
<data>
534.02373 0. 341.01149
0. 533.86709 233.26555
0. 0. 1.
</data>
</Intrinsics_Camera_Left>
</opencv_storage>
Distortion_Camera_Left.xml:
<?xml version="1.0"?>
<opencv_storage>
<Distortion type_id="opencv-matrix">
<rows>5</rows>
<cols>1</cols>
<dt>d</dt>
<data>
-0.28668 0.10398 0.00171 -0.00063 0.00000
</data>
</Distortion>
</opencv_storage>
Intrinsics_Camera_Right.xml:
<?xml version="1.0"?>
<opencv_storage>
<Intrinsics_Camera_Right type_id="opencv-matrix">
<rows>3</rows>
<cols>3</cols>
<dt>d</dt>
<data>
537.82796 0. 321.73805
0. 537.87268 249.47070
0. 0. 1.
</data>
</Intrinsics_Camera_Right>
</opencv_storage>
Distortion_Camera_Right.xml:
<?xml version="1.0"?>
<opencv_storage>
<Distortion type_id="opencv-matrix">
<rows>5</rows>
<cols>1</cols>
<dt>d</dt>
<data>
-0.29416 0.13839 -0.00009 0.00061 0.00000
</data>
</Distortion>
</opencv_storage>
RotRodrigues.xml:
<?xml version="1.0"?>
<opencv_storage>
<RotRodrigues type_id="opencv-matrix">
<rows>3</rows>
<cols>1</cols>
<dt>d</dt>
<data>
0.00918 0.01162 -0.00369
</data>
</RotRodrigues>
</opencv_storage>
Translation.xml:
<?xml version="1.0"?>
<opencv_storage>
<Translation type_id="opencv-matrix">
<rows>3</rows>
<cols>1</cols>
<dt>d</dt>
<data>
-83.09797 0.95964 1.09394
</data>
</Translation>
</opencv_storage>
将上述语句复制到txt中,然后直接修改后缀为xml即可,以上数值都是MATLAB立体标定结果内容,自己复制后只需将数字对应改成自己的标定结果就行。
六、拍照程序如下:C++编程,
也可以用python进行双目拍照。
#include "stdafx.h"
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
char* name_l = (char*)malloc(sizeof(char)*200);
char* name_r = (char*)malloc(sizeof(char)*200);
int main()
{
int i=0;
IplImage *img0 , *img1;
cvNamedWindow("camera_left");
cvNamedWindow("camera_right");
CvCapture* cap_left= cvCreateCameraCapture(2); //这里我的摄像头ID是2,1,也有可能是1,0
CvCapture* cap_right= cvCreateCameraCapture(1);
while(1)
{
img0 = cvQueryFrame(cap_left);
img1 = cvQueryFrame(cap_right);
if( !img0 || !img1)
{
cout << "camera0 error" << endl;
break;
}
cvShowImage("camera_left", img0);
cvShowImage("camera_right", img1);
char c = cvWaitKey(33);
if(c == 27)
break;
if(c == 32)
{
i++;
sprintf(name_l, "leftPic%d.jpg", i);
sprintf(name_r, "rightPic%d.jpg", i);
cvSaveImage(name_l, img0);
cvSaveImage(name_r, img1);
}
}
cvReleaseCapture(&cap_left);
cvReleaseCapture(&cap_right);
cvDestroyWindow("camera_left");
cvDestroyWindow("camera_right");
return 0;
}
最后,附加链接1、https://www.cnblogs.com/star91/p/6012425.html 里面很详细标定步骤与原理;
链接2、https://blog.csdn.net/jkhere/article/details/8784865 matlab标定工具箱的使用说明的中文翻译
python双目拍照程序如下:
# -*- coding: utf-8 -*-
import cv2
import time
AUTO = True # 自动拍照,或手动按s键拍照
INTERVAL = 2 # 自动拍照间隔
cv2.namedWindow("left")
cv2.namedWindow("right")
cv2.moveWindow("left", 0, 0)
cv2.moveWindow("right", 400, 0)
left_camera = cv2.VideoCapture(0)
right_camera = cv2.VideoCapture(1)
counter = 0
utc = time.time()
pattern = (12, 8) # 棋盘格尺寸
folder = "./snapshot/" # 拍照文件目录
def shot(pos, frame):
global counter
path = folder + pos + "_" + str(counter) + ".jpg"
cv2.imwrite(path, frame)
print("snapshot saved into: " + path)
while True:
ret, left_frame = left_camera.read()
ret, right_frame = right_camera.read()
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 == ord("s"):
shot("left", left_frame)
shot("right", right_frame)
counter += 1
left_camera.release()
right_camera.release()
cv2.destroyWindow("left")
cv2.destroyWindow("right")