本文CameraCalibrator
类源代码来自于OpenCV2
计算机视觉编程手册(Robert Laganiere 著 张静 译)
强烈建议阅读机器视觉学习笔记(4)——单目摄像机标定参数说明之后再阅读本文
1.单目摄像机标定目的
单目摄像机标定的目的就是使摄像机实际状态无限接近理论推导的理想状态。单目摄像机标定最终将确定9个参数,摄像机内参数有4个,透镜畸变参数5个。
2.单目摄像机标定流程
- 制作标定板
- 使用摄像机拍摄不同角度的标定板
- 将照片放置于预设的文件夹中
- 编写程序计算摄像机内参数和透镜畸变参数
- 保存9个参数
3.关键源代码说明
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();
}
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;
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);
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;
}
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
5.总结
- 尽管核心函数都是OpenCV库函数,但是通过面向对象思想把相关函数和变量整合起来定义一个类是非常棒的方式,这样就可以专注于逻辑思考而不是一些变量和语法
- 标定结果是否准确可以通过相机内参数矩阵大致推算出来。笔者自己的1280*720分辨率相机标定的x0,y0分别是622pix,370pix,恰好是分辨率的一半左右,符合其物理意义,可以断定标定正确(精度另说)
- 本文实例中的x0,y0分别是156pix,119pix,由此我们可以推断作者相机的分辨率是312*234左右,由于视频分辨率常见的也就那几种,所以可以断定实例程序相机的分辨率是320*240
转自:http://blog.csdn.net/xuelabizp/article/details/50327393