Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/opencv/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Opencv 给定4个已知点的平面世界点的摄影机像素_Opencv_3d_Camera Calibration - Fatal编程技术网

Opencv 给定4个已知点的平面世界点的摄影机像素

Opencv 给定4个已知点的平面世界点的摄影机像素,opencv,3d,camera-calibration,Opencv,3d,Camera Calibration,我假设我的问题很简单,但由于我之前在线性代数方面的经验,我仍然无法解决它。我读过几所大学发表的演讲稿,但我似乎无法遵循某种程度上的非标准化符号。如果有人有更好的例子,我们将不胜感激 问题: 摄像机向下倾斜,面向地面。给定一个像素坐标,我希望能够得到地板平面上相应的3D世界坐标 已知: 地板上有4个点,我知道像素(x,y)坐标和相关的世界(x,y,Z=0)坐标 相机的位置是固定的,我知道相机在X、Y、Z方向上的位移 未知: 相机绕x、y、z轴旋转。首先,相机是围绕X轴旋转的,Y和Z轴是最小的

我假设我的问题很简单,但由于我之前在线性代数方面的经验,我仍然无法解决它。我读过几所大学发表的演讲稿,但我似乎无法遵循某种程度上的非标准化符号。如果有人有更好的例子,我们将不胜感激

问题: 摄像机向下倾斜,面向地面。给定一个像素坐标,我希望能够得到地板平面上相应的3D世界坐标

已知:

  • 地板上有4个点,我知道像素(x,y)坐标和相关的世界(x,y,Z=0)坐标
  • 相机的位置是固定的,我知道相机在X、Y、Z方向上的位移
未知:

  • 相机绕x、y、z轴旋转。首先,相机是围绕X轴旋转的,Y和Z轴是最小的旋转,但我认为应该考虑到这一点
  • 失真系数,但是,线条中的图像弯曲最小,更希望不引入棋盘格校准程序。由此产生的某些错误不是交易的破坏者
我调查的内容 一个现象性的例子本质上是同一个问题,但有一些后续问题:

SolvePnP看起来是我的朋友,但我不太确定如何处理相机矩阵或距离系数。有没有什么方法可以避免摄像机矩阵和距离系数校准步骤,我认为这是通过棋盘过程完成的(可能会以牺牲一些精度为代价)?还是有更简单的方法


非常感谢你的意见

当然可以,您可以将
cameraMatrix
设置为身份矩阵(
eye(3)
),并将
distcourties
设置为NULL,solvePNP将假定您拥有完美的相机。正如你所说,这会带来一些额外的不准确,但你仍然会得到答案

如果你发现你的结果不够准确,那么相机校准其实没什么大不了的。

试试这种方法:

从4点对应计算单应性,为您提供在图像平面和地平面坐标之间转换的所有信息

这种方法的局限性在于它假设了一个统一参数化的图像平面(针孔相机),所以镜头畸变会给你们带来误差,如我的例子所示。如果你能够消除镜头失真的影响,我想你会很好地使用这种方法。 此外,如果在对应关系中给出的像素坐标稍有错误,则会出现一些错误。如果提供更多的对应关系,则可以获得更稳定的值

使用此输入图像

我从一个图像处理软件中读取了一个棋场的4个角,这与你在图像中知道4个点的事实相对应。我选择了这些点(标记为绿色):

现在我已经做了两件事:首先将棋盘图案坐标转换为图像(0,0),(0,1)等。这会给人一个映射质量的良好视觉印象。第二,我从图像转换到世界。读取图像位置(87291)中的最左角位置,该位置对应于棋盘坐标中的(0,0)。如果我变换那个像素位置,你会期望结果是(0,0)

