转载:https://blog.csdn.net/aptx704610875/article/details/48914043

这一节我们首先介绍下计算机视觉领域中常见的三个坐标系:图像坐标系,相机坐标系,世界坐标系。以及他们之间的关系。然后介绍如何使用张正友相机标定法标定相机。

图像坐标系:

理想的图像坐标系原点O1和真实的O0有一定的偏差,由此我们建立了等式(1)和(2),可以用矩阵形式(3)表示。

相机坐标系(C)和世界坐标系(W):

通过相机与图像的投影关系,我们得到了等式(4)和等式(5),可以用矩阵形式(6)表示。我们又知道相机坐标系和世界坐标的关系可以用等式(7)表示:

由等式(3),等式(6)和等式(7)我们可以推导出图像坐标系和世界坐标系的关系:

其中M1称为相机的内参矩阵,包含内参(fx,fy,u0,v0)。M2称为相机的外参矩阵,包含外参(R:旋转矩阵,T:平移矩阵)。

众所周知,相机镜头存在一些畸变,主要是径向畸变(下图dr),也包括切向畸变(下图dt)等。

上图右侧等式中,k1,k2,k3,k4,k5,k6为径向畸变,p1,p2为切向畸变。在OpenCV中我们使用张正友相机标定法通过10幅不同角度的棋盘图像来标定相机获得相机内参和畸变系数。函数为calibrateCamera(objectPoints, imagePoints, imageSize, cameraMatrix, distCoeffs, rvecs, tvecs,flag)

objectPoints: 一组世界坐标系中的3D

imagePoints: 超过10张图片的角点集合

imageSize: 每张图片的大小

cameraMatrix: 内参矩阵

distCoeffs: 畸变矩阵(默认获得5个即便参数k1,k2,p1,p2,k3,可修改)

rvecs: 外参:旋转向量

tvecs: 外参:平移向量

flag: 标定时的一些选项:

CV_CALIB_USE_INTRINSIC_GUESS:使用该参数时,在cameraMatrix矩阵中应该有fx,fy,u0,v0的估计值。否则的话,将初始化(u0,v0)图像的中心点,使用最小二乘估算出fx,fy。

CV_CALIB_FIX_PRINCIPAL_POINT:在进行优化时会固定光轴点。当CV_CALIB_USE_INTRINSIC_GUESS参数被设置,光轴点将保持在中心或者某个输入的值。

CV_CALIB_FIX_ASPECT_RATIO:固定fx/fy的比值,只将fy作为可变量,进行优化计算。当CV_CALIB_USE_INTRINSIC_GUESS没有被设置,fx和fy将会被忽略。只有fx/fy的比值在计算中会被用到。

CV_CALIB_ZERO_TANGENT_DIST:设定切向畸变参数(p1,p2)为零。

CV_CALIB_FIX_K1,...,CV_CALIB_FIX_K6:对应的径向畸变在优化中保持不变。

CV_CALIB_RATIONAL_MODEL:计算k4,k5,k6三个畸变参数。如果没有设置,则只计算其它5个畸变参数。

首先我们打开摄像头并按下'g'键开始标定:

  1. VideoCapture cap(1);

  2. cap.set(CV_CAP_PROP_FRAME_WIDTH,640);

  3. cap.set(CV_CAP_PROP_FRAME_HEIGHT,480);

  4. if(!cap.isOpened()){

  5. std::cout<<"打开摄像头失败,退出";

  6. exit(-1);

  7. }

  8. namedWindow("Calibration");

  9. std::cout<<"Press 'g' to start capturing images!"<<endl;

  1. if( cap.isOpened() && key == 'g' )

  2. {

  3. <span style="white-space:pre"> </span>mode = CAPTURING;

  4. }

按下空格键(SPACE)后使用findChessboardCorners函数在当前帧寻找是否存在可用于标定的角点,如果存在将其提取出来后亚像素化并压入角点集合,保存当前图像:

  1. if( (key & 255) == 32 )

  2. {

  3. image_size = frame.size();

  4. /* 提取角点 */

  5. Mat imageGray;

  6. cvtColor(frame, imageGray , CV_RGB2GRAY);

  7. bool patternfound = findChessboardCorners(frame, board_size, corners,CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE + CALIB_CB_FAST_CHECK );

  8. if (patternfound)

  9. {

  10. n++;

  11. tempname<<n;

  12. tempname>>filename;

  13. filename+=".jpg";

  14. /* 亚像素精确化 */

  15. cornerSubPix(imageGray, corners, Size(11, 11), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));

  16. count += corners.size();

  17. corners_Seq.push_back(corners);

  18. imwrite(filename,frame);

  19. tempname.clear();

  20. filename.clear();

  21. }

  22. else

  23. {

  24. std::cout<<"Detect Failed.\n";

  25. }

  26. }

