上次介绍了calibrateCamera()接口参数,这次实际调用。
程序中所用标准标定板。
一、图片预处理
使用的图片原像素是3072*2048,即600万像素,处理起来不快;改成了560*420,即20万像素。调用opencv接口如下:
// 最小分辨率(560x420像素)
Size dsize = Size(560, 420);
Mat shrink;
resize(img, shrink, dsize, 0, 0, INTER_AREA);
//保存
stringstream str;
str << "../opencv_/data/pic/11" << ".png";
imwrite(str.str(), shrink);
二、相机标定流程
主要是objectPoints:世界坐标系中的点。使用标准棋盘,传入的是交叉点(不包括边角)的实际坐标,以物理实际尺度(如mm)为单位。写坐标时,保证z轴为0,按照先x变化,后y变化,从小到大的顺序来写。如果网格尺寸为12.5毫米,写作:(0,0,0),(12.5,0,0), (25,0,0)...
①读取图片,找到角点,对粗角点精确化
cv::imread(pic)
cv::findCirclesGrid()
cv::find4QuadCornerSubpix()
②设置棋盘三维物理坐标
我使用的是标准圆网格,7*7=49个。
③调用calibrateCamera()接口
程序如下:
程序中cv::Size2f(12.5,12.5)是两圆的中心距。
std::vector imagePointBuf; /* 缓存每幅图像上检测到的角点 */
std::vector imagePointSeq; /* 保存检测到的所有角点 */
int imageCount=0; /* 图像数量 */
cv::Size boardSize = cv::Size(7,7); /* 标定板上每行、列的角点数 */
cv::Size imageSize; /* 图像的尺寸 */
for(int i=1; i<12; i++){
std::string pic("../CalibrateCamera/data/pic/" + std::to_string(i) +".png" );
cv::Mat imageInput = cv::imread(pic);
//cv::findChessboardCorners(imageInput,boardSize,imagePointBuf);
bool ret = cv::findCirclesGrid(imageInput,boardSize,imagePointBuf);
if(true == ret){
qDebug() << "findChessboardCorners success " << i;
imageCount++;
if (1 == imageCount) {
imageSize.width = imageInput.cols;
imageSize.height =imageInput.rows;
}
cv::Mat viewGray;
// cv::cvtColor(imageInput,viewGray,CV_BGR2GRAY);
cv::cvtColor(imageInput,viewGray,cv::COLOR_BGR2GRAY);
/* 亚像素精确化 */
cv::find4QuadCornerSubpix(viewGray,imagePointBuf,cv::Size(7,7)); //对粗提取的角点进行精确化
imagePointSeq.push_back(imagePointBuf); //保存亚像素角点
// cv::drawChessboardCorners(imageInput, boardSize, imagePointBuf, true);
// cv::imshow("Camera Calibration",viewGray);//显示图片
}else{
qDebug() << "findChessboardCorners failed " << i;
}
}
qDebug() << "角点提取完成!\n";
//以下是摄像机标定
qDebug() << "开始标定………………";
/*棋盘三维信息 mm*/
cv::Size2f squareSize = cv::Size2f(12.5,12.5); /* 实际测量得到的标定板上每个棋盘格的大小 */
std::vector <std::vector> objectPoints; /* 保存标定板上角点的三维坐标 */
/*内外参数*/
cv::Mat cameraMatrix = cv::Mat(3,3,CV_32FC1,cv::Scalar::all(0)); /* 摄像机内参数矩阵 */
std::vector pointCounts; // 每幅图像中角点的数量
cv::Mat distCoeffs = cv::Mat(1,5,CV_32FC1,cv::Scalar::all(0)); /* 摄像机的5个畸变系数:k1,k2,p1,p2,k3 */
std::vector rotateMat; /* 每幅图像的旋转向量 */
std::vector transMat; /* 每幅图像的平移向量 */
int i,j,t;
for (t=0;t
std::vector tempPointSet;
for (i=0;i <boardSize.height;i++){< span> </boardSize.height;i++){<>
for (j=0;j <boardSize.width;j++){< span> </boardSize.width;j++){<>
cv::Point3f realPoint;
/* 假设标定板放在世界坐标系中z=0的平面上 */
realPoint.x = i*squareSize.width;
realPoint.y = j*squareSize.height;
realPoint.z = 0;
tempPointSet.push_back(realPoint);
}
}
objectPoints.push_back(tempPointSet);
}
/* 初始化每幅图像中的角点数量,假定每幅图像中都可以看到完整的标定板 */
for (i=0;i <imageCount;i++){< span> </imageCount;i++){<>
pointCounts.push_back(boardSize.width*boardSize.height);
}
/* 开始标定 */
cv::calibrateCamera(objectPoints, imagePointSeq, imageSize,
cameraMatrix, distCoeffs, rotateMat, transMat, 0);
qDebug() <<"标定完成!\n";
未完待续......
如需修改像素程序可在后台留言“修改图片像素”.