(单/双目)图像标定全流程(C++/Opencv实现)---原理篇

最近在做图像标定工作,现对标定相关工作做个总结,以便后续查看。
相关代码参考:
想要学习目标标定,首先要了解,相机模型中的四个平面坐标系,以及他们之间的转化关系。
理论如下:
(1)图像像素坐标系(u, v)
以像素为单位,是以图像的左上方为原点的图像坐标系;
(2)图像物理坐标系(也叫像平面坐标系)(x, y)
以mm为单位,用物理单位表示图像像素位置,定义坐标系O-XY,原点O定义在相机与图像平面交点;
(3)相机坐标系(摄影机坐标系) (Xc, Yc, Zc)
以mm为单位,以相机的光心作为原点,Zc轴与光轴重合,并垂直于成像平面,且取摄影方向为正方向,Xc、Yc轴与图像物理坐标系的x, y轴平行,且OcO为摄像机的焦距f;
(4)世界坐标系 (Xw, Yw, Zw)
根据具体情况而定,该坐标系描述环境中任何物体的位置,满足右手法则;

坐标转化

u = x d x + u 0 v = y d y + v 0 u = \frac{x} {{dx}} + {u_0}{\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} {\kern 1pt} v = \frac{y} {{dy}} + {v_0} u=dxx+u0v=dyy+v0
latex加矩阵的公式实在过于繁琐,遂直接截图了
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
其中,内参矩阵
在这里插入图片描述
外参矩阵
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
摄像机坐标与世界坐标系之间的转换(刚体变换和平移)。
在这里插入图片描述
R为分别绕XYZ轴旋转的效果总和
在这里插入图片描述
在这里插入图片描述
其由三个方向的 控制,故有三个自由度。T是指两个坐标系原点的XYZ坐标分量,即平移向量

单目标定:

基本思路:求得每个标定板对应的单应矩阵,再联合优化所有标定板数据得到相机内参矩阵,再得到每个标定板对应的外参。
相机标定的目的就是建立摄像机图像像素位置与场景点位置之间的关系,即世界坐标系与图像坐标系之间的关系。方法就是根据摄像机模型,由已知特征点的图像坐标求解摄像机的模型参数,从而可以从图像出发恢复出空间点三维坐标,即三维重建。所以要求解的参数包括4个内参数和5个畸变参数,对于外参数,即旋转矩阵的三个旋转参数R和平移向量的三个参数T。

双目立体标定:

双目摄像机标定和单目摄像机标定最主要的区别就是双目摄像机需要标定出左右摄像机坐标系之间的相对关系。
双目摄像机需要标定的参数:摄像机内参数矩阵,畸变系数矩阵,本征矩阵,基础矩阵,旋转矩阵以及平移矩阵。
双目视觉中两个摄像头之间的相对位置关系,即两个坐标系之间的相对位置关系,可以通过两个矩阵来描述:旋转矩阵R和平移矩阵T。
我们用旋转矩阵R和平移矩阵T来描述左右两个摄像机坐标系的相对关系,具体为:将左摄像机下的坐标转换到右摄像机下的坐标。
假设空间中有一点P,其在世界坐标系下的坐标为Pw,其在左右摄像机坐标系下的坐标可以表示为
在这里插入图片描述
Rl,Tl为左摄像头经过单目标定得到的相对标定物的旋转矩阵和平移向量,Rr,Tr为右摄像头经过单目标定得到的相对标定物的旋转矩阵和平移向量。
左右相机分别进行单目标定,就可以分别得到Rl,Tl,Rr,Tr,带入上式就可以求出左右相机之间的旋转矩阵R和平移T。求得的R和T就是立体标定要得到的结果。
亚像素定位:通常图像被离散化成像素形式,每个像素对应一个整数坐标位置,而为了达到精确性,需要精确到浮点坐标位置,因此涉及到亚像素定位问题。亚像素定位就是计算特征所在图像中的真实位置,而真实位置有时候并不在像素所在整数坐标位置上,而是在像素的内部。即存在于两个实际像素之间的像素,被称为“亚像素”。

  • 0
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
双目相机标定是计算机视觉中的一个重要步骤,它可以通过计算双目相机之间的相对位置和姿态,将两个相机的图像进行联合,实现三维重构和深度测量等功能。OpenCV提供了一套完整的双目相机标定工具,下面是一个简标定流程: 1.采集双目图像数据,包括左右相机的内参矩阵、畸变系数、图像尺寸等信息; 2.通过对图像数据进行预处理,包括去畸变、矫正等操作,使得标定结果更加精确; 3.提取双目图像中的特征点,并进行匹配,计算出左右相机之间的基础矩阵和本质矩阵; 4.通过标定板上的特征点的三维坐标和它们在相机图像中的对应点的二维坐标,计算出左右相机之间的外参矩阵; 5.对标定结果进行评估,包括重投影误差、立体重建误差等指标,以判断标定结果的准确性和可靠性。 下面是一个基于OpenCV双目相机标定示例代码: ```c #include <opencv2/opencv.hpp> #include <iostream> #include <vector> using namespace cv; using namespace std; int main() { //读取标定图像 vector<vector<Point3f>> objectPoints; //标定板上的三维坐标 vector<vector<Point2f>> imagePoints1, imagePoints2; //左右相机上对应的二维图像点 Size imageSize; //图像尺寸 Mat cameraMatrix1, distCoeffs1; //左相机内参矩阵和畸变系数 Mat cameraMatrix2, distCoeffs2; //右相机内参矩阵和畸变系数 Mat R, T, E, F; //左右相机之间的旋转矩阵、平移矩阵、本质矩阵、基础矩阵 //设置标定板参数 Size boardSize(9, 6); //标定板内部角点数目 float squareSize = 30; //标定板内部边长,位毫米 //生成标定板上的三维坐标 vector<Point3f> corners; for (int i = 0; i < boardSize.height; i++) { for (int j = 0; j < boardSize.width; j++) { corners.push_back(Point3f(j * squareSize, i * squareSize, 0)); } } //读取标定图像 vector<String> filenames1, filenames2; glob("left/*.jpg", filenames1); //左相机图像文件夹 glob("right/*.jpg", filenames2); //右相机图像文件夹 for (int i = 0; i < filenames1.size(); i++) { Mat image1 = imread(filenames1[i]); Mat image2 = imread(filenames2[i]); imageSize = image1.size(); //提取标定板上的角点 vector<Point2f> corners1, corners2; bool found1 = findChessboardCorners(image1, boardSize, corners1); bool found2 = findChessboardCorners(image2, boardSize, corners2); if (found1 && found2) { //亚像素精确化角点位置 Mat gray1, gray2; cvtColor(image1, gray1, COLOR_BGR2GRAY); cvtColor(image2, gray2, COLOR_BGR2GRAY); cornerSubPix(gray1, corners1, Size(11, 11), Size(-1, -1), TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 30, 0.1)); cornerSubPix(gray2, corners2, Size(11, 11), Size(-1, -1), TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 30, 0.1)); //保存角点坐标 objectPoints.push_back(corners); imagePoints1.push_back(corners1); imagePoints2.push_back(corners2); } } //标定相机 double rms = stereoCalibrate(objectPoints, imagePoints1, imagePoints2, cameraMatrix1, distCoeffs1, cameraMatrix2, distCoeffs2, imageSize, R, T, E, F, CALIB_FIX_INTRINSIC + CALIB_USE_INTRINSIC_GUESS + CALIB_SAME_FOCAL_LENGTH + CALIB_RATIONAL_MODEL + CALIB_FIX_K3 + CALIB_FIX_K4 + CALIB_FIX_K5, TermCriteria(TermCriteria::EPS + TermCriteria::COUNT, 100, 1e-5)); cout << "Stereo calibration done with RMS error = " << rms << endl; //保存标定结果 FileStorage fs("stereo_calib.xml", FileStorage::WRITE); fs << "cameraMatrix1" << cameraMatrix1; fs << "distCoeffs1" << distCoeffs1; fs << "cameraMatrix2" << cameraMatrix2; fs << "distCoeffs2" << distCoeffs2; fs << "R" << R; fs << "T" << T; fs << "E" << E; fs << "F" << F; fs.release(); return 0; } ``` 以上代码仅供参考,实际应用中需要根据具体情况进行修改和调整。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值