角点提取完成后开始标定,首先初始化定标板上角点的三维坐标:

  1. for (int t=0;t<image_count;t++)

  2. {

  3. <span style="white-space:pre"> </span>vector<Point3f> tempPointSet;

  4. for (int i=0;i<board_size.height;i++)

  5. {

  6. <span style="white-space:pre"> </span>for (int j=0;j<board_size.width;j++)

  7. {

  8. /* 假设定标板放在世界坐标系中z=0的平面上 */

  9. Point3f tempPoint;

  10. tempPoint.x = i*square_size.width;

  11. tempPoint.y = j*square_size.height;

  12. tempPoint.z = 0;

  13. tempPointSet.push_back(tempPoint);

  14. <span style="white-space:pre"> </span>}

  15. }

  16. object_Points.push_back(tempPointSet);

  17. }

使用calibrateCamera函数开始标定:

calibrateCamera(object_Points, corners_Seq, image_size,  intrinsic_matrix  ,distortion_coeffs, rotation_vectors, translation_vectors);  

完成定标后对标定进行评价,计算标定误差并写入文件:

  1. std::cout<<"每幅图像的定标误差:"<<endl;

  2. fout<<"每幅图像的定标误差:"<<endl<<endl;

  3. for (int i=0; i<image_count; i++)

  4. {

  5. vector<Point3f> tempPointSet = object_Points[i];

  6. /**** 通过得到的摄像机内外参数,对空间的三维点进行重新投影计算,得到新的投影点 ****/

  7. projectPoints(tempPointSet, rotation_vectors[i], translation_vectors[i], intrinsic_matrix, distortion_coeffs, image_points2);

  8. /* 计算新的投影点和旧的投影点之间的误差*/

  9. vector<Point2f> tempImagePoint = corners_Seq[i];

  10. Mat tempImagePointMat = Mat(1,tempImagePoint.size(),CV_32FC2);

  11. Mat image_points2Mat = Mat(1,image_points2.size(), CV_32FC2);

  12. for (int j = 0 ; j < tempImagePoint.size(); j++)

  13. {

  14. image_points2Mat.at<Vec2f>(0,j) = Vec2f(image_points2[j].x, image_points2[j].y);

  15. tempImagePointMat.at<Vec2f>(0,j) = Vec2f(tempImagePoint[j].x, tempImagePoint[j].y);

  16. }

  17. err = norm(image_points2Mat, tempImagePointMat, NORM_L2);

  18. total_err += err/= point_counts[i];

  19. std::cout<<"第"<<i+1<<"幅图像的平均误差:"<<err<<"像素"<<endl;

  20. fout<<"第"<<i+1<<"幅图像的平均误差:"<<err<<"像素"<<endl;

  21. }

  22. std::cout<<"总体平均误差:"<<total_err/image_count<<"像素"<<endl;

  23. fout<<"总体平均误差:"<<total_err/image_count<<"像素"<<endl<<endl;

  24. std::cout<<"评价完成!"<<endl;

显示标定结果并写入文件:

  1. std::cout<<"开始保存定标结果………………"<<endl;

  2. Mat rotation_matrix = Mat(3,3,CV_32FC1, Scalar::all(0)); /* 保存每幅图像的旋转矩阵 */

  3. fout<<"相机内参数矩阵:"<<endl;

  4. fout<<intrinsic_matrix<<endl<<endl;

  5. fout<<"畸变系数:\n";

  6. fout<<distortion_coeffs<<endl<<endl<<endl;

  7. for (int i=0; i<image_count; i++)

  8. {

  9. fout<<"第"<<i+1<<"幅图像的旋转向量:"<<endl;

  10. fout<<rotation_vectors[i]<<endl;

  11. /* 将旋转向量转换为相对应的旋转矩阵 */

  12. Rodrigues(rotation_vectors[i],rotation_matrix);

  13. fout<<"第"<<i+1<<"幅图像的旋转矩阵:"<<endl;

  14. fout<<rotation_matrix<<endl;

  15. fout<<"第"<<i+1<<"幅图像的平移向量:"<<endl;

  16. fout<<translation_vectors[i]<<endl<<endl;

  17. }

  18. std::cout<<"完成保存"<<endl;

  19. fout<<endl;

具体的代码实现和工程详见:Calibration

运行截图:

下一节我们将使用RPP相机姿态算法得到相机的外部参数:旋转和平移。

==============================================================================================

2015/11/14补充:

所有分辨率下的畸变(k1,k2,p1,p2)相同,但内参不同(fx,fy,u0,v0),不同分辨率下需要重新标定相机内参。以下是罗技C920在1920*1080下的内参:

==============================================================================================

2016/08/20补充:

findChessboardCorners函数的第二个参数是定义棋盘格的横纵内角点个数,要设置正确,不然函数找不到合适的角点,返回false。如下图中的横内角点是12,纵内角点是7,则Size board_size = Size(12, 7);

--------------------- 本文来自 cc_sunny 的CSDN 博客 ,全文地址请点击:https://blog.csdn.net/aptx704610875/article/details/48914043?utm_source=copy

