简体   繁体   English

使用OpenCV从2D图像点计算3D世界点

[英]Calculating 3D world point from 2D image point using OpenCV

I'm developing application for iOS. 我正在为iOS开发应用程序。 I'm using the camera matrix according to the book Mastering OpenCV. 我根据Mastering OpenCV一书使用相机矩阵。 In my scenario I have a well known box. 在我的场景中,我有一个众所周知的盒子。 I know its real dimensions and I know exactly its corner's pixels. 我知道它的真实尺寸,我确切地知道它的角落的像素。 Using this information I calculate the camera rotation and the translation vector. 使用此信息,我计算相机旋转和平移向量。 From these parameters I'm able to calculate the camera position. 从这些参数我可以计算摄像机位置。 I'm checking my calculation by projecting the 3D world coordinate back to the image and I get very accurate results. 我通过将3D世界坐标投影回图像来检查我的计算,并得到非常准确的结果。

The world origin in my case is the middle of the bottom line of the box. 在我的情况下,世界起源是盒子底线的中间位置。 The box is open from one side. 盒子从一侧打开。 The image is taken in that direction, so I can see the content of the box. 图像是在那个方向拍摄的,所以我可以看到盒子的内容。

Now, I have object in the box. 现在,我在框中有对象。 I know very well image coordinate (2D) of the corners of this object. 我非常清楚这个物体角落的图像坐标(2D)。 I know the real hight of the corner (the real Y and Y <> 0). 我知道角落的真正高度(真正的Y和Y <> 0)。 How do I calculate the world X and Z of the corners of the object. 如何计算对象角落的世界X和Z.

Here my code: 这是我的代码:

#include "opencv2/core/core.hpp"
#include "opencv2/imgproc/imgproc.hpp"
#include "opencv2/calib3d/calib3d.hpp"
#include "opencv2/highgui/highgui.hpp"

#include <iostream>
#include <ctype.h>

using namespace cv;
using namespace std;


Point2f point;
vector<vector<Point2f>> objectPoints(1);
vector<vector<Point2f>> boxPoints(1);

Point3f calc3DPointOutOf2DwithYknown(double u, double v, float worldY, double fx, double fy, double cx, double cy, Mat tvec, Mat rotMat)
{
    Point3f tmpPoint;

    // This fiunction I need to complete
    return tmpPoint;
}

