Skip to content

相机阵列知识点总结

注意点

  • 在拍摄的时候设置相机之间的baseline小一点,因为拍摄出来的分辨率够高,可以集中某个区域来裁剪,来构建有视差的数据集,主要是保证裁剪部分是足够清晰的
  • 相机标定的工作
  • 能不能拍摄一个大点的相机镜头

曝光时间的确认

标定、对齐试试看

  • 遮挡物有哪些?如何构建遮挡物?物体?

利用标定板对相机阵列进行标定

1. 标定板拍摄的详细过程

1.1 选择合适的标定板

通常使用棋盘格标定板进行相机标定。棋盘格标定板的设计应确保有足够的特征点(角点),这些特征点用于计算相机的内外参。

  • 棋盘格的尺寸:通常选择9x6或10x7的棋盘格,具体取决于的相机阵列的视场。
  • 棋盘格的格子大小:需要根据的相机阵列的分辨率和视场大小来选择合适的格子大小,通常为2~3厘米的格子边长。

1.2 设置相机阵列和标定板

  1. 摆放标定板:将标定板放置在多个不同的位置和角度下拍摄。每个相机拍摄标定板时,应保证标定板占据图像的较大部分,并且在整个相机阵列中,各个视角都有对标定板的观测。
    • 位置和角度:尽量保证标定板在各个视角下的拍摄位置和角度有所不同,这样可以帮助提高标定精度。
    • 避免遮挡:确保标定板不会被相邻的相机遮挡,并且每个相机的视角都能覆盖到标定板的多个角点。
  2. 拍摄过程
    • 对每个相机进行拍摄,确保每个相机的图像都有清晰的标定板特征点。
    • 为了提高标定的精度,建议拍摄时每个相机的视角有所变化,覆盖不同的深度和位置。

1.3 标定板图像的采集

  • 在不同的位置和角度拍摄多张标定板图像。每个相机至少需要拍摄10张不同视角的标定板图像。
  • 每个相机拍摄时,应记录每张图像的拍摄位置(相机位置和姿态),这些信息将在后期的标定过程中使用。

2. 相机阵列标定过程

2.1 提取角点

(使用OpenCV的findChessboardCorners

  • 对于每个相机的图像,使用OpenCV的findChessboardCorners函数提取标定板上的角点。这个步骤可以帮助确定标定板上每个格子的实际位置。
python
import cv2
import numpy as np

# 假设已有标定板图像
image = cv2.imread('chessboard_image.jpg')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)

# 设置棋盘格的内角点数量
chessboard_size = (9, 6)

# 查找角点
ret, corners = cv2.findChessboardCorners(gray, chessboard_size, None)

if ret:
    # 提取角点
    cv2.drawChessboardCorners(image, chessboard_size, corners, ret)
    cv2.imshow('Chessboard Corners', image)
    cv2.waitKey(0)
    cv2.destroyAllWindows()
else:
    print("Corners not found")
  • 如果找到角点,可以将这些角点在图像中显示出来,并进行下一步标定。

2.2 标定过程

计算相机的内参和外参

使用多个标定图像(每个视角的标定板图像)来计算相机的内参和外参。

  1. 内参:包括相机的焦距(fx, fy)、主点(cx, cy)和畸变系数(k1, k2, p1, p2)。
  2. 外参:包括相机的位置和朝向(旋转矩阵R和平移向量T)。
python
# 假设标定板每个格子的实际尺寸是 30mm
square_size = 0.03  # 单位是米

# 3D点的世界坐标系(假设标定板位于z=0的平面)
obj_points = []
img_points = []

# 假设标定板角点的数量是9x6
obj_point = np.zeros((chessboard_size[0] * chessboard_size[1], 3), np.float32)
obj_point[:, :2] = np.indices(chessboard_size).T.reshape(-1, 2)
obj_point *= square_size  # 按照标定板格子尺寸进行缩放

# 假设有多个图像,提取角点后将其添加到img_points列表
img_points.append(corners)  # corners为从findChessboardCorners函数获取的角点
obj_points.append(obj_point)

