单目相机标定-原理及实现

一、 标定原理

     相机标定的目的就是要获得相机的内参数,得到二维平面像素坐标和三维世界坐标的关系,从而进行三维重建。

1、几个坐标系及其变换

(1)图像坐标系:是一个以像素为单位的坐标系,它的原点在左上方,每个像素点的位置是以像素为单位来表示的,所以这样的坐标系叫图像像素坐标系(u,v),u和v分别表示像素在数字图像中的列数和行数,但是并没有用物理单位表示像素的位置,因此还需建立以物理单位表示的图像坐标系,叫图像物理坐标系(x,y),该坐标系是以光轴与图像平面的交点为原点,该点一般位于图像中心,但是由于制造原因,很多情况下会偏移。以毫米为单位。两个坐标轴分别与图像像素坐标系平行。

若图像物理坐标系的原点在图像像素坐标系中的坐标为,每个像素在图像物理坐标系中的尺寸为dx,dy,则两个坐标系的关系为:

化为齐次坐标和矩阵形式:

(2)相机坐标系:是以相机的光心为原点Oc,Zc轴与光轴重合,与成像平面垂直,Xc和Yc轴与图像坐标系的两个坐标轴平行。OOc为摄像机的焦距,即相机坐标系的原点与图像物理坐标系原点之间的距离。

(3)世界坐标系:是由用户定义的三维坐标系,用于描述三维空间中的物体和相机的位置。用表示XwYwZw。

三者可用如下图表示:

(1)从世界坐标系到相机坐标系的变换:可以由一个旋转矩阵R和一个平移向量t来描述:

化为齐次坐标:

(2)相机坐标系到图像物理坐标系:

其中f是焦距。化成齐次坐标为:

所以可以得到从世界坐标系到图像坐标系的转换:

其中是相机的内参数,是外参数。

2、透镜畸变

实际的摄像机由于镜头制作工艺等原因,使摄像机获取的原始图像存在畸变,畸变有两种,径向畸变和切向畸变。径向畸变来自透镜形状,切向畸变来自于整个摄像机的组装过程。径向畸变可以由三个参数k1,k2,k3确定,切向畸变可由两个参数p1,p2确定。

3、总结

相机标定的目的就是建立摄像机图像像素位置与场景点位置之间的关系,即世界坐标系与图像坐标系之间的关系。方法就是根据摄像机模型,由已知特征点的图像坐标求解摄像机的模型参数,从而可以从图像出发恢复出空间点三维坐标,即三维重建。所以要求解的参数包括4个内参数和5个畸变参数,对于外参数,即旋转矩阵的三个旋转参数和平移向量的三个参数。内参数直接与期盼所在空间的3D几何相关,即外参数。而畸变参数则与点集如何畸变的2D集合相关。对于外参数,需要知道棋盘的位置,对棋盘的6个不同的视场图像,需要这6个参数,总之,在每个视场中,需要计算4个内参数和6个外参数。

4、opencv中要用到的函数

Opencv中使用的求解焦距和偏移的算法是基于zhang的方法,求解畸变参数是基于Brown的方法。Opencv不是使用基于3D构造物体的视场,而是使用平面物体的多个视场,使用黑白方块交替排列的模式能保证在测量上任何一边都没有偏移,并且格线角点也让亚像素定位函数的使用更自然。

1、给定一个棋盘图像,可以使用opencv函数findChessboardCorner()来定位棋盘的角点:

int
cvFindChessboardCorners(const void* image, CvSize patternSize, CvPoint2D32f* corners, nt* cornerCount=NULL, int flags=CV_CALIB_CB_ADAPTIVE_THRESH)

参数的意义为:

image:是一个输入变量,包含棋盘的单幅图像,必须为8位灰度图像。

patternSize:表示棋盘的每行和每列有多少个角点,值应为cvSize(columns,rows).

corners:存储角点位置的数组指针。

注:如果函数成功找到所有的角点,则返回非0,反之,返回0.最后的flags变量可以用来定义额外的滤波步长以有助于寻找棋盘角点。

2、cvFindChessboardCorners()返回的角点仅仅是近似值,实际上位置的精度受限于图像设备的精度,即小于一个像素,必须单独使用另外的函数来计算角点的精确位置以达到亚像素精度,即函数cvFindCornerSubPix().

