如图所示,棋盘格是很常见使用的标定工具
左下角写着棋盘格的参数:30-12×9,表明:棋盘格边长为30mm,共有12×9格,也可以自己数出来
cv::Mat image = cv::imread("Chessboard.png", 0);//读入图片
int width = 11;
int height = 8;
cv::Size board_size = cv::Size(width , height); // 行列方向内角点数量
std::vector<cv::Point2f> image_points_buff;//保存内角点的向量
cv::findChessboardCorners(image, board_size, image_points_buff,
cv::CALIB_CB_ADAPTIVE_THRESH |cv::CALIB_CB_NORMALIZE_IMAGE);
// 对粗提取的角点精细化,有以下两种方式可供选择
cv::cornerSubPix(image, image_points_buff, cv::Size(3,3), cv::Size(-1, -1),
cv::TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));
//cv::find4QuadCornerSubpix(image, image_points_buff, cv::Size(5, 5));
cv::Mat image_color;
cv::cvtColor(image, image_color, CV_GRAY2BGR);
cv::drawChessboardCorners(image_color, board_size, image_points_buff, true);
以上代码段需要注意的是:
1)findChessboardCorners函数中填入的是内角点数量,是11×8
2)需要用subpix相应算法进行细化
最终得到的角点图片是这样的:
可以看到,角点的检测结果是有先后顺序的,无论棋盘格如何旋转,角点检测的顺序都是跟下图中一样,注意看1、2、 3、 4四个点对应的红色箭头,四个顶点的特征都是不一致的。
而且下面的结果必成立
这11×8个角点会被存储在image_points_buff数组中
image_points_buff.size() = height;
image_points_buff[0].size() = width;
image_points_buff[0][0] //对应下图1号点
image_points_buff[0][width-1] //对应下图2号点
image_points_buff[height-1][0] //对应下图3号点
image_points_buff[height-1][width-1] //对应下图4号点
相机无畸变模型:
其中,
(
U
,
V
,
W
)
(U,V,W)
(U,V,W)为在世界坐标系下一点的物理坐标,
(
u
,
v
)
(u,v)
(u,v)为该点对应的在像素坐标系下的像素坐标。
将下面的矩阵称为相机的内参矩阵,内参矩阵取决于相机的内部参数。其中,
f
f
f为像距,
d
X
dX
dX ,
d
Y
dY
dY分别表示
X
X
X ,
Y
Y
Y方向上的一个像素在相机感光板上的物理长度(即一个像素在感光板上是多少毫米),
u
0
v
0
u_{0} v_{0}
u0?v0?分别表示相机感光板中心在像素坐标系下的坐标,
θ
\theta
θ 表示感光板的横边和纵边之间的角度(
9
0
°
90^{°}
90°表示无误差)。
将矩阵 ( R T 0 0 ) \begin{pmatrix} R&T\\ 0&0 \end{pmatrix} (R0?T0?)称为相机的外参矩阵,外参矩阵取决于相机坐标系和世界坐标系的相对位置, R R R表示旋转矩阵, T T T表示平移矢量。
另外,相机拍摄的图片还存在一定的畸变,畸变包括桶形畸变和枕形畸变。
畸变模型包括径向畸变和切向畸变。
径向畸变公式(3阶)如下:
张正友标定法标定相机的内外参数的思路如下: