温馨提示×

温馨提示×

您好,登录后才能下订单哦!

密码登录×
登录注册×
其他方式登录
点击 登录注册 即表示同意《亿速云用户服务条款》

OpenCV相机标定的示例分析

发布时间:2021-06-11 14:00:30 来源:亿速云 阅读:273 作者:小新 栏目:编程语言

这篇文章将为大家详细讲解有关OpenCV相机标定的示例分析,小编觉得挺实用的,因此分享给大家做个参考,希望大家阅读完这篇文章后可以有所收获。

相机标定:简单的说,就是获得相机参数的过程。参数如:相机内参数矩阵,投影矩阵,旋转矩阵和平移矩阵等

什么叫相机参数?

简单的说,将现实世界中的人、物,拍成一张图像(二维)。人或物在世界中的三维坐标,和图像上对应的二维坐标间的关系。表达两种不同维度坐标间的关系用啥表示?用相机参数。

相机的成像原理

先来看一下,相机的成像原理:

OpenCV相机标定的示例分析 

如图所示,这是一个相机模型。将物体简化看成一个点。来自物体的光,通过镜头,击中图像平面(图像传感器),以此成像。d0是物体到镜头的距离,di时镜头到图像平面的距离,f是镜头的焦距。三者满足以下关系。

OpenCV相机标定的示例分析 

现在,简化上面的相机模型。

将相机孔径看成无穷小,只考虑中心位置的射线,这样就忽视了透镜的影响。然后由于d0远远大于di,将图像平面放在焦距处,这样物体在图像平面上成像为倒立的影像(没有透镜的影响,只考虑从中心的孔径进入的光线)。这个简化的模型就是针孔摄像机模型。然后,我们在镜头前,将图像平面放在焦距距离的位置,就可以简单获得一个笔直的图像(不倒立)。当然,这只是理论上的,你不可能将图像传感器从相机里拿出来,放在镜头前面。实际应用中,针孔摄像机应该是将成像后的图像倒过来,以获得正立的图像。
到此,我们获得了一个简化的模型,如下图:

OpenCV相机标定的示例分析 

h0是物体的高,hi是图像上物体的高,f是焦距(距离),d0是图像到镜头的距离。四者满足如下关系:

OpenCV相机标定的示例分析(1)

物体在图像中的高度hi,和d0成反比。也就是说,离镜头越远,物体在图像中越小,离得越近越大(好吧,这句话是废话)。
但通过这个式子,我们便能够预测三维中的物体,在图像(二维)中的位置。那么怎么预测?

相机标定

如下图所示,根据上面简化的模型,考虑三维世界中的一个点,和其在图像(二维)中的坐标关系。

OpenCV相机标定的示例分析 

(X,Y,Z)为点的三维坐标,(x,y)为其通过相机成像后在图像(二维)上的坐标。u0和v0是相机的中心点(主点),该点位于图像平面中心(理论上是这样。但实际的相机会有几个像素的偏差)
现在只考虑y方向上,由于需要将三维世界中的坐标,转换为图像上的像素(图像上的坐标,实际上是像素的位置),需要求y方向上焦距等于多少个像素(用像素值表示焦距),Py表示像素的高,焦距f(米或毫米)。垂直像素表示的焦距为

OpenCV相机标定的示例分析

根据式子(1),只考虑y方向。我们三维世界中得点,在图像(二维)中y的坐标。

OpenCV相机标定的示例分析 

同理,得到x的坐标。

OpenCV相机标定的示例分析 

现在,将上图中的坐标系的原点O,移动到图像的左上角。由于(x,y)是关于(u0,v0)的偏移,上面表示图像(二维)中点的坐标的式子不变。将式子以矩阵的形式重写,得。

OpenCV相机标定的示例分析 

其中,等式左边的第一个矩阵,叫做“相机内参数矩阵”,第二个矩阵叫(投影矩阵)。

更为一般的情况,开始时的参考坐标系不位于主点(中心点),需要额外两个参数“旋转向量”和“平移向量”来表示这个式子,这两个参数在不同视角中是不一样的。整合后,上述式子重写为。

OpenCV相机标定的示例分析

校正畸变

通过相机标定,获得了相机参数后,可以计算两个映射函数(x坐标和y坐标),它们分别给出了没有畸变的图像坐标。将畸变的图像重新映射成为没有畸变的图像。

代码:

做相机标定时,一般用标定板(棋盘)拍摄一组图像,利用这些图像提取角点,通过角点在图像中得坐标和三维世界中的坐标(通常自定义3维坐标),计算相机参数。

std::vector<cv::Point2f>imageConers; //提取标定图像角点,保存角点坐标(二维)  cv::findChessboardCorners(image,  boardSize, //角点数目如(6,4)六行,四列  imageConers);

函数calibrateCamera完成相机标定工作。