相机标定-opencv相关推荐

  1. 张正友相机标定Opencv实现以及标定流程标定结果评价图像矫正流程解析(附标定程序和棋盘图)

    from:https://blog.csdn.net/dcrmg/article/details/52939318 使用Opencv实现张正友法相机标定之前,有几个问题事先要确认一下,那就是相机为什么 ...

  2. 双目相机标定OpenCV源码讲解

    双目相机标定OpenCV源码讲解 背景介绍 所述内容 参考资料 摄像机标定部分代码 代码思路 代码中的其他函数 找角点&求内参 求外参 求矫正映射矩阵 后记 背景介绍 暑假接近两个月的时间做了 ...

  3. 张正友相机标定Opencv实现程序(ubuntu下)

    相机标定的目的:获取摄像机的内参和外参矩阵(同时也会得到每一幅标定图像的选择和平移矩阵),内参和外参系数可以对之后相机拍摄的图像就进行矫正,得到畸变相对很小的图像. 相机标定的输入:标定图像上所有内角 ...

  4. 相机标定-opencv单应性矩阵实现平面坐标标定(kinect v1)

    opencv单应性矩阵实现平面坐标标定 说明 一.使用单应性矩阵的原因 二.标定原理 三.findHomography 函数与 getPerspectiveTransform函数的区别 1.两者联系 ...

  5. 相机标定:PNP基于单应面解决多点透视问题

              利用二维视野内的图像,求出三维图像在场景中的位姿,这是一个三维透视投影的反向求解问题.常用方法是PNP方法,需要已知三维点集的原始模型. 本文做了大量修改,如有不适,请移步原文:  ...

  6. python相机标定流程图_相机标定——OpenCV-Python Tutorials

    目标 我们将了解导致相机失真.扭曲的内因与外因 我们将试着找到这些畸变参数,并消除畸变 基础 如今大量廉价的摄像机导致了很多照片畸变.两个主要的畸变是径向畸变和切向畸变. 由于径向畸变,直线会变弯.距 ...

  7. 工业互联网(十四)——相机标定(Camera calibration)原理、步骤

    转载: 最详细.最完整的相机标定讲解 图像处理--相机标定(Camera calibration) 相机标定 相机标定(Camera calibration)原理.步骤 工业相机标定相关知识整理 相机 ...

  8. OpenCV-Python相机标定

    OpenCV-Python相机标定--张正友标定法为例(待更新) 写在前面 数学/物理原理(不更新) 编程实现 参考与致谢 写在前面 为什么机器视觉要用相机标定:直接目的是求出相机的内.外参数,以及畸 ...

  9. 相机标定 matlab opencv ROS三种方法标定步骤(2)

    二  ubuntu下Opencv的相机标定 一般直接用Opencv的源码就可以进行相机的标定,但是可能只是会实现结果,却不懂实现的过程,我也是模模糊糊的看了<计算机视觉中的多视图几何>以及 ...

  10. 相机标定 matlab opencv ROS三种方法标定步骤(3)

    三 ,  ROS 环境下 如何进行相机标定 刚开始做到的时候遇到一些问题没有记录下来,现在回头写的时候都是没有错误的结果了,首先使用ROS标定相机, 要知道如何查看节点之间的流程图  rosrun r ...

最新文章

  1. Rancher-创建自己的应用商店教程
  2. leetcode算法题--增量元素之间的最大差值
  3. 将jar文件转换成exe可执行文件
  4. java字符串构造函数的应用_StringTokenizer类的使用
  5. 2017.8.10 loli 测试
  6. mysql 拒绝访问的解决办法
  7. 教程视图Android教程(十三)-- Activity间的切换
  8. 1.7 单层卷积网络
  9. 远离疲倦,告别非理性思维
  10. mysql怎么进行删除操作_利用PHP怎么对MySQL数据库进行删除操作
  11. [2019杭电多校第六场][hdu6641]TDL
  12. html5在线表格生成器,js简单实现自动生成表格功能示例
  13. linux脚本菜鸟教程,菜鸟教程之shell _1
  14. Git 基础命令与事件详解(基础版)
  15. 前端开发和后端开发究竟有什么区别?详细介绍
  16. Hyper-V安装lede软路由历程及注意事项
  17. django如何连接Mysql中已有的数据库
  18. Delphi软件工程师试题
  19. Springboot 整合Rabbit MQ
  20. 关于批量取消微博关注

热门文章

  1. ls 列出文件、ll以长格式列出文件详细信息
  2. html怎么隐藏信息,3.2.5 在HTML文件中隐藏信息
  3. 都柏林理工学院计算机,入爱尔兰都柏林理工大学,硕博连读全免费
  4. python字符串介绍_Python字符串详细介绍
  5. python画图设置彩色线条_Python数据处理从零开始----第四章(可视化)(19)一文解决线图line chart...
  6. 当xshell关闭时如何保持一个jar包程序在后台运行
  7. Java学习笔记——JDBC
  8. java程序dna,蓝桥杯——DNA(Java题解)
  9. 脚本文件不变色_LoadRunner脚本开发
  10. js获取url参数值的几种方式