Opencv 如何确定相机的世界坐标?

Opencv 如何确定相机的世界坐标?,opencv,pose-estimation,Opencv,Pose Estimation,我在墙上有一个已知尺寸和位置的矩形目标,机器人上有一个移动摄像机。当机器人在房间里行驶时,我需要定位目标并计算摄像机的位置及其姿势。作为进一步的改变,摄像机的仰角和方位角可以通过伺服装置来改变。我可以使用OpenCV定位目标,但在计算相机的位置时仍然模糊不清(实际上,上周我的头撞到墙上,额头上有一个平点)。以下是我正在做的: 读取先前计算的相机内部文件 从轮廓中获取目标矩形的4个点的像素坐标 使用矩形的世界坐标、像素坐标、相机矩阵和失真矩阵调用solvePnP 使用旋转和平移向量调用projec

我在墙上有一个已知尺寸和位置的矩形目标,机器人上有一个移动摄像机。当机器人在房间里行驶时,我需要定位目标并计算摄像机的位置及其姿势。作为进一步的改变,摄像机的仰角和方位角可以通过伺服装置来改变。我可以使用OpenCV定位目标,但在计算相机的位置时仍然模糊不清(实际上,上周我的头撞到墙上,额头上有一个平点)。以下是我正在做的:

  • 读取先前计算的相机内部文件
  • 从轮廓中获取目标矩形的4个点的像素坐标
  • 使用矩形的世界坐标、像素坐标、相机矩阵和失真矩阵调用solvePnP
  • 使用旋转和平移向量调用projectPoints
  • 我读过OpenCV的书,但我想我只是缺少了一些关于如何使用投影点、旋转和平移向量来计算相机的世界坐标及其姿势的知识(我不是数学天才):-(

    2013-04-02 按照“morynicz”的建议,我编写了这个简单的独立程序

    #include <Windows.h>
    #include "opencv\cv.h"
    
    using namespace cv;
    
    int main (int argc, char** argv)
    {
    const char          *calibration_filename = argc >= 2 ? argv [1] : "M1011_camera.xml";
    FileStorage         camera_data (calibration_filename, FileStorage::READ);
    Mat                 camera_intrinsics, distortion;
    vector<Point3d>     world_coords;
    vector<Point2d>     pixel_coords;
    Mat                 rotation_vector, translation_vector, rotation_matrix, inverted_rotation_matrix, cw_translate;
    Mat                 cw_transform = cv::Mat::eye (4, 4, CV_64FC1);
    
    
    // Read camera data
    camera_data ["camera_matrix"] >> camera_intrinsics;
    camera_data ["distortion_coefficients"] >> distortion;
    camera_data.release ();
    
    // Target rectangle coordinates in feet
    world_coords.push_back (Point3d (10.91666666666667, 10.01041666666667, 0));
    world_coords.push_back (Point3d (10.91666666666667, 8.34375, 0));
    world_coords.push_back (Point3d (16.08333333333334, 8.34375, 0));
    world_coords.push_back (Point3d (16.08333333333334, 10.01041666666667, 0));
    
    // Coordinates of rectangle in camera
    pixel_coords.push_back (Point2d (284, 204));
    pixel_coords.push_back (Point2d (286, 249));
    pixel_coords.push_back (Point2d (421, 259));
    pixel_coords.push_back (Point2d (416, 216));
    
    // Get vectors for world->camera transform
    solvePnP (world_coords, pixel_coords, camera_intrinsics, distortion, rotation_vector, translation_vector, false, 0);
    dump_matrix (rotation_vector, String ("Rotation vector"));
    dump_matrix (translation_vector, String ("Translation vector"));
    
    // We need inverse of the world->camera transform (camera->world) to calculate
    // the camera's location
    Rodrigues (rotation_vector, rotation_matrix);
    Rodrigues (rotation_matrix.t (), camera_rotation_vector);
    Mat t = translation_vector.t ();
    camera_translation_vector = -camera_rotation_vector * t;
    
    printf ("Camera position %f, %f, %f\n", camera_translation_vector.at<double>(0), camera_translation_vector.at<double>(1), camera_translation_vector.at<double>(2));
    printf ("Camera pose %f, %f, %f\n", camera_rotation_vector.at<double>(0), camera_rotation_vector.at<double>(1), camera_rotation_vector.at<double>(2));
    }
    
    如果我的世界坐标的Y轴与OpenCV的屏幕Y轴的Y轴相反,这会有问题吗?(我的坐标系的原点在目标左侧的地板上,而OpenCV的orgin在屏幕的左上角)


    姿势的单位是什么?

    你可以从中得到平移和旋转向量,它们告诉你物体在摄像机坐标中的位置。你需要得到一个逆变换

    变换摄影机->对象可以写为齐次坐标的矩阵
    [R^T;0 1]
    。使用其特殊属性,该矩阵的逆矩阵是
    [R^T-R^T*T;0 1]
    其中R^t是R转置的。你可以从变换中得到R矩阵。这样你可以得到变换对象->相机坐标的平移向量和旋转矩阵

    如果知道对象在世界坐标中的位置,可以使用世界->对象变换*对象->摄影机变换矩阵提取摄影机平移和姿势

    姿势可以用单矢量或R矩阵来描述,你肯定会在你的书中找到它。如果是“学习OpenCV”,你会在401-402页找到它:)

    看看你的代码,你需要这样做

        cv::Mat R;
        cv::Rodrigues(rotation_vector, R);
    
        cv::Mat cameraRotationVector;
    
        cv::Rodrigues(R.t(),cameraRotationVector);
    
        cv::Mat cameraTranslationVector = -R.t()*translation_vector;
    

    cameraTranslationVector
    包含摄像机坐标
    cameraRotationVector
    包含相机姿势。

    我花了很长时间才理解它,但姿势的含义是绕x、y、z轴旋转。 它以弧度为单位。值介于饼图到负饼图(-3.14-3.14)之间

    编辑:
    我可能弄错了。我读到姿势是一个矢量,表示摄像机的方向,矢量的长度表示摄像机围绕该矢量旋转了多少。

    我不确定我是否明白你的意思。如果R是一个3x3矩阵(来自传递给Rodrigues的solvePnP的旋转向量输出),并且它与T连接,T是平移向量(来自solvePnP的输出),则会产生一个3x4摄影机->对象矩阵。然后,我使用cv::transpose,正如您所展示的那样,反转矩阵,得到object->camera变换矩阵。世界->对象变换矩阵从何而来?我使用投影点还是findHomography?然后将其乘以前面计算的对象->摄影机矩阵。如何从生成的矩阵中提取相机的平移和姿势?R是3x3旋转矩阵,T是3x1平移向量。如果你把零放在R下面,把1放在T下面,你会得到一个齐次坐标系下的4x4变换矩阵(3个dims+1个位置向量)。世界->对象变换来自您的假设和自己的测量。在379-380的“学习OpenCV”一书中,我想我理解了379-380,它描述了从物体坐标到相机坐标的转换。我对“世界->对象”转换仍然不清楚。这就是物体的世界坐标吗?是否有一些代码可以帮我计算相机的姿势和XYZ位置?对于OpenCV库和转换概念来说,这是一个全新的概念,这真是让我大吃一惊!是的,那个物体坐标写在矩阵上(很抱歉不清楚)。关于计算摄像机的位置和所有的问题,是一个增强现实库,它一直在为它的标记做这件事。看看他们是怎么做的。我已经写了一个独立的程序,我相信它遵循了你的建议,但我一定是误解了一些事情。有什么想法吗?从姿势(
    solvePnP
    )得到的旋转向量是罗德里格斯旋转矩阵的紧凑表示。它们不是欧拉角(例如:俯仰、偏航、横摇)。使用
    Rodrigues
    [1]获取旋转矩阵。如果必须,可以在Rodrigues矩阵和Euler角度之间进行转换,请参见[2]。[1] [2]
        cv::Mat R;
        cv::Rodrigues(rotation_vector, R);
    
        cv::Mat cameraRotationVector;
    
        cv::Rodrigues(R.t(),cameraRotationVector);
    
        cv::Mat cameraTranslationVector = -R.t()*translation_vector;