OpenCV相機(jī)標(biāo)定與畸變校正
點(diǎn)擊上方“小白學(xué)視覺(jué)”,選擇加"星標(biāo)"或“置頂”
重磅干貨,第一時(shí)間送達(dá)
相機(jī)標(biāo)定定義與原理
在圖像測(cè)量過(guò)程以及機(jī)器視覺(jué)應(yīng)用中,為確定空間物體表面某點(diǎn)的三維幾何位置與其在圖像中對(duì)應(yīng)點(diǎn)之間的相互關(guān)系,必須建立相機(jī)成像的幾何模型,這些幾何模型參數(shù)就是相機(jī)參數(shù)。在大多數(shù)條件下這些參數(shù)必須通過(guò)實(shí)驗(yàn)與計(jì)算才能得到,這個(gè)求解參數(shù)的過(guò)程就稱之為相機(jī)標(biāo)定(或攝像機(jī)標(biāo)定)。相機(jī)標(biāo)定常見(jiàn)的分為:
單目相機(jī)標(biāo)定
雙目相機(jī)標(biāo)定
相機(jī)標(biāo)定是想從二維的圖像中獲取三維信息,實(shí)現(xiàn)圖像的畸變校正、對(duì)象測(cè)量、三維重建等。由于光線投射導(dǎo)致實(shí)際對(duì)象物體跟投影到2D平面的圖像不一致,幸運(yùn)的是這種不一致性是穩(wěn)定的,我們可以通過(guò)對(duì)相機(jī)標(biāo)定,計(jì)算出畸變參數(shù)來(lái)實(shí)現(xiàn)對(duì)后續(xù)圖像的畸變校正。根據(jù)標(biāo)定技術(shù)不一樣可以分為下面幾類標(biāo)定方法:
基于3D對(duì)象參照標(biāo)定
基于2D平面標(biāo)定
基于1D線性標(biāo)定
自標(biāo)定
最常見(jiàn)的相機(jī)成像方式是基于pinhole的模型、它的成像模型可以圖示如下:

下面我們首先對(duì)這個(gè)相機(jī)成像模型做一番解釋

通過(guò)標(biāo)定算法同時(shí)求出相機(jī)內(nèi)參與外參。最常用的算法是張正友標(biāo)定算法。OpenCV/Matlab中均已經(jīng)實(shí)現(xiàn)該算法。
標(biāo)定板介紹與制作
要想實(shí)現(xiàn)對(duì)相機(jī)的標(biāo)定,我們首先需要給相機(jī)找到個(gè)參考對(duì)象,常見(jiàn)的就是標(biāo)定版的類型有如下幾種
Chessboard
Circel-grid
RandPattern
ArUco
ChArUc

OpenCV源碼在其sample/data目錄下面一個(gè)自帶的棋盤圖(chessboard.png),顯示如下:

在標(biāo)定的時(shí)候,算法要求提供的棋盤格的寬度與高度,還有他們的間隔距離。需要特別注意是這里的寬高是指他們的內(nèi)部交叉點(diǎn)的個(gè)數(shù),以上圖為例,它的大小為7x7而不是8x8。間隔是指棋盤格之間的距離,可以用像素距離表示,也可以用實(shí)際毫米為單位表示。
制作標(biāo)定版與圖像生成
最簡(jiǎn)單的辦法就是把上述圖像直接打印出來(lái),貼到一個(gè)塑料底板上就好啦。如果是土豪可以直接購(gòu)買各種玻璃底板的標(biāo)定板。另外還有一個(gè)更惡搞的方法,連打印都省啦,直接把chessboard.png這張圖在另外一臺(tái)電腦的顯示器上顯示,然后把攝像頭對(duì)著它各種牌即可完成圖像數(shù)據(jù)采集。這個(gè)是我手寫的采集程序代碼,每次想保存圖像的時(shí)候請(qǐng)安Q字母鍵即可,代碼如下:
void create_images() {
Mat frame;
VideoCapture capture(0);
int index = 1;
while (true) {
bool ret = capture.read(frame);
flip(frame, frame, 1);
if (!ret) break;
imshow("frame", frame);
char c = waitKey(50);
printf("%d
", c);
if (c == 113) { // Q
imwrite(format("D:/images/zsxq/%d.png", index), frame);
index += 1;
}
if (c == 27) {
break; // ESC
}
}
capture.release();
}記得拿著棋盤格圖,在鏡頭面前各種擺POSE,這個(gè)是屬于你的表演時(shí)間,不要客氣!具體參考下圖:

相機(jī)標(biāo)定程序?qū)崿F(xiàn)
大家好,現(xiàn)在我們開(kāi)始程序?qū)崿F(xiàn)環(huán)節(jié),OpenCV中在camera模塊中已經(jīng)實(shí)現(xiàn)了張正友標(biāo)定算法。我們只需要正確調(diào)用,就可以計(jì)算出相機(jī)的內(nèi)參與外參,完成相機(jī)的標(biāo)定。具體的代碼實(shí)現(xiàn)步驟如下:
定義相機(jī)標(biāo)定的相關(guān)常量設(shè)置與變量
// load image files
vector<string> files;
glob("D:/images/camera2d", files);
// 定義變量
vector<vector<Point2f>> imagePoints;
vector<vector<Point3f>> objectPoints;
TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER, 30, 0.001);
int numCornersHor = 7;
int numCornersVer = 7;
int numSquares = 50;
vector<Point3f> obj;
for (int i = 0; i < numCornersHor; i++)
for (int j = 0; j < numCornersVer; j++)
obj.push_back(Point3f((float)j * numSquares, (float)i * numSquares, 0));發(fā)現(xiàn)與繪制棋盤格位置
// 發(fā)現(xiàn)棋盤格與繪制
Size s;
for (int i = 0; i < files.size(); i++) {
printf("image file : %s
", files[i].c_str());
Mat image = imread(files[i]);
s = image.size();
Mat gray;
cvtColor(image, gray, COLOR_BGR2GRAY);
vector<Point2f> corners;
bool ret = findChessboardCorners(gray, Size(7, 7), corners, CALIB_CB_ADAPTIVE_THRESH | CALIB_CB_FILTER_QUADS);
if (ret) {
cornerSubPix(gray, corners, Size(11, 11), Size(-1, -1), criteria);
drawChessboardCorners(image, Size(7, 7), corners, ret);
imagePoints.push_back(corners);
objectPoints.push_back(obj);
imshow("calibration-demo", image);
waitKey(500);
}
}發(fā)現(xiàn)棋盤格顯示如下(我是直接打印OpenCV自帶那張圖的)

相機(jī)校正-計(jì)算內(nèi)參數(shù)
// 相機(jī)校正
Mat intrinsic = Mat(3, 3, CV_32FC1);
Mat distCoeffs;
vector<Mat> rvecs;
vector<Mat> tvecs;
intrinsic.ptr<float>(0)[0] = 1;
intrinsic.ptr<float>(1)[1] = 1;
calibrateCamera(objectPoints, imagePoints, s, intrinsic, distCoeffs, rvecs, tvecs);畸變圖像校正

關(guān)于畸變類型,常見(jiàn)的圖像畸變類型有徑向與切向畸變、OpenCV中的相機(jī)標(biāo)定方法只能對(duì)徑向畸變有效,使用內(nèi)參對(duì)畸變圖像實(shí)現(xiàn)校正。相關(guān)的代碼如下:
// 畸變校正
for (int i = 0; i < files.size(); i++) {
Mat dst;
Mat image = imread(files[i]);
undistort(image, dst, intrinsic, distCoeffs);
imshow("image", image);
imshow("undistort image", dst);
waitKey(1000);
}
好消息!
小白學(xué)視覺(jué)知識(shí)星球
開(kāi)始面向外開(kāi)放啦??????
下載1:OpenCV-Contrib擴(kuò)展模塊中文版教程 在「小白學(xué)視覺(jué)」公眾號(hào)后臺(tái)回復(fù):擴(kuò)展模塊中文教程,即可下載全網(wǎng)第一份OpenCV擴(kuò)展模塊教程中文版,涵蓋擴(kuò)展模塊安裝、SFM算法、立體視覺(jué)、目標(biāo)跟蹤、生物視覺(jué)、超分辨率處理等二十多章內(nèi)容。 下載2:Python視覺(jué)實(shí)戰(zhàn)項(xiàng)目52講 在「小白學(xué)視覺(jué)」公眾號(hào)后臺(tái)回復(fù):Python視覺(jué)實(shí)戰(zhàn)項(xiàng)目,即可下載包括圖像分割、口罩檢測(cè)、車道線檢測(cè)、車輛計(jì)數(shù)、添加眼線、車牌識(shí)別、字符識(shí)別、情緒檢測(cè)、文本內(nèi)容提取、面部識(shí)別等31個(gè)視覺(jué)實(shí)戰(zhàn)項(xiàng)目,助力快速學(xué)校計(jì)算機(jī)視覺(jué)。 下載3:OpenCV實(shí)戰(zhàn)項(xiàng)目20講 在「小白學(xué)視覺(jué)」公眾號(hào)后臺(tái)回復(fù):OpenCV實(shí)戰(zhàn)項(xiàng)目20講,即可下載含有20個(gè)基于OpenCV實(shí)現(xiàn)20個(gè)實(shí)戰(zhàn)項(xiàng)目,實(shí)現(xiàn)OpenCV學(xué)習(xí)進(jìn)階。 交流群
歡迎加入公眾號(hào)讀者群一起和同行交流,目前有SLAM、三維視覺(jué)、傳感器、自動(dòng)駕駛、計(jì)算攝影、檢測(cè)、分割、識(shí)別、醫(yī)學(xué)影像、GAN、算法競(jìng)賽等微信群(以后會(huì)逐漸細(xì)分),請(qǐng)掃描下面微信號(hào)加群,備注:”昵稱+學(xué)校/公司+研究方向“,例如:”張三 + 上海交大 + 視覺(jué)SLAM“。請(qǐng)按照格式備注,否則不予通過(guò)。添加成功后會(huì)根據(jù)研究方向邀請(qǐng)進(jìn)入相關(guān)微信群。請(qǐng)勿在群內(nèi)發(fā)送廣告,否則會(huì)請(qǐng)出群,謝謝理解~

