寫在開頭
最近在學(xué)習(xí)三維重建的相關(guān)知識(shí)埋泵,打算將三維重建SFM的整個(gè)過程用代碼的形式梳理一下砂竖,本章節(jié)主要實(shí)現(xiàn)相機(jī)標(biāo)定代碼遂蛀。
這里我們假定你有一定的三維重建相關(guān)的基本知識(shí)谭跨,作者在這里推薦高翔博士的《視覺SLAM十四講:從理論到實(shí)踐》,在B站上有高翔博士的講解視頻。
程序流程
- 使用相機(jī)拍攝一系列的棋盤格的圖片螃宙。
- 對每一個(gè)圖片提取角點(diǎn)信息蛮瞄,對于角點(diǎn)信息不夠精確,進(jìn)一步提取亞像素角點(diǎn)信息谆扎;
- 在圖片中提取出角點(diǎn)挂捅。
- 相機(jī)標(biāo)定。
- 對標(biāo)定結(jié)果評價(jià)堂湖,計(jì)算誤差闲先。
- 使用標(biāo)定結(jié)果對原圖片進(jìn)行矯正。
步驟一:拍攝圖片
標(biāo)定圖片一般來說需要我們在不同位置无蜂、不同角度伺糠、不同姿態(tài)下拍攝。在之前我們的數(shù)學(xué)推到中我們得知酱讶,一般來說我們需要至少3張圖片才可以確定為一解退盯。但是,通常我們使用10~20張圖片來標(biāo)定泻肯。
步驟二:提取角點(diǎn)信息和提取亞像素角點(diǎn)信息
OPENCV中提取棋盤格中內(nèi)角點(diǎn)的函數(shù):findChessboardCorners()
函數(shù)原型
CV_EXPORTS_W bool findChessboardCorners( InputArray image, Size patternSize, OutputArray corners,
int flags = CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE );
函數(shù)說明:
這個(gè)函數(shù)的功能是確定輸入圖像中是否有棋盤格圖案,并檢測棋盤格的內(nèi)角點(diǎn)慰照。如果所有的內(nèi)角點(diǎn)都找到了灶挟,那么函數(shù)返回一個(gè)非0值;如果沒有找到所有的內(nèi)角點(diǎn)毒租,就會(huì)返回0稚铣。
參數(shù)說明:
- image:輸入的棋盤格圖像,必須是8位的灰度或彩色圖像墅垮。
- patternSize:每一個(gè)圖片中惕医,每行和每列角點(diǎn)的個(gè)數(shù)。注意算色,每行和每列的角點(diǎn)個(gè)數(shù)不能相同抬伺,因?yàn)檫@樣不易辨別方向。
- corners:輸入角點(diǎn)的坐標(biāo)灾梦。通常用 cv:Point2f 向量來保存峡钓。
-
flags:默認(rèn)為0∪艉樱可選參數(shù)如下:
- CALIB_CB_ADAPTIVE_THRESH 使用自適應(yīng)閾值(通過平均圖像亮度計(jì)算得到)將圖像轉(zhuǎn)換為黑白圖能岩,而不是一個(gè)固定的閾值。
- CALIB_CB_NORMALIZE_IMAGE 在使用固定閾值或者自適應(yīng)閾值進(jìn)行二值化之前萧福,先使用equalizeHist()來均衡化圖像亮度拉鹃。
- CALIB_CB_FILTER_QUADS 使用其他的準(zhǔn)則(如輪廓面積,周長,方形形狀)來去除在輪廓檢測階段檢測到的錯(cuò)誤方塊膏燕。
有兩個(gè)函數(shù)可以實(shí)現(xiàn)提取亞像素角點(diǎn)信息:cornerSubPix钥屈、find4QuadCornerSubpix。在提取棋盤格角點(diǎn)時(shí)兩者的效果差不多煌寇,隨便使用哪一個(gè)都行焕蹄。
函數(shù)原型
void cornerSubPix(InputArray image, InputOutputArray corners, Size winSize, Size zeroZone, TermCriteria criteria)
參數(shù)說明
- image:輸入圖像。
- corners:初始的角點(diǎn)坐標(biāo)阀溶,同時(shí)也會(huì)作為亞像素角點(diǎn)坐標(biāo)的輸出腻脏;通常用cv::Point2f/Point2d 向量來保存,vector<cv::Point2f/Point2d> points银锻。
- winSize:大小為搜索窗口的一半永品。
- zeroZone:死區(qū)的一般尺寸,死區(qū)為不對搜索區(qū)的中央位置做求和運(yùn)算的區(qū)域击纬。
- criteria:迭代的終止條件鼎姐。
函數(shù)原型
CV_EXPORTS bool find4QuadCornerSubpix( InputArray img, InputOutputArray corners, Size region_size )
參數(shù)說明
- img:輸入圖像,最好是8位灰度圖像更振,檢測效率更高炕桨;
- corners:初始的角點(diǎn)坐標(biāo),同時(shí)也會(huì)作為亞像素角點(diǎn)坐標(biāo)的輸出肯腕;通常用cv::Point2f/Point2d 向量來保存献宫,vector<cv::Point2f/Point2d> points。
- region_size:角點(diǎn)搜索窗口的大小实撒。
步驟三:畫出角點(diǎn)
函數(shù)原型
CV_EXPORTS_W void drawChessboardCorners( InputOutputArray image, Size patternSize, InputArray corners, bool patternWasFound )
函數(shù)說明
畫出檢測的角點(diǎn)姊途。
參數(shù)說明
- image:圖像,8位灰度或彩色圖像知态。
- patternSize:每一幅棋盤格圖片中捷兰,每行和每列角點(diǎn)的個(gè)數(shù)。
- corners:初始的角點(diǎn)坐標(biāo)负敏,同時(shí)也會(huì)作為亞像素角點(diǎn)坐標(biāo)的輸出贡茅;通常用cv::Point2f/Point2d 向量來保存,vector<cv::Point2f/Point2d> points原在。
- patternWasFound:標(biāo)志位友扰,用來只是是否檢測倒所有的棋盤內(nèi)角點(diǎn)。true表示完整地檢測到了所有內(nèi)角點(diǎn)庶柿,函數(shù)會(huì)用直線將角點(diǎn)依次連接起來村怪;false表示沒有完整檢測到所有內(nèi)角點(diǎn),函數(shù)會(huì)用紅色圓圈標(biāo)出檢測到的內(nèi)角點(diǎn)浮庐。
步驟四:相機(jī)標(biāo)定
函數(shù)原型
CV_EXPORTS_W double calibrateCamera( InputArrayOfArrays objectPoints,
InputArrayOfArrays imagePoints, Size imageSize,
InputOutputArray cameraMatrix, InputOutputArray distCoeffs,
OutputArrayOfArrays rvecs, OutputArrayOfArrays tvecs,
int flags = 0, TermCriteria criteria = TermCriteria(
TermCriteria::COUNT + TermCriteria::EPS, 30, DBL_EPSILON) );
參數(shù)說明
- objectPoints:一系列點(diǎn)的三維坐標(biāo)甚负,即若干張圖片中對應(yīng)的若干個(gè)點(diǎn)的三維坐標(biāo)柬焕。在使用時(shí)應(yīng)該建立一個(gè)二維的vector,即vector<vector<Point3f>> objectPoints梭域。我們需要根據(jù)棋盤格每個(gè)黑白格子的長寬斑举,計(jì)算出各個(gè)內(nèi)角點(diǎn)的三維坐標(biāo)。通常我們會(huì)取z=0病涨,而只計(jì)算x和y 坐標(biāo)富玷。
- imagePoints:若干張圖片對應(yīng)的若干的內(nèi)角點(diǎn)的坐標(biāo),通常采用vector<vector<Point2f>> image_points表示既穆。
- imageSize:圖像的像素尺寸大小赎懦。
- cameraMatrix:相機(jī)的內(nèi)參矩陣,對應(yīng)推導(dǎo)時(shí)的內(nèi)參矩陣幻工,大小為励两。
- distCoeffs:相機(jī)的畸變參數(shù)矩陣,有5個(gè)畸變參數(shù):囊颅,矩陣大小為当悔。
- rvecs:旋轉(zhuǎn)向量,羅德里格旋轉(zhuǎn)向量踢代,是相機(jī)外參盲憎;因?yàn)橛腥舾蓮垐D片,所以通常使用Mat類型的vector 表示胳挎,vector<Mat> rvecs焙畔。
- tvecs:位移向量,與旋轉(zhuǎn)向量一樣串远,也是相機(jī)外參,通常使用Mat類型的vector 表示儿惫,vector<Mat> tvecs澡罚。
- flags:表示標(biāo)定時(shí)采用的算法。默認(rèn)為0肾请,其他有:
- CV_CALIB_USE_INTRINSIC_GUESS:使用該參數(shù)時(shí)留搔,在cameraMatrix矩陣中應(yīng)該有fx,fy,u0,v0的估計(jì)值。否則的話铛铁,將初始化(u0,v0)圖像的中心點(diǎn)隔显,使用最小二乘估算出fx,fy饵逐。
- CV_CALIB_FIX_PRINCIPAL_POINT:在進(jìn)行優(yōu)化時(shí)會(huì)固定光軸點(diǎn)括眠。當(dāng)CV_CALIB_USE_INTRINSIC_GUESS參數(shù)被設(shè)置,光軸點(diǎn)將保持在中心或者某個(gè)輸入的值倍权。
- CV_CALIB_FIX_ASPECT_RATIO:固定fx/fy的比值掷豺,只將fy作為可變量,進(jìn)行優(yōu)化計(jì)算。當(dāng)CV_CALIB_USE_INTRINSIC_GUESS沒有被設(shè)置当船,fx和fy將會(huì)被忽略题画。只有fx/fy的比值在計(jì)算中會(huì)被用到。
- CV_CALIB_ZERO_TANGENT_DIST:設(shè)定切向畸變參數(shù)(p1,p2)為零德频。
- CV_CALIB_FIX_K1,…,CV_CALIB_FIX_K6:對應(yīng)的徑向畸變在優(yōu)化中保持不變苍息。
- CV_CALIB_RATIONAL_MODEL:計(jì)算k4,k5壹置,k6三個(gè)畸變參數(shù)竞思。如果沒有設(shè)置,則只計(jì)算其它5個(gè)畸變參數(shù)蒸绩。
-
criteria:迭代的終止條件衙四。
這個(gè)函數(shù)解決的就是我們以前推導(dǎo)的極大似然優(yōu)化問題:
其中:表示的是點(diǎn)在第個(gè)圖像上的投影。
步驟五:評價(jià)標(biāo)定結(jié)果
我們在進(jìn)行相機(jī)標(biāo)定時(shí)患亿,本身要解決的是一個(gè)優(yōu)化問題传蹈,而優(yōu)化的對象就是角點(diǎn)與三維點(diǎn)投影到圖像點(diǎn)坐標(biāo)之間的差值,通過不斷迭代步藕,盡可能地最小化這個(gè)差值惦界。我們對標(biāo)定結(jié)果評價(jià)時(shí),就是計(jì)算投影點(diǎn)與檢測到的亞像素角點(diǎn)坐標(biāo)的差值咙冗。由于是二維的沾歪,所以分別對x和y坐標(biāo)求差值,再求平方根雾消,即求L2范數(shù)灾搏。
函數(shù)原型
CV_EXPORTS_W void projectPoints( InputArray objectPoints,
InputArray rvec, InputArray tvec,
InputArray cameraMatrix, InputArray distCoeffs,
OutputArray imagePoints,
OutputArray jacobian = noArray(),
double aspectRatio = 0 );
參數(shù)說明
- objectPoints:一系列點(diǎn)的三維坐標(biāo),即若干張圖片中對應(yīng)的若干個(gè)點(diǎn)的三維坐標(biāo)立润。在使用時(shí)應(yīng)該建立一個(gè)二維的vector狂窑,即vector<vector<Point3f>> objectPoints。我們需要根據(jù)棋盤格每個(gè)黑白格子的長寬桑腮,計(jì)算出各個(gè)內(nèi)角點(diǎn)的三維坐標(biāo)泉哈。通常我們會(huì)取z=0,而只計(jì)算x和y 坐標(biāo)破讨。
- rvecs:旋轉(zhuǎn)向量丛晦,羅德里格旋轉(zhuǎn)向量,是相機(jī)外參提陶;因?yàn)橛腥舾蓮垐D片烫沙,所以通常使用Mat類型的vector 表示,vector<Mat> rvecs搁骑。
- tvecs:位移向量斧吐,與旋轉(zhuǎn)向量一樣又固,也是相機(jī)外參,通常使用Mat類型的vector 表示煤率,vector<Mat> tvecs仰冠。
- cameraMatrix:相機(jī)的內(nèi)參矩陣,對應(yīng)推導(dǎo)時(shí)的內(nèi)參矩陣A蝶糯,大小為洋只。
-
distCoeffs:相機(jī)的畸變參數(shù)矩陣,有5個(gè)畸變參數(shù):
昼捍,矩陣大小為识虚。 - imagePoints:若干張圖片對應(yīng)的若干的內(nèi)角點(diǎn)的坐標(biāo),通常采用vector<vector<Point2f>> image_points表示妒茬。
步驟六:矯正圖像
使用前面求得的內(nèi)參和外參以及畸變參數(shù)數(shù)據(jù)担锤,可以對圖像進(jìn)行畸變矯正。使用initUndistortRectifyMap和remap兩個(gè)函數(shù)來實(shí)現(xiàn)乍钻。initUndistortRectifyMap用來計(jì)算畸變映射肛循,remap把求得的映射應(yīng)用到圖像上。
函數(shù)原型
CV_EXPORTS_W void initUndistortRectifyMap( InputArray cameraMatrix, InputArray distCoeffs,
InputArray R, InputArray newCameraMatrix,
Size size, int m1type, OutputArray map1, OutputArray map2 );
參數(shù)說明
- cameraMatrix:相機(jī)的內(nèi)參矩陣银择;
- distCoeffs:相機(jī)的畸變參數(shù)構(gòu)成的矩陣多糠;
- R:可選的輸入,是第一和第二相機(jī)坐標(biāo)之間的旋轉(zhuǎn)矩陣浩考;
- newCameraMatrix:校正后的內(nèi)參矩陣夹孔;
- size:攝像機(jī)采集的無失真的圖像尺寸;
- m1type:定義map1的數(shù)據(jù)類型析孽,可以是CV_32FC1或者CV_16SC2搭伤;
- map1和map2:分別對應(yīng)X和Y坐標(biāo)的重映射參數(shù)。
函數(shù)原型
CV_EXPORTS_W void remap( InputArray src, OutputArray dst,
InputArray map1, InputArray map2,
int interpolation, int borderMode = BORDER_CONSTANT,
const Scalar& borderValue = Scalar());
參數(shù)說明
- src:輸入圖像袜瞬,原始有畸變的圖像闷畸;
- dst:輸出圖像,校正后的圖像吞滞;
- map1:X坐標(biāo)的映射;
- map2:Y坐標(biāo)的映射盾沫;
- interpolation:圖像的插值方式裁赠;
- borderMode:邊界填充方式;
Code
#include <iostream>
#include <vector>
#include <fstream>
#include <string>
#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/calib3d/calib3d.hpp>
using namespace std;
using namespace cv;
int main()
{
ifstream inImgPath("calibdata.txt"); //標(biāo)定所用圖像文件的路徑
vector<string> imgList;
vector<string>::iterator p;
string temp;
if (!inImgPath.is_open())
{
cout << "沒有找到文件" << endl;
}
//讀取文件中保存的圖片文件路徑赴精,并存放在數(shù)組中
while (getline(inImgPath, temp))
{
imgList.push_back(temp);
}
ofstream fout("caliberation_result.txt"); //保存標(biāo)定結(jié)果的文件
cout << "開始提取角點(diǎn)......" << endl;
cv::Size image_size;//保存圖片大小
cv::Size pattern_size = cv::Size(4, 6);//標(biāo)定板上每行佩捞、每列的角點(diǎn)數(shù);測試圖片中的標(biāo)定板上內(nèi)角點(diǎn)數(shù)為4*6
vector<cv::Point2f> corner_points_buf;//建一個(gè)數(shù)組緩存檢測到的角點(diǎn)蕾哟,通常采用Point2f形式
vector<cv::Point2f>::iterator corner_points_buf_ptr;
vector<vector<cv::Point2f>> corner_points_of_all_imgs;
int image_num = 0;
string filename;
while(image_num < imgList.size())
{
filename = imgList[image_num++];
cout << "image_num = " << image_num << endl;
cout << filename.c_str() << endl;
cv::Mat imageInput = cv::imread(filename.c_str());
if (image_num == 1)
{
image_size.width = imageInput.cols;
image_size.height = imageInput.rows;
cout << "image_size.width = " << image_size.width << endl;
cout << "image_size.height = " << image_size.height << endl;
}
if (findChessboardCorners(imageInput, pattern_size, corner_points_buf) == 0)
{
cout << "can not find chessboard corners!\n"; //找不到角點(diǎn)
exit(1);
}
else
{
cv::Mat gray;
cv::cvtColor(imageInput, gray, CV_RGB2GRAY);
cv::find4QuadCornerSubpix(gray, corner_points_buf, cv::Size(5, 5));
corner_points_of_all_imgs.push_back(corner_points_buf);
cv::drawChessboardCorners(gray, pattern_size, corner_points_buf, true);
cv::imshow("camera calibration", gray);
cv::waitKey(100);
}
}
int total = corner_points_of_all_imgs.size();
cout << "total=" << total << endl;
int cornerNum = pattern_size.width * pattern_size.height;//每張圖片上的總的角點(diǎn)數(shù)
for (int i = 0; i < total;i++)
{
cout << "--> 第" << i + 1 << "幅圖片的數(shù)據(jù) -->:" << endl;
for (int j = 0;j < cornerNum;j++)
{
cout << "-->" << corner_points_of_all_imgs[i][j].x;
cout << "-->" << corner_points_of_all_imgs[i][j].y;
if ((j + 1) % 3 == 0)
{
cout << endl;
}
else
{
cout.width(10);
}
}
cout << endl;
}
cout << endl << "角點(diǎn)提取完成" << endl;
//攝像機(jī)標(biāo)定
cout << "開始標(biāo)定………………" << endl;
cv::Mat cameraMatrix = cv::Mat(3, 3, CV_32FC1, cv::Scalar::all(0));//內(nèi)外參矩陣一忱,H——單應(yīng)性矩陣
cv::Mat distCoefficients = cv::Mat(1, 5, CV_32FC1, cv::Scalar::all(0));//攝像機(jī)的5個(gè)畸變系數(shù):k1,k2,p1,p2,k3
vector<cv::Mat> tvecsMat;//每幅圖像的平移向量莲蜘,t
vector<cv::Mat> rvecsMat;//每幅圖像的旋轉(zhuǎn)向量(羅德里格旋轉(zhuǎn)向量)
vector<vector<cv::Point3f>> objectPoints;//保存所有圖片的角點(diǎn)的三維坐標(biāo)
//初始化每一張圖片中標(biāo)定板上角點(diǎn)的三維坐標(biāo)
int i, j, k;
for (k = 0;k < image_num;k++)//遍歷每一張圖片
{
vector<cv::Point3f> tempCornerPoints;//每一幅圖片對應(yīng)的角點(diǎn)數(shù)組
//遍歷所有的角點(diǎn)
for (i = 0;i < pattern_size.height;i++)
{
for (j = 0;j < pattern_size.width;j++)
{
cv::Point3f singleRealPoint;//一個(gè)角點(diǎn)的坐標(biāo)
singleRealPoint.x = i * 10;
singleRealPoint.y = j * 10;
singleRealPoint.z = 0;//假設(shè)z=0
tempCornerPoints.push_back(singleRealPoint);
}
}
objectPoints.push_back(tempCornerPoints);
}
cv::calibrateCamera(objectPoints, corner_points_of_all_imgs, image_size, cameraMatrix, distCoefficients, rvecsMat, tvecsMat, 0);
cout << "標(biāo)定完成" << endl;
//開始保存標(biāo)定結(jié)果
cout << "開始保存標(biāo)定結(jié)果" << endl;
cout << endl << "相機(jī)相關(guān)參數(shù):" << endl;
fout << "相機(jī)相關(guān)參數(shù):" << endl;
cout << "1.內(nèi)外參數(shù)矩陣:" << endl;
fout << "1.內(nèi)外參數(shù)矩陣:" << endl;
cout << "大小:" << cameraMatrix.size() << endl;
fout << "大辛庇:" << cameraMatrix.size() << endl;
cout << cameraMatrix << endl;
fout << cameraMatrix << endl;
cout << "2.畸變系數(shù):" << endl;
fout << "2.畸變系數(shù):" << endl;
cout << "大衅鼻:" << distCoefficients.size() << endl;
fout << "大小:" << distCoefficients.size() << endl;
cout << distCoefficients << endl;
fout << distCoefficients << endl;
cout << endl << "圖像相關(guān)參數(shù):" << endl;
fout << endl << "圖像相關(guān)參數(shù):" << endl;
cv::Mat rotation_Matrix = cv::Mat(3, 3, CV_32FC1, cv::Scalar::all(0));//旋轉(zhuǎn)矩陣
for (i = 0;i < image_num;i++)
{
cout << "第" << i + 1 << "幅圖像的旋轉(zhuǎn)向量:" << endl;
fout << "第" << i + 1 << "幅圖像的旋轉(zhuǎn)向量:" << endl;
cout << rvecsMat[i] << endl;
fout << rvecsMat[i] << endl;
cout << "第" << i + 1 << "幅圖像的旋轉(zhuǎn)矩陣:" << endl;
fout << "第" << i + 1 << "幅圖像的旋轉(zhuǎn)矩陣:" << endl;
cv::Rodrigues(rvecsMat[i], rotation_Matrix);//將旋轉(zhuǎn)向量轉(zhuǎn)換為相對應(yīng)的旋轉(zhuǎn)矩陣
cout << rotation_Matrix << endl;
fout << rotation_Matrix << endl;
cout << "第" << i + 1 << "幅圖像的平移向量:" << endl;
fout << "第" << i + 1 << "幅圖像的平移向量:" << endl;
cout << tvecsMat[i] << endl;
fout << tvecsMat[i] << endl;
}
cout << "結(jié)果保存完畢" << endl;
//對標(biāo)定結(jié)果進(jìn)行評價(jià)
cout << "開始評價(jià)標(biāo)定結(jié)果......" << endl;
//計(jì)算每幅圖像中的角點(diǎn)數(shù)量芬迄,假設(shè)全部角點(diǎn)都檢測到了
int corner_points_counts;
corner_points_counts = pattern_size.width * pattern_size.height;
cout << "每幅圖像的標(biāo)定誤差:" << endl;
fout << "每幅圖像的標(biāo)定誤差:" << endl;
double err = 0;//單張圖像的誤差
double total_err = 0;//所有圖像的平均誤差
for (i = 0;i < image_num;i++)
{
vector<cv::Point2f> image_points_calculated;//存放新計(jì)算出的投影點(diǎn)的坐標(biāo)
vector<cv::Point3f> tempPointSet = objectPoints[i];
cv::projectPoints(tempPointSet, rvecsMat[i], tvecsMat[i], cameraMatrix, distCoefficients, image_points_calculated);
//計(jì)算新的投影點(diǎn)與舊的投影點(diǎn)之間的誤差
vector<cv::Point2f> image_points_old = corner_points_of_all_imgs[i];
//將兩組數(shù)據(jù)換成Mat格式
cv::Mat image_points_calculated_mat = cv::Mat(1, image_points_calculated.size(), CV_32FC2);
cv::Mat image_points_old_mat = cv::Mat(1, image_points_old.size(), CV_32FC2);
for (j = 0;j < tempPointSet.size();j++)
{
image_points_calculated_mat.at<cv::Vec2f>(0, j) = cv::Vec2f(image_points_calculated[j].x, image_points_calculated[j].y);
image_points_old_mat.at<cv::Vec2f>(0, j) = cv::Vec2f(image_points_old[j].x, image_points_old[j].y);
}
err = cv::norm(image_points_calculated_mat, image_points_old_mat, cv::NORM_L2);
err /= corner_points_counts;
total_err += err;
cout << "第" << i + 1 << "幅圖像的平均誤差:" << err << "像素" << endl;
fout << "第" << i + 1 << "幅圖像的平均誤差:" << err << "像素" << endl;
}
cout << "總體平均誤差:" << total_err / image_num << "像素" << endl;
fout << "總體平均誤差:" << total_err / image_num << "像素" << endl;
cout << "評價(jià)完成" << endl;
fout.close();
cv::Mat mapx = cv::Mat(image_size, CV_32FC1);
cv::Mat mapy = cv::Mat(image_size, CV_32FC1);
cv::Mat R = cv::Mat::eye(3, 3, CV_32F);
cout << "保存矯正圖像" << endl;
string imageFileName;
std::stringstream StrStm;
for (int i = 0;i < image_num;i++)
{
cout << "Frame #" << i + 1 << endl;
cv::initUndistortRectifyMap(cameraMatrix, distCoefficients, R, cameraMatrix, image_size, CV_32FC1, mapx, mapy);
cv::Mat src_image = cv::imread(imgList[i].c_str(), 1);
cv::Mat new_image = src_image.clone();
cv::remap(src_image, new_image, mapx, mapy, cv::INTER_LINEAR);
imshow("原始圖像", src_image);
imshow("矯正后圖像", new_image);
StrStm.clear();
imageFileName.clear();
StrStm << i + 1;
StrStm >> imageFileName;
imageFileName += "_d.jpg";
cv::imwrite(imageFileName, new_image);
cv::waitKey(200);
}
cout << "保存結(jié)束" << endl;
cv::waitKey(0);
return 0;
}