cv::Point2f transformPoint(cv::Point2f current, cv::Mat transformation)
{
    cv::Point2f transformedPoint;
    transformedPoint.x = current.x * transformation.at<double>(0,0) + current.y * transformation.at<double>(0,1) + transformation.at<double>(0,2);
    transformedPoint.y = current.x * transformation.at<double>(1,0) + current.y * transformation.at<double>(1,1) + transformation.at<double>(1,2);
    float z = current.x * transformation.at<double>(2,0) + current.y * transformation.at<double>(2,1) + transformation.at<double>(2,2);
    transformedPoint.x /= z;
    transformedPoint.y /= z;

    return transformedPoint;
}

int main()
{
    // image from http://d20uzhn5szfhj2.cloudfront.net/media/catalog/product/cache/1/image/9df78eab33525d08d6e5fb8d27136e95/5/2/52440-chess-board.jpg

    cv::Mat chessboard = cv::imread("../inputData/52440-chess-board.jpg");

    // known input:
    // image locations / read pixel values
    //  478,358
    //  570, 325
    //  615,382
    //  522,417

    std::vector<cv::Point2f> imageLocs;
    imageLocs.push_back(cv::Point2f(478,358));
    imageLocs.push_back(cv::Point2f(570, 325));
    imageLocs.push_back(cv::Point2f(615,382));
    imageLocs.push_back(cv::Point2f(522,417));

    for(unsigned int i=0; i<imageLocs.size(); ++i)
    {
        cv::circle(chessboard, imageLocs[i], 5, cv::Scalar(0,0,255));
    }
    cv::imwrite("../outputData/chessboard_4points.png", chessboard);

    // known input: this is one field of the chessboard. you could enter any (corresponding) real world coordinates of the ground plane here.
    // world location:
    // 3,3
    // 3,4
    // 4,4
    // 4,3

    std::vector<cv::Point2f> worldLocs;
    worldLocs.push_back(cv::Point2f(3,3));
    worldLocs.push_back(cv::Point2f(3,4));
    worldLocs.push_back(cv::Point2f(4,4));
    worldLocs.push_back(cv::Point2f(4,3));


    // for exactly 4 correspondences. for more you can use cv::findHomography
    // this is the transformation from image coordinates to world coordinates:
    cv::Mat image2World = cv::getPerspectiveTransform(imageLocs, worldLocs);
    // the inverse is the transformation from world to image.
    cv::Mat world2Image = image2World.inv();


    // create all known locations of the chessboard (0,0) (0,1) etc we will transform them and test how good the transformation is.
    std::vector<cv::Point2f> worldLocations;
    for(unsigned int i=0; i<9; ++i)
        for(unsigned int j=0; j<9; ++j)
        {
            worldLocations.push_back(cv::Point2f(i,j));
        }


    std::vector<cv::Point2f> imageLocations;

    for(unsigned int i=0; i<worldLocations.size(); ++i)
    {
        // transform the point
        cv::Point2f tpoint = transformPoint(worldLocations[i], world2Image);
        // draw the transformed point
        cv::circle(chessboard, tpoint, 5, cv::Scalar(255,255,0));
    }

    // now test the other way: image => world
    cv::Point2f imageOrigin = cv::Point2f(87,291);
    // draw it to show which origin i mean
    cv::circle(chessboard, imageOrigin, 10, cv::Scalar(255,255,255));
    // transform point and print result. expected result is "(0,0)"
    std::cout << transformPoint(imageOrigin, image2World) << std::endl;

    cv::imshow("chessboard", chessboard);
    cv::imwrite("../outputData/chessboard.png", chessboard);
    cv::waitKey(-1);


}
预期/完美的结果应该是
[0,0]


希望这能有所帮助。

嘿,我很感谢您的回复。嗯,我本该想到假设完美的条件。在我标出答案之前,让我试一试。计算从图像到地板坐标的单应性。如果相机是静态的,这不是你所需要的吗?嘿,这是个很酷的主意。所以本质上我是在计算透视变换矩阵,然后这就是你来回循环的方式。所以我更多地研究了镜头失真等问题,看起来还不算太糟。这一因素在哪里?在第一次读取图像时,立即取消对其的扭曲?是的,取消对原始图像的扭曲(也调整已知点的图像位置),就完成了
[0.174595, 0.144853]