首页 开源项目 问答 动弹 博客 翻译 资讯 专题 活动 招聘
[ 登录 | 注册 ]
博客专区 > abcijkxyz的博客 > 博客详情
张正友相机标定Opencv实现以及标定流程&&标定结果评价&&图像矫正流程解析(附标定程序和棋盘图)
abcijkxyz 发表于4个月前
转 张正友相机标定Opencv实现以及标定流程&&标定结果评价&&图像矫正流程解析(附标定程序和棋盘图)
收藏
abcijkxyz
发表于 4个月前 阅读 1247 收藏 1 点赞 0 评论 0
【阿里云发福利】100%有奖,最高1888元>>>
使用Opencv实现张正友法相机标定之前,有几个问题事先要确认一下,那就是相机为什么需要标定,标定需要的输入和输出分别是哪些?
相机标定的目的:获取摄像机的内参和外参矩阵(同时也会得到每一幅标定图像的选择和平移矩阵),内参和外参系数可以对之后相机拍摄的图像就进行矫正,得到畸变相对很小的图像。
相机标定的输入:标定图像上所有内角点的图像坐标,标定板图像上所有内角点的空间三维坐标(一般情况下假定图像位于Z=0平面上)。
相机标定的输出:摄像机的内参、外参系数。
这三个基础的问题就决定了使用Opencv实现张正友法标定相机的标定流程、标定结果评价以及使用标定结果矫正原始图像的完整流程:
准备标定图片
对每一张标定图片,提取角点信息
对每一张标定图片,进一步提取亚像素角点信息
在棋盘标定图上绘制找到的内角点(非必须,仅为了显示)
相机标定
对标定结果进行评价
查看标定效果——利用标定结果对棋盘图进行矫正
准备标定图片
标定图片需要使用标定板在不同位置、不同角度、不同姿态下拍摄,最少需要3张,以10~20张为宜。标定板需要是黑白相间的矩形构成的棋盘图,制作精度要求较高,如下图所示:
2.对每一张标定图片,提取角点信息
需要使用findChessboardCorners函数提取角点,这里的角点专指的是标定板上的内角点,这些角点与标定板的边缘不接触。
findChessboardCorners函数原型:
//! finds checkerboard pattern of the specified size in the image
CV_EXPORTS_W bool findChessboardCorners( InputArray image, Size patternSize,
OutputArray corners,
int flags=CALIB_CB_ADAPTIVE_THRESH+CALIB_CB_NORMALIZE_IMAGE );
第一个参数Image,传入拍摄的棋盘图Mat图像,必须是8位的灰度或者彩色图像;
第二个参数patternSize,每个棋盘图上内角点的行列数,一般情况下,行列数不要相同,便于后续标定程序识别标定板的方向;
第三个参数corners,用于存储检测到的内角点图像坐标位置,一般用元素是Point2f的向量来表示:vector image_points_buf;
第四个参数flage:用于定义棋盘图上内角点查找的不同处理方式,有默认值。
- 对每一张标定图片,进一步提取亚像素角点信息
为了提高标定精度,需要在初步提取的角点信息上进一步提取亚像素信息,降低相机标定偏差,常用的方法是cornerSubPix,另一个方法是使用find4QuadCornerSubpix函数,这个方法是专门用来获取棋盘图上内角点的精确位置的,或许在相机标定的这个特殊场合下它的检测精度会比cornerSubPix更高?
cornerSubPix函数原型:
//! adjusts the corner locations with sub-pixel accuracy to maximize the certain cornerness criteria
CV_EXPORTS_W void cornerSubPix( InputArray image, InputOutputArray corners,
Size winSize, Size zeroZone,
TermCriteria criteria );
第一个参数image,输入的Mat矩阵,最好是8位灰度图像,检测效率更高;
第二个参数corners,初始的角点坐标向量,同时作为亚像素坐标位置的输出,所以需要是浮点型数据,一般用元素是Pointf2f/Point2d的向量来表示:vector
include “opencv2/core/core.hpp”
include “opencv2/imgproc/imgproc.hpp”
include “opencv2/calib3d/calib3d.hpp”
include “opencv2/highgui/highgui.hpp”
include
include
using namespace cv;
using namespace std;
void main()
{
ifstream fin(“calibdata.txt”); /* 标定所用图像文件的路径 */
ofstream fout(“caliberation_result.txt”); /* 保存标定结果的文件 */
//读取每一幅图像,从中提取出角点,然后对角点进行亚像素精确化
cout<<”开始提取角点………………”;
int image_count=0; /* 图像数量 */
Size image_size; /* 图像的尺寸 */
Size board_size = Size(4,6); /* 标定板上每行、列的角点数 */
vector image_points_buf; /* 缓存每幅图像上检测到的角点 */
vector