【问题标题】:Determine camera pose?确定相机姿势?
【发布时间】:2015-02-06 07:25:46
【问题描述】:

我正在尝试根据场景中找到的基准标记来确定相机姿势。

基准:http://tinypic.com/view.php?pic=4r6k3q&s=8#.VNLnWTVVK1E

当前进程:

  1. 使用 SIFT 进行特征检测
  2. 使用 SIFT 进行描述符提取
  3. 使用 FLANN 进行匹配
  4. 使用 CV_RANSAC 查找单应性
  5. 识别基准点的角
  6. 使用 perspectiveTransform() 识别场景中基准点的角
  7. 在拐角处画线(即证明它在场景中找到了基准点
  8. 运行相机校准
  9. 负载校准结果(cameraMatrix 和失真系数)

现在我正在尝试找出相机的姿势。 我尝试使用:

void solvePnP(const Mat& objectPoints, const Mat& imagePoints, const Mat& cameraMatrix, const Mat& distCoeffs, Mat& rvec, Mat& tvec, bool useExtrinsicGuess=false)

地点:

  • obectPoints 是基准角
  • imagePoints 是场景中的基准角
  • 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;

【问题讨论】:

    标签: c++ opencv computer-vision camera-calibration perspectivecamera


    【解决方案1】:

    好的,所以solvePnP() 为您提供了从模型框架(即立方体)到相机框架(称为视图矩阵)的传输矩阵。

    输入参数:

    • objectPoints – 对象坐标空间中的对象点数组,3xN/Nx3 1 通道或 1xN/Nx1 3 通道,其中 N 是点数。 std::vector&lt;cv::Point3f&gt; 也可以在这里传递。这些点是 3D 的,但由于它们位于(基准标记的)图案坐标系中,因此装备是平面的,因此每个输入对象点的 Z 坐标为 0,
    • imagePoints – 对应图像点的阵列,2xN/Nx2 1 通道或 1xN/Nx1 2 通道,其中 N 是点数。 std::vector&lt;cv::Point2f&gt;这里也可以传,
    • 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;
    

    另外,你能分享你的代码和错误信息吗?

    【讨论】:

    • 找到标定棋盘的外参。我试图根据基准标记找到相机姿势。还是我误会了你?
    • Kornel - 所以如果我想找到相机相对于基准的 (xyz) 位置,我会采用基准 xyz,根据旋转矩阵旋转,然后平移?
    • 抱歉迟到了。因此,对于姿势估计,您应该有一个具有已知 3D 几何形状和图像平面上位置的校准图案(例如您的基准图案)。 cv::solvePnP() 将从 3D-2D 点对应关系中找到所需的对象姿势,因此此函数的输出(rvecstvecs)将点从模型坐标系带到相机坐标系。如果您想找到相机相对于基准图案的位置,您应该反转转换。
    • 还有一件事,在你的情况下是图案修复的位置,相机是否漂浮在它周围?
    • 固定图案周围的浮动摄像头
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2013-11-05
    • 2017-11-27
    • 1970-01-01
    • 2019-01-16
    • 2013-02-15
    • 2016-03-10
    • 2015-05-01
    相关资源
    最近更新 更多