(一)初始化需要的数据、资源
(二)calibrate第一步-----求内外参数
(三)calibrate第二步-----利用ceres第一次优化
(四)calibrate第三步-----求畸变系数
(五)calibrate第四步-----第二次优化
(六)利用优化后的内外参、畸变系数矫正整个图像
棋盘格图片素材来自opencv库中自带的棋盘格图片,在如下目录自取,共14张图
例如:
如果利用opencv提供的图片求出内外参数,怎么检验求出的结果对不对呢?
两种方法:
1.找这个文件,里面有参数,将自己求得的参数对照下,如果差的像素不多,说明求得的正确,笔者求得差3-10像素。
2.利用自己求得的参数进行重投影,投影到图像上,观察是否和角点位置相差不多。
为了后面讲解方便,将所有需要用到变量声明
int main(){
ifstream fin("calibration.txt"); //标定所用图像文件的路径为避免出错最后是绝对路径
ofstream fout("calibration_result.txt"); //保存标定结果的文件
int image_count = 0; // 图像数量
Size image_size; // 图像的尺寸
Size board_size = Size(9, 6); // 标定板上每行、列的角点数
vector<Point2f> image_points_buf; //缓存每幅图像上检测到的角点
vector<vector<Point2f> > image_points_seq; //保存检测到的所有角点
string filename; // 图片名
vector<string> filenames;
vector<vector<Point3f> > object_points; //标定板上角点的三维坐标
Mat distCoeffs= Mat(1, 5, CV_32FC1,Scalar::all(0)); //5个畸变系数:k1,k2,p1,p2,k3
vector<int> point_counts; //每幅图像中角点的数量
vector<Mat> tvecsMat; //每幅图像的旋转向量
vector<Mat> rvecsMat; //每幅图像的平移向量
vector<vector<Point2f> > uv;
vector<vector<Point3f> > uv1;
vector<vector<Point3f> > xy1;
vector<vector<Mat> > M_alluv1;
vector<vector<Mat> > M_allxy1;
vector<Mat> H;
Mat cameraMatrix = Mat(3, 3, CV_32FC1, Scalar::all(0)); //内参数矩阵
float scale;
vector<Mat> R_r;
vector<Mat> Jett;
vector<Mat> tvecsMat1;
vector<Mat> outcan;
vector<vector<Point2d> > uuvv;
vector<vector<Point3d> > object_pointses;
int CornerNum = board_size.width * board_size.height;
double incamera[5];
vector<Mat> outcameraR1;
vector<Mat> outcameraR2;
vector<Mat> outcameraT;
InintRead_Save(fin,image_count,image_size,board_size,image_points_buf,image_points_seq,filename,filenames);//初始化角点并存储
Init_object_points(object_points, image_count, board_size);//初始化标定板上角点的三维坐标
Init_point_counts(point_counts, image_count, board_size); //初始化每幅图像中的角点数量
}
此函数功能是读取图片,获取角点并初始化
void InintRead_Save(ifstream& fin, int& image_count, Size& image_size, Size& board_size,
vector<Point2f>& image_points_buf, vector<vector<Point2f> >& image_points_seq,
string& filename, vector<string>& filenames)
{
while (getline(fin, filename))
{
++image_count;
cout<<"image_count = "<<image_count<<endl;
cout<<"filename: "<<filename<<endl;
Mat imageInput = imread(filename);
filenames.push_back(filename);
if(image_count == 1)
{
image_size.width = imageInput.cols;
image_size.height = imageInput.rows;
cout<<"image_size.width = "<<image_size.width<<endl;
cout<<"image_size.height = "<<image_size.height<<endl;
}
// 提取角点 需要使用findChessboardCorners函数提取角点,必须是8位的灰度或者彩色图像
if (0 == findChessboardCorners(imageInput, board_size, image_points_buf))
{
cout << "can not find chessboard corners!\n"; // 找不到角点
exit(1);
}
else
{
Mat view_gray;
cvtColor(imageInput, view_gray, CV_RGB2GRAY); // 转灰度图
cornerSubPix(view_gray, image_points_buf, Size(5,5), Size(-1,-1), TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 30, 0.1));//亚像素精确化
image_points_seq.push_back(image_points_buf); // 保存亚像素角点
drawChessboardCorners(view_gray, board_size, image_points_buf, false); // 图片中标记角点
imshow("Camera Calibration", view_gray); // 显示图片
waitKey(0);
}
}
}
此函数功能是初始化每张图片上角点对应的三维点坐标
void Init_object_points(vector<vector<Point3f> >& object_points, int& image_count, Size& board_size)
{
Size square_size = Size(10,10);/* 实际测量得到的标定板上每个棋盘格的大小 */
for (int t=0; t<image_count; t++) //第几张图片
{
vector<Point3f> tempPointSet;
for (int i=0; i<board_size.height; i++)
{
for (int j=0; j<board_size.width; j++)
{
Point3f realPoint;
realPoint.x = j * square_size.width;
realPoint.y = i * square_size.height;
realPoint.z = 0;
tempPointSet.push_back(realPoint);
}
}
object_points.push_back(tempPointSet);
}
}
初始化每幅图像中的角点数量
void Init_point_counts(vector<int>& point_counts, int& image_count, Size& board_size)
{
for (int i=0; i<image_count; i++)
{
point_counts.push_back(board_size.width * board_size.height);
}
}
下一篇博客讲介绍calibrate()函数中第一步------求解内外参数。
转载请注明出处。