<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
bool findChessboardCorners( InputArray image, Size patternSize, OutputArray corners, int flags = CALIB_CB_ADAPTIVE_THRESH + CALIB_CB_NORMALIZE_IMAGE );
第一個引數是輸入的棋盤格影象(可以是8位元單通道或三通道影象);
第二個引數是棋盤格內部的角點的行列數(注意:不是棋盤格的行列數,如棋盤格的行列數分別為4、8,而內部角點的行列數分別是3、7,因此這裡應該指定為cv::Size(3, 7));
第三個引數是檢測到的棋盤格角點,型別為std::vectorcv::Point2f。
第四個引數flag,用於指定在檢測棋盤格角點的過程中所應用的一種或多種過濾方法,可以使用下面的一種或多種,如果都是用則使用OR:
drawChessboardCorners( InputOutputArray image, Size patternSize, InputArray corners, bool patternWasFound );
find4QuadCornerSubpix( InputArray img, InputOutputArray corners, Size region_size );
void cornerSubPix( InputArray image, InputOutputArray corners, Size winSize, Size zeroZone, TermCriteria criteria );
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) );
objectPoints,世界座標,用vector<vector>,輸入x,y座標,z座標為0
imagePoints,影象座標,vector<vector>
imageSize,影象的大小用於初始化標定攝像機的image的size
cameraMatrix,內引數矩陣
distCoeffs,畸變矩陣
rvecs,位移向量
tvecs,旋轉向量
flags,可以組合:
CV_CALIB_USE_INTRINSIC_GUESS:使用該引數時,將包含有效的fx,fy,cx,cy的估計值的內參矩陣cameraMatrix,作為初始值輸入,然後函數對其做進一步優化。如果不使用這個引數,用影象的中心點初始化光軸點座標(cx, cy),使用最小二乘估算出fx,fy(這種求法好像和張正友的論文不一樣,不知道為何要這樣處理)。注意,如果已知內部引數(內參矩陣和畸變係數),就不需要使用這個函數來估計外參,可以使用solvepnp()函數計算外引數矩陣。
CV_CALIB_FIX_PRINCIPAL_POINT:在進行優化時會固定光軸點,光軸點將保持為影象的中心點。當CV_CALIB_USE_INTRINSIC_GUESS引數被設定,保持為輸入的值。
CV_CALIB_FIX_ASPECT_RATIO:固定fx/fy的比值,只將fy作為可變數,進行優化計算。當
CV_CALIB_USE_INTRINSIC_GUESS沒有被設定,fx和fy的實際輸入值將會被忽略,只有fx/fy的比值被計算和使用。
CV_CALIB_ZERO_TANGENT_DIST:切向畸變係數(P1,P2)被設定為零並保持為零。
CV_CALIB_FIX_K1,…,CV_CALIB_FIX_K6:對應的徑向畸變係數在優化中保持不變。如果設定了CV_CALIB_USE_INTRINSIC_GUESS引數,就從提供的畸變係數矩陣中得到。否則,設定為0。
CV_CALIB_RATIONAL_MODEL(理想模型):啟用畸變k4,k5,k6三個畸變引數。使標定函數使用有理模型,返回8個係數。如果沒有設定,則只計算其它5個畸變引數。
CALIB_THIN_PRISM_MODEL (薄稜鏡畸變模型):啟用畸變係數S1、S2、S3和S4。使標定函數使用薄稜柱模型並返回12個係數。如果不設定標誌,則函數計算並返回只有5個失真係數。
CALIB_FIX_S1_S2_S3_S4 :優化過程中不改變薄稜鏡畸變係數S1、S2、S3、S4。如果cv_calib_use_intrinsic_guess設定,使用提供的畸變係數矩陣中的值。否則,設定為0。
CALIB_TILTED_MODEL (傾斜模型):啟用畸變係數tauX and tauY。標定函數使用傾斜感測器模型並返回14個係數。如果不設定標誌,則函數計算並返回只有5個失真係數。
CALIB_FIX_TAUX_TAUY :在優化過程中,傾斜感測器模型的係數不被改變。如果cv_calib_use_intrinsic_guess設定,從提供的畸變係數矩陣中得到。否則,設定為0。
void initUndistortRectifyMap(InputArray cameraMatrix, InputArray distCoeffs, InputArray R, InputArray newCameraMatrix, Size size, int m1type, OutputArray map1, OutputArray map2)
這裡自己畫一個棋盤格用作標定,長度為1280畫素,寬490畫素,橫向10方格,縱向7方格
std_cb = Vision::makeCheckerboard(1280, 490, 10, 7, 0, (char *)"../blizzard/res/calibration/std_cb.png");
效果如圖
Vision是我個人建立的視覺類,可以用來繪製標準的棋盤格。
標頭檔案vision.h
// // Created by czh on 18-10-16. // #ifndef OPENGL_PRO_VISION_H #define OPENGL_PRO_VISION_H #include "opencv2/opencv.hpp" #include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgcodecs/imgcodecs.hpp> #include "iostream" class Vision { public: static cv::Mat read(std::string file_path, int flags = cv::IMREAD_ANYCOLOR | cv::IMREAD_ANYDEPTH); static cv::Mat write(std::string file_path, int flags = cv::IMREAD_ANYCOLOR | cv::IMREAD_ANYDEPTH); static void dispConfig(cv::Mat img); static cv::Mat makeCheckerboard(int bkgWidth, int bkgHeight, int sqXnum, int sqYnum = 0, int borderThickness = 0, char *savePath = NULL); private: }; #endif //OPENGL_PRO_VISION_H
原始檔vision.cpp
// // Created by czh on 18-10-16. // #include "vision.h" #include "string.h" using namespace std; using namespace cv; const char *findName(const char *ch) { const char *name = strrchr(ch, '/'); return ++name; } cv::Mat Vision::read(std::string file_path, int flags) { printf("#Vision readn"); cv::Mat img; img = cv::imread(file_path, flags); if (img.data == NULL) { printf("tError:vision readn"); } else { dispConfig(img); } return img; } void Vision::dispConfig(cv::Mat img) { printf("tpixel:%d*%d, channels:%dn", img.size().width, img.size().height, img.channels()); } cv::Mat Vision::makeCheckerboard(int bkgWidth, int bkgHeight, int sqXnum, int sqYnum, int thickNum, char *savePath) { if(sqYnum == 0){ sqYnum = sqXnum; } if(savePath == NULL){ char *defaultPath = (char *)"../res/calibration/maths.png"; savePath = defaultPath; } int checkboardX = 0;//棋盤x座標 int checkboardY = 0;//棋盤y座標 int xLen = bkgWidth / sqXnum;//x方格長度 int yLen = bkgHeight / sqYnum;//y方格長度 cv::Mat img(bkgHeight + thickNum * 2, bkgWidth + thickNum * 2, CV_8UC4, cv::Scalar(0, 255, 255, 255)); for (int i = 0; i < img.rows; i++) { for (int j = 0; j < img.cols; j++) { if (i < thickNum || i >= thickNum + bkgHeight || j < thickNum || j >= thickNum + bkgWidth) { img.at<Vec<uchar, 4>>(i, j) = cv::Scalar(0, 0, 0, 255); continue; } checkboardX = j - thickNum; checkboardY = i - thickNum; if (checkboardY / yLen % 2 == 0) { if ((checkboardX) / xLen % 2 == 0) { img.at<Vec<uchar, 4>>(i, j) = cv::Scalar(255, 255, 255, 255); } else { img.at<Vec<uchar, 4>>(i, j) = cv::Scalar(0, 0, 0, 255); } } else{ if ((checkboardX) / xLen % 2 != 0) { img.at<Vec<uchar, 4>>(i, j) = cv::Scalar(255, 255, 255, 255); } else { img.at<Vec<uchar, 4>>(i, j) = cv::Scalar(0, 0, 0, 255); } } } } imwrite(savePath, img); //儲存生成的圖片 printf("#makeCheckerboard %d*%dn", bkgWidth + thickNum, bkgHeight + thickNum); return img; }
用A4紙列印棋盤格,相機拍攝照片。
我偷懶,拿了別人的標定照片
下面是相機標定程式碼
cv::imwrite("../blizzard/res/calibration/cb_source.png", cb_source); printf("#Start scan cornern"); cv::Mat img; std::vector<cv::Point2f> image_points; std::vector<std::vector<cv::Point2f>> image_points_seq; /* 儲存檢測到的所有角點 */ if (cv::findChessboardCorners(cb_source, cv::Size(aqXnum, aqYnum), image_points, 0) == 0) { printf("#Error: Corners not find "); return 0; } else { cvtColor(cb_source, img, CV_RGBA2GRAY); cv::imwrite("../blizzard/res/calibration/cb_gray.png", img); //find4QuadCornerSubpix(img, image_points, cv::Size(5, 5)); cv::cornerSubPix(img, image_points, cv::Size(11, 11), cv::Size(-1, -1), cv::TermCriteria(CV_TERMCRIT_ITER + CV_TERMCRIT_EPS, 30, 0.01)); image_points_seq.push_back(image_points); cv::Mat cb_corner; cb_corner = cb_source.clone(); drawChessboardCorners(cb_corner, cv::Size(aqXnum, aqYnum), image_points, true); cv::imwrite("../blizzard/res/calibration/cb_corner.png", cb_corner); } printf("#Start calibraten"); cv::Size square_size = cv::Size(14.2222, 12); std::vector<std::vector<cv::Point3f>> object_points; /* 儲存標定板上角點的三維座標 */ cv::Mat cameraMatrix = cv::Mat(3, 3, CV_32FC1, cv::Scalar::all(0)); /* 攝像機內引數矩陣 */ cv::Mat distCoeffs = cv::Mat(1, 5, CV_32FC1, cv::Scalar::all(0)); /* 攝像機的5個畸變係數:k1,k2,p1,p2,k3 */ std::vector<cv::Mat> tvecsMat; /* 每幅影象的旋轉向量 */ std::vector<cv::Mat> rvecsMat; /* 每幅影象的平移向量 */ std::vector<cv::Point3f> realPoint; for (int i = 0; i < aqYnum; i++) { for (int j = 0; j < aqXnum; j++) { cv::Point3f tempPoint; /* 假設標定板放在世界座標系中z=0的平面上 */ tempPoint.x = i * square_size.width; tempPoint.y = j * square_size.height; tempPoint.z = 0; realPoint.push_back(tempPoint); } } object_points.push_back(realPoint); printf("#objectPoints: %ldn", sizeof(object_points[0])); std::cout << object_points[0] << std::endl; printf("#image_points: %ldn", sizeof(image_points_seq[0])); std::cout << image_points << std::endl; printf("#image sizen"); std::cout << SCREEN_WIDTH << "*" << SCREEN_HEIGHT << std::endl; cv::calibrateCamera(object_points, image_points_seq, cb_source.size(), cameraMatrix, distCoeffs, rvecsMat, tvecsMat, CV_CALIB_FIX_K3); std::cout << "tvecsMat:n" << tvecsMat[0] << std::endl; std::cout << "rvecsMat:n" << rvecsMat[0] << std::endl; std::cout << "#cameraMatrix:n" << cameraMatrix << std::endl; std::cout << "#distCoeffs:n" << distCoeffs << std::endl;
cv::Mat cb_final; cv::Mat mapx = cv::Mat(cb_source.size(), CV_32FC1); cv::Mat mapy = cv::Mat(cb_source.size(), CV_32FC1); cv::Mat R = cv::Mat::eye(3, 3, CV_32F); //initUndistortRectifyMap(cameraMatrix, distCoeffs, R, cv::Mat(), cb_source.size(), CV_32FC1, // mapx, mapy); //cv::remap(cb_source, cb_final, mapx, mapy, cv::INTER_LINEAR); undistort(cb_source, cb_final, cameraMatrix, distCoeffs); cv::imwrite("../blizzard/res/calibration/cb_final.png", cb_final);
1.校正前的圖片
2.校正後的圖片
到此這篇關於OpenCV相機標定的文章就介紹到這了,更多相關OpenCV相機標定內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45