鱼眼相机外参的计算
主要是借助cv::solvepnp和cv::solvePnPRansac或calibrate來求解相機外參,但魚眼相機外參的計算,在調用
參考鏈接:
(185條消息) 魚眼相機外參的計算和圖像的透視變換_求解魚眼相機外參_Mega_Li的博客-CSDN博客
我:
你是opencv專家,教我計算魚眼相機的外參,用c++代碼實現
openai(chatgpt4):
計算魚眼相機的外參需要使用相機標定和姿態估計兩個步驟。以下是一些基本的步驟和C++代碼實現。
1. 相機標定
相機標定是用于估計相機的內部參數和畸變系數的過程。這可以通過拍攝一組已知3D世界坐標和對應2D圖像坐標的圖像來實現。OpenCV提供了一個函數cv::fisheye::calibrate()用于魚眼相機的標定。以下是一個示例代碼:
cv::Mat cameraMatrix, distCoeffs;
std::vector<std::vector<cv::Point3f>> objectPoints;
std::vector<std::vector<cv::Point2f>> imagePoints;
cv::Size imageSize;
double rms = cv::fisheye::calibrate(objectPoints, imagePoints, imageSize, cameraMatrix, distCoeffs, cv::noArray(), cv::noArray());
其中objectPoints是一個vector<vector<Point3f>>,包含所有標定板上的三維點的坐標,imagePoints是一個vector<vector<Point2f>>,包含這些點在標定圖像中的二維坐標。imageSize是標定圖像的尺寸。cameraMatrix和distCoeffs是輸出的相機內部參數和畸變系數。rms是根據標定結果計算出的標定誤差。
2. 姿態估計
姿態估計是將相機從其初始位置移動到新位置并確定相機在該位置的旋轉和平移。在這里,我們可以使用OpenCV的solvePnP函數進行姿態估計。以下是一個示例代碼:
cv::Mat rvec, tvec;
std::vector<cv::Point3f> objectPoints3D;
std::vector<cv::Point2f> imagePoints2D;
cv::Mat cameraMatrix, distCoeffs;
cv::fisheye::projectPoints(objectPoints3D, rvec, tvec, cameraMatrix, distCoeffs, imagePoints2D);
其中objectPoints3D是一個vector<Point3f>,包含標定板上的三維點的坐標,imagePoints2D是一個vector<Point2f>,包含這些點在當前圖像中的二維坐標。cameraMatrix和distCoeffs是在相機標定中獲得的相機內部參數和畸變系數。rvec和tvec是輸出的旋轉向量和平移向量。
使用solvePnP函數,我們可以得到旋轉向量和平移向量。將它們轉換為旋轉矩陣和平移矩陣,就可以獲得相機的外部參數。以下是一個示例代碼:
cv::Mat R;
cv::Rodrigues(rvec, R);
cv::Mat T = tvec;
?
3.計算魚眼相機的外參可以分為以下幾個步驟:
1)標定魚眼相機內參和畸變參數。這個步驟可以使用OpenCV中的calibrateCamera函數完成。
2)采集魚眼相機的圖像,并使用角點檢測算法(如OpenCV中的findChessboardCorners函數)檢測出標定板的角點。
3)根據標定板上的已知空間點和對應的圖像點,計算魚眼相機的外參。這個步驟可以使用OpenCV中的solvePnP函數完成。
4)將得到的旋轉向量和平移向量轉換為旋轉矩陣和平移矩陣,得到魚眼相機的外參矩陣。
下面是用C++代碼實現上述步驟的示例:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
? ? // 讀取標定板圖像
? ? Mat boardImg = imread("board.png");
? ? // 設置標定板尺寸和空間點坐標
? ? Size boardSize = Size(9, 6);
? ? vector<Point3f> objectPoints;
? ? for (int i = 0; i < boardSize.height; i++)
? ? {
? ? ? ? for (int j = 0; j < boardSize.width; j++)
? ? ? ? {
? ? ? ? ? ? objectPoints.push_back(Point3f(i, j, 0));
? ? ? ? }
? ? }
? ? // 標定相機內參和畸變參數
? ? Mat cameraMatrix, distCoeffs;
? ? vector<vector<Point2f>> imagePoints;
? ? vector<Mat> rvecs, tvecs;
? ? vector<float> reprojErrs;
? ? double rms = calibrateCamera(vector<vector<Point3f>>{objectPoints}, vector<vector<Point2f>>{imagePoints},
? ? ? ? boardImg.size(), cameraMatrix, distCoeffs, rvecs, tvecs);
? ? // 檢測標定板角點
? ? vector<Point2f> corners;
? ? bool found = findChessboardCorners(boardImg, boardSize, corners);
? ? // 計算相機外參
? ? Mat rvec, tvec;
? ? solvePnP(objectPoints, corners, cameraMatrix, distCoeffs, rvec, tvec);
? ? // 將旋轉向量和平移向量轉換為旋轉矩陣和平移矩陣
? ? Mat R;
? ? Rodrigues(rvec, R);
? ? Mat T = tvec.reshape(1, 3);
? ? // 得到相機的外參矩陣
? ? Mat extrinsicMat = Mat::eye(4, 4, CV_32F);
? ? R.copyTo(extrinsicMat(Rect(0, 0, 3, 3)));
? ? T.copyTo(extrinsicMat(Rect(3, 0, 1, 3)));
? ? cout << "相機內參:" << endl << cameraMatrix << endl;
? ? cout << "相機畸變參數:" << endl << distCoeffs << endl;
? ? cout << "相機外參:" << endl << extrinsicMat << endl;
? ? return 0;
}
4.計算魚眼相機的外參可以分為以下幾個步驟:
1)采集圖像和相應的3D坐標??梢允褂脴硕ò搴鸵阎?D坐標來獲取多個圖像和對應的3D坐標。
2)進行相機標定,得到內參矩陣和畸變系數??梢允褂肙penCV的calibrateCamera函數實現。
3)通過多視角幾何理論,將3D坐標轉換到相機坐標系下。
4)通過求解外參矩陣,將相機坐標系下的3D點轉換到世界坐標系下。
以下是一個C++實現的示例代碼,用于計算魚眼相機的外參:
#include <iostream>
#include <opencv2/opencv.hpp>
using namespace std;
using namespace cv;
int main()
{
? ? // 讀取標定板圖像和對應的3D坐標
? ? vector<vector<Point3f>> objectPoints;
? ? vector<vector<Point2f>> imagePoints;
? ? // ...
? ? // 進行相機標定
? ? Mat cameraMatrix, distCoeffs;
? ? vector<Mat> rvecs, tvecs;
? ? calibrateCamera(objectPoints, imagePoints, imageSize, cameraMatrix, distCoeffs, rvecs, tvecs);
? ? // 定義3D點和2D點
? ? vector<Point3f> objectPoints3D;
? ? vector<Point2f> imagePoints2D;
? ? // ...
? ? // 將3D點轉換到相機坐標系下
? ? Mat objectPointsMat(objectPoints3D);
? ? Mat rvec, tvec;
? ? solvePnP(objectPointsMat, imagePoints2D, cameraMatrix, distCoeffs, rvec, tvec);
? ? // 將相機坐標系下的3D點轉換到世界坐標系下
? ? Mat R;
? ? Rodrigues(rvec, R);
? ? Mat extrinsicMat(3, 4, CV_64FC1);
? ? hconcat(R, tvec, extrinsicMat);
? ? // 輸出外參矩陣
? ? cout << extrinsicMat << endl;
? ? return 0;
}
?
其中,solvePnP函數用于求解外參矩陣,Rodrigues函數用于將旋轉向量轉換為旋轉矩陣,hconcat函數用于將旋轉矩陣和平移向量合并成一個3×4的外參矩陣。請根據實際情況修改代碼中的變量和參數。
5 計算魚眼相機的外參需要以下步驟:
1)計算相機的內參矩陣,包括焦距、主點、畸變系數等參數。這些參數通??梢酝ㄟ^相機的廠商提供的文檔或者相機標定得到。
2)采集至少4個不同位置的圖像,每個位置需要拍攝至少3張不同朝向的圖像。這些圖像可以用來計算相機的外參。
3)提取每個圖像中的特征點,可以使用ORB或者SURF等特征點檢測算法。
4)對于每個特征點,通過魚眼模型將其投影到球面上。具體可以參考OpenCV的fisheye模塊。
5)使用RANSAC等算法來估計每個圖像的外參。具體可以參考OpenCV的solvePnP函數。
6)將所有圖像的外參融合起來,可以使用Bundle Adjustment等算法來優化結果。
下面是一個簡單的C++代碼示例,可以計算魚眼相機的外參:
#include <iostream>
#include <vector>
#include <opencv2/opencv.hpp>
#include <opencv2/features2d.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <opencv2/core/types.hpp>
#include <opencv2/calib3d.hpp>
#include <opencv2/core/eigen.hpp>
using namespace std;
using namespace cv;
using namespace cv::xfeatures2d;
void calculateExtrinsics(const vector<vector<Point2f>>& imagePoints,
? ? ? ? ? ? ? ? ? ? ? ? ?const vector<vector<Point3f>>& objectPoints,
? ? ? ? ? ? ? ? ? ? ? ? ?const Mat& cameraMatrix,
? ? ? ? ? ? ? ? ? ? ? ? ?const Mat& distCoeffs,
? ? ? ? ? ? ? ? ? ? ? ? ?Mat& R,
? ? ? ? ? ? ? ? ? ? ? ? ?Mat& t)
{
? ? vector<Mat> rvecs, tvecs;
? ? solvePnPRansac(objectPoints, imagePoints, cameraMatrix, distCoeffs, rvecs, tvecs);
? ? Rodrigues(rvecs[0], R);
? ? t = tvecs[0];
}
int main()
{
? ? // load images and corresponding object points
? ? vector<vector<Point2f>> imagePoints;
? ? vector<vector<Point3f>> objectPoints;
? ? // TODO: load imagePoints and objectPoints from file or capture them from camera
? ? // calculate camera matrix and distortion coefficients
? ? Mat cameraMatrix, distCoeffs;
? ? // TODO: calculate cameraMatrix and distCoeffs using calibration data
? ? // calculate extrinsics for each image
? ? vector<Mat> Rs, ts;
? ? for (int i = 0; i < imagePoints.size(); i++) {
? ? ? ? Mat R, t;
? ? ? ? calculateExtrinsics(imagePoints[i], objectPoints, cameraMatrix, distCoeffs, R, t);
? ? ? ? Rs.push_back(R);
? ? ? ? ts.push_back(t);
? ? }
? ? // bundle adjustment to refine extrinsics
? ? TermCriteria criteria(TermCriteria::COUNT + TermCriteria::EPS, 100, 1e-5);
? ? vector<Mat> Rs_opt, ts_opt;
? ? vector<vector<Point2f>> imagePoints_opt;
? ? bundleAdjustment(objectPoints, imagePoints, cameraMatrix, distCoeffs, Rs, ts, Rs_opt, ts_opt, imagePoints_opt, criteria);
? ? // print results
? ? for (int i = 0; i < Rs_opt.size(); i++) {
? ? ? ?
5.
計算魚眼相機的外參需要知道相機內參和一些已知的場景信息。下面是用C++實現計算魚眼相機的外參的步驟:
1)加載圖像并提取圖像中的特征點。可以使用OpenCV中的cv::KeyPoint和cv::FeatureDetector來提取圖像中的特征點。
2)在場景中選擇幾個已知的三維點,并計算它們在相機坐標系下的坐標。這些三維點應該是靜態的,并且相機可以觀察到它們??梢允褂肙penCV中的cv::solvePnP函數來計算相機坐標系和圖像坐標系之間的變換關系,即相機的外參。
3)計算相機的畸變參數。可以使用OpenCV中的cv::calibrateCamera函數來計算相機的內參和畸變參數。需要提供一組已知的三維點和它們在圖像中的投影,以及相機的內參。
4)將相機的內參和外參組合起來,得到相機的投影矩陣。
5)使用相機的投影矩陣將場景中的三維點投影到圖像中,并與實際提取的特征點進行匹配??梢允褂肙penCV中的cv::findHomography函數來計算相機的投影矩陣和特征點之間的變換關系。
下面是一個示例代碼,用于計算魚眼相機的外參:
#include <opencv2/opencv.hpp>
using namespace cv;
int main()
{
? ? // 加載圖像
? ? Mat image = imread("image.jpg");
? ? // 提取圖像中的特征點
? ? Ptr<FeatureDetector> detector = FastFeatureDetector::create();
? ? std::vector<KeyPoint> keypoints;
? ? detector->detect(image, keypoints);
? ? // 在場景中選擇幾個已知的三維點
? ? std::vector<Point3f> objectPoints;
? ? objectPoints.push_back(Point3f(0, 0, 0));
? ? objectPoints.push_back(Point3f(1, 0, 0));
? ? objectPoints.push_back(Point3f(0, 1, 0));
? ? objectPoints.push_back(Point3f(0, 0, 1));
? ? // 計算相機的外參
? ? Mat cameraMatrix = Mat::eye(3, 3, CV_64F); ?// 相機內參
? ? Mat distCoeffs = Mat::zeros(1, 5, CV_64F); ?// 畸變參數
? ? Mat rvec, tvec;
? ? solvePnP(objectPoints, keypoints, cameraMatrix, distCoeffs, rvec, tvec);
? ? // 計算相機的投影矩陣
? ? Mat R;
? ? Rodrigues(rvec, R);
? ? Mat projectionMatrix = Mat::zeros(3, 4, CV_64F);
? ? hconcat(R, tvec, projectionMatrix.rowRange(0, 3).colRange(0, 4));
? ? // 投影三維點到圖
?
6.
計算魚眼相機的外參需要先獲取相機的內參和畸變系數,這些參數可以通過相機的標定得到。假設已經獲取到這些參數,下面就可以使用OpenCV庫中的函數計算魚眼相機的外參了。
首先,你需要準備好至少6組二維點和三維點的對應關系。這些對應關系可以通過手動標記或者使用其他算法(如SIFT、SURF等)檢測到的特征點來獲取。在這里,我們假設這些對應關系已經準備好了。
下面是一個使用OpenCV庫函數計算魚眼相機的外參的示例代碼:
#include <opencv2/opencv.hpp>
#include <iostream>
using namespace std;
using namespace cv;
int main()
{
? ? // 讀取相機內參和畸變系數
? ? Mat K, D;
? ? FileStorage fs("calibration.xml", FileStorage::READ);
? ? fs["K"] >> K;
? ? fs["D"] >> D;
? ? // 讀取三維點和二維點的對應關系
? ? vector<Point3f> objectPoints;
? ? vector<Point2f> imagePoints;
? ? FileStorage fs2("points.xml", FileStorage::READ);
? ? fs2["objectPoints"] >> objectPoints;
? ? fs2["imagePoints"] >> imagePoints;
? ? // 計算外參
? ? Mat rvec, tvec;
? ? solvePnP(objectPoints, imagePoints, K, D, rvec, tvec);
? ? // 打印旋轉向量和平移向量
? ? cout << "Rotation Vector: " << rvec << endl;
? ? cout << "Translation Vector: " << tvec << endl;
? ? return 0;
}
在這個示例代碼中,我們首先讀取了相機的內參和畸變系數,然后讀取了三維點和二維點的對應關系。接下來,使用OpenCV中的solvePnP函數計算相機的外參,最后打印出旋轉向量和平移向量。
需要注意的是,在讀取相機內參和畸變系數以及三維點和二維點的對應關系時,你需要根據你自己的文件格式進行修改。另外,由于魚眼相機的畸變比較大,建議使用至少10組對應關系進行計算外參。
總結:
求魚眼相機的外參之前,需要先確定魚眼相機的內參+畸變參??梢酝ㄟ^solvePnP接口使用3d坐標、2d坐標、內參+畸變參求魚眼相機的外參,也可以先通過undistortPoints用內參+畸變參把2d坐標先去畸變,再用去畸變的2d坐標和3d坐標通過solvePnP接口求魚眼相機的外參。
總結
- 上一篇: 2017第十九届中国国际地面材料及铺装技
- 下一篇: 灵魂讲师分享的:po是什么?自动化测试p