OpenCV相机标定与畸变校正(附代码)

2022 年 7 月 18 日 极市平台
↑ 点击 蓝字  关注极市平台

作者丨gloomyfish
来源丨小白学视觉
编辑丨极市平台

极市导读

 

本文详细介绍了相机标定的定义、原理和程序实现步骤,并提供制作标定板、相机标定和校正畸变图像的代码。 >>加入极市CV技术交流群,走在计算机视觉的最前沿

01 相机标定定义与原理

在图像测量过程以及机器视觉应用中,为确定空间物体表面某点的三维几何位置与其在图像中对应点之间的相互关系,必须建立相机成像的几何模型,这些几何模型参数就是相机参数。在大多数条件下这些参数必须通过实验与计算才能得到,这个求解参数的过程就称之为相机标定(或摄像机标定)。相机标定常见的分为:
  • 单目相机标定
  • 双目相机标定
相机标定是想从二维的图像中获取三维信息,实现图像的畸变校正、对象测量、三维重建等。由于光线投射导致实际对象物体跟投影到2D平面的图像不一致,幸运的是这种不一致性是稳定的,我们可以通过对相机标定,计算出畸变参数来实现对后续图像的畸变校正。根据标定技术不一样可以分为下面几类标定方法:
  • 基于3D对象参照标定
  • 基于2D平面标定
  • 基于1D线性标定
  • 自标定
最常见的相机成像方式是基于pinhole的模型、它的成像模型可以图示如下:
通过标定算法同时求出相机内参与外参。最常用的算法是张正友标定算法。OpenCV/Matlab中均已经实现该算法。

02 标定板介绍与制作

要想实现对相机的标定,我们首先需要给相机找到个参考对象,常见的就是标定版的类型有如下几种
  • Chessboard
  • Circel-grid
  • RandPattern
  • ArUco
  • ChArUc
OpenCV源码在其sample/data目录下面一个自带的棋盘图(chessboard.png),显示如下:
在标定的时候,算法要求提供的棋盘格的 宽度高度,还有他们的 间隔距离。需要特别注意是这里的宽高是指他们的内部交叉点的个数,以上图为例,它的大小为7x7而不是8x8。 间隔是指棋盘格之间的距离,可以用像素距离表示,也可以用实际毫米为单位表示。

03 制作标定版与图像生成

最简单的办法就是把上述图像直接打印出来,贴到一个塑料底板上就好啦。如果是土豪可以直接购买各种玻璃底板的标定板。另外还有一个更恶搞的方法,连打印都省啦,直接把chessboard.png这张图在另外一台电脑的显示器上显示,然后把摄像头对着它各种牌即可完成图像数据采集。这个是我手写的采集程序代码,每次想保存图像的时候请安Q字母键即可,代码如下:
  
  
    
void create_images() {
    Mat frame;
    VideoCapture capture( 0);
    int index =  1;
     while (true) {
        bool ret = capture.read(frame);
        flip(frame, frame,  1);
         if (!ret)  break;
        imshow( "frame", frame);
        char c = waitKey( 50);
        printf( "%d ", c);
         if (c ==  113) { // Q
            imwrite(format( "D:/images/zsxq/%d.png", index), frame);
            index +=  1;
        }
         if (c ==  27) {
             break; // ESC
        }
    }
    capture.release();
}
记得拿着棋盘格图,在镜头面前各种摆POSE,这个是属于你的表演时间,不要客气!具体参考下图:

04 相机标定程序实现

大家好,现在我们开始程序实现环节,OpenCV中在camera模块中已经实现了张正友标定算法。我们只需要正确调用,就可以计算出相机的内参与外参,完成相机的标定。具体的代码实现步骤如下:

1. 定义相机标定的相关常量设置与变量

  
  
    
// load image files
vector<string> files;
glob( "D:/images/camera2d", files);

// 定义变量
vector<vector<Point2f>> imagePoints;
vector<vector<Point3f>> objectPoints;
TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER,  300.001);
int numCornersHor =  7;
int numCornersVer =  7;
int numSquares =  50;
vector<Point3f> obj;
for (int i =  0; i < numCornersHor; i++)
     for (int j =  0; j < numCornersVer; j++)
        obj.push_back(Point3f((float)j * numSquares, (float)i * numSquares,  0));

2. 发现与绘制棋盘格位置

  
  
    
// 发现棋盘格与绘制
Size s;
for (int i =  0; i < files.size(); i++) {
    printf( "image file : %s 
"
, files[i].c_str());
    Mat image = imread(files[i]);
    s = image.size();
    Mat gray;
    cvtColor(image, gray, COLOR_BGR2GRAY);
    vector<Point2f> corners;
    bool ret = findChessboardCorners(gray, Size( 77), corners, CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_FILTER_QUADS);
     if (ret) {
        cornerSubPix(gray, corners, Size( 1111), Size( -1-1), criteria);
        drawChessboardCorners(image, Size( 77), corners, ret);
        imagePoints.push_back(corners);
        objectPoints.push_back(obj);
        imshow( "calibration-demo", image);
        waitKey( 500);
    }
}

3. 发现棋盘格显示如下(我是直接打印OpenCV自带那张图的)

4. 相机校正-计算内参数

  
  
    
// 相机校正Mat intrinsic = Mat(3, 3, CV_32FC1);Mat distCoeffs;vector<Mat> rvecs;vector<Mat> tvecs;intrinsic.ptr< float>(0)[0] = 1;intrinsic.ptr< float>(1)[1] = 1;calibrateCamera(objectPoints, imagePoints, s, intrinsic, distCoeffs, rvecs, tvecs);

05 畸变图像校正