cv::calibrateCamera(objectPoints,//三维坐标  imagePoints, //二维坐标  imageSize,//图像大小  camerMatirx,//相机内参数矩阵  disCoeffs,//投影矩阵  rvecs, //旋转  tvecs,//平移 flag //标记opencv提供几种参数,可以参看在线的opencv document );

计算畸变参数,去畸变

//计算畸变参数 cv::initUndistortRectifyMap(camerMatirx, disCoeffs,   cv::Mat(), cv::Mat(), image.size(), CV_32FC1,    map1, //x映射函数   map2 //y映射函数   ); //应用映射函数 cv::remap(image, //畸变图像 undistorted, //去畸变图像 map1, map2, cv::INTER_LINEAR);

现在整合代码。

示例:

标头.h

#include<opencv2\core\core.hpp> #include<opencv2\highgui\highgui.hpp> #include<opencv2\imgproc\imgproc.hpp> #include<opencv2\calib3d\calib3d.hpp> #include <opencv2/features2d/features2d.hpp> #include<string> #include<vector> class CameraCalibrator { private:   //世界坐标   std::vector < std::vector<cv::Point3f >> objectPoints;   //图像坐标   std::vector <std::vector<cv::Point2f>> imagePoints;   //输出矩阵   cv::Mat camerMatirx;   cv::Mat disCoeffs;   //标记   int flag;   //去畸变参数   cv::Mat map1, map2;   //是否去畸变   bool mustInitUndistort;   ///保存点数据   void addPoints(const std::vector<cv::Point2f>&imageConers, const std::vector<cv::Point3f>&objectConers)   {     imagePoints.push_back(imageConers);     objectPoints.push_back(objectConers);   } public:   CameraCalibrator() :flag(0), mustInitUndistort(true){}   //打开棋盘图片,提取角点   int addChessboardPoints(const std::vector<std::string>&filelist,cv::Size &boardSize)   {     std::vector<cv::Point2f>imageConers;     std::vector<cv::Point3f>objectConers;     //输入角点的世界坐标     for (int i = 0; i < boardSize.height; i++)     {       for (int j = 0; j < boardSize.width; j++)       {         objectConers.push_back(cv::Point3f(i, j, 0.0f));       }     }     //计算角点在图像中的坐标     cv::Mat image;     int success = 0;     for (int i = 0; i < filelist.size(); i++)     {       image = cv::imread(filelist[i],0);       //找到角点坐标       bool found = cv::findChessboardCorners(image, boardSize, imageConers);       cv::cornerSubPix(image,          imageConers,         cv::Size(5, 5),         cv::Size(-1, -1),         cv::TermCriteria(cv::TermCriteria::MAX_ITER + cv::TermCriteria::EPS,         30, 0.1));       if (imageConers.size() == boardSize.area())       {         addPoints(imageConers, objectConers);         success++;       }       //画出角点       cv::drawChessboardCorners(image, boardSize, imageConers, found);       cv::imshow("Corners on Chessboard", image);       cv::waitKey(100);     }     return success;   }   //相机标定   double calibrate(cv::Size&imageSize)   {     mustInitUndistort = true;     std::vector<cv::Mat>rvecs, tvecs;     //相机标定     return cv::calibrateCamera(objectPoints, imagePoints, imageSize,       camerMatirx, disCoeffs, rvecs, tvecs, flag);   }   ///去畸变   cv::Mat remap(const cv::Mat &image)   {     cv::Mat undistorted;     if (mustInitUndistort)     {       //计算畸变参数       cv::initUndistortRectifyMap(camerMatirx, disCoeffs,         cv::Mat(), cv::Mat(), image.size(), CV_32FC1, map1, map2);       mustInitUndistort = false;     }     //应用映射函数     cv::remap(image, undistorted, map1, map2, cv::INTER_LINEAR);     return undistorted;   }   //常成员函数,获得相机内参数矩阵、投影矩阵数据   cv::Mat getCameraMatrix() const { return camerMatirx; }   cv::Mat getDistCoeffs()  const { return disCoeffs; } };

源.cpp

#include"标头.h" #include<iomanip> #include<iostream> int main() {   CameraCalibrator Cc;   cv::Mat image;   std::vector<std::string> filelist;   cv::namedWindow("Image");   for (int i = 1; i <= 22; i++)   {     ///读取图片     std::stringstream s;     s << "D:/images/chessboards/chessboard" << std::setw(2) << std::setfill('0') << i << ".jpg";     std::cout << s.str() << std::endl;     filelist.push_back(s.str());     image = cv::imread(s.str(),0);     cv::imshow("Image", image);     cv::waitKey(100);   }   //相机标定   cv::Size boardSize(6, 4);   Cc.addChessboardPoints(filelist, boardSize);   Cc.calibrate(image.size());   //去畸变   image = cv::imread(filelist[1]);   cv::Mat uImage=Cc.remap(image);   cv::imshow("原图像", image);   cv::imshow("去畸变", uImage);   //显示相机内参数矩阵   cv::Mat cameraMatrix = Cc.getCameraMatrix();   std::cout << " Camera intrinsic: " << cameraMatrix.rows << "x" << cameraMatrix.cols << std::endl;   std::cout << cameraMatrix.at<double>(0, 0) << " " << cameraMatrix.at<double>(0, 1) << " " << cameraMatrix.at<double>(0, 2) << std::endl;   std::cout << cameraMatrix.at<double>(1, 0) << " " << cameraMatrix.at<double>(1, 1) << " " << cameraMatrix.at<double>(1, 2) << std::endl;   std::cout << cameraMatrix.at<double>(2, 0) << " " << cameraMatrix.at<double>(2, 1) << " " << cameraMatrix.at<double>(2, 2) << std::endl;   cv::waitKey(0); }

实验结果:

OpenCV相机标定的示例分析
OpenCV相机标定的示例分析 

看以看到,相机内参数矩阵为

172.654 、0、157.829
0、184.195、118.635
0 、0 、1

关于“OpenCV相机标定的示例分析”这篇文章就分享到这里了,希望以上内容可以对大家有一定的帮助,使各位可以学到更多知识,如果觉得文章不错,请把它分享出去让更多的人看到。

向AI问一下细节

免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。

AI