聊一聊OpenCV相機(jī)標(biāo)定
相機(jī)標(biāo)定:簡(jiǎn)單的說(shuō),就是獲得相機(jī)參數(shù)的過(guò)程。參數(shù)如:相機(jī)內(nèi)參數(shù)矩陣,投影矩陣,旋轉(zhuǎn)矩陣和平移矩陣等
什么叫相機(jī)參數(shù)?
簡(jiǎn)單的說(shuō),將現(xiàn)實(shí)世界中的人、物,拍成一張圖像(二維)。人或物在世界中的三維坐標(biāo),和圖像上對(duì)應(yīng)的二維坐標(biāo)間的關(guān)系。表達(dá)兩種不同維度坐標(biāo)間的關(guān)系用啥表示?用相機(jī)參數(shù)。
相機(jī)的成像原理
先來(lái)看一下,相機(jī)的成像原理:
如圖所示,這是一個(gè)相機(jī)模型。將物體簡(jiǎn)化看成一個(gè)點(diǎn)。來(lái)自物體的光,通過(guò)鏡頭,擊中圖像平面(圖像傳感器),以此成像。d0是物體到鏡頭的距離,di時(shí)鏡頭到圖像平面的距離,f是鏡頭的焦距。三者滿(mǎn)足以下關(guān)系。
現(xiàn)在,簡(jiǎn)化上面的相機(jī)模型。
將相機(jī)孔徑看成無(wú)窮小,只考慮中心位置的射線(xiàn),這樣就忽視了透鏡的影響。然后由于d0遠(yuǎn)遠(yuǎn)大于di,將圖像平面放在焦距處,這樣物體在圖像平面上成像為倒立的影像(沒(méi)有透鏡的影響,只考慮從中心的孔徑進(jìn)入的光線(xiàn))。這個(gè)簡(jiǎn)化的模型就是針孔攝像機(jī)模型。然后,我們?cè)阽R頭前,將圖像平面放在焦距距離的位置,就可以簡(jiǎn)單獲得一個(gè)筆直的圖像(不倒立)。當(dāng)然,這只是理論上的,你不可能將圖像傳感器從相機(jī)里拿出來(lái),放在鏡頭前面。實(shí)際應(yīng)用中,針孔攝像機(jī)應(yīng)該是將成像后的圖像倒過(guò)來(lái),以獲得正立的圖像。
到此,我們獲得了一個(gè)簡(jiǎn)化的模型,如下圖:
h0是物體的高,hi是圖像上物體的高,f是焦距(距離),d0是圖像到鏡頭的距離。四者滿(mǎn)足如下關(guān)系:
(1)
物體在圖像中的高度hi,和d0成反比。也就是說(shuō),離鏡頭越遠(yuǎn),物體在圖像中越小,離得越近越大(好吧,這句話(huà)是廢話(huà))。
但通過(guò)這個(gè)式子,我們便能夠預(yù)測(cè)三維中的物體,在圖像(二維)中的位置。那么怎么預(yù)測(cè)?
相機(jī)標(biāo)定
如下圖所示,根據(jù)上面簡(jiǎn)化的模型,考慮三維世界中的一個(gè)點(diǎn),和其在圖像(二維)中的坐標(biāo)關(guān)系。
(X,Y,Z)為點(diǎn)的三維坐標(biāo),(x,y)為其通過(guò)相機(jī)成像后在圖像(二維)上的坐標(biāo)。u0和v0是相機(jī)的中心點(diǎn)(主點(diǎn)),該點(diǎn)位于圖像平面中心(理論上是這樣。但實(shí)際的相機(jī)會(huì)有幾個(gè)像素的偏差)
現(xiàn)在只考慮y方向上,由于需要將三維世界中的坐標(biāo),轉(zhuǎn)換為圖像上的像素(圖像上的坐標(biāo),實(shí)際上是像素的位置),需要求y方向上焦距等于多少個(gè)像素(用像素值表示焦距),Py表示像素的高,焦距f(米或毫米)。垂直像素表示的焦距為
根據(jù)式子(1),只考慮y方向。我們?nèi)S世界中得點(diǎn),在圖像(二維)中y的坐標(biāo)。
同理,得到x的坐標(biāo)。
現(xiàn)在,將上圖中的坐標(biāo)系的原點(diǎn)O,移動(dòng)到圖像的左上角。由于(x,y)是關(guān)于(u0,v0)的偏移,上面表示圖像(二維)中點(diǎn)的坐標(biāo)的式子不變。將式子以矩陣的形式重寫(xiě),得。
其中,等式左邊的第一個(gè)矩陣,叫做“相機(jī)內(nèi)參數(shù)矩陣”,第二個(gè)矩陣叫(投影矩陣)。
更為一般的情況,開(kāi)始時(shí)的參考坐標(biāo)系不位于主點(diǎn)(中心點(diǎn)),需要額外兩個(gè)參數(shù)“旋轉(zhuǎn)向量”和“平移向量”來(lái)表示這個(gè)式子,這兩個(gè)參數(shù)在不同視角中是不一樣的。整合后,上述式子重寫(xiě)為。
校正畸變
通過(guò)相機(jī)標(biāo)定,獲得了相機(jī)參數(shù)后,可以計(jì)算兩個(gè)映射函數(shù)(x坐標(biāo)和y坐標(biāo)),它們分別給出了沒(méi)有畸變的圖像坐標(biāo)。將畸變的圖像重新映射成為沒(méi)有畸變的圖像。
代碼:
做相機(jī)標(biāo)定時(shí),一般用標(biāo)定板(棋盤(pán))拍攝一組圖像,利用這些圖像提取角點(diǎn),通過(guò)角點(diǎn)在圖像中得坐標(biāo)和三維世界中的坐標(biāo)(通常自定義3維坐標(biāo)),計(jì)算相機(jī)參數(shù)。
std::vector<cv::Point2f>imageConers; //提取標(biāo)定圖像角點(diǎn),保存角點(diǎn)坐標(biāo)(二維) cv::findChessboardCorners(image, boardSize, //角點(diǎn)數(shù)目如(6,4)六行,四列 imageConers);
函數(shù)calibrateCamera完成相機(jī)標(biāo)定工作。
cv::calibrateCamera(objectPoints,//三維坐標(biāo) imagePoints, //二維坐標(biāo) imageSize,//圖像大小 camerMatirx,//相機(jī)內(nèi)參數(shù)矩陣 disCoeffs,//投影矩陣 rvecs, //旋轉(zhuǎn) tvecs,//平移 flag //標(biāo)記opencv提供幾種參數(shù),可以參看在線(xiàn)的opencv document );
計(jì)算畸變參數(shù),去畸變
//計(jì)算畸變參數(shù) cv::initUndistortRectifyMap(camerMatirx, disCoeffs, cv::Mat(), cv::Mat(), image.size(), CV_32FC1, map1, //x映射函數(shù) map2 //y映射函數(shù) ); //應(yīng)用映射函數(shù) cv::remap(image, //畸變圖像 undistorted, //去畸變圖像 map1, map2, cv::INTER_LINEAR);
現(xiàn)在整合代碼。
示例:
標(biāo)頭.h
#include<opencv2\core\core.hpp> #include<opencv2\highgui\highgui.hpp> #include<opencv2\imgproc\imgproc.hpp> #include<opencv2\calib3d\calib3d.hpp> #include <opencv2/features2d/features2d.hpp> #include<string> #include<vector> class CameraCalibrator { private: //世界坐標(biāo) std::vector < std::vector<cv::Point3f >> objectPoints; //圖像坐標(biāo) std::vector <std::vector<cv::Point2f>> imagePoints; //輸出矩陣 cv::Mat camerMatirx; cv::Mat disCoeffs; //標(biāo)記 int flag; //去畸變參數(shù) cv::Mat map1, map2; //是否去畸變 bool mustInitUndistort; ///保存點(diǎn)數(shù)據(jù) void addPoints(const std::vector<cv::Point2f>&imageConers, const std::vector<cv::Point3f>&objectConers) { imagePoints.push_back(imageConers); objectPoints.push_back(objectConers); } public: CameraCalibrator() :flag(0), mustInitUndistort(true){} //打開(kāi)棋盤(pán)圖片,提取角點(diǎn) int addChessboardPoints(const std::vector<std::string>&filelist,cv::Size &boardSize) { std::vector<cv::Point2f>imageConers; std::vector<cv::Point3f>objectConers; //輸入角點(diǎn)的世界坐標(biāo) for (int i = 0; i < boardSize.height; i++) { for (int j = 0; j < boardSize.width; j++) { objectConers.push_back(cv::Point3f(i, j, 0.0f)); } } //計(jì)算角點(diǎn)在圖像中的坐標(biāo) cv::Mat image; int success = 0; for (int i = 0; i < filelist.size(); i++) { image = cv::imread(filelist[i],0); //找到角點(diǎn)坐標(biāo) bool found = cv::findChessboardCorners(image, boardSize, imageConers); cv::cornerSubPix(image, imageConers, cv::Size(5, 5), cv::Size(-1, -1), cv::TermCriteria(cv::TermCriteria::MAX_ITER + cv::TermCriteria::EPS, 30, 0.1)); if (imageConers.size() == boardSize.area()) { addPoints(imageConers, objectConers); success++; } //畫(huà)出角點(diǎn) cv::drawChessboardCorners(image, boardSize, imageConers, found); cv::imshow("Corners on Chessboard", image); cv::waitKey(100); } return success; } //相機(jī)標(biāo)定 double calibrate(cv::Size&imageSize) { mustInitUndistort = true; std::vector<cv::Mat>rvecs, tvecs; //相機(jī)標(biāo)定 return cv::calibrateCamera(objectPoints, imagePoints, imageSize, camerMatirx, disCoeffs, rvecs, tvecs, flag); } ///去畸變 cv::Mat remap(const cv::Mat &image) { cv::Mat undistorted; if (mustInitUndistort) { //計(jì)算畸變參數(shù) cv::initUndistortRectifyMap(camerMatirx, disCoeffs, cv::Mat(), cv::Mat(), image.size(), CV_32FC1, map1, map2); mustInitUndistort = false; } //應(yīng)用映射函數(shù) cv::remap(image, undistorted, map1, map2, cv::INTER_LINEAR); return undistorted; } //常成員函數(shù),獲得相機(jī)內(nèi)參數(shù)矩陣、投影矩陣數(shù)據(jù) cv::Mat getCameraMatrix() const { return camerMatirx; } cv::Mat getDistCoeffs() const { return disCoeffs; } };
源.cpp
#include"標(biāo)頭.h" #include<iomanip> #include<iostream> int main() { CameraCalibrator Cc; cv::Mat image; std::vector<std::string> filelist; cv::namedWindow("Image"); for (int i = 1; i <= 22; i++) { ///讀取圖片 std::stringstream s; s << "D:/images/chessboards/chessboard" << std::setw(2) << std::setfill('0') << i << ".jpg"; std::cout << s.str() << std::endl; filelist.push_back(s.str()); image = cv::imread(s.str(),0); cv::imshow("Image", image); cv::waitKey(100); } //相機(jī)標(biāo)定 cv::Size boardSize(6, 4); Cc.addChessboardPoints(filelist, boardSize); Cc.calibrate(image.size()); //去畸變 image = cv::imread(filelist[1]); cv::Mat uImage=Cc.remap(image); cv::imshow("原圖像", image); cv::imshow("去畸變", uImage); //顯示相機(jī)內(nèi)參數(shù)矩陣 cv::Mat cameraMatrix = Cc.getCameraMatrix(); std::cout << " Camera intrinsic: " << cameraMatrix.rows << "x" << cameraMatrix.cols << std::endl; std::cout << cameraMatrix.at<double>(0, 0) << " " << cameraMatrix.at<double>(0, 1) << " " << cameraMatrix.at<double>(0, 2) << std::endl; std::cout << cameraMatrix.at<double>(1, 0) << " " << cameraMatrix.at<double>(1, 1) << " " << cameraMatrix.at<double>(1, 2) << std::endl; std::cout << cameraMatrix.at<double>(2, 0) << " " << cameraMatrix.at<double>(2, 1) << " " << cameraMatrix.at<double>(2, 2) << std::endl; cv::waitKey(0); }
實(shí)驗(yàn)結(jié)果:
看以看到,相機(jī)內(nèi)參數(shù)矩陣為
172.654 、0、157.829
0、184.195、118.635
0 、0 、1
以上就是本文的全部?jī)?nèi)容,希望對(duì)大家的學(xué)習(xí)有所幫助,也希望大家多多支持我們。
上一篇:C++實(shí)現(xiàn)英文句子中的單詞逆序輸出的方法
欄 目:C語(yǔ)言
下一篇:C語(yǔ)言實(shí)現(xiàn)桶排序的方法示例
本文標(biāo)題:聊一聊OpenCV相機(jī)標(biāo)定
本文地址:http://mengdiqiu.com.cn/a1/Cyuyan/996.html
您可能感興趣的文章
- 01-10實(shí)現(xiàn)opencv圖像裁剪分屏顯示示例
- 01-10使用opencv拉伸圖像擴(kuò)大分辨率示例
- 01-10C++設(shè)計(jì)模式之享元模式
- 01-10基于C++實(shí)現(xiàn)kinect+opencv 獲取深度及彩色數(shù)據(jù)
- 01-10socket多人聊天程序C語(yǔ)言版(二)
- 01-10socket多人聊天程序C語(yǔ)言版(一)
- 01-10淺談CMake配置OpenCV 時(shí)靜態(tài)鏈接與動(dòng)態(tài)鏈接的選擇
- 01-10OpenCV中C++函數(shù)imread讀取圖片的問(wèn)題及解決方法
- 01-10visual studio 2013中配置opencv圖文教程 Opencv2.4.9安裝配置教程
- 01-10OPENCV批量讀取圖片實(shí)現(xiàn)方法


