上次介绍了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;tstd::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";
未完待续......
5_相机标定_1_标定板选取与角点绘制
5_相机标定2_calibrateCamera()与内外参
如需修改像素程序可在后台留言“修改图片像素”.