# 相机标定
ret, camera_matrix, dist_coeffs, rvecs, tvecs = cv2.calibrateCamera(obj_points, img_points, gray.shape[::-1], None, None)

# 打印标定结果
print("Camera Matrix:\n", camera_matrix)
print("Distortion Coefficients:\n", dist_coeffs)

在标定的过程中,cv2.calibrateCamera会计算相机的内参(camera_matrix)和畸变系数(dist_coeffs),并为每个图像计算出相机的外参(旋转向量rvecs和平移向量tvecs)。

2.3 计算相机阵列的外参

如果有多个相机,接下来需要进行相机阵列的标定。可以通过匹配不同相机拍摄到的标定板图像来计算相机之间的相对变换(即相对位置和姿态)。使用cv2.stereoCalibrate或者cv2.calibrateCamera来完成这一过程。

python
# 假设已经获得了两个相机的角点图像和3D世界坐标系中的角点
# 使用`cv2.stereoCalibrate`来计算相机之间的相对旋转和平移
ret, camera_matrix1, dist_coeffs1, camera_matrix2, dist_coeffs2, R, T, E, F = cv2.stereoCalibrate(
    obj_points, img_points1, img_points2, camera_matrix1, dist_coeffs1, camera_matrix2, dist_coeffs2, gray.shape[::-1], criteria, flags
)

print("Rotation Matrix (R):\n", R)
print("Translation Vector (T):\n", T)
  • R 是旋转矩阵,表示从一个相机坐标系到另一个相机坐标系的旋转。
  • T 是平移向量,表示两个相机之间的平移。

2.4 校正畸变

在标定过程中,还需要进行畸变校正,以便从畸变图像中恢复出真实图像。可以使用cv2.undistort函数进行图像的畸变校正:

python
# 对图像进行畸变校正
undistorted_img = cv2.undistort(image, camera_matrix, dist_coeffs)
cv2.imshow('Undistorted Image', undistorted_img)
cv2.waitKey(0)
cv2.destroyAllWindows()

3. 结果分析与应用

  1. 内参(相机矩阵):对于每个相机,将获得其内参矩阵(焦距、主点坐标)和畸变系数。这些参数可以用于后续的图像处理,如去畸变或深度估计。
  2. 外参(旋转矩阵和平移向量):对于相机阵列的标定,外参矩阵表示相机之间的相对位置和姿态。通过这些参数,可以计算出各相机之间的相对变换,用于图像对齐。

相机内参外参

相机内参(不随位置变化)

相机的内参是固定的,不会随着相机位置的变化而改变。内参包括:

  • 焦距(f):决定了相机的视场大小。
  • 主点(cx, cy):图像坐标系原点的位置,通常接近图像的中心。
  • 畸变系数:表示镜头引起的畸变(如径向畸变和切向畸变)。

这些内参描述了相机的光学属性,它们与相机的位置和方向无关。因此,无论相机在空间中如何移动,只要相机的镜头、传感器等硬件不发生变化,内参就不需要重新计算。

也就是说,相机内参经过标定之后可以重复使用,除非相机本身硬件发生变化(如焦距)。

相机外参(会随着位置变化而变化)

相机的外参描述了相机相对于世界坐标系或其他相机坐标系的位置和姿态(即旋转和平移),它们会随着相机位置的变化而变化。

  • 旋转矩阵(R):描述相机坐标系与世界坐标系之间的旋转关系。
  • 平移向量(T):描述相机坐标系原点相对于世界坐标系原点的平移量。

如果移动了相机的位置,或者改变了相机的朝向,那么它的外参(旋转矩阵和平移向量)就会发生变化。

举例

  • 内参:比如,假设使用的是一个固定的相机,焦距和主点位置是由相机的光学设计决定的,除非更换镜头或进行其他硬件更改,否则这些参数始终不变。
  • 外参:如果将相机从一个位置移动到另一个位置,或者改变其角度,外参就会发生变化。例如,如果从一个房间的一角移动到另一个角落,或者将相机从水平位置旋转到垂直位置,那么相机的外参(旋转和平移)会改变。

因此,在实际应用中,如果相机的位置或朝向发生变化,需要重新计算相机的外参,但内参保持不变。