确定相机姿势?
Determine camera pose?
我正在尝试根据在场景中找到的基准标记来确定相机姿势。
基准:http://tinypic.com/view.php?pic=4r6k3q&s=8#.VNLnWTVVK1E
当前进程:
- 使用 SIFT 进行特征检测
- 使用 SIFT 进行描述符提取
- 使用FLANN进行匹配
- 使用CV_RANSAC
求单应性
- 识别基准点的角
- 使用 perspectiveTransform() 识别场景中基准的角点
- 在拐角处画线(即证明它在场景中找到了基准点
- 运行 相机校准
- 加载校准结果(相机矩阵和失真系数)
现在我想弄清楚相机的姿势。
我尝试使用:
void solvePnP(const Mat& objectPoints, const Mat&
imagePoints, const Mat& cameraMatrix, const Mat& distCoeffs,
Mat& rvec, Mat& tvec, bool useExtrinsicGuess=false)
其中:
- obectPoints 是基准角
- 图像点是场景中的基准角
- cameraMatrix 来自校准
- distCoeffs 来自校准
- rvec 和 tvec 应该从这个函数返回给我
但是,当我 运行 这样做时,我得到一个核心转储错误,所以我不确定我做错了什么。
我没有找到关于 solvePNP() 的非常好的文档 - 我是否误解了函数或输入参数?
感谢您的帮助
更新
这是我的过程:
OrbFeatureDetector detector; //Orb seems more accurate than SIFT
vector<KeyPoint> keypoints1, keypoints2;
detector.detect(marker_im, keypoints1);
detector.detect(scene_im, keypoints2);
Mat display_marker_im, display_scene_im;
drawKeypoints(marker_im, keypoints1, display_marker_im, Scalar(0,0,255));
drawKeypoints(scene_im, keypoints2, display_scene_im, Scalar(0,0,255));
SiftDescriptorExtractor extractor;
Mat descriptors1, descriptors2;
extractor.compute( marker_im, keypoints1, descriptors1 );
extractor.compute( scene_im, keypoints2, descriptors2 );
BFMatcher matcher; //BF seems to match better than FLANN
vector< DMatch > matches;
matcher.match( descriptors1, descriptors2, matches );
Mat img_matches;
drawMatches( marker_im, keypoints1, scene_im, keypoints2,
matches, img_matches, Scalar::all(-1), Scalar::all(-1),
vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
vector<Point2f> obj, scene;
for (int i = 0; i < matches.size(); i++) {
obj.push_back(keypoints1[matches[i].queryIdx].pt);
scene.push_back(keypoints2[matches[i].trainIdx].pt);
}
Mat H;
H = findHomography(obj, scene, CV_RANSAC);
//Get corners of fiducial
vector<Point2f> obj_corners(4);
obj_corners[0] = cvPoint(0,0);
obj_corners[1] = cvPoint(marker_im.cols, 0);
obj_corners[2] = cvPoint(marker_im.cols, marker_im.rows);
obj_corners[3] = cvPoint(0, marker_im.rows);
vector<Point2f> scene_corners(4);
perspectiveTransform(obj_corners, scene_corners, H);
FileStorage fs2("cal.xml", FileStorage::READ);
Mat cameraMatrix, distCoeffs;
fs2["Camera_Matrix"] >> cameraMatrix;
fs2["Distortion_Coefficients"] >> distCoeffs;
Mat rvec, tvec;
//same points as object_corners, just adding z-axis (0)
vector<Point3f> objp(4);
objp[0] = cvPoint3D32f(0,0,0);
objp[1] = cvPoint3D32f(gray.cols, 0, 0);
objp[2] = cvPoint3D32f(gray.cols, gray.rows, 0);
objp[3] = cvPoint3D32f(0, gray.rows, 0);
solvePnPRansac(objp, scene_corners, cameraMatrix, distCoeffs, rvec, tvec );
Mat rotation, viewMatrix(4, 4, CV_64F);
Rodrigues(rvec, rotation);
for(int row=0; row<3; ++row)
{
for(int col=0; col<3; ++col)
{
viewMatrix.at<double>(row, col) = rotation.at<double>(row, col);
}
viewMatrix.at<double>(row, 3) = tvec.at<double>(row, 0);
}
viewMatrix.at<double>(3, 3) = 1.0f;
cout << "rotation: " << rotation << endl;
cout << "viewMatrix: " << viewMatrix << endl;
好的,所以 solvePnP()
给出了从模型框架(即立方体)到相机框架(称为视图矩阵)的传输矩阵。
输入参数:
objectPoints
– 对象坐标 space 中的对象点数组,3xN/Nx3 1 通道或 1xN/Nx1 3 通道,其中 N 是点数。 std::vector<cv::Point3f>
这里也可以传。这些点是 3D 的,但由于它们位于(基准标记的)图案坐标系中,因此装备是平面的,因此每个输入对象点的 Z 坐标为 0,
imagePoints
– 相应图像点的数组,2xN/Nx2 1 通道或 1xN/Nx1 2 通道,其中 N 是点数。 std::vector<cv::Point2f>
这里也可以传,
intrinsics
:相机矩阵(焦距,主点),
distortion
:失真系数,如果为空则假定失真系数为零,
rvec
:输出旋转向量
tvec
: 输出平移向量
视图矩阵的构建是这样的:
cv::Mat rvec, tvec;
cv::solvePnP(objectPoints, imagePoints, intrinsics, distortion, rvec, tvec);
cv::Mat rotation, viewMatrix(4, 4, CV_64F);
cv::Rodrigues(rvec, rotation);
for(int row=0; row<3; ++row)
{
for(int col=0; col<3; ++col)
{
viewMatrix.at<double>(row, col) = rotation.at<double>(row, col);
}
viewMatrix.at<double>(row, 3) = tvec.at<double>(row, 0);
}
viewMatrix.at<double>(3, 3) = 1.0f;
另外,能否分享一下你的代码和报错信息?
我正在尝试根据在场景中找到的基准标记来确定相机姿势。
基准:http://tinypic.com/view.php?pic=4r6k3q&s=8#.VNLnWTVVK1E
当前进程:
- 使用 SIFT 进行特征检测
- 使用 SIFT 进行描述符提取
- 使用FLANN进行匹配
- 使用CV_RANSAC 求单应性
- 识别基准点的角
- 使用 perspectiveTransform() 识别场景中基准的角点
- 在拐角处画线(即证明它在场景中找到了基准点
- 运行 相机校准
- 加载校准结果(相机矩阵和失真系数)
现在我想弄清楚相机的姿势。 我尝试使用:
void solvePnP(const Mat& objectPoints, const Mat& imagePoints, const Mat& cameraMatrix, const Mat& distCoeffs, Mat& rvec, Mat& tvec, bool useExtrinsicGuess=false)
其中:
- obectPoints 是基准角
- 图像点是场景中的基准角
- cameraMatrix 来自校准
- distCoeffs 来自校准
- rvec 和 tvec 应该从这个函数返回给我
但是,当我 运行 这样做时,我得到一个核心转储错误,所以我不确定我做错了什么。
我没有找到关于 solvePNP() 的非常好的文档 - 我是否误解了函数或输入参数?
感谢您的帮助
更新 这是我的过程:
OrbFeatureDetector detector; //Orb seems more accurate than SIFT
vector<KeyPoint> keypoints1, keypoints2;
detector.detect(marker_im, keypoints1);
detector.detect(scene_im, keypoints2);
Mat display_marker_im, display_scene_im;
drawKeypoints(marker_im, keypoints1, display_marker_im, Scalar(0,0,255));
drawKeypoints(scene_im, keypoints2, display_scene_im, Scalar(0,0,255));
SiftDescriptorExtractor extractor;
Mat descriptors1, descriptors2;
extractor.compute( marker_im, keypoints1, descriptors1 );
extractor.compute( scene_im, keypoints2, descriptors2 );
BFMatcher matcher; //BF seems to match better than FLANN
vector< DMatch > matches;
matcher.match( descriptors1, descriptors2, matches );
Mat img_matches;
drawMatches( marker_im, keypoints1, scene_im, keypoints2,
matches, img_matches, Scalar::all(-1), Scalar::all(-1),
vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS );
vector<Point2f> obj, scene;
for (int i = 0; i < matches.size(); i++) {
obj.push_back(keypoints1[matches[i].queryIdx].pt);
scene.push_back(keypoints2[matches[i].trainIdx].pt);
}
Mat H;
H = findHomography(obj, scene, CV_RANSAC);
//Get corners of fiducial
vector<Point2f> obj_corners(4);
obj_corners[0] = cvPoint(0,0);
obj_corners[1] = cvPoint(marker_im.cols, 0);
obj_corners[2] = cvPoint(marker_im.cols, marker_im.rows);
obj_corners[3] = cvPoint(0, marker_im.rows);
vector<Point2f> scene_corners(4);
perspectiveTransform(obj_corners, scene_corners, H);
FileStorage fs2("cal.xml", FileStorage::READ);
Mat cameraMatrix, distCoeffs;
fs2["Camera_Matrix"] >> cameraMatrix;
fs2["Distortion_Coefficients"] >> distCoeffs;
Mat rvec, tvec;
//same points as object_corners, just adding z-axis (0)
vector<Point3f> objp(4);
objp[0] = cvPoint3D32f(0,0,0);
objp[1] = cvPoint3D32f(gray.cols, 0, 0);
objp[2] = cvPoint3D32f(gray.cols, gray.rows, 0);
objp[3] = cvPoint3D32f(0, gray.rows, 0);
solvePnPRansac(objp, scene_corners, cameraMatrix, distCoeffs, rvec, tvec );
Mat rotation, viewMatrix(4, 4, CV_64F);
Rodrigues(rvec, rotation);
for(int row=0; row<3; ++row)
{
for(int col=0; col<3; ++col)
{
viewMatrix.at<double>(row, col) = rotation.at<double>(row, col);
}
viewMatrix.at<double>(row, 3) = tvec.at<double>(row, 0);
}
viewMatrix.at<double>(3, 3) = 1.0f;
cout << "rotation: " << rotation << endl;
cout << "viewMatrix: " << viewMatrix << endl;
好的,所以 solvePnP()
给出了从模型框架(即立方体)到相机框架(称为视图矩阵)的传输矩阵。
输入参数:
objectPoints
– 对象坐标 space 中的对象点数组,3xN/Nx3 1 通道或 1xN/Nx1 3 通道,其中 N 是点数。std::vector<cv::Point3f>
这里也可以传。这些点是 3D 的,但由于它们位于(基准标记的)图案坐标系中,因此装备是平面的,因此每个输入对象点的 Z 坐标为 0,imagePoints
– 相应图像点的数组,2xN/Nx2 1 通道或 1xN/Nx1 2 通道,其中 N 是点数。std::vector<cv::Point2f>
这里也可以传,intrinsics
:相机矩阵(焦距,主点),distortion
:失真系数,如果为空则假定失真系数为零,rvec
:输出旋转向量tvec
: 输出平移向量
视图矩阵的构建是这样的:
cv::Mat rvec, tvec;
cv::solvePnP(objectPoints, imagePoints, intrinsics, distortion, rvec, tvec);
cv::Mat rotation, viewMatrix(4, 4, CV_64F);
cv::Rodrigues(rvec, rotation);
for(int row=0; row<3; ++row)
{
for(int col=0; col<3; ++col)
{
viewMatrix.at<double>(row, col) = rotation.at<double>(row, col);
}
viewMatrix.at<double>(row, 3) = tvec.at<double>(row, 0);
}
viewMatrix.at<double>(3, 3) = 1.0f;
另外,能否分享一下你的代码和报错信息?