int main( int argc, char** argv )
{

    ///////// Loading image
    Mat sourceImage = imread("/Users/Ilan/Xcode/LK Test/LK Test/images/box_center640X480.jpg");

    namedWindow( "Source", 1 );

    ///// Setting box corners /////
    point = Point2f((float)102,(float)367.5);  //640X480
    boxPoints[0].push_back(point);
    circle( sourceImage, boxPoints[0][0], 3, Scalar(0,255,0), -1, 8);

    point = Point2f((float)83,(float)90.5);  //640X480
    boxPoints[0].push_back(point);
    circle( sourceImage, boxPoints[0][1], 3, Scalar(0,255,0), -1, 8);

    point = Point2f((float)520,(float)82.5);  //640X480
    boxPoints[0].push_back(point);
    circle( sourceImage, boxPoints[0][2], 3, Scalar(0,255,0), -1, 8);

    point = Point2f((float)510.5,(float)361);  //640X480
    boxPoints[0].push_back(point);
    circle( sourceImage, boxPoints[0][3], 3, Scalar(0,255,0), -1, 8);

    ///// Setting object corners /////
    point = Point2f((float)403.5,(float)250);  //640X480
    objectPoints[0].push_back(point);
    circle( sourceImage, objectPoints[0][0], 3, Scalar(0,255,0), -1, 8);

    point = Point2f((float)426.5,(float)251.5);  //640X480
    objectPoints[0].push_back(point);
    circle( sourceImage, objectPoints[0][1], 3, Scalar(0,255,0), -1, 8);

    imshow("Source", sourceImage);

    vector<vector<Point3f>> worldBoxPoints(1);
    Point3f tmpPoint;

    tmpPoint = Point3f((float)-100,(float)0,(float)0);
    worldBoxPoints[0].push_back(tmpPoint);
    tmpPoint = Point3f((float)-100,(float)-150,(float)0);
    worldBoxPoints[0].push_back(tmpPoint);
    tmpPoint = Point3f((float)100,(float)-150,(float)0);
    worldBoxPoints[0].push_back(tmpPoint);
    tmpPoint = Point3f((float)100,(float)0,(float)0);
    worldBoxPoints[0].push_back(tmpPoint);

    std::cout << "There are " << boxPoints[0].size() << " roomPoints and " << worldBoxPoints[0].size() << " worldRoomPoints." << std::endl;

    cv::Mat cameraMatrix1(3,3,cv::DataType<double>::type);
    cv::setIdentity(cameraMatrix1);

    cv::Mat distCoeffs1(4,1,cv::DataType<double>::type);
    distCoeffs1.at<double>(0) = 0;
    distCoeffs1.at<double>(1) = 0;
    distCoeffs1.at<double>(2) = 0;
    distCoeffs1.at<double>(3) = 0;


    //Taken from Mastring OpenCV
    double fx = 6.24860291e+02 * ((float)(sourceImage.cols)/352.);
    double fy = 6.24860291e+02 * ((float)(sourceImage.rows)/288.);
    double cx = (float)(sourceImage.cols)/2.;
    double cy = (float)(sourceImage.rows)/2.;

    cameraMatrix1.at<double>(0, 0) = fx;
    cameraMatrix1.at<double>(1, 1) = fy;
    cameraMatrix1.at<double>(0, 2) = cx;
    cameraMatrix1.at<double>(1, 2) = cy;

    std::cout << "After calib cameraMatrix --- 1: " << cameraMatrix1 << std::endl;
    std::cout << "After calib distCoeffs: --- 1" << distCoeffs1 << std::endl;

    cv::Mat rvec1(3,1,cv::DataType<double>::type);
    cv::Mat tvec1(3,1,cv::DataType<double>::type);

    cv::solvePnP(worldBoxPoints[0], boxPoints[0], cameraMatrix1, distCoeffs1, rvec1, tvec1);

    std::cout << "rvec --- 1: " << rvec1 << std::endl;
    std::cout << "tvec --- 1: " << tvec1 << std::endl;

    cv::Mat rvecM1(3,3,cv::DataType<double>::type);
    cv::Rodrigues(rvec1,rvecM1);

    std::cout << "cameraRotation --- 1 : " << rvecM1 << std::endl;
    std::cout << "cameraPosition --- 1 : " << (rvecM1.t())*((-1.0)*tvec1) << std::endl;

    std::vector<cv::Point2f> projectedPoints1;
    cv::projectPoints(worldBoxPoints[0], rvec1, tvec1, cameraMatrix1, distCoeffs1, projectedPoints1);

    for(unsigned int i = 0; i < projectedPoints1.size(); ++i)
    {
        std::cout << "box point --- 1: " << boxPoints[0][i] << " Projected to --- 1: " << projectedPoints1[i] << std::endl;
    }

    vector<vector<Point3f>> worldObjectPoints(1);

    tmpPoint = calc3DPointOutOf2DwithYknown(objectPoints[0][0].x, objectPoints[0][0].y, /*the real Y of the object*/ -40.0, fx, fy, cx, cy, tvec1, rvecM1);
    worldObjectPoints[0].push_back(tmpPoint);

    tmpPoint = calc3DPointOutOf2DwithYknown(objectPoints[0][1].x, objectPoints[0][1].y, /*the real Y of the object*/ -40.0, fx, fy, cx, cy, tvec1, rvecM1);
    worldObjectPoints[0].push_back(tmpPoint);

    cv::projectPoints(worldObjectPoints[0], rvec1, tvec1, cameraMatrix1, distCoeffs1, projectedPoints1);
    for(unsigned int i = 0; i < projectedPoints1.size(); ++i)
    {
        std::cout << "object point --- 1: " << objectPoints[0][i] << " Projected to --- 1: " << projectedPoints1[i] << std::endl;
    }

    waitKey(0);

    return 0;
}

So, I want to implement the calc3DPointOutOf2DwithYknown function. 所以,我想实现calc3DPointOutOf2DwithYknown函数。 Of course the parameters are according to what I understand now. 当然参数是根据我现在理解的。 If I need other parameters I'll use others. 如果我需要其他参数,我会使用其他参数。

Thanks you so much, Ilan 非常感谢你,Ilan

I succeed to solve it by myself. 我成功地自己解决了这个问题。 If it will help to any one, heres the code: 如果它对任何人都有帮助,那么下面是代码:

Point3f calc3DPointOutOf2DwithYknown(double u, double v, float worldY, double fx, double fy, double cx, double cy, Mat tvec, Mat rotMat)
{
    Point3f tmpPoint;

    float r1 = rotMat.at<double>(0,0);
    float r2 = rotMat.at<double>(0,1);
    float r3 = rotMat.at<double>(0,2);

    float r4 = rotMat.at<double>(1,0);
    float r5 = rotMat.at<double>(1,1);
    float r6 = rotMat.at<double>(1,2);

    float r7 = rotMat.at<double>(2,0);
    float r8 = rotMat.at<double>(2,1);
    float r9 = rotMat.at<double>(2,2);

    float t1 = tvec.at<double>(0,0);
    float t2 = tvec.at<double>(1,0);
    float t3 = tvec.at<double>(2,0);

    float xt = (u/fx) - (cx/fx);
    float yt = (v/fy) - (cy/fy);

    float K1 = xt*r8*worldY + xt*t3 - r2*worldY - t1;
    float K2 = xt*r9 - r3;
    float K3 = r1 - xt*r7;


    float worldZ = (yt*r7*K1 + yt*K3*r8*worldY + yt*K3*t3 - r4*K1 - K3*r5*worldY - K3*t2)/
                    (r4*K2 + K3*r6 - yt*r7*K2 - yt*K3*r9);

    float worldX = (K1 + worldZ*K2)/K3;


    tmpPoint = Point3f(worldX, worldY, worldZ);

    return tmpPoint;
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM