首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >如何使用openCV正确校准广角镜头的相机?

如何使用openCV正确校准广角镜头的相机?
EN

Stack Overflow用户
提问于 2017-09-14 18:23:06
回答 1查看 1.6K关注 0票数 1

我正在用鱼眼镜头校准相机。因此,我使用鱼眼镜头模块,但不断得到奇怪的结果,无论我确定什么样的失真参数。这是我使用的输入映像:https://i.imgur.com/apBuAwF.png

红色的圆圈表示我用来校准相机的角落。

这是我所能得到的最好的输出:https://imgur.com/a/XeXk5

我目前还不知道相机传感器的尺寸是什么,但是根据我的本征矩阵中正在计算的像素焦距,我推断出我的传感器大小大约是3.3mm (假设我的物理焦距是1.8mm),这对我来说是现实的。然而,当我不扭曲我的输入图像时,我就变得无稽之谈。有人能告诉我我可能做错了什么吗?

校准输出的矩阵和均方根:

代码语言:javascript
复制
K:[263.7291703200009, 0, 395.1618975493187;
 0, 144.3800397321767, 188.9308218101271;
 0, 0, 1]

D:[0, 0, 0, 0]

rms: 9.27628

我的代码:

代码语言:javascript
复制
#include <opencv2/opencv.hpp>
#include "opencv2/core.hpp"
#include "opencv2/imgcodecs.hpp"
#include "opencv2/imgproc.hpp"
#include "opencv2/highgui.hpp"
#include "opencv2/ccalib/omnidir.hpp"

using namespace std;
using namespace cv;

vector<vector<Point2d> > points2D;
vector<vector<Point3d> > objectPoints;

Mat src;

//so that I don't have to select them manually every time
void initializePoints2D()
{
    points2D[0].push_back(Point2d(234, 128));
    points2D[0].push_back(Point2d(300, 124));
    points2D[0].push_back(Point2d(381, 126));
    points2D[0].push_back(Point2d(460, 127));
    points2D[0].push_back(Point2d(529, 137));
    points2D[0].push_back(Point2d(207, 147));
    points2D[0].push_back(Point2d(280, 147));
    points2D[0].push_back(Point2d(379, 146));
    points2D[0].push_back(Point2d(478, 153));
    points2D[0].push_back(Point2d(551, 165));
    points2D[0].push_back(Point2d(175, 180));
    points2D[0].push_back(Point2d(254, 182));
    points2D[0].push_back(Point2d(377, 185));
    points2D[0].push_back(Point2d(502, 191));
    points2D[0].push_back(Point2d(586, 191));
    points2D[0].push_back(Point2d(136, 223));
    points2D[0].push_back(Point2d(216, 239));
    points2D[0].push_back(Point2d(373, 253));
    points2D[0].push_back(Point2d(534, 248));
    points2D[0].push_back(Point2d(624, 239));
    points2D[0].push_back(Point2d(97, 281));
    points2D[0].push_back(Point2d(175, 322));
    points2D[0].push_back(Point2d(370, 371));
    points2D[0].push_back(Point2d(578, 339));
    points2D[0].push_back(Point2d(662, 298));


    for(int j=0; j<25;j++)
    {   
        circle(src, points2D[0].at(j), 5, Scalar(0, 0, 255), 1, 8, 0);
    }

    imshow("src with circles", src);
    waitKey(0);
}

int main(int argc, char** argv)
{
    Mat srcSaved;

    src = imread("images/frontCar.png");
    resize(src, src, Size(), 0.5, 0.5);
    src.copyTo(srcSaved);

    vector<Point3d> objectPointsRow;
    vector<Point2d> points2DRow;
    objectPoints.push_back(objectPointsRow);
    points2D.push_back(points2DRow);

    for(int i=0; i<5;i++)
    {

        for(int j=0; j<5;j++)
        {
            objectPoints[0].push_back(Point3d(5*j,5*i,1));        
        }
    }

    initializePoints2D();
    cv::Matx33d K;
    cv::Vec4d D;
    std::vector<cv::Vec3d> rvec;
    std::vector<cv::Vec3d> tvec;


    int flag = 0;
    flag |= cv::fisheye::CALIB_RECOMPUTE_EXTRINSIC;
    flag |= cv::fisheye::CALIB_CHECK_COND;
    flag |= cv::fisheye::CALIB_FIX_SKEW; 
    flag |= cv::fisheye::CALIB_FIX_K1; 
    flag |= cv::fisheye::CALIB_FIX_K2; 
    flag |= cv::fisheye::CALIB_FIX_K3; 
    flag |= cv::fisheye::CALIB_FIX_K4; 


    double rms =cv::fisheye::calibrate(
 objectPoints, points2D, src.size(), 
 K, D, rvec, tvec, flag, cv::TermCriteria(3, 20, 1e-6)     
 );

    Mat output;
    cerr<<"K:"<<K<<endl;
    cerr<<"D:"<<D<<endl;
    cv::fisheye::undistortImage(srcSaved, output, K, D);
    cerr<<"rms: "<<rms<<endl;
    imshow("output", output);
    waitKey(0);

    cerr<<"image .size: "<<srcSaved.size()<<endl;

}

如果有人有想法,可以在C++中任意一种共享Python中的代码。不管你的船是什么。

编辑:

正如你可能已经注意到,我不使用黑白棋盘进行校准,但角落从瓷砖构成我的地毯。在一天结束时,目标-I认为-是获得角坐标,代表样本的失真半径。地毯在某种程度上和棋盘是一样的,我认为唯一的区别是,在地毯上的那些角落里,你的高频边缘比黑白棋盘上的高频率边缘要少。

我知道图片的数量非常有限(只有1张)(我希望图像在一定程度上不失真,但我也希望图像不失真会做得很好。)但在这种情况下,图像输出看起来完全是胡说八道。

最后,我用这个网站提供的棋盘:https://imgur.com/a/WlLBRhttps://sites.google.com/site/scarabotix/ocamcalib-toolbox/ocamcalib-toolbox-download-page使用了这个图像,但是结果仍然很差:像我发布的其他输出图像一样的对角线。

谢谢

EN

回答 1

Stack Overflow用户

发布于 2017-09-15 00:50:18

您的第一个问题是,您只使用一个图像。即使你有一个没有失真的理想针孔相机,你也无法从一个共面点的图像中估计出它的本质。一幅共面点的图像根本没有给你足够的约束来解决本质问题。

你至少需要两个不同的三维方向的图像,或一个三维校准平台,其中的点不是共面的。当然,在实践中,您需要至少20幅图像来进行精确的校准。

你的第二个问题是你用地毯做棋盘。你需要能够以亚像素的精度检测图像中的点。小的定位误差会导致估计的摄像机参数产生较大的误差。我很怀疑你是否能用任何合理的准确性探测到你的地毯的角。事实上,你甚至不能非常准确地测量地毯上的实际点位置,因为它是模糊的。

祝你好运!

票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/46225943

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档