標定相機函式演示
calibrateCamera函式的實際用法
標定相機引數之前,要拍10張以上標定板圖片併成功提取標定板中的角點之後才可以進行標定相機的內外引數
程式碼如下:
//計算標定資料
void QGuiCalib3d::btnCalcCalibData_clicked()
{
int ImgTotal = m_vcImagePointsSeq。size();
if (ImgTotal < 11)
{
QMessageBox msgBox;
msgBox。setText(“圖片數量不夠12張”);
msgBox。setIcon(QMessageBox::Warning);
msgBox。setWindowIcon(QIcon(“:/OpenCVTestSf/ico/opencv-logo。ico”));
msgBox。exec();
return;
}
m_boardSize。width = ui。lineEditBoardCol->text()。toInt();
m_boardSize。height = ui。lineEditBoardRow->text()。toInt();
m_squareSize。width = ui。lineEditSquareWidth->text()。toInt();
m_squareSize。height = ui。lineEditSquareHeight->text()。toInt();
//在指定的資料夾中寫入到指定的檔案
QString qsFilepath = QCoreApplication::applicationDirPath() + “/Calibration/”;
QDir* pFolder = new QDir;
bool bExist = pFolder->exists(qsFilepath);//資料夾是否存在
if (!bExist)
pFolder->mkdir(qsFilepath);//建立資料夾
QDateTime* datatime = new QDateTime(QDateTime::currentDateTime());
QString strTime = datatime->toString(“yyyy_MM_dd hh_mm_ss ”);
string filepath = qsFilepath。toStdString();
string fileTime = strTime。toStdString();
string filexmlname = “CalibrationCalibData。yaml”;
string fileName = filepath + fileTime + filexmlname;
FileStorage fwriteCalibData(fileName, FileStorage::WRITE);//以寫入的模式開啟檔案
vector
int i, j, t;
for (t = 0; t < ImgTotal; t++)
{
vector
for (i = 0; i < m_boardSize。height; i++)
{
for (j = 0; j < m_boardSize。width; j++)
{
Point3f realPoint;
// 假設標定板放在世界座標系中z=0的平面上
realPoint。x = (float)i * m_squareSize。width;
realPoint。y = (float)j * m_squareSize。height;
realPoint。z = 0;
tempPointSet。push_back(realPoint);
}
}
objectPoints。push_back(tempPointSet);//每張標定板圖的所有座標
}
fwriteCalibData << “worldPoints”
<< “{”
<< “objectPoints” << objectPoints
<< “}”;
vector
vector
try
{
/*開始標定 返回值是重投影的總的均方根誤差*/
double res = calibrateCamera(
objectPoints,//世界座標系中的三維點
m_vcImagePointsSeq,//為每一個內角點對應的影象座標點
m_imageSize,//為影象的畫素尺寸大小,在計算相機的內參和畸變矩陣時需要使用到該引數
m_cameraMatrix,//為相機的內參矩陣
m_distCoeffs,//為畸變矩陣
vcRotateMat,//為旋轉向量
vcMoveMat,//為位移向量
0);//為標定時所採用的演算法
}
catch (cv::Exception& e)
{
const char* err_msg = e。what();
QMessageBox msgBox;
msgBox。setText(err_msg);
msgBox。setIcon(QMessageBox::Warning);
msgBox。setWindowIcon(QIcon(“:/OpenCVTestSf/ico/opencv-logo。ico”));
msgBox。exec();
return;
}
// 每幅影象中角點的數量
vector
for (i = 0; i < ImgTotal; i++)
{
// 初始化每幅影象中的角點數量,假定每幅影象中都可以看到完整的標定板
pointCounts。push_back(m_boardSize。width * m_boardSize。height);
fwriteCalibData << “pointCounts”
<< “{”
<< “num” << i
<< “count” << m_boardSize
<< “point” << objectPoints[i]
<< “RotateMat” << vcRotateMat[i]
<< “MoveMat” << vcMoveMat[i]
<< “}”;
}
double totalErr = 0。0; // 所有影象的平均誤差的總和
for (i = 0; i < ImgTotal; i++)
{
// 儲存重新計算得到的投影點
vector
//對空間的三維點進行重新投影計算,得到新的投影點
projectPoints(
objectPoints[i], //世界座標系中的三維點
vcRotateMat[i], //旋轉向量
vcMoveMat[i], //平移向量
m_cameraMatrix, //相機內參
m_distCoeffs, //相機外參
newPoints); //計算出的新的投影點
// 計算新的投影點和舊的投影點之間的誤差
Mat tempImagePointMat = Mat(1, m_vcImagePointsSeq[i]。size(), CV_32FC2);
Mat imagePoints2Mat = Mat(1, newPoints。size(), CV_32FC2);
for (int j = 0; j < (int)m_vcImagePointsSeq[i]。size(); j++)
{
float fx = newPoints[j]。x;
float fy = newPoints[j]。y;
imagePoints2Mat。at
float imgx = m_vcImagePointsSeq[i][j]。x;
float imgy = m_vcImagePointsSeq[i][j]。y;
tempImagePointMat。at
}
double err = norm(imagePoints2Mat, tempImagePointMat, NORM_L2);// 每幅影象的平均誤差
double err1 = err / pointCounts[i];
totalErr += err1;
fwriteCalibData << “imgpoints”
<< “{”
<< “imgnum” << i
<< “newx” << newPoints
<< “oldx” << m_vcImagePointsSeq[i]
<< “normerr” << err
<< “err” << err1
<< “totalerr” << totalErr
<< “}”;
}
double rAverErr = totalErr / ImgTotal;
fwriteCalibData << “AverErr” << rAverErr;
QString szText1;
szText1。sprintf(“標定平均誤差 %。3f \n”, rAverErr);
vector
vcCamera。clear();
vector
vcCoeff。clear();
//獲得的內參引數
QString szText2 = “內參引數:\n”;
for (int i = 0; i < m_cameraMatrix。rows; i++)
{
for (int j = 0; j < m_cameraMatrix。cols; j++)
{
double value = m_cameraMatrix。at
QString temp = QString(“%1 ”)。arg(value);
szText2。append(temp);
vcCamera。push_back(value);
}
szText2。append(“\n”);
}
//畸變係數
QString szText3 = “畸變係數:\n”;
for (int i = 0; i < m_distCoeffs。rows; i++)
{
fwriteCalibData << “i” << i;
for (int j = 0; j < m_distCoeffs。cols; j++)
{
double value = m_distCoeffs。at
QString temp = QString(“%1 ”)。arg(value);
szText3。append(temp);
vcCoeff。push_back(value);
}
szText3。append(“\n”);
}
//儲存每幅影象的旋轉矩陣
vector
rotationMatrix。clear();
for (int i = 0; i < ImgTotal; i++)
{
Mat matric = Mat(3, 3, CV_32FC1, Scalar::all(0));
rotationMatrix。push_back(matric);
}
for (int i = 0; i < ImgTotal; i++)
{
// 將旋轉向量轉換為相對應的旋轉矩陣
Rodrigues(vcRotateMat[i], rotationMatrix[i]);
}
fwriteCalibData << “cameraData”
<< “{”
<< “cameraMatrix” << m_cameraMatrix
<< “distCoeffs” << m_distCoeffs
<< “vcRotateMat” << vcRotateMat
<< “rotationMatrix” << rotationMatrix
<< “}”;
fwriteCalibData。release();//關閉檔案
QString readStr;
readStr。append(szText1);
readStr。append(szText2);
readStr。append(szText3);
ui。textBrowser->clear();
ui。textBrowser->setText(readStr);
}
我這裡取的是不低於11張標定板圖片的角點資料
上一篇:opencv_相機標定
下一篇:碳酸氫鈉為什麼叫小蘇打?