1. 程式人生 > >單目相機標定

單目相機標定

主要轉自http://blog.csdn.net/dcrmg/article/details/52929669
執行前需要先準備標定圖片和記錄標定圖片列表的文字檔案,並放入程式所在目錄下
文字檔案的內容如下:
calibdata.txt
裡面填寫好需要標定的圖片名稱
left02.jpg
left03.jpg
left04.jpg
left05.jpg
left06.jpg
left07.jpg
left08.jpg
left09.jpg
left10.jpg
left11.jpg
left12.jpg
left13.jpg
left14.jpg

#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 cv; using namespace std; int main() { ifstream fin("calibdata.txt"); /* 標定所用影象檔案的路徑 */ ofstream fout("caliberation_result.txt"
); /* 儲存標定結果的檔案 */ //讀取每一幅影象,從中提取出角點,然後對角點進行亞畫素精確化 cout<<"開始提取角點………………"; int image_count=0; /* 影象數量 */ Size image_size; /* 影象的尺寸 */ Size board_size = Size(8,7); /* 標定板上每行、列的角點數 */ vector<Point2f> image_points_buf; /* 快取每幅影象上檢測到的角點 */ vector< vector<Point2f>
>
image_points_seq; /* 儲存檢測到的所有角點 */ string filename; int count= -1 ;//用於儲存角點個數。 while (getline(fin,filename)) { image_count++; // 用於觀察檢驗輸出 cout<<"image_count = "<<image_count<<endl; /* 輸出檢驗*/ cout<<"-->count = "<<count; Mat imageInput=imread(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; } /* 提取角點 */ 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); /* 亞畫素精確化 */ find4QuadCornerSubpix(view_gray,image_points_buf,Size(21,21)); //對粗提取的角點進行精確化 image_points_seq.push_back(image_points_buf); //儲存亞畫素角點 /* 在影象上顯示角點位置 */ drawChessboardCorners(view_gray,board_size,image_points_buf,true); //用於在圖片中標記角點 imshow("Camera Calibration",view_gray);//顯示圖片 waitKey(500);//暫停0.5S } } int total = image_points_seq.size(); cout<<"total = "<<total<<endl; int CornerNum=board_size.width*board_size.height; //每張圖片上總的角點數 for (int ii=0 ; ii<total ;ii++) { if (0 == ii%CornerNum)// 24 是每幅圖片的角點個數。此判斷語句是為了輸出 圖片號,便於控制檯觀看 { int i = -1; i = ii/CornerNum; int j=i+1; cout<<"--> 第 "<<j <<"圖片的資料 --> : "<<endl; } if (0 == ii%3) // 此判斷語句,格式化輸出,便於控制檯檢視 { cout<<endl; } else { cout.width(10); } //輸出所有的角點 cout<<" -->"<<image_points_seq[ii][0].x; cout<<" -->"<<image_points_seq[ii][0].y; } cout<<"角點提取完成!\n"; //以下是攝像機標定 cout<<"開始標定………………"; /*棋盤三維資訊*/ Size square_size = Size(20,20); /* 實際測量得到的標定板上每個棋盤格的大小 */ vector<vector<Point3f> > object_points; /* 儲存標定板上角點的三維座標 */ /*內外引數*/ Mat cameraMatrix=Mat(3,3,CV_32FC1,Scalar::all(0)); /* 攝像機內參數矩陣 */ vector<int> point_counts; // 每幅影象中角點的數量 Mat distCoeffs=Mat(1,5,CV_32FC1,Scalar::all(0)); /* 攝像機的5個畸變係數:k1,k2,p1,p2,k3 */ vector<Mat> tvecsMat; /* 每幅影象的旋轉向量 */ vector<Mat> rvecsMat; /* 每幅影象的平移向量 */ /* 初始化標定板上角點的三維座標 */ int i,j,t; for (t=0;t<image_count;t++) { vector<Point3f> tempPointSet; for (i=0;i<board_size.height;i++) { for (j=0;j<board_size.width;j++) { Point3f realPoint; /* 假設標定板放在世界座標系中z=0的平面上 */ realPoint.x = i*square_size.width; realPoint.y = j*square_size.height; realPoint.z = 0; tempPointSet.push_back(realPoint); } } object_points.push_back(tempPointSet); } /* 初始化每幅影象中的角點數量,假定每幅影象中都可以看到完整的標定板 */ for (i=0;i<image_count;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<<"標定完成!\n"; //對標定結果進行評價 cout<<"開始評價標定結果………………\n"; double total_err = 0.0; /* 所有影象的平均誤差的總和 */ double err = 0.0; /* 每幅影象的平均誤差 */ vector<Point2f> image_points2; /* 儲存重新計算得到的投影點 */ cout<<"\t每幅影象的標定誤差:\n"; fout<<"每幅影象的標定誤差:\n"; for (i=0;i<image_count;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]; std::cout<<"第"<<i+1<<"幅影象的平均誤差:"<<err<<"畫素"<<endl; fout<<"第"<<i+1<<"幅影象的平均誤差:"<<err<<"畫素"<<endl; } std::cout<<"總體平均誤差:"<<total_err/image_count<<"畫素"<<endl; fout<<"總體平均誤差:"<<total_err/image_count<<"畫素"<<endl<<endl; std::cout<<"評價完成!"<<endl; //儲存定標結果 std::cout<<"開始儲存定標結果………………"<<endl; Mat rotation_matrix = Mat(3,3,CV_32FC1, Scalar::all(0)); /* 儲存每幅影象的旋轉矩陣 */ fout<<"相機內參數矩陣:"<<endl; fout<<cameraMatrix<<endl<<endl; fout<<"畸變係數:\n"; fout<<distCoeffs<<endl<<endl<<endl; for (int i=0; i<image_count; i++) { fout<<"第"<<i+1<<"幅影象的旋轉向量:"<<endl; fout<<tvecsMat[i]<<endl; /* 將旋轉向量轉換為相對應的旋轉矩陣 */ Rodrigues(tvecsMat[i],rotation_matrix); fout<<"第"<<i+1<<"幅影象的旋轉矩陣:"<<endl; fout<<rotation_matrix<<endl; fout<<"第"<<i+1<<"幅影象的平移向量:"<<endl; fout<<rvecsMat[i]<<endl<<endl; } std::cout<<"完成儲存"<<endl; fout<<endl; system("pause"); return 0; }