3、在图像上绘制找到的棋盘角点,这样就可以看到投影的角点与观察的角点是否匹配,opencv提供了函数cvDrawChessboardCorners()将发现的所有角点绘制到所提供的图像上,如果没有发现所有的角点,那么得到的角点将用红色圆圈绘制,如果都找到就使用不同颜色绘制,并且把角点以一定的顺序用线连接起来。

Void
cvDrawChessboardCorners(CvArr* image, CvSize patternSize, CvPoint2D32f* corners, int count, int patternWasFound)

参数的意义:

image:要绘制的图像。必须是8位的彩色图像。就是findChessboardCorners()所使用的图像的复制品。

patternSize和corners与发现角点函数的参数意义一样。

count:等于角点数目,是整数。

最后一个参数表示是否所有的棋盘模式都成功找到。

4、一旦有多个图像的角点,就可以调用函数函数cvCalibrateCamera2(),可以得到摄像机内参数矩阵、畸变系数、旋转向量和平移向量。

double cvCalibrateCamera2(const
CvMat* objectPoints, const CvMat* imagePoints, const  CvMat* pointCounts,CvSize imageSize, CvMat* cameraMatrix, CvMat*distCoeffs, CvMat* rvecs=NULL, CvMat* tvecs=NULL,
int flags=0 )

参数的意义:

object_points:是一个N*3的矩阵,包含物体的每k个点在每M个图像上的物理坐标,N=K*M.这些点位于物体的坐标

平面上。

Image_points:是一个N*2的矩阵,包含object_points所提供的所有点的像素坐标,就是由M此调用cvFindChessboardCorners()的返回值构成。

points_count:表示每个图像的点的个数,以M*1矩阵形式表示。

image_size:是以像素衡量的图像尺寸。

cameraMatrix:3*3的相机内参数矩阵。

distCoeffs:5*1的畸变参数。

rvecs:旋转参数,M*3,代表棋盘围绕相机坐标系统下三维空间的坐标轴的旋转,每个向量的长度表示逆时针旋转的角度,可以通过调用cvRodrigues2()转换为3*3的旋转矩阵。

tvecs():平移参数,M*3。

代码:

#include<opencv2\core\core.hpp>
#include<opencv2\highgui\highgui.hpp>
#include<opencv2\calib3d\calib3d.hpp>
#include<opencv\cv.h>

using namespace std;
using namespace cv;

class CameraCalibrator
{
	int board_w;
	int board_h;
	int board_n;
	int N;
	CvSize board_sz;
	CvMat* image_points;
	CvMat* object_points;
	CvMat* point_counts;
	CvMat* intrinsic;
	CvMat* distortion;
	CvPoint2D32f* corners;
	int corner_count;
	int success;

	char filename[10];
	char windowname[20];

	IplImage* image;
	IplImage* gray_image;

public:
	CameraCalibrator(void);
	CameraCalibrator(int w,int h,int n);
	~CameraCalibrator(void);

	void FindCorners();
	void calibrate();

};

类的实现:

#include "CameraCalibrator.h"

CameraCalibrator::CameraCalibrator(int w,int h,int n)
{
	board_w=w;
	board_h=h;
	N=n;
	board_n=w*h;
	board_sz=cvSize(board_w,board_h);
	image_points=cvCreateMat(N*board_n,2,CV_32FC1);
	object_points=cvCreateMat(N*board_n,3,CV_32FC1);
	point_counts=cvCreateMat(N,1,CV_32SC1);
	intrinsic=cvCreateMat(3,3,CV_32FC1);
	distortion=cvCreateMat(5,1,CV_32FC1);
	corners=new CvPoint2D32f[board_n];
	success=0;
}

