## 双目标定过程 ##

1. **获取棋盘格图片**

   要进行标定，首先需要双目拍摄的各种角度的棋盘格图片，左右图像各不少于20张，棋盘格文件在同级目录下。

   由于该双目摄像头只有一个设备号，拍出照片为左右图像堆叠的形式，故在拍摄完照片之后还需要将左右图像分割出来分别保存到左右图片文件夹中。分割代码如下（代码为Code/stereo.py）：

   ```python
   import cv2
   import os
   
   # 定义输入文件夹路径和输出文件夹路径
   input_folder = 'images'  # 替换为你的输入文件夹路径
   output_folder_left = 'left'
   output_folder_right = 'right'
   
   # 创建输出文件夹，如果不存在则创建
   if not os.path.exists(output_folder_left):
       os.makedirs(output_folder_left)
   if not os.path.exists(output_folder_right):
       os.makedirs(output_folder_right)
   
   # 遍历输入文件夹中的所有图片
   for filename in os.listdir(input_folder):
       if filename.endswith(".png") or filename.endswith(".jpg"):
           # 构建图片的完整路径
           img_path = os.path.join(input_folder, filename)
           
           # 读取图片
           image = cv2.imread(img_path)
           
           if image is None:
               print(f"无法读取图像文件: {filename}")
               continue
           
           # 获取图片的高度和宽度
           height, width, _ = image.shape
           
           # 计算左右图像的宽度
           half_width = width // 2
           
           # 切割出左半部分和右半部分图像
           left_image = image[:, :half_width]
           right_image = image[:, half_width:]
           
           # 构建保存路径
           left_image_path = os.path.join(output_folder_left, f"left_{filename}")
           right_image_path = os.path.join(output_folder_right, f"right_{filename}")
           
           # 保存左右图像
           cv2.imwrite(left_image_path, left_image)
           cv2.imwrite(right_image_path, right_image)
           
           print(f"已保存：{left_image_path} 和 {right_image_path}")
   
   print("所有图像已处理完成！")
   ```

   左摄像头图片如下：![image-20241023201900183](C:\Users\dd\AppData\Roaming\Typora\typora-user-images\image-20241023201900183.png)            右摄像头图片如下：![image-20241023203350774](C:\Users\dd\AppData\Roaming\Typora\typora-user-images\image-20241023203350774.png)

2. **标定**

   首先调用OpenCV库函数对左右相机分别进行单目标定得到每个相机的内参矩阵：

   ```python
   print('开始左相机标定')
   ret_l = calibrate_camera(object_points, corners_left, imgsize)    #object_points表示标定板上检测到的棋盘格角点的三维坐标；corners_left[i]表示棋盘格角点在图像中的二维坐标；imgsize表示图像大小
   retval_l, cameraMatrix_l, distCoeffs_l, rvecs_l, tvecs_l = ret_l[:5]    #返回值里就包含了标定的参数
   
   print('开始右相机标定')
   ret_r = calibrate_camera(object_points, corners_right, imgsize)
   retval_r, cameraMatrix_r, distCoeffs_r, rvecs_r, tvecs_r = ret_r[:5]
   ```

   然后进行立体标定（双目标定），得到左右相机的外参：旋转矩阵、平移矩阵、本质矩阵、基本矩阵：

   ```python
   criteria_stereo = (cv2.TERM_CRITERIA_EPS + cv2.TERM_CRITERIA_MAX_ITER, 30, 1e-5)
   ret_stereo = cv2.stereoCalibrate(object_points, corners_left, corners_right,
                                    cameraMatrix_l, distCoeffs_l,
                                    cameraMatrix_r, distCoeffs_r,
                                    imgsize, criteria=criteria_stereo,
                                    flags=cv2.CALIB_FIX_INTRINSIC)
   ret, _, _, _, _, R, T, E, F = ret_stereo
   ```

   完整代码位于Code/biaoding.py

3. **矫正**

   利用标定得到相机内外参对图像进行矫正（去畸变等）：

   ```python
   R1, R2, P1, P2, Q, roi1, roi2 = cv2.stereoRectify(cameraMatrix_l, distCoeffs_l,
                                                        cameraMatrix_r, distCoeffs_r,
                                                        img_size, R, T)
   
       # 计算映射参数
       map1_l, map2_l = cv2.initUndistortRectifyMap(cameraMatrix_l, distCoeffs_l, R1, P1, img_size, cv2.CV_32FC1)
       map1_r, map2_r = cv2.initUndistortRectifyMap(cameraMatrix_r, distCoeffs_r, R2, P2, img_size, cv2.CV_32FC1)
   
       # 应用映射并显示结果
       rectified_img_l = cv2.remap(img_left, map1_l, map2_l, cv2.INTER_LINEAR)
       rectified_img_r = cv2.remap(img_right, map1_r, map2_r, cv2.INTER_LINEAR)
   
       # 合并图像显示
       combined_img = np.hstack((rectified_img_l, rectified_img_r))
       cv2.imshow('Rectified Images', combined_img)
       cv2.waitKey(0)
       cv2.destroyAllWindows()
   ```
   得到的标定结果如下所示：

   完整代码位于Code/rectify.py