<视觉>——双目相机的标定(简单原理+Opencv实现)

深度相机原理揭秘--双目立体视觉

双目相机空间坐标计算:(good)

https://www.cnblogs.com/zyly/p/9373991.html

深度相机原理:

https://blog.youkuaiyun.com/electech6/article/details/78526800

上文的博客总结双目相机和单目相机的区别和原理很好,值得学习。 

在这里我总结一下主要是以下几点:

深度相机主要有一下几种:

  • 基于TOF(time of flight)飞行时间测距法--发射反射接收
  • 基于结构光:结构光成像的硬件:1.相机、2.投射器。 原理:1.投射到被测物体表面 2.由单个或多个相机拍摄表面即得的结构光 3.基于三角测量原理,经图像三维解析计算--》三维重建  常见的仪器:kinect
  • 基于双目的立体视觉

我们主要总结下双目立体视觉:

在单目的视野A情况下,点的远近是看不出的,加上视野B我们就可以看出

 而通过相机A、B我们就可以判断三点的远近

在Opencv中我们可以很好的实现双目相机的标定等一系列操作:

  1. 分别校正左相机和右相机,得到他们的内参和畸变系数
  2. 找到左右标定图的内角点坐标,加上三维的世界坐标,加上上面的左右相机内参矩阵和畸变系数,求出双目的标定参数矩阵R、T、E、F(旋转矩阵、平移矩阵、本征矩阵、基础矩阵)
  3. 根据上面的标定结果,对图像进行矫正--------极线约束,矫正后两图像位于同一平面且互相平行
  4. 对矫正后的两张图像进行像素匹配(有很多算法),获得视差图,计算每个图像的深度,获得深度图

左右棋盘图如下:

https://pan.baidu.com/s/1-U_1v6idEKKvTS1Z6_kXig       提取码:0k3u

在Opencv中的代码如下,有详细的注释:

 main.cpp

#include"11.h"

int main() 
{
	
	calibrator calib(LEFT_FOLDER, RIGHT_FOLDER, 1.f, 5, 4);
	
	calib.calc_image_points(true);    //找到左右标定图的角点坐标
	
	bool done = calib.calibrate();    //双目标定计算,并保存stereo_calib.xml,得到 R, T, E, F
		// R– 输出第一和第二相机坐标系之间的旋转矩阵。
		// T– 输出第一和第二相机坐标系之间的旋转矩阵平移向量。
		// E–输出本征矩阵。
		// F–输出基础矩阵。
	                                 
	if (!done) 
	{
		cout << "立体标定失败......." << endl;
	}
	else
	{
		cout << "立体标定成功......." << endl;
	}

	Size image_size(320, 240);
	
	rectifier rec(filename11, image_size);//标定过的摄像机进行校正,stereoRectify(),得到 Rl, Rr, Pl, Pr, Q
	
	//R1– 输出第一个相机的3x3矫正变换(旋转矩阵) .
	//R2– 输出第二个相机的3x3矫正变换(旋转矩阵) .
	//P1–在第一台相机的新的坐标系统(矫正过的)输出 3x4 的投影矩阵
	//P2–在第二台相机的新的坐标系统(矫正过的)输出 3x4 的投影矩阵
	//Q–输出深度视差映射矩阵    
	rec.show_rectified(image_size);

	disparity disp(filename11, image_size);  //SGBM求视差图,进而求解深度图
	disp.show_disparity(image_size);

	system("pause");
	return 0;
}

11.h

#pragma once
// Program illustrate stereo camera calibration
// Author: Samarth Manoj Brahmbhatt, University of Pennsylvania

#include <opencv2/opencv.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/calib3d/calib3d.hpp>

#define LEFT_FOLDER "./left/"
#define RIGHT_FOLDER "./right/"

#define DATA_FOLDER "./cam_calib/"

#define filename11 "./cam_calib/stereo_calib.xml"

using namespace cv;
using namespace std;



class calibrator 
{
public:
	calibrator(string, string, float, int, int);      //初始化构造函数

	Size get_image_size();                            //获取单张图片的大小