void CameraCalibrator::FindCorners()
{
	int index=1;
	while(index<=N)
	{
		sprintf(filename,"chess%d.jpg",index);
		image=cvLoadImage(filename);
		gray_image=cvCreateImage(cvGetSize(image),8,1);

		int found=cvFindChessboardCorners(image,board_sz,corners,&corner_count,
		CV_CALIB_CB_ADAPTIVE_THRESH|CV_CALIB_CB_FILTER_QUADS);
	    cvCvtColor(image,gray_image,CV_BGR2GRAY);

	    cout<<corner_count<<endl;

		cvFindCornerSubPix(gray_image,corners,corner_count,cvSize(11,11),cvSize(-1,-1),
		cvTermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,30,0.1));

		cvDrawChessboardCorners(image,board_sz,corners,corner_count,found);

	    sprintf(windowname,"chesscalib%d",index);
	    cvShowImage(windowname,image);	

	    cvWaitKey(0);

	  if(found)
	 {
		for(int i=success*board_n,j=0;j<board_n;++i,++j)
		{
			CV_MAT_ELEM(*image_points,float,i,0)=corners[j].x;
			CV_MAT_ELEM(*image_points,float,i,1)=corners[j].y;
			CV_MAT_ELEM(*object_points,float,i,0)=j/board_w;
			CV_MAT_ELEM(*object_points,float,i,1)=j%board_w;
			CV_MAT_ELEM(*object_points,float,i,2)=0.0f;
		}//endfor

		CV_MAT_ELEM(*point_counts,int,success,0)=board_n;
		success++;

	  }//endif

	  index++;
	}//endwhile

}
void CameraCalibrator::calibrate()
{
    CV_MAT_ELEM(*intrinsic,float,0,0)=1.0f;
	CV_MAT_ELEM(*intrinsic,float,1,1)=1.0f;

	//进行标定 计算参数
	cvCalibrateCamera2(object_points,image_points,point_counts,
		cvGetSize(image),intrinsic,distortion,NULL,NULL,0);

	cvSave("intrinsic.xml",intrinsic);
	cvSave("distortion.xml",distortion);
}

CameraCalibrator::~CameraCalibrator(void)
{
	cvReleaseMat(&object_points);
	cvReleaseMat(&image_points);
	cvReleaseMat(&point_counts);
}

//主函数:
#include"CameraCalibrator.h"
int main()
{
	CameraCalibrator cam1(5,7,7);
	cam1.FindCorners();
	cam1.calibrate();
	return 0;
}	

结果:

内参数矩阵:

畸变参数矩阵:

内参数矩阵中:

F是相机的物理焦距长度,Sx是x方向每个单元像素个数,单位是像素/每单元, 所以fx的单位是像素。

图像的高:240 图像的宽:320

设相机传感器的大小为m*n

Cx,Cy是成像中心相对于光轴与成像平面交点的偏移量:

畸变参数矩阵:

径向畸变参数k1=-1.82442880,k2=16.5068817,k3=-49.8691101

切向畸变参数p1=-0.0106841922,p2=-0.00607223995

图像的高:240 图像的宽:320

时间: 2024-10-07 20:23:46

单目相机标定-原理及实现的相关文章

基于OpenCV单目相机的快速标定--源码、工程、实现过程

相机的标定是所有人走进视觉世界需要做的第一件事,辣么多的视觉标定原理解释你可以随便在网上找到,这里只讲到底如何去实现,也算是给刚入门的朋友做个简单的分享. 1.单目相机标定的工程源码 首先请到同性交友网站Github上下载工程源码(https://github.com/Zhanggx0102/Camera_Calibration),注意以下几点: 1).这是一个MS Visual Studio 2010的工程源码(版本是201x都可以). 2).在编译运行之前请先在VS中配置好OpenCV(网上

单目相机测距

单目测距的小项目,大概需要就是用单目相机,对一个特定的目标进行识别并测算相机与该目标的距离.所以便去网上找了一堆教程,这里给大家总结一下,希望给小白们一个参考. 首先是基本需求了 opencv自然要会的,这咱就不多说了,会一点就行 需要一个摄像头,我用的是一个畸变很大的鱼眼免驱动摄像头,大家用电脑上的那个自带摄像头也可以的,就是不方便. 需要MATLAB进行相机标定 其实上面都是废话,下面进入正题吧. 网上的方法大概有两种,这里主要介绍一个我身边的大哥们都称做PnP问题的一个方法,但会另外简单介

相机标定原理介绍(二)

所有的相机标定方法,本质都是在求取内参和外参中所含的参数. 基于3D标定物的标定方法 使用基于3D标定物进行相机标定,是一种传统且常见的相机标定法.计算机视觉中,经典的3D标定物,棋盘方形格图案,并且提供其中角点的精确坐标. 主要流程 这一类标定法,主要包括四个步骤: 检测每张图片中的棋盘图案的角点: 通过使用线性最小二乘法估算相机投影矩阵P: 根据P矩阵就解内参矩阵K和外参矩阵R,t; 通过非线性优化,提高K,R,t矩阵的精度. 除了上述的流程,还有另外一种做法是先通过非线性优化改善相机投影矩

毫米波雷达与单目相机融合

说起融合,大家肯定会想到 融合的几个层次.数据级融合.特征级融合.决策级融合. 目前我们所采用的融合策略是决策级融合. ( 1)特征级融合的特点,主要是雷达辅助图像. 基本的思路是将雷达的点目标投影到图像上,围绕该点我们生成一个矩阵的感兴趣区域,然后我们只对该区域内进行搜索,搜索到以后跟雷达点目标进行匹配.它的优点是可以迅速地排除大量不会有车辆的区域,极大地提高识别速度.而且呢,可以迅速排除掉雷达探测到的非车辆目标,增强结果的可靠性. 缺点: 1)首先,这个方法实现起来有难度.理想情况下雷达点出

