具体的张氏标定过程参考1(获得初值):



参考2(极大似然估计):


张氏标定(单平面棋盘格的摄像机标定方法)


目的:得到相机的内参、外参和畸变系数。


过程:

  • 标定平面到图像平面的单应性,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中标定的使用有很多参考,我主要参考了:


           


                (主要参考程序自己加以修改为C++的形式)


在主要想说明遇到的一个关键问题和一个理解:


      关键问题:是将标定后的参数输出的问题,在程序中标定后的参数格式为MAT形式(float)但我在calibrationcamera函数后面使用ptr,at形式的输出Mat的数据均不能得到正常的结果,如图:





opencv为图像添加光晕 opencv光平面标定_角点



很明显标定后的内参结果不正确。后来对比前面参考的网站内容发现函数使用均正确,果断把问题定位在打印输出问题上,故尝试了几种Mat的数据访问,但结果是一样,使用 at 访问时程序在 at 访问处报错。然后查看参考网站内容 发现其并没有在显示上打印输出数据,而是使用保存为文件的格式。尝试将输出改为使用文件的额形式,在文件中可观察到正确结果。




opencv为图像添加光晕 opencv光平面标定_角点_02


具体的打印输出格式我暂且没有找到可以正确的输出方法。




            一个理解:是关于坐标系的理解。很显然如果要想正确的标定出结果,必须把标定板在世界坐标的点与图片上的点相对应,这就涉及到世界坐标系的建立问题。我参考了:


findChessboardCorners检测顺序有关。但具体的坐标建立我有自己的理解。


           

               



opencv为图像添加光晕 opencv光平面标定_世界坐标系_03

     

opencv为图像添加光晕 opencv光平面标定_世界坐标系_04



检测到一个角点图,检测顺序如作者所说 先由右下方红色(右到左)再向上到左上方。可以断点查看数据进行确认。然后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轴可由右手法则得到。