确定相机姿势?

时间:2015-02-05 03:57:15

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

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

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

当前流程:

  1. 使用SIFT进行特征检测
  2. 使用SIFT进行描述符提取
  3. 使用FLANN进行匹配
  4. 使用CV_RANSAC
  5. 查找单应性
  6. 确定基准的角落
  7. 使用perspectiveTransform()
  8. 识别场景中基准点的角落
  9. 在角落周围画线(即证明它在场景中找到了基准
  10. 运行相机校准
  11. 加载校准结果(cameraMatrix& distortionCoefficients)
  12. 现在我想弄清楚相机的姿势。 我试图使用:

    void solvePnP(const Mat& objectPoints,const Mat&     imagePoints,const Mat& cameraMatrix,const Mat& distCoeffs,     垫&安培; 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;
    

1 个答案:

答案 0 :(得分:0)

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

输入参数:

  • objectPoints - 对象坐标空间中的对象点数组,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;

此外,您可以分享您的代码和错误消息吗?