opencv单目摄像机标定

#include <cv.h> #include <highgui.h> #include <iostream> #include <stdio.h> #include <stdlib.h> using namespace std; int n_boards=0;//图像数目 const int board_dt=20;//等20帧每棋盘视图 //int sn_board=0;//成功找到角点的图像数目 int board_w;//图像的角点行列

双目相机标定以及立体测距原理及OpenCV实现

作者:dcrmg 单目相机标定的目标是获取相机的内参和外参,内参(1/dx,1/dy,Cx,Cy,f)表征了相机的内部结构参数,外参是相机的旋转矩阵R和平移向量t.内参中dx和dy是相机单个感光单元芯片的长度和宽度,是一个物理尺寸,有时候会有dx=dy,这时候感光单元是一个正方形.Cx和Cy分别代表相机感光芯片的中心点在x和y方向上可能存在的偏移,因为芯片在安装到相机模组上的时候,由于制造精度和组装工艺的影响,很难做到中心完全重合.f代表相机的焦距. 双目标定的第一步需要分别获取左右相机的内外参

基于opencv的相机标定

双目相机标定以及立体测距原理及OpenCV实现 作者:dcrmg 单目相机标定的目标是获取相机的内参和外参,内参(1/dx,1/dy,Cx,Cy,f)表征了相机的内部结构参数,外参是相机的旋转矩阵R和平移向量t.内参中dx和dy是相机单个感光单元芯片的长度和宽度,是一个物理尺寸,有时候会有dx=dy,这时候感光单元是一个正方形.Cx和Cy分别代表相机感光芯片的中心点在x和y方向上可能存在的偏移,因为芯片在安装到相机模组上的时候,由于制造精度和组装工艺的影响,很难做到中心完全重合.f代表相机的焦距

OpenCV相机标定及距离估计(单目)

相机标定基本知识 对于摄像机模型,一幅视图是通过透视变换将三维空间中的点投影到图像平面.投影公式如下: 或者 这里(X, Y, Z)是一个点的世界坐标,(u, v)是点投影在图像平面的坐标,以像素为单位.A被称作摄像机矩阵,或者内参数矩阵.(cx, cy)是基准点(通常在图像的中心),fx, fy是以像素为单位的焦距.所以如果因为某些因素对来自于摄像机的一幅图像升采样或者降采样,所有这些参数(fx, fy, cx和cy)都将被缩放(乘或者除)同样的尺度.内参数矩阵不依赖场景的视图,一旦计算出,可

相机标定简介与MatLab相机标定工具箱的使用(未涉及原理公式推导)

相机标定 一.相机标定的目的 确定空间物体表面某点的三维几何位置与其在图像中对应点之间的相互关系,建立摄像机成像的几何模型,这些几何模型参数就是摄像机参数. 二.通用摄像机模型 世界坐标系.摄像机坐标系和像平面坐标系都不重合.同时考虑两个因素 : (1)摄像机镜头的畸变误差,像平面上的成像位置与线性变换公式计算的透视变换投影结果有偏差: (2)计算机中图像坐标单位是存储器中离散像素的个数,所以像平面上的连续坐标还需取整转换. 摄像机参数 l  摄像机内部参数 (Intrinsic Paramet