3D视觉(三):双目摄像头的标定与校正 |
您所在的位置:网站首页 › 摄像头HLS是什么意思 › 3D视觉(三):双目摄像头的标定与校正 |
3D视觉(三):双目摄像头的标定与校正
对于双目摄像头而言,除了需要分别标定左目摄像头的内参矩阵K1、畸变系数D1、右目摄像头的内参矩阵K2、畸变系数D2,还需要标定左右目对应的旋转矩阵R和平移向量T。当双目摄像头固定在一个平面上时,旋转矩阵R可近似为一个单位阵,平移向量T的欧式范数即为基线长度b。
双目相机一般由左目和右目两个水平放置的相机组成。当然也可以做成上下两目,但日常见到的主流双目都是做成左右的。两个相机的光圈中心都位于x轴上,它们的距离称为双目相机的基线 Baseline,记作b。
根据三角形P-PL-PR和三角形P-OL-OR的相似关系,可以得到:
虽然由视差计算深度的公式很简洁, 但视差d本身的计算却比较困难,我们需要确切地知道左眼图像某个像素出现在右眼图像的哪一个位置(即对应关系)。此外如果想计算每个像素的深度,其计算量与精度都将成为问题,并且只有在图像纹理变化丰富的地方才能计算视差。 二、双目相机标定流程第1步:准备一张棋盘格,粘贴于墙面,并用直尺测量黑白方格的真实物理长度。 第2步:调用双目摄像头,分别从不同角度拍摄得到一系列棋盘格图像。 第3步:利用左目图片数据集,进行左目相机标定,得到左目内参矩阵K1、左目畸变系数向量D1。 第4步:利用右目图片数据集,进行右目相机标定,得到右目内参矩阵K2、右目畸变系数向量D2。 第5步:将左右目测量得到的参数K1、K2、D1、D2作为输入,再同时利用左右目一一对应好的棋盘格图片,调用stereoCalibrate函数,输出左右目的旋转矩阵R、平移向量T。 第6步:基于测量得到的K1、K2、D1、D2、R、T,进行双目视觉的图像校正。 备注:需要用直尺测量黑白方格的真实物理长度,因为我们会将真实世界的棋盘格3D坐标,以相同的尺度(米为单位),存储于object_points容器中,这样求解得到的平移向量T才会有意义,它的尺度才会和真实世界尺度相对应。然后我们会借助OpenCV棋盘格检测函数,将每张图片对应的棋盘格坐标索引,对应存储于left_img_points、 right_img_points容器中。在得到一系列对应好的2D、3D坐标点后,就可通过线性方程求解参数估计。 三、实验过程准备一张棋盘格,内点size分别是6和4,直尺测量黑白方格的长度为0.0405米。
双目视觉标定: #include // core是OpenCV的主要头文件,包括数据结构,矩阵运算,数据变换,内存管理,文本和数学等功能 #include // calib3d模块主要是相机校准和三维重建相关的内容,包括基本的多视角几何算法,单个立体摄像头标定,物体姿态估计,立体相似性算法,3D信息的重建等 #include // highgui模块,高层GUI图形用户界面,包括媒体的I/O输入输出、视频捕捉、图像和视频的编码解码、图形交互界面的接口等内容 #include // imgproc模块,图像处理模块,包括线性和非线性的图像滤波、图像的几何变换、特征检测等 #include #include #include "opencv2/imgcodecs/legacy/constants_c.h" // OpenCV4.5.3版本,解决未定义标识符"CV_LOAD_IMAGE_COLOR" #include // OpenCV4.5.3版本,解决未定义标识符"CV_L2" using namespace std; using namespace cv; // obj_points中每个元素都是一个小vector,每个小vector存储的每个元素都是opencv的cv::Point3f数据结构 vector object_points; // image_points1、imagePoints2中每个元素都是一个小vector,每个小vector存储的每个元素都是opencv的cv::Point2f数据结构 vector imagePoints1, imagePoints2; // corners1是一个小vector,存储左目图片中检测出的所有的棋盘格内点索引 // corners2是一个小vector,存储右目图片中检测出的所有的棋盘格内点索引 vector corners1, corners2; // left_img_points, right_img_points的作用和image_points1、imagePoints2相同 // 这里重复赋值一次,是为了保证两个容器存储的样本数相同,正好一一对应 vector left_img_points, right_img_points; // img表示rgb图像,gray表示对应的灰度图 Mat img1, img2, gray1, gray2; /* * board_width: 棋盘格宽方向上的内点数量,此处为9 * board_height: 棋盘格高方向上的内点数量,此处为6 * num_imgs: 图片数量 * square_size: 黑白格真实世界中的边长,单位为米,此处为0.02423米 * leftimg_dir: 左目图片存储文件夹位置,此处为"../calib_imgs/1/" * rightimg_dir: 右目图片存储文件夹位置,此处为"../calib_imgs/1/" * leftimg_filename: 左目相机拍摄的图片名称,此处为"left" * rightimg_filename: 右目相机拍摄的图片名称,此处为"right" * extension: 图片后缀,此处为"jpg" */ void load_image_points(int board_width, int board_height, int num_imgs, float square_size, char* leftimg_dir, char* rightimg_dir, char* leftimg_filename, char* rightimg_filename, char* extension) { Size board_size = Size(board_width, board_height); int board_n = board_width * board_height; int all = 0; for (int k = 1; k |
今日新闻 |
推荐新闻 |
CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3 |