本文CameraCalibrator类源代码来自于OpenCV2
计算机视觉编程手册(Robert Laganiere 著 张静 译)

强烈建议阅读机器视觉学习笔记(4)——单目摄像机标定参数说明之后再阅读本文

1.单目摄像机标定目的

单目摄像机标定的目的就是使摄像机实际状态无限接近理论推导的理想状态。单目摄像机标定最终将确定9个参数,摄像机内参数有4个,透镜畸变参数5个。

2.单目摄像机标定流程

  • 制作标定板
  • 使用摄像机拍摄不同角度的标定板
  • 将照片放置于预设的文件夹中
  • 编写程序计算摄像机内参数和透镜畸变参数
  • 保存9个参数

3.关键源代码说明

3.1bool findChessboardCorners((InputArray image, Size patternSize,
OutputArray corners)

Finds the positions of internal corners of the chessboard. 

(寻找棋盘格标定板的角点)

  • 三个参数依次代表输入图像,角点数目,存储角点的变量
  • 检测到角点以后,常常需要用void drawChessboardCorners()函数将其画出来
  • 如果找到的角点数目和输入的角点数目相同,就会用彩色圆圈画出角点,否则只用红色圆圈画出角点

示例程序如下:

void test()
{
vector<Point2f> imageCorners;
Size boardSize(9, 6);
Mat image = imread("left01.jpg");
bool found = findChessboardCorners(image, boardSize, imageCorners);
//绘制角点
drawChessboardCorners(image, boardSize, imageCorners, found);
namedWindow("test");
imshow("test", image);//角点如未全部检测出来只是红色圆圈画出角点
waitKey();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12

3.2Class CameraCalibrator

class CameraCalibrator{

    //输入点
std::vector<std::vector<cv::Point3f>> objectPoints;//世界坐标系下的点
std::vector<std::vector<cv::Point2f>> imagePoints;//像素坐标系下的点
//输出矩阵
cv::Mat cameraMatrix;//摄像机内参数矩阵
cv::Mat distCoeffs;//透镜畸变系数矩阵
//标定方式
int flag;
//用于图像去畸变
cv::Mat map1,map2;
bool mustInitUndistort; public:
CameraCalibrator() : flag(0), mustInitUndistort(true) {}; //导入标定图片提取角点
int addChessboardPoints(const std::vector<std::string>& filelist, cv::Size & boardSize);
//添加场景点与对应的图像点
void addPoints(const std::vector<cv::Point2f>& imageCorners, const std::vector<cv::Point3f>& objectCorners);
//标定相机
double calibrate(cv::Size &imageSize);
//设置标定方式
void setCalibrationFlag(bool radial8CoeffEnabled=false, bool tangentialParamEnabled=false);
//消除透镜畸变(标定之后调用有效)
cv::Mat CameraCalibrator::remap(const cv::Mat &image); // 获取矩阵
cv::Mat getCameraMatrix() { return cameraMatrix; }
cv::Mat getDistCoeffs() { return distCoeffs; }
};
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32

4.单目标定实例

int main()
{
cv::namedWindow("Image");
cv::Mat image;
std::vector<std::string> filelist;//存放标定图片路径 //生成路径,此处表示图片放在工程根目录下的chessboards文件夹
for (int i=1; i<=20; i++)
{
std::stringstream str;
str << "chessboards/chessboard" << std::setw(2) << std::setfill('0') << i << ".jpg";//图片的相对路径
std::cout << str.str() << std::endl; filelist.push_back(str.str());
image= cv::imread(str.str());
cv::imshow("Image",image);
cv::waitKey(100);
} CameraCalibrator cameraCalibrator;
//从棋盘格添加角点
cv::Size boardSize(6, 4);
cameraCalibrator.addChessboardPoints(
filelist, //图片路径
boardSize); //角点数目
//标定相机
cameraCalibrator.calibrate(image.size());
//选取某张图片,消除透镜畸变
image = cv::imread(filelist[6]);
cv::Mat uImage= cameraCalibrator.remap(image);
imshow("Original Image", image);
imshow("Undistorted Image", uImage); //打印相机内参数矩阵(3*3矩阵)
Mat cameraMatrix = cameraCalibrator.getCameraMatrix();
std::cout << " 相机内参数矩阵:" << cameraMatrix.rows << "x" << cameraMatrix.cols << std::endl;
for (int i=0; i<cameraMatrix.rows; i++)
for (int j=0; j<cameraMatrix.cols; j++)
{
cout<<setw(10)<<cameraMatrix.at<double>(i, j);
if (j==2)
cout<<endl;
}
//打印畸变系数矩阵(1*5矩阵)
Mat distCoeffs = cameraCalibrator.getDistCoeffs();
std::cout << "畸变系数矩阵:" << distCoeffs.rows << "x" << distCoeffs.cols << std::endl;
for (int i=0; i<distCoeffs.rows; i++)
for (int j=0; j<distCoeffs.cols; j++)
cout<<distCoeffs.at<double>(i, j)<<"\t";
waitKey(0);
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 畸变校正之前 

  • 畸变校正之后 

  • 相机内参数矩阵为 
    ⎡⎣⎢167.156000178.0970155.89119.3721⎤⎦⎥
  • 透镜畸变系数矩阵(分别表示k1,k2,p1,p2,k3)为 
    [−0.34560.1319−0.0004−0.0034−0.0227]

5.总结

  • 尽管核心函数都是OpenCV库函数,但是通过面向对象思想把相关函数和变量整合起来定义一个类是非常棒的方式,这样就可以专注于逻辑思考而不是一些变量和语法
  • 标定结果是否准确可以通过相机内参数矩阵大致推算出来。笔者自己的1280*720分辨率相机标定的x0,y0分别是622pix,370pix,恰好是分辨率的一半左右,符合其物理意义,可以断定标定正确(精度另说)
  • 本文实例中的x0,y0分别是156pix,119pix,由此我们可以推断作者相机的分辨率是312*234左右,由于视频分辨率常见的也就那几种,所以可以断定实例程序相机的分辨率是320*240

转自:http://blog.csdn.net/xuelabizp/article/details/50327393

机器视觉学习笔记(5)——基于OpenCV的单目摄像机标定的更多相关文章

  1. opencv单目摄像机标定(一)

    #include <string> #include <iostream> #include <cv.h> #include <highgui.h> u ...

  2. opencv单目摄像机标定

    #include <cv.h> #include <highgui.h> #include <iostream> #include <stdio.h> ...

  3. opencv单目摄像机标定(二)

    // 引入实际标定板方格宽度的标定程序 #include <string> #include <iostream> #include <cv.h> #include ...

  4. Django学习笔记(五)—— 表单

    疯狂的暑假学习之  Django学习笔记(五)-- 表单 參考:<The Django Book> 第7章 1. HttpRequest对象的信息 request.path         ...

  5. OpenCV 学习笔记 02 使用opencv处理图像

    1 不同色彩空间的转换 opencv 中有数百种关于不同色彩空间的转换方法,但常用的有三种色彩空间:灰度.BRG.HSV(Hue-Saturation-Value) 灰度 - 灰度色彩空间是通过去除彩 ...

  6. SpringMVC:学习笔记(5)——数据绑定及表单标签

    SpringMVC——数据绑定及表单标签 理解数据绑定 为什么要使用数据绑定 基于HTTP特性,所有的用户输入的请求参数类型都是String,比如下面表单: 按照我们以往所学,如果要获取请求的所有参数 ...

  7. Flutter学习笔记(13)--表单组件

    如需转载,请注明出处:Flutter学习笔记(13)--表单组件 表单组件是个包含表单元素的区域,表单元素允许用户输入内容,比如:文本区域,下拉表单,单选框.复选框等,常见的应用场景有:登陆.注册.输 ...

  8. Hadoop学习笔记(两)设置单节点集群

    本文描写叙述怎样设置一个单一节点的 Hadoop 安装.以便您能够高速运行简单的操作,使用 Hadoop MapReduce 和 Hadoop 分布式文件系统 (HDFS). 參考官方文档:Hadoo ...

  9. 学习笔记:使用opencv做双目测距(相机标定+立体匹配+测距).

    最近在做双目测距,觉得有必要记录点东西,所以我的第一篇博客就这么诞生啦~ 双目测距属于立体视觉这一块,我觉得应该有很多人踩过这个坑了,但网上的资料依旧是云里雾里的,要么是理论讲一大堆,最后发现还不知道 ...

随机推荐

  1. Python jieba 分词

    环境 Anaconda3 Python 3.6, Window 64bit 目的 利用 jieba 进行分词,关键词提取 代码 # -*- coding: utf-8 -*- import jieba ...

  2. Python IOError: [Errno 22] invalid mode ('r') 解决方法

    环境 Anaconda3 Python 3.6, Window 64bit 书籍 O'Reilly出版的Wes McKinney编的<Python for Data Analysis> r ...

  3. easyui-textbox高为0

    之前在项目中也遇到过,一段时间没遇到这种问题居然又忘记了,想着还是在博客中记录一下,方便自己记忆,也供大家参考. 大家是否也遇到过easyui-textbox高为0的情况呢 像这样:  用户名:< ...

  4. 音悦台mv视频下载

    需要获取的页面: 参考了此处,做了修改,代码如下: #coding:utf-8 import urllib2 import urllib import re import sys import os ...

  5. Linux下用c语言实现whereis.

    简单的一个whereis的实现,代码如下: #include <stdio.h> #include <errno.h> #include <dirent.h> #i ...

  6. 面试题48:用C++设计一个不能被继承的类

    解法一:把构造函数设为私有 将构造函数定义为私有,然后通过定义公有的静态函数来创建和释放类的实例. { public: static SealedClass1* GetInstance() { ret ...

  7. 关于htonl()

    htons #include <arpa/inet.h> uint16_t htons(uint16_t hostshort); htons的功能:                     ...

  8. About toupper()

    // toupper.c #include <stdio.h> #include <string.h> #include <ctype.h> int main() ...

  9. CentOS 7下sqlite3的问题修复

    Centos7下的nltk启动问题 CentOS 7, Python 3.6,ipython 6.0.0 问题描述 ipython 启动ipython命令 import nltk 爆出以下的错误信息: ...

  10. libwebsockets 运行问题

    /****************************************************************************** * libwebsockets 运行问题 ...