关于畸变类型,常见的图像畸变类型有 径向与切向畸变、OpenCV中的相机标定方法只能对径向畸变有效,使用内参对畸变图像实现校正。相关的代码如下:
  
  
    
// 畸变校正
for (int i =  0; i < files.size(); i++) {
    Mat dst;
    Mat image = imread(files[i]);
    undistort(image, dst, intrinsic, distCoeffs);
    imshow( "image", image);
    imshow( "undistort image", dst);
    waitKey( 1000);
}



公众号后台回复“项目实践”获取50+CV项目实践机会~

△点击卡片关注极市平台,获取 最新CV干货
极市干货
最新数据集资源 医学图像开源数据集汇总(二)
技术解读 一文打尽NMS技术的种种这是一篇对YOLOv7的详细解读和剖析
极视角动态: 青岛日报专访|极视角陈振杰:创业的每一个决定都要经得起逻辑推演 启动报名|2022GCVC全球人工智能视觉产业与技术大会,7月22日青岛见!

极市原创作者激励计划 #


极市平台深耕CV开发者领域近5年,拥有一大批优质CV开发者受众,覆盖微信、知乎、B站、微博等多个渠道。通过极市平台,您的文章的观点和看法能分享至更多CV开发者,既能体现文章的价值,又能让文章在视觉圈内得到更大程度上的推广。

对于优质内容开发者,极市可推荐至国内优秀出版社合作出书,同时为开发者引荐行业大牛,组织个人分享交流会,推荐名企就业机会,打造个人品牌 IP。

投稿须知:
1. 作者保证投稿作品为自己的 原创作品。
2. 极市平台尊重原作者署名权,并支付相应稿费。文章发布后,版权仍属于原作者。
3.原作者可以将文章发在其他平台的个人账号,但需要在文章顶部标明首发于极市平台

投稿方式:
添加小编微信Fengcall(微信号:fengcall19),备注:姓名-投稿
△长按添加极市平台小编

点击阅读原文进入CV社区

收获更多技术干货

登录查看更多
0

相关内容

【CVPR2022】多机器人协同主动建图算法
专知会员服务
46+阅读 · 2022年4月3日
【经典书】《学习OpenCV 3》,1018页pdf
专知会员服务
130+阅读 · 2021年2月28日
专知会员服务
12+阅读 · 2020年9月19日
【干货书】图形学基础,427页pdf
专知会员服务
145+阅读 · 2020年7月12日
【精通OpenCV 4】Mastering OpenCV 4 - Third Edition 随书代码
专知会员服务
39+阅读 · 2019年11月13日
实操教程|OpenCV中保存不同深度图像的技巧
极市平台
0+阅读 · 2022年2月14日
实践教程|基于OpenCV提取特定区域方法汇总
极市平台
1+阅读 · 2021年12月5日
LOAM 代码部分的公式推导(前端里程计部分)
计算机视觉life
4+阅读 · 2021年9月5日
最详细、最完整的相机标定讲解
计算机视觉life
55+阅读 · 2019年11月24日
实战 | 相机标定
计算机视觉life
15+阅读 · 2019年1月15日
实战 | 用Python做图像处理(二)
七月在线实验室
17+阅读 · 2018年5月25日
OpenCV特征提取与图像检索实现(附代码)
文本分类实战: 机器学习vs深度学习算法对比(附代码)
机器学习研究会
35+阅读 · 2017年10月25日
国家自然科学基金
1+阅读 · 2015年12月31日
国家自然科学基金
1+阅读 · 2015年12月31日
国家自然科学基金
0+阅读 · 2014年12月31日
国家自然科学基金
0+阅读 · 2014年12月31日
国家自然科学基金
1+阅读 · 2014年12月31日
国家自然科学基金
0+阅读 · 2013年12月31日
国家自然科学基金
0+阅读 · 2012年12月31日
国家自然科学基金
0+阅读 · 2011年12月31日
国家自然科学基金
0+阅读 · 2009年12月31日
Test-Time Training with Masked Autoencoders
Arxiv
0+阅读 · 2022年9月15日
Arxiv
0+阅读 · 2022年9月13日
Arxiv
13+阅读 · 2020年4月12日
Deformable Style Transfer
Arxiv
14+阅读 · 2020年3月24日
Arxiv
10+阅读 · 2018年2月17日
VIP会员
相关资讯
实操教程|OpenCV中保存不同深度图像的技巧
极市平台
0+阅读 · 2022年2月14日
实践教程|基于OpenCV提取特定区域方法汇总
极市平台
1+阅读 · 2021年12月5日
LOAM 代码部分的公式推导(前端里程计部分)
计算机视觉life
4+阅读 · 2021年9月5日
最详细、最完整的相机标定讲解
计算机视觉life
55+阅读 · 2019年11月24日
实战 | 相机标定
计算机视觉life
15+阅读 · 2019年1月15日
实战 | 用Python做图像处理(二)
七月在线实验室
17+阅读 · 2018年5月25日
OpenCV特征提取与图像检索实现(附代码)
文本分类实战: 机器学习vs深度学习算法对比(附代码)
机器学习研究会
35+阅读 · 2017年10月25日
相关基金
国家自然科学基金
1+阅读 · 2015年12月31日
国家自然科学基金
1+阅读 · 2015年12月31日
国家自然科学基金
0+阅读 · 2014年12月31日
国家自然科学基金
0+阅读 · 2014年12月31日
国家自然科学基金
1+阅读 · 2014年12月31日
国家自然科学基金
0+阅读 · 2013年12月31日
国家自然科学基金
0+阅读 · 2012年12月31日
国家自然科学基金
0+阅读 · 2011年12月31日
国家自然科学基金
0+阅读 · 2009年12月31日
Top
微信扫码咨询专知VIP会员