棋盘格标定程序及源码
-
**相机标定的目的:**获取摄像机的内参和外参矩阵(同时也会得到每一幅标定图像的旋转和平移矩阵),
内参和外参系数可以对之后相机拍摄的图像就进行矫正,得到畸变相对很小的图像。
-
**相机标定的输入:**标定图像上所有内角点的图像坐标,标定板图像上所有内角点的空间三维坐标(一般情况下假定图像位于Z=0平面上)。对于每张拍摄的棋盘图片,检测图片中所有棋盘格的特征点(内角点,也就是黑白棋盘交叉点)。我们定义打印的棋盘图纸位于世界坐标系zw=0的平面上,世界坐标系的原点位于棋盘图纸的固定一角。像素坐标系原点位于图片左上角。
-
**相机标定的输出:**摄像机的内参、外参系数。
-
标定方法: 单目相机标定,张氏标定法
-
标定图片: opencv的安装路径下opencv\sources\samples\data
-
Progress:
step1. 准备标定图片
step2. 对每一张标定图片,提取角点信息
step3. 对每一张标定图片进一步提取亚像素角点信息
step4. 在期盼标定图上绘制找到的内角点(仅用作显示)
step5. 进行标定,并对标定结果进行评价
step6. 对比标定前后的图片
其中main()函数中 string infilename 为filenameLeft.txt文档所在路径,该文本文件存储的是每一张图片的路径(注意文档中的空白行)
string outfilename为保存标定结果的文本文档路径
/*************************************************************************************
************************************************************************************/
#include <opencv2/core/core.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/calib3d/calib3d.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <iostream>
#include <fstream>
#include <vector>
using namespace cv;
using namespace std;
void main(char *args)
{
//保存文件名称
std::vector<std::string> filenames;
//需要更改的参数
//左相机标定,指定左相机图片路径,以及标定结果保存文件
string infilename = "C:/Users/TXL/Desktop/work/0805minDistanceMeasure/cameraCalibration/filenameLeft.txt"; //存放图片路径的txt文件
string outfilename = "C:/Users/TXL/Desktop/work/0805minDistanceMeasure/cameraCalibration/left_caliberation_result.txt";
//标定所用图片文件的路径,每一行保存一个标定图片的路径 ifstream 是从硬盘读到内存
ifstream fin(infilename);
//保存标定的结果 ofstream 是从内存写到硬盘
ofstream fout(outfilename);
/*
1.读取毎一幅图像,从中提取出角点,然后对角点进行亚像素精确化、获取每个角点在像素坐标系中的坐标
像素坐标系(u,v)的原点位于图像的左上角
*/
std::cout << "开始提取角点......" << std::endl;;
//图像数量
int imageCount = 0;
//图像尺寸
cv::Size imageSize;
//修改参数//标定板上每行每列的角点数
cv::Size boardSize = cv::Size(9, 6);
//缓存每幅图像上检测到的角点
std::vector<Point2f> imagePointsBuf;
//保存检测到的所有角点
std::vector<std::vector<Point2f>> imagePointsSeq;
char filename[100];
if (fin.is_open())
{
//读取完毕?
while (!fin.eof())//判断文件是否为空,或者是读到了文件末尾
{
//一次读取一行
fin.getline(filename, sizeof(filename) / sizeof(char));
//保存文件名
filenames.push_back(filename);//将图片的每一行路径存到filenames向量里
//读取图片
cv::Mat imageInput = cv::imread(filename);
//读入第一张图片时获取图宽高信息
if (imageCount == 0)
{
imageSize.width = imageInput.cols;
imageSize.height = imageInput.rows;
std::cout << "imageSize.width = " << imageSize.width << std::endl;
std::cout << "imageSize.height = " << imageSize.height << std::endl;
}
std::cout << "imageCount = " << imageCount << std::endl;
imageCount++;
//提取每一张图片的角点