一、首先說明幾個情況:
1、完成雙目標定必須是自個拿棋盤圖擺拍,網上涉及用opencv自帶的標定圖完成雙目標定僅僅是提供個參考流程。我原來還以爲用自帶的圖標定就行,但想不通的是咱們實際擺放的雙目攝像頭和人家當時擺放的肯定不一樣,那用人家的標定圖怎麼能反應自己攝像頭的實際情況;後來問了大神,才知道用opencv自帶的標定圖(或者說別人提供的圖)進行標定,這是完全沒有意義的。
2、進行雙目標定必須是左右相機同時進行拍攝,再把圖保存下來。這點我是看opencv自帶的圖發現的,左右相機對應的圖擺拍的姿勢是一模一樣的,除了左右相機視角帶來的影響。
3、我是先完成單目標定,再完成雙目標定。記得把理論看看,要不然有些概念不清楚。
二、先固定好左右相機,拿棋盤標定圖擺拍並保存,我左右相機各15張,網上看的說是總共30~40張爲宜,這個大家隨意
1,單目
const int boardWidth = 11; //橫向角點的數目
const int boardHeight = 8; //縱向角點的數目
const int boardCorner = boardWidth * boardHeight; //總角點的數目
const int frameNumber = 19; //共有多少幀的數據
const int squareSize = 25; //標定板黑白格子的大小 單位:mm
const Size boardSize = Size(boardWidth, boardHeight); //總的角點
Mat intrinsic; //相機的內參數
Mat distortion_coeff; //相機的外參數
vector<Mat> rvecs; //旋轉向量
vector<Mat> tvecs; //平移向量
vector<vector<Point2f>> corners; //各個圖找到的角點的集合
vector<vector<Point3f>> objRealPoint; //各個圖的角點的實際物理座標集合
vector<Point2f> corner; //某一副圖像找到的角點
void calRealPoint(vector<vector<Point3f>>& obj, int boardwidth, int boardheight, int imgNumber, int squaresize)
{
vector<Point3f> imgpoint;
for (int rowIndex = 0; rowIndex < boardheight; rowIndex++)
{
for (int colIndex = 0; colIndex < boardwidth; colIndex++)
{
imgpoint.push_back(Point3f(rowIndex * squaresize, colIndex * squaresize, 0));
}
}
for (int imgIndex = 0; imgIndex < imgNumber; imgIndex++)
{
obj.push_back(imgpoint);
}
}
/*設置相機的初始參數,也可以不估計*/
void guessCameraParam()
{
/*分配內存*/
intrinsic.create(3, 3, CV_64FC1); //相機內參數
distortion_coeff.create(5, 1, CV_64FC1); //畸變參數
/*
fx 0 cx
0 fy cy
0 0 1 內參數
*/
intrinsic.at<double>(0, 0) = 256.8093262; //fx
intrinsic.at<double>(0, 2) = 160.2826538; //cx
intrinsic.at<double>(1, 1) = 254.7511139; //fy
intrinsic.at<double>(1, 2) = 127.6264572; //cy
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; //k1
distortion_coeff.at<double>(1, 0) = -0.378588; //k2
distortion_coeff.at<double>(2, 0) = 0.028980; //p1
distortion_coeff.at<double>(3, 0) = 0.008136; //p2
distortion_coeff.at<double>(4, 0) = 1; //p3
}
//打印出結果看一看
void outputCameraParam()
{
printf("fx:%lf...\n", intrinsic.at<double>(0, 0));
printf("fy:%lf...\n", intrinsic.at<double>(1, 1));
printf("cx:%lf...\n", intrinsic.at<double>(0, 2));
printf("cy:%lf...\n", intrinsic.at<double>(1, 2));
printf("k1:%lf...\n", distortion_coeff.at<double>(0, 0));
printf("k2:%lf...\n", distortion_coeff.at<double>(1, 0));
printf("p1:%lf...\n", distortion_coeff.at<double>(2, 0));
printf("p2:%lf...\n", distortion_coeff.at<double>(3, 0));
printf("p3:%lf...\n", distortion_coeff.at<double>(4, 0));
}
//單目相機的
void CameraCalibration()
{
int imageHeight, imageWidth;
vector<String> leftStrings, rightStrings;
vector<Mat> leftMats, rightMats;
glob("C:\\Users\\Ring\\Desktop\\0420\\left\\", leftStrings);
glob("C:\\Users\\Ring\\Desktop\\0420\\right\\", rightStrings);
for (int i = 0; i < leftStrings.size(); i++)
{
leftMats.push_back(imread(leftStrings[i], 0));
rightMats.push_back(imread(rightStrings[i], 0));
}
Mat rgbMat;
for (int i = 0; i < leftMats.size(); i++)
{
Mat src = leftMats[i];
imageHeight = src.rows; imageWidth = src.cols;
cvtColor(src, rgbMat, CV_GRAY2RGB);
Mat showMat = rgbMat.clone();
bool isFind = findChessboardCorners(src, boardSize, corner, CALIB_CB_ADAPTIVE_THRESH +
CALIB_CB_NORMALIZE_IMAGE);
//所有角點都被找到
if (isFind)
{
//精確角點位置,亞像素角點檢測
cornerSubPix(src, corner, Size(5, 5), Size(-1, -1), TermCriteria(CV_TERMCRIT_EPS | CV_TERMCRIT_ITER, 20, 0.1));
//繪製角點
drawChessboardCorners(showMat, boardSize, corner, isFind);
corners.push_back(corner);
}
}
//設置實際初始參數 根據calibrateCamera來 如果flag = 0 也可以不進行設置
guessCameraParam();
//計算實際的校正點的三維座標
calRealPoint(objRealPoint, boardWidth, boardHeight, frameNumber, squareSize);
//標定攝像頭
calibrateCamera(objRealPoint, corners, Size(imageWidth, imageHeight), intrinsic, distortion_coeff, rvecs, tvecs, 0);
//保存並輸出結果
outputCameraParam();
//顯示畸變矯正效果
Mat cImage;
undistort(rgbMat, cImage, intrinsic, distortion_coeff);
cout << "";
}
注意:把你得到的左右相機標定完的參數記下來,雙目標定的時候會用;
2,雙目標定
待完善。。。