【OpenCV】攝像機標定+畸變校正
攝像機標定
本文目的在於記錄如何使用MATLAB做攝像機標定,並通過opencv進行校正後的顯示。
對於攝像機我們所關心的主要引數為攝像機內參,以及幾個畸變係數。上面的連線中後半部分也給瞭如何標定,然而OpenCV自帶的標定程式稍顯繁瑣。因而在本文中我主推使用MATLAB的工具箱。下面讓我們開始標定過程。
標定板
方法二:逼格滿滿(MATLAB)
J = (checkerboard(300,4,5)>0.5);
figure, imshow(J);
採集資料
那麼有了棋盤格之後自然是需要進行照片了。不多說,直接上程式。按q鍵即可儲存影象,儘量把鏡頭的各個角度都覆蓋好。
#include "opencv2/opencv.hpp"
#include <string>
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
VideoCapture inputVideo(0);
//inputVideo.set(CV_CAP_PROP_FRAME_WIDTH, 320);
//inputVideo.set(CV_CAP_PROP_FRAME_HEIGHT, 240);
if (!inputVideo.isOpened())
{
cout << "Could not open the input video " << endl;
return -1;
}
Mat frame;
string imgname;
int f = 1;
while (1) //Show the image captured in the window and repeat
{
inputVideo >> frame; // read
if (frame.empty()) break; // check if at end
imshow("Camera", frame);
char key = waitKey(1);
if (key == 27)break;
if (key == 'q' || key == 'Q')
{
imgname = to_string(f++) + ".jpg";
imwrite(imgname, frame);
}
}
cout << "Finished writing" << endl;
return 0;
}
儲存大約15到20張即可。大家可以看到我的方法,直接對著實驗室的螢幕拍攝的。這個階段有個注意事項就是測量好螢幕上每個方格的大小,這個標定的時候會用到。
進行標定
直接而在MATLAB的Command Window裡面輸入cameraCalibrator即可呼叫標定應用。
首先先把之前照好的影象新增進去,這是出現:
這就是之前讓你記錄的標定板中每個方格的大小。
輸入無誤後就涉及到最關鍵的一步了(MATLAB的這個實在太方便了,都是傻瓜式操作),選擇引數。
為什麼說他關鍵呢,因為如果你仔細閱讀了OpenCV的說明之後你會大概明白畸變引數,總共有五個,徑向畸變3個(k1,k2,k3)和切向畸變2個(p1,p2)。
徑向畸變:
切向畸變:
以及在OpenCV中的畸變係數的排列(這點一定要注意k1,k2,p1,p2,k3),千萬不要以為k是連著的。
並且通過實驗表明,三個引數的時候由於k3所對應的非線性較為劇烈。估計的不好,容易產生極大的扭曲,所以我們在MATLAB中選擇使用兩引數,並且選擇錯切和桶形畸變。
點選開始後等待一段時間即可完成標定。並且MATLAB給出的視覺化還是很不錯的,可以對比校正前後的樣子。
點選show Undistorted即可看到無畸變的影象。
到這為止,你已經完成了標定過程。選擇匯出引數,即可把引數進行儲存。
儲存後可以退出標定應用,在MATLAB主介面中將儲存的Mat檔案開啟。
第二行就是引數
裡面的RadialDistortion對應k1,k2,k3設定為0了。
TangentialDistortion對應p1,p2。
IntrinsicMatrix對應內參,注意這個和OpenCV中是轉置的關係,注意不要搞錯。
對應
OpenCV中檢視標定的結果
直接上程式碼。
#include "opencv2/opencv.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main()
{
VideoCapture inputVideo(0);
if (!inputVideo.isOpened())
{
cout << "Could not open the input video: " << endl;
return -1;
}
Mat frame;
Mat frameCalibration;
inputVideo >> frame;
Mat cameraMatrix = Mat::eye(3, 3, CV_64F);
cameraMatrix.at<double>(0, 0) = 4.450537506243416e+02;
cameraMatrix.at<double>(0, 1) = 0.192095145445498;
cameraMatrix.at<double>(0, 2) = 3.271489590204837e+02;
cameraMatrix.at<double>(1, 1) = 4.473690628394497e+02;
cameraMatrix.at<double>(1, 2) = 2.442734958206504e+02;
Mat distCoeffs = Mat::zeros(5, 1, CV_64F);
distCoeffs.at<double>(0, 0) = -0.320311439187776;
distCoeffs.at<double>(1, 0) = 0.117708464407889;
distCoeffs.at<double>(2, 0) = -0.00548954846049678;
distCoeffs.at<double>(3, 0) = 0.00141925006352090;
distCoeffs.at<double>(4, 0) = 0;
Mat view, rview, map1, map2;
Size imageSize;
imageSize = frame.size();
initUndistortRectifyMap(cameraMatrix, distCoeffs, Mat(),
getOptimalNewCameraMatrix(cameraMatrix, distCoeffs, imageSize, 1, imageSize, 0),
imageSize, CV_16SC2, map1, map2);
while (1) //Show the image captured in the window and repeat
{
inputVideo >> frame; // read
if (frame.empty()) break; // check if at end
remap(frame, frameCalibration, map1, map2, INTER_LINEAR);
imshow("Origianl", frame);
imshow("Calibration", frameCalibration);
char key = waitKey(1);
if (key == 27 || key == 'q' || key == 'Q')break;
}
return 0;
}
相信此時你的鏡頭的畸變也得到了修復。
還有就是之前討論的為什麼選2係數而不是3係數。因為。。。。。。。
下面是三係數的修正結果,慘不忍睹啊。