	void calc_image_points(bool);                     //通过检测棋盘格角点计算图像点
	                                                  //得到 l_image_points, r_image_points
	bool calibrate();                
<think>好的,我现在要解决用户关于使用Python和OpenCV进行双目相机标定的问题,特别是涉及棋盘格标定板的教程或代码示例。首先,我需要回忆一下双目相机标定的基本流程,以及OpenCV中相关的函数和步骤。 用户提到了几个引用,我需要先快速浏览这些引用内容,看看是否有相关的信息可以利用。引用[2]、[3]、[4]、[5]都提到了Python和OpenCV的相机标定,特别是引用[4]明确提到了双目相机标定,并且使用了6×9的棋盘格。这可能是一个关键点。此外,引用[5]提到生成yaml文件,这可能涉及标定参数的保存。 接下来,我需要确定双目相机标定的步骤。通常,这包括以下几个步骤: 1. 准备标定板,比如棋盘格,并知道其参数(如内角点数、方格尺寸)。 2. 使用双目相机拍摄多张不同角度的棋盘格图片。 3. 提取每张图片中的角点(corner points)。 4. 使用单目标定分别标定左右相机的内部参数和畸变系数。 5. 进行双目标定,计算两个相机之间的位置关系(旋转矩阵和平移向量)。 6. 保存标定结果,可能生成yaml文件供后续使用。 用户需要的是示例代码和教程,所以我需要提供详细的步骤和代码片段。同时,代码需要符合用户的要求,比如行内数学公式用$...$,独立公式用$$...$$,并且正确使用LaTeX语法。 接下来,我需要检查OpenCV中相关的函数。例如,cv2.findChessboardCorners用于检测棋盘格角点,cv2.cornerSubPix用于提高角点检测精度,cv2.calibrateCamera用于单目标定,cv2.stereoCalibrate用于双目标定。此外,保存结果可以使用cv2.FileStorage写入yaml文件。 在编写代码示例时,需要注意参数的正确设置,比如棋盘格的内角点数,这里引用[4]提到的是6×9方格,内点数为5×8。因此,代码中的棋盘格参数应该设置为(5,8)。此外,方格的实际尺寸需要用户根据打印的棋盘格大小来设置,比如每个方格的宽度为2cm,这在代码中需要转换为米或其他单位,具体取决于用户的需求。 在步骤说明中,需要详细解释每个步骤的目的和关键参数,比如为什么需要拍摄多张不同角度的图片,角点检测的作用,单目标定双目标定的区别,以及如何评估标定结果的好坏(如重投影误差)。 同时,用户可能对如何应用标定结果感兴趣,比如立体校正和深度图生成,但根据问题描述,用户主要关注标定过程本身,所以可能不需要深入讨论后续应用,但可以简要提及作为相关扩展。 最后,生成相关问题,需要围绕双目相机标定的步骤、参数调整、优化方法、应用场景等展开。例如,如何选择棋盘格尺寸,如何优化标定精度,标定结果的应用等。 现在,我需要确保所有步骤和代码正确无误,并正确引用用户提供的参考文献。例如,引用[4]提到了棋盘格参数和标定图片拍摄,引用[5]提到了生成yaml文件,这些都需要在回答中适当标注引用标识。 在代码部分,要确保使用正确的语法,比如正确调用OpenCV函数,处理返回值,以及正确保存结果。同时,需要提醒用户注意实际使用时的调整,比如棋盘格参数、图片路径等。 总结来说,回答需要结构清晰,分步骤讲解,提供可运行的代码示例,正确引用相关文献,并生成相关的问题列表,帮助用户进一步学习。</think>### 双目相机标定步骤及Python示例 以下是基于OpenCV-Python的双目相机标定流程,使用棋盘格标定实现: --- #### **1. 准备标定板与数据采集** - 使用 **内点数为$(w,h)=(5,8)$** 的棋盘格(即6×9方格,单格尺寸需实际测量,例如2cm/格)[^4]。 - 使用双目相机从不同角度拍摄 **15-20组** 棋盘格图片,确保左右相机同步拍摄。 --- #### **2. 提取棋盘格角点** ```python import cv2 import numpy as np # 定义棋盘格参数 chessboard_size = (5, 8) # 内角点数量 square_size = 0.02 # 单格实际尺寸(单位:米) # 存储角点坐标 obj_points = [] # 3D世界坐标 left_points = [] # 左图2D像素坐标 right_points = [] # 右图2D像素坐标 # 生成标定板的3D坐标模板 objp = np.zeros((chessboard_size[0]*chessboard_size[1], 3), np.float32) objp[:, :2] = np.mgrid[0:chessboard_size[0], 0:chessboard_size[1]].T.reshape(-1, 2) * square_size # 遍历左右相机图片 for left_img, right_img in image_pairs: # 左图角点检测 gray_left = cv2.cvtColor(left_img, cv2.COLOR_BGR2GRAY) ret_left, corners_left = cv2.findChessboardCorners(gray_left, chessboard_size, None) # 右图角点检测 gray_right = cv2.cvtColor(right_img, cv2.COLOR_BGR2GRAY) ret_right, corners_right = cv2.findChessboardCorners(gray_right, chessboard_size, None) if ret_left and ret_right: # 亚像素优化 corners_left = cv2.cornerSubPix(gray_left, corners_left, (11,11), (-1,-1), (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.01)) corners_right = cv2.cornerSubPix(gray_right, corners_right, (11,11), (-1,-1), (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 0.01)) # 存储坐标 obj_points.append(objp) left_points.append(corners_left) right_points.append(corners_right) ``` --- #### **3. 单目标定(左右相机分别标定)** ```python # 左相机标定 ret_left, K_left, D_left, rvecs_left, tvecs_left = cv2.calibrateCamera( obj_points, left_points, gray_left.shape[::-1], None, None ) # 右相机标定 ret_right, K_right, D_right, rvecs_right, tvecs_right = cv2.calibrateCamera( obj_points, right_points, gray_right.shape[::-1], None, None ) ``` --- #### **4. 双目标定(计算相对位姿)** ```python # 双目联合标定 flags = cv2.CALIB_FIX_INTRINSIC # 固定单目内参,仅优化外参 ret_stereo, K_left, D_left, K_right, D_right, R, T, E, F = cv2.stereoCalibrate( obj_points, left_points, right_points, K_left, D_left, K_right, D_right, gray_left.shape[::-1], criteria=(cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 100, 1e-5), flags=flags ) ``` - **输出参数**: - $R$:右相机相对于左相机的旋转矩阵。 - $T$:右相机相对于左相机的平移向量[^1]。 --- #### **5. 保存标定结果(YAML文件)** ```python # 使用FileStorage保存参数 fs = cv2.FileStorage("stereo_calib.yaml", cv2.FILE_STORAGE_WRITE) fs.write("K_left", K_left) fs.write("D_left", D_left) fs.write("K_right", K_right) fs.write("D_right", D_right) fs.write("R", R) fs.write("T", T) fs.release() ``` 参考棋盘格参数设置与文件生成方法[^5]。 --- #### **6. 标定结果验证** 计算重投影误差(通常要求误差小于0.5像素): $$ \text{误差} = \frac{1}{N}\sum_{i=1}^{N} \| p_i - \hat{p}_i \|^2 $$ 其中$p_i$为检测角点,$\hat{p}_i$为通过标定参数反投影的角点。 --- ###
评论 19
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值