具体的张氏标定过程参考1(获得初值):http://blog.csdn.net/PINBODEXIAOZHU/article/details/43373247
参考2(极大似然估计):http://blog.csdn.net/pinbodexiaozhu/article/details/43374181
目的:得到相机的内参、外参和畸变系数。
过程:
- 标定平面到图像平面的单应性,H = A[R T] , sx = HX
- 标定平面建立世界坐标系,Z=0, X可通过测量标定平面获得世界坐标 ,x通过图片坐标获得像素坐标。
- H为3*3矩阵,有八个未知参数,通过四组点对可解出具体值。(所以用棋盘格)
- 利用旋转向量的约束求解内参。H=[h1 h2 h3] = sA[r1 r2 t] 。
- r1 r2 正交,故r1*r2=0。旋转后长度不变,故|r1|=|r2|=1。故可建立俩个方程
- 内参A有5个未知量,通过三个已知的不同的单应矩阵 H 可解得内参 A(所以需要改变摄像机和标定板的相对位置)
- 通过[h1 h2 h3] = A[r1 r2 t] 获得外参[r1 r2 t]
- 以上为获得的初值 (角点存在噪声),进行极大似然估计(最小二乘)
- 求得内外参将世界坐标投影到像素坐标得到m™,图片上检测到的坐标为m。最小二乘 minΣ||m-m™||²
关于opencv中标定的使用有很多参考,我主要参考了:
https://www.2cto.com/kf/201610/559735.html(关于函数的使用)及
http://blog.csdn.net/u011574296/article/details/73823569(主要参考程序自己加以修改为C++的形式)
在主要想说明遇到的一个关键问题和一个理解:
关键问题:是将标定后的参数输出的问题,在程序中标定后的参数格式为MAT形式(float)但我在calibrationcamera函数后面使用ptr,at形式的输出Mat的数据均不能得到正常的结果,如图:
很明显标定后的内参结果不正确。后来对比前面参考的网站内容发现函数使用均正确,果断把问题定位在打印输出问题上,故尝试了几种Mat的数据访问,但结果是一样,使用 at 访问时程序在 at 访问处报错。然后查看参考网站内容 发现其并没有在显示上打印输出数据,而是使用保存为文件的格式。尝试将输出改为使用文件的额形式,在文件中可观察到正确结果。
具体的打印输出格式我暂且没有找到可以正确的输出方法。
一个理解:是关于坐标系的理解。很显然如果要想正确的标定出结果,必须把标定板在世界坐标的点与图片上的点相对应,这就涉及到世界坐标系的建立问题。我参考了:http://blog.csdn.net/shenxiaolu1984/article/details/50165635
可能时我没能理解作者的具体意思,在我多次尝试后,可以确定的是坐标系确实时如作者所说与object_point与
findChessboardCorners检测顺序有关。但具体的坐标建立我有自己的理解。
检测到一个角点图,检测顺序如作者所说 先由右下方红色(右到左)再向上到左上方。可以断点查看数据进行确认。然后object_point的话按照常规的我们会定义为先x不变y变化,即按我下面的程序:
bool MyCalibration::ComputeWorldPoint()
{
for (int n = 0; n < imgCount; n++)
{
vector<Point3f> temp;
for (int i = 0; i <patternSize.height; i++)
{
for (int j = 0; j <patternSize.width; j++)
{
Point3f point;
point.x = squareSize.width * i;
point.y = squareSize.height * j;
point.z = 0;
temp.push_back(point);
}
}
worldPoint.push_back(temp);
}
return true;
}
断点查看到数据:如上图。
我们即可发现世界坐标系下的(0,0,0)点即为检测道德第一个角点为图片的右下角。所以世界坐标系的坐标原点认为是标定板右下角第一个角点。然后图片坐标系下 点先向左移动的。对应的worldPoint是y轴变化的,所以 y 轴指向左方,同理 X 轴指向上方,z轴可由右手法则得到。