您的位置:首页 > 运维架构

基于opencv的鱼眼矫正法-棋盘标定

2016-12-04 15:34 393 查看
<网页blog已经上线,一大波干货即将来袭:https://faiculty.com/>

这篇文章主要谈论了基于opencv的棋盘标定法的鱼眼矫正步骤。

这篇文章主要参考博客:棋盘标定。感谢博主。

主要矫正函数:opencv:fisheye

序言

棋盘标定法需要预先求得内参矩阵畸变矩阵,之后同一摄像头拍摄的鱼眼图像就可以直接根据他们之间的变换关系确定。

具体的有关理论可以移步到:

一、程序环境

openCV3.1 + VS2013 + win10

二、角点检测



2.1 输入图像

为了提高我们的标定参数精度,我们输入多张带棋盘的鱼眼图像。

注意:

多张带棋盘(棋盘是一样的)鱼眼图像,只是简单的重复取样。

需要知道棋盘的每行每列角点数 ,比如 Size board_size = Size(9,6)

需要知道棋盘格小的大小Size square_size = Size(20,20)

2.2 提取角点坐标

1.先把彩色图像变成灰度图:

这个步骤利用cvtColor函数:

void cvCvtColor(const CvArr* src, CvArr* dst, int code)

Parameters:
src – Source image: 8-bit unsigned, 16-bit unsigned ( CV_16UC... ), or single-precision floating-point.
dst – Destination image of the same size and depth as src .
code – Color space conversion code. See the description below.
dstCn – Number of channels in the destination image. If the parameter is 0, the number of the channels is derived automatically from src and code .

/* 例如 */
cvtColor(image, imageGray , CV_RGB2GRAY);


2. 提取角点:

这个步骤可以直接用findChessboardCorners函数:

findChessboardCorners(image, board_size, corners,CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE+
CALIB_CB_FAST_CHECK );

/* 函数的具体参数可以参考openCV手册 */


2.3. 亚像素精确化

这个步骤可以直接用CornerSubPix函数:

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

/* 函数的具体参数可以参考openCV手册 */

/* 然后标记角点,可以在角点周围画一个圆: */
for (int j = 0; j < corners.size(); j++)
{
circle( imageTemp, corners[j], 10, Scalar(0,0,255), 2, 8, 0);
}


2.4. 保存好找到角点

1. 把标定好的图像另存为。。。

2. 把每张图像得到的coroners保存下来

三、摄像机标定

摄像机的标定主要是利用fisheye::calibrate()函数,所以后面的工作将围绕函数所需要的参数展开,函数定义如下:

double cv::fisheye::calibrate   (   InputArrayOfArrays  objectPoints,
InputArrayOfArrays  imagePoints,
const Size &    image_size,
InputOutputArray    K,
InputOutputArray    D,
OutputArrayOfArrays     rvecs,
OutputArrayOfArrays     tvecs,
int     flags = 0,
TermCriteria    criteria = TermCriteria(TermCriteria::COUNT+TermCriteria::EPS, 100, DBL_EPSILON)
)

/* 参数定义如下: */




3.1 objectPoints参数

这个参数是角点在棋盘中三维坐标(令Z = 0),是一个元素为Vector的Vector类型,定义如下:

vector<vector<Point3f>>  object_Points;        /**  保存定标板上角点的三维坐标   **/


每个vector元素是一行角点的坐标。计算可以根据以下两个条件:

每行每列的角点数

棋盘格的大小

3.2 imagePoints参数

这个参数是角点在图像中的坐标,在之前我们已经保存好的。这个也是一个元素为Vector的Vector类型类型,定义如下:

vector<vector<Point2f>>  corners_Seq;    /** 保存检测到的所有角点 **/


3.3 image_size参数

可以用每张图像的size大小,一般都设定为原图的大小。

3.4 K参数

摄像机内参数矩阵。这个是个输出的结果,所以初始化一个矩阵就可以了。

cv::Matx33d intrinsic_matrix;


3.5 D参数

畸变参数。也是输出参数。

cv::Vec4d distortion_coeffs;


3.6 rvecs参数

图像输出的旋转参数。这也是输出结果。

std::vector<cv::Vec3d> rotation_vectors;


3.7 tvecs参数

这个是图像的平移参数,这也是输出结果。

std::vector<cv::Vec3d> translation_vectors;


3.8 flag

int flags = 0;
flags |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC;
flags |= cv::fisheye::CALIB_CHECK_COND;
flags |= cv::fisheye::CALIB_FIX_SKEW;
fisheye::calibrate(object_Points, corners_Seq, image_size, intrinsic_matrix, distortion_coeffs, rotation_vectors, translation_vectors, flags, cv::TermCriteria(3, 20, 1e-6));


四、矫正图像

得到参数后,我们把原图做映射,得到矫正后的图像。



4.1 initUndistortRectifyMap

这个函数大概的思路就是从目标图像触发找到对应的原始图像的坐标,然后将其值复制到目标图像。

函数定义如下:



注意这几个函数的输入

K:这个是相机的内参矩阵3x3

D: 这个是畸变系数

R: 这个是旋转矩阵(摄像头与水平面的夹角)

P:新的camera maxtrix,新的参数矩阵。我们可以通过调节它来控制我们的视野,具体怎么做下文有参考,理论来源于哪里(请移步摄像机成像原理)

size:就是你要求输出的图像size

m1type:输出映射矩阵的类型 (也就是后面map的类型)

map1:映射矩阵1

map2: 映射矩阵2,有了这两个映射矩阵我们就可以在后面用remap来映射出图像

得到参数后的矫正公式如下:

内参模型:



矫正:



新的new camera matrix矩阵的作用:

fx、fy:fx,fy变大(小),视场变小(大),裁剪较多(少),但细节清晰(模糊);

cx、cy这个是圆心坐标

通过控制new camera matrix可以控制畸变矫正图像的范围。

4.2 remap

这个函数做的工作就是映射。根据前面得到的map1 map2做图像的映射。然后做插值操作。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
相关文章推荐