OpenCV张正友相机标定棋盘图中自带的棋盘格照片的边长是多少?

本文基于:
这篇博客写得虽然很详细,但是其代码和结果有些明显的不当之处,所以本文进行了更为详细准确的介绍,若有问题欢迎指正。
一.本程序基于以下配置:
- Visual Studio 2015
- OpenCV 3.1.0
开发环境配置参考:
二.本程序准备工作:
本程序使用的标定板是10行14列棋盘格图案,示意图如下:
在不同视角拍摄这样的照片14张,依次命名为chess1、chess2、…、chess14,并将其放在当前.cpp文件目录下面,如下图所示:
其中calibdata文本文档的内容如下:
三.完整源程序如下:
#include"opencv2/core/core.hpp"
#include"opencv2/imgproc/imgproc.hpp"
#include"opencv2/calib3d/calib3d.hpp"
#include"opencv2/highgui/highgui.hpp"
#include&iostream&
#include&fstream&
using namespace std;
using namespace
int main()
ifstream fin("calibdata.txt");
ofstream fout("calibration_result.txt");
cout&&"开始提取特征点..........";
int image_count = 0;
Size image_
Size board_size = Size(13,9);
vector&Point2f& image_points_
vector&vector&Point2f&& image_points_
int count = 0;
while(getline(fin,filename))
image_count++;
cout&&"image_count = "&&image_count&&
Mat imageInput = imread(filename);
if(image_count == 1)
image_size.width = imageInput.
image_size.height = imageInput.
cout&&"image_size.width = "&&image_size.width&&
cout&&"image_size.height = "&&image_size.height&&
if(0 == findChessboardCorners(imageInput,board_size,image_points_buf))
cout&&"Cannot find chessboard corners!\n";
cvtColor(imageInput,view_gray,CV_RGB2GRAY);
cornerSubPix(view_gray,image_points_buf,Size(5,5),Size(-1,-1),
count += image_points_buf.size();
image_points_seq.push_back(image_points_buf);
drawChessboardCorners(view_gray,board_size,image_points_buf,false);
imshow("Camera Calibration",view_gray);
waitKey(500);
cout && "count = " && count&&
int total = image_points_seq.size();
cout && "total = " && total &&
int CornerNum = board_size.width*board_size.
for(int ii = 0;ii&ii++)
cout && "第" && ii + 1 && "张图片的数据:" &&
for(int jj = 0;jj&CornerNjj++)
if (0 == jj % 3)
cout.width(10);
cout && "(" && image_points_seq[ii][jj].x && "," && image_points_seq[ii][jj].y && ")";
cout&&"角点提取完成!\n";
cout&&"开始标定............";
Size square_size = Size(10,10);
vector&vector&Point3f&& object_
Mat cameraMatrix = Mat(3,3,CV_32FC1,Scalar::all(0));
vector&int& point_
Mat distCoeffs = Mat(1,5,CV_32FC1,Scalar::all(0));
vector&Mat& tvecsM
vector&Mat& rvecsM
int i,j,t;
for(t = 0;t&image_t++)
vector&Point3f& temPointS
for(i = 0;i&board_size.i++)
for(j = 0;j&board_size.j++)
Point3f realP
realPoint.x = i*square_size.
realPoint.y = j*square_size.
realPoint.z = 0;
temPointSet.push_back(realPoint);
object_points.push_back(temPointSet);
for(i = 0;i&image_i++)
point_counts.push_back(board_size.width*board_size.height);
calibrateCamera(object_points,image_points_seq,image_size,
cameraMatrix,distCoeffs,rvecsMat,tvecsMat,0);
cout&&"标定完成!"&&
cout&&"开始输出标定结果....."&&
double total_err = 0.0;
double err = 0.0;
vector&Point2f& image_points2;
cout&&"每幅图像的标定误差:\n";
fout&&"每幅图像的标定误差:\n";
for(i = 0;i&image_i++)
vector&Point3f& tempPointSet = object_points[i];
projectPoints(tempPointSet,rvecsMat[i],tvecsMat[i],
cameraMatrix,distCoeffs,image_points2);
vector&Point2f& tempImagePoint = image_points_seq[i];
Mat tempImagePointMat = Mat(1,tempImagePoint.size(),CV_32FC2);
Mat image_points2Mat = Mat(1,image_points2.size(),CV_32FC2);
for(int j = 0;j &tempImagePoint.size(); j++)
image_points2Mat.at&Vec2f&(0,j) = Vec2f(image_points2[j].x,image_points2[j].y);
tempImagePointMat.at&Vec2f&(0,j) = Vec2f(tempImagePoint[j].x,tempImagePoint[j].y);
err = norm(image_points2Mat,tempImagePointMat,NORM_L2);
total_err += err /= point_counts[i];
cout&&"第"&&i+1&&"幅图像的平均误差:"&&err&&"像素"&&
fout&&"第"&&i+1&&"幅图像的平均误差:"&&err&&"像素"&&
cout&&"总体平均误差:"&&total_err/image_count&&"像素"&&
fout&&"总体平均误差:"&&total_err/image_count&&"像素"&&endl&&
cout&&"评价完成!"&&
cout&&"开始保存标定结果............"&&
Mat rotation_matrix = Mat(3,3,CV_32FC1,Scalar::all(0));
fout&&"相机内参数矩阵:"&&
fout&&cameraMatrix&&endl&&
fout&&"畸变系数:\n";
fout&&distCoeffs&&endl&&endl&&
for(i = 0; i&image_i++)
fout&&"第"&&i+1&&"幅图像的旋转向量:"&&
fout&&rvecsMat[i]&&
Rodrigues(rvecsMat[i],rotation_matrix);
fout&&"第"&&i+1&&"幅图像的旋转矩阵:"&&
fout&&rotation_matrix&& endl &&
fout&&"第"&&i+1&&"幅图像的平移向量:"&&
fout&&tvecsMat[i]&& endl &&
cout&&"完成保存"&&
Mat mapx = Mat(image_size,CV_32FC1);
Mat mapy = Mat(image_size,CV_32FC1);
Mat R = Mat::eye(3,3,CV_32F);
cout&&"保存矫正图像"&&
string imageFileN
std::stringstream StrS
for(int i = 0;i & image_i++)
cout&&"Frame # "&&i+1&&"....."&&
initUndistortRectifyMap(cameraMatrix, distCoeffs, R, cameraMatrix,
image_size, CV_32FC1, mapx, mapy);
StrStm.clear();
imageFileName.clear();
string filePath = "chess";
StrStm&&i+1;
StrStm&&imageFileN
filePath += imageFileN
filePath += ".bmp";
Mat imageSource = imread(filePath);
Mat newimage = imageSource.clone();
remap(imageSource,newimage,mapx,mapy,INTER_LINEAR);
imageFileName += "_d.jpg";
imwrite(imageFileName,newimage);
cout&&"保存结束"&&
fin.close();
fout.close();
getchar();
四.运行结果:
图片太多,中间省略几张。。。
calibration_result.txt的结果如下:
每幅图像的标定误差:
第1幅图像的平均误差:0.0316613像素
第2幅图像的平均误差:0.0389023像素
第3幅图像的平均误差:0.0382147像素
第4幅图像的平均误差:0.0370629像素
第5幅图像的平均误差:0.0385986像素
第6幅图像的平均误差:0.0411222像素
第7幅图像的平均误差:0.0301272像素
第8幅图像的平均误差:0.0356303像素
第9幅图像的平均误差:0.0376777像素
第10幅图像的平均误差:0.0327415像素
第11幅图像的平均误差:0.0257617像素
第12幅图像的平均误差:0.0254189像素
第13幅图像的平均误差:0.0288391像素
第14幅图像的平均误差:0.0281152像素
总体平均误差:0.0335624像素
相机内参数矩阵:
畸变系数:
[-0.791, 0.1111, -0..249e-05, -1.361]
第1幅图像的旋转向量:
第1幅图像的旋转矩阵:
[-0.62338, -0.8331, -0.6397;
-0., -0.34665;
0.53, -0.445]
第1幅图像的平移向量:
第2幅图像的旋转向量:
第2幅图像的旋转矩阵:
[-0.1815, -0.548, -0.6227;
-0.8, 0.0835;
0.73, -0.5021]
第2幅图像的平移向量:
第3幅图像的旋转向量:
第3幅图像的旋转矩阵:
[-0.6785, -0.9897, -0.3095;
-0.6, 0.1941;
-0.8, -0.9247]
第3幅图像的平移向量:
第4幅图像的旋转向量:
第4幅图像的旋转矩阵:
[-0.9861, -0.9;
-0.2, 0.2097;
-0.3, -0.2705]
第4幅图像的平移向量:
第5幅图像的旋转向量:
第5幅图像的旋转矩阵:
[-0.4779, -0.8;
-0.3, 0.7545;
-0.717, 0.7603, -0.2951]
第5幅图像的平移向量:
第6幅图像的旋转向量:
第6幅图像的旋转矩阵:
[-0.0246, -0.3;
-0.324, 0.2435, -0.6591;
-0.9962, -0.1554, -0.8697]
第6幅图像的平移向量:
第7幅图像的旋转向量:
第7幅图像的旋转矩阵:
[-0.2, 0.0879;
0.5, -0.0896;
-0., -0.7832]
第7幅图像的平移向量:
第8幅图像的旋转向量:
第8幅图像的旋转矩阵:
[-0.5, 0.168;
0.5, 0.706;
0., -0.0308]
第8幅图像的平移向量:
第9幅图像的旋转向量:
第9幅图像的旋转矩阵:
[-0.1, 0.1871;
0.4, 0.4665;
0.411, 0.0529, -0.9759]
第9幅图像的平移向量:
第10幅图像的旋转向量:
第10幅图像的旋转矩阵:
[-0.7, 0.7916;
0.8, -0.717;
-0., -0.219]
第10幅图像的平移向量:
第11幅图像的旋转向量:
第11幅图像的旋转矩阵:
[-0.6, -0.9889;
0., -0.632;
-0.9682, -0.0942, -0.5336]
第11幅图像的平移向量:
第12幅图像的旋转向量:
第12幅图像的旋转矩阵:
[-0.4, 0.1291;
0.1, -0.814;
-0.8599, -0.354715, -0.9114]
第12幅图像的平移向量:
第13幅图像的旋转向量:
第13幅图像的旋转矩阵:
[-0.417, 0.3;
0.1, 0.1983;
0.2, -0.1795]
第13幅图像的平移向量:
第14幅图像的旋转向量:
第14幅图像的旋转矩阵:
[-0.626, 0.9;
0.1, 0.35755;
-0.55, -0.7354]
第14幅图像的平移向量:
第一次写博客~7167人阅读
opencv(11)
前一段时间,研究了下相机标定。关于opencv相机标定,包括标定完后,世界坐标到 图像坐标的转换,以评估图像的标定误差,这些网上有很多资源和源代码。
可是,相机标定完之后,我们想要的是,知道了图像坐标,想要得到它的世界坐标,或者我们已知图像上两个点之间的像素距离,现在我们想知道两个点之间的实际距离。
楼主在网上搜了很多资源,问了很多人,都没有相关的代码,可以得到这样的结论:opencv没有提供现成的函数,满足从图像坐标到世界坐标的转换。
所以,我们最想要的这一步,是需要自己写的。(如果我理解的不对,希望看到这篇博文的人,能够批评指正)
相机标定的主要思路为:
一、获取十几张不同角度拍摄的图片,角点检测,得到每个角点的坐标;
二、分别定义十几张照片中,世界坐标系下的角点坐标,一般x、y为等间距,z为0 ;
三、开始标定,主要函数为calibrateCamera;
四、得到了相机内参和畸变系数,这是标定完后相机的属性,还会得到外参,外参代表着每张图片所在的平面;
五、opencv提供了世界坐标到图像坐标的转换函数,主要用来评估标定的误差;
六、我们最想要的,根据图像坐标到世界坐标的转换,本质上就是矩阵的运算,需要自己写;
下面贴出代码,开发环境opencv2.4.9+vs2013
#include &opencv2/core/core.hpp&
#include &opencv2/imgproc/imgproc.hpp&
#include &opencv2/calib3d/calib3d.hpp&
#include &opencv2/highgui/highgui.hpp&
#include &iostream&
#include &fstream&
const int imageWidth = 1600;
//摄像头的分辨率
const int imageHeight = 1200;
const int boardWidth = 39;
//横向的角点数目
const int boardHeight = 39;
//纵向的角点数据
const int boardCorner = boardWidth * boardH
//总的角点数据
const int frameNumber =7;
//相机标定时需要采用的图像帧数
const int squareSize = 10;
//标定板黑白格子的大小 单位mm
const Size boardSize = Size(boardWidth, boardHeight);
//相机内参数
Mat distortion_
//相机畸变参数
vector&Mat&
//旋转向量
vector&Mat&
//平移向量
vector&vector&Point2f&&
//各个图像找到的角点的集合 和objRealPoint 一一对应
vector&vector&Point3f&& objRealP
//各副图像的角点的实际物理坐标集合
vector&Point2f&
//某一副图像找到的角点
Mat rgbImage, grayI
/*计算标定板上模块的实际物理坐标*/
void calRealPoint(vector&vector&Point3f&&& obj, int boardwidth, int boardheight, int imgNumber, int squaresize)
Mat imgpoint(boardheight, boardwidth, CV_32FC3,Scalar(0,0,0));
vector&Point3f&
for (int rowIndex = 0; rowIndex & rowIndex++)
for (int colIndex = 0; colIndex & colIndex++)
imgpoint.at&Vec3f&(rowIndex, colIndex) = Vec3f(rowIndex * squaresize, colIndex*squaresize, 0);
imgpoint.push_back(Point3f(colIndex * squaresize, rowIndex * squaresize, 0));
for (int imgIndex = 0; imgIndex & imgN imgIndex++)
obj.push_back(imgpoint);
/*设置相机的初始参数 也可以不估计*/
void CalibrationEvaluate(void)//标定结束后进行评价
double err=0;
double total_err=0;
//calibrateCamera(objRealPoint, corners, Size(imageWidth, imageHeight), intrinsic, distortion_coeff, rvecs, tvecs, 0);
cout && &每幅图像的定标误差:& &&
for (int i = 0; i & corners.size(); i++)
vector&Point2f& image_points2;
vector&Point3f& tempPointSet = objRealPoint[i];
projectPoints(tempPointSet, rvecs[i], tvecs[i], intrinsic, distortion_coeff, image_points2);
vector&Point2f& tempImagePoint = corners[i];
Mat tempImagePointMat = Mat(1, tempImagePoint.size(), CV_32FC2);
Mat image_points2Mat = Mat(1, image_points2.size(), CV_32FC2);
for (int j = 0; j & tempImagePoint.size(); j++)
image_points2Mat.at&Vec2f&(0, j) = Vec2f(image_points2[j].x, image_points2[j].y);
tempImagePointMat.at&Vec2f&(0, j) = Vec2f(tempImagePoint[j].x, tempImagePoint[j].y);
err = norm(image_points2Mat, tempImagePointMat, NORM_L2);
total_err = err + total_
cout && &第& && i + 1 && &幅图像的平均误差:& && err && &像素& &&
cout && &总体平均误差:& && total_err / (corners.size() + 1) && &像素& &&
void guessCameraParam(void)
/*分配内存*/
intrinsic.create(3, 3, CV_64FC1);
distortion_coeff.create(5, 1, CV_64FC1);
intrinsic.at&double&(0, 0) = 256.8093262;
intrinsic.at&double&(0, 2) = 160.2826538;
intrinsic.at&double&(1, 1) = 254.7511139;
intrinsic.at&double&(1, 2) = 127.6264572;
intrinsic.at&double&(0, 1) = 0;
intrinsic.at&double&(1, 0) = 0;
intrinsic.at&double&(2, 0) = 0;
intrinsic.at&double&(2, 1) = 0;
intrinsic.at&double&(2, 2) = 1;
k1 k2 p1 p2 p3
distortion_coeff.at&double&(0, 0) = -0.193740;
distortion_coeff.at&double&(1, 0) = -0.378588;
distortion_coeff.at&double&(2, 0) = 0.028980;
distortion_coeff.at&double&(3, 0) = 0.008136;
distortion_coeff.at&double&(4, 0) = 0;
void outputCameraParam(void)
/*保存数据*/
//cvSave(&cameraMatrix.xml&, &intrinsic);
//cvSave(&cameraDistoration.xml&, &distortion_coeff);
//cvSave(&rotatoVector.xml&, &rvecs);
//cvSave(&translationVector.xml&, &tvecs);
/*输出数据*/
cout && &fx :& && intrinsic.at&double&(0, 0) && endl && &fy :& && intrinsic.at&double&(1, 1) &&
cout && &cx :& && intrinsic.at&double&(0, 2) && endl && &cy :& && intrinsic.at&double&(1, 2) &&
cout && &k1 :& && distortion_coeff.at&double&(0, 0) &&
cout && &k2 :& && distortion_coeff.at&double&(1, 0) &&
cout && &p1 :& && distortion_coeff.at&double&(2, 0) &&
cout && &p2 :& && distortion_coeff.at&double&(3, 0) &&
cout && &p3 :& && distortion_coeff.at&double&(4, 0) &&
//int _tmain(int argc, _TCHAR* argv[])
int main()
int goodFrameCount = 0;
namedWindow(&chessboard&);
cout && &按Q退出 ...& &&
while (goodFrameCount & frameNumber)
char filename[100];
sprintf_s(filename, &chao%d.bmp&, goodFrameCount);
//sprintf_s(filename, &chess%d.jpg&, goodFrameCount);
goodFrameCount++;
rgbImage = imread(filename, 1);
cvtColor(rgbImage, grayImage, CV_BGR2GRAY);
imshow(&Camera&, grayImage);
bool isFind = findChessboardCorners(rgbImage, boardSize, corner, 0);
//bool isFind = findChessboardCorners(rgbImage, boardSize, corner, CV_CALIB_CB_NORMALIZE_IMAGE);
if (isFind == true) //所有角点都被找到 说明这幅图像是可行的
Size(5,5) 搜索窗口的一半大小
Size(-1,-1) 死区的一半尺寸
TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 20, 0.1)迭代终止条件
cornerSubPix(grayImage, corner, Size(5, 5), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 20, 0.1));
drawChessboardCorners(rgbImage, boardSize, corner, isFind);
imshow(&chessboard&, rgbImage);
corners.push_back(corner);
//string filename = &res\\image\\calibration&;
//filename += goodFrameCount + &.jpg&;
//cvSaveImage(filename.c_str(), &IplImage(rgbImage));
//把合格的图片保存起来
cout && &The image is good& &&
cout && &The image is bad please try again& &&
cout && &Press any key to continue...& &&
waitKey(0);
if (waitKey(10) == 'q')
imshow(&chessboard&, rgbImage);
图像采集完毕 接下来开始摄像头的校正
calibrateCamera()
输入参数 objectPoints
角点的实际物理坐标
imagePoints
角点的图像坐标
图像的大小
cameraMatrix
相机的内参矩阵
distCoeffs
相机的畸变参数
旋转矢量(外参数)
平移矢量(外参数)
/*设置实际初始参数 根据calibrateCamera来 如果flag = 0 也可以不进行设置*/
guessCameraParam();
cout && &guess successful& &&
/*计算实际的校正点的三维坐标*/
calRealPoint(objRealPoint, boardWidth, boardHeight, frameNumber, squareSize);
cout && &cal real successful& &&
/*标定摄像头*/
calibrateCamera(objRealPoint, corners, Size(imageWidth, imageHeight), intrinsic, distortion_coeff, rvecs, tvecs, 0);
cout && &calibration successful& &&
/*保存并输出参数*/
outputCameraParam();
CalibrationEvaluate();
cout && &out successful& &&
/*显示畸变校正效果*/
undistort(rgbImage, cImage, intrinsic, distortion_coeff);
imshow(&Corret Image&, cImage);
cout && &Correct Image& &&
cout && &Wait for Key& &&
waitKey(0);
system(&pause&);
以上只贴出了部分代码,完整的C++代码,可到&&下载。他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)他的最新文章
他的热门文章
您举报文章:
举报原因:
原文地址:
原因补充:
(最多只允许输入30个字)}

我要回帖

更多关于 相机标定棋盘格 的文章

更多推荐

版权声明:文章内容来源于网络,版权归原作者所有,如有侵权请点击这里与我们联系,我们将及时删除。

点击添加站长微信