閱讀排行
- 1C語(yǔ)言 while語(yǔ)句的用法詳解
- 2java 實(shí)現(xiàn)簡(jiǎn)單圣誕樹(shù)的示例代碼(圣誕
- 3利用C語(yǔ)言實(shí)現(xiàn)“百馬百擔(dān)”問(wèn)題方法
- 4C語(yǔ)言中計(jì)算正弦的相關(guān)函數(shù)總結(jié)
- 5c語(yǔ)言計(jì)算三角形面積代碼
- 6什么是 WSH(腳本宿主)的詳細(xì)解釋
- 7C++ 中隨機(jī)函數(shù)random函數(shù)的使用方法
- 8正則表達(dá)式匹配各種特殊字符
- 9C語(yǔ)言十進(jìn)制轉(zhuǎn)二進(jìn)制代碼實(shí)例
- 10C語(yǔ)言查找數(shù)組里數(shù)字重復(fù)次數(shù)的方法
本欄相關(guān)
- 04-02c語(yǔ)言函數(shù)調(diào)用后清空內(nèi)存 c語(yǔ)言調(diào)用
- 04-02func函數(shù)+在C語(yǔ)言 func函數(shù)在c語(yǔ)言中
- 04-02c語(yǔ)言的正則匹配函數(shù) c語(yǔ)言正則表達(dá)
- 04-02c語(yǔ)言用函數(shù)寫(xiě)分段 用c語(yǔ)言表示分段
- 04-02c語(yǔ)言中對(duì)數(shù)函數(shù)的表達(dá)式 c語(yǔ)言中對(duì)
- 04-02c語(yǔ)言編寫(xiě)函數(shù)冒泡排序 c語(yǔ)言冒泡排
- 04-02c語(yǔ)言沒(méi)有round函數(shù) round c語(yǔ)言
- 04-02c語(yǔ)言分段函數(shù)怎么求 用c語(yǔ)言求分段
- 04-02C語(yǔ)言中怎么打出三角函數(shù) c語(yǔ)言中怎
- 04-02c語(yǔ)言調(diào)用函數(shù)求fibo C語(yǔ)言調(diào)用函數(shù)求
隨機(jī)閱讀
- 08-05織夢(mèng)dedecms什么時(shí)候用欄目交叉功能?
- 08-05DEDE織夢(mèng)data目錄下的sessions文件夾有什
- 01-10C#中split用法實(shí)例總結(jié)
- 01-10使用C語(yǔ)言求解撲克牌的順子及n個(gè)骰子
- 08-05dedecms(織夢(mèng))副欄目數(shù)量限制代碼修改
- 04-02jquery與jsp,用jquery
- 01-10SublimeText編譯C開(kāi)發(fā)環(huán)境設(shè)置
- 01-11Mac OSX 打開(kāi)原生自帶讀寫(xiě)NTFS功能(圖文
- 01-10delphi制作wav文件的方法
- 01-11ajax實(shí)現(xiàn)頁(yè)面的局部加載