下面是几种常见的方法来获得三维点云重建的坐标系:
-
外部标定方法:在采集点云数据之前,通过使用已知尺寸和形状的校准物体在场景中放置特定的标记点或标定板。通过捕捉这些已知的标记点,可以建立一个参考坐标系,所有的点云数据都将相对于这个坐标系进行转换和合并。
-
内在参数和外在参数:对于基于摄像头的三维重建系统,首先需要通过相机标定的方式获取相机的内在参数(如焦距、主点等)和外在参数(相机相对于世界坐标系的位置和朝向)。这些参数可以用来将二维图像中的像素点转换为三维空间中的点,并建立一个全局坐标系。
-
迭代最近点(ICP)算法:在获得初步的三维点云之后,可以使用ICP算法来细化对齐和合并过程。ICP算法通过最小化两个点云之间的距离来优化它们之间的对齐,进而可以用来精确确定点云数据之间的相对位置和姿态,从而建立一个统一的坐标系。
-
多视图几何和结构从运动(SfM):结构从运动技术通过分析多个视角下的图像来估计摄像头的运动和场景的三维结构。这种方法不仅可以恢复出场景的三维结构,还可以确定相机视角之间的关系,进而构建一个全局坐标系。
-
深度学习方法:近年来,深度学习技术也被应用于三维重建和坐标系建立中,通过训练模型来预测点云数据或图像之间的空间关系,自动化地建立坐标系。
1. 相机标定
相机标定的目的是获取相机的内在参数(包括焦距、主点坐标、畸变系数等)和外在参数(相机相对于某些世界坐标系的位置和朝向)。为什么要进行相机标定呢?比如,当我们拿到一张图片,进行识别之后,得到的两部分之间的距离为多少多少像素,但是这多少多少像素究竟对应实际世界中的多少米呢?这就需要利用相机标定的结果来将像素坐标转换到物理坐标来计算距离(当然这里值得说明,仅仅利用单目相机标定的结果,是无法直接从像素坐标转化到物理坐标的,因为透视投影丢失了一个维度的坐标,所以测距其实需要双目相机)。
import numpy as np
import cv2
import glob# 准备标定板上角点的物理坐标,假设标定板正好在世界坐标系的原点,
# 例如,使用一个标准的棋盘格标定板,每个格子的大小为square_size,
# 棋盘格的大小为 (width, height)。
square_size = 1.0 # 实际测量的格子大小
width, height = 9, 6 # 内角点的数量
objp = np.zeros((width*height, 3), np.float32)
objp[:,:2] = np.mgrid[0:width,0:height].T.reshape(-1,2) * square_size# 保存角点的数组
objpoints = [] # 3d point in real world space
imgpoints = [] # 2d points in image plane.# 读取图像文件
images = glob.glob('path/to/calibration/images/*.jpg')for fname in images:img = cv2.imread(fname)gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)# 查找棋盘格角点ret, corners = cv2.findChessboardCorners(gray, (width,height), None)# 如果找到了,添加物理坐标和图像坐标if ret == True:objpoints.append(objp)imgpoints.append(corners)# 可以选择绘制并显示角点cv2.drawChessboardCorners(img, (width,height), corners, ret)cv2.imshow('img', img)cv2.waitKey(500)cv2.destroyAllWindows()# 标定
ret, mtx, dist, rvecs, tvecs = cv2.calibrateCamera(objpoints, imgpoints, gray.shape[::-1], None, None)print("Camera matrix : \n")
print(mtx)
print("dist : \n")
print(dist)
print("rvecs : \n")
print(rvecs)
print("tvecs : \n")
print(tvecs)
cv2.calibrateCamera
函数是OpenCV中用于相机标定的核心函数。它计算相机的内在参数(如焦距、主点坐标)和畸变系数,以及每个视图的旋转和平移向量。这些参数对于校正图像畸变、三维重建、物体定位等任务至关重要。
函数原型
ret, cameraMatrix, distCoeffs, rvecs, tvecs = cv2.calibrateCamera(objectPoints, imagePoints, imageSize, cameraMatrix, distCoeffs[, flags[, criteria]])
objectPoints
:世界坐标系中的点。这是一个列表,其中每个元素是一个表示标定板上每个角点的三维点(X, Y, Z)的数组。对于每张标定图像,都有一个对应的点集。imagePoints
:图像坐标系中的点。这也是一个列表,其中每个元素是一个表示图像上对应角点的二维点(x, y)的数组。objectPoints
和imagePoints
中的点必须是一一对应的。imageSize
:图像的大小。这应该是图像的宽度和高度,形式为(width, height)
。cameraMatrix
:输入/输出的相机内在参数矩阵。如果提供了初始估计值,标定算法会以此为基础进行优化。distCoeffs
:输入/输出的畸变系数。同样,如果提供了初始值,标定算法会进行优化。
返回值
ret
:重投影误差,表示标定的质量。较小的值表示更好的标定结果。cameraMatrix
:优化后的相机内在参数矩阵。distCoeffs
:优化后的畸变系数。rvecs
:旋转向量,每张图像一个。表示将标定板从模型坐标系旋转到相机坐标系所需的旋转。tvecs
:平移向量,每张图像一个。表示将标定板从模型坐标系平移到相机坐标系所需的平移。
内部实现原理
相机标定的内部实现原理基于解决一个最小化重投影误差的优化问题。重投影误差是指在相机模型(包括内在参数、畸变系数、旋转和平移向量)下,将三维世界坐标点投影回二维图像平面上时,预测的图像点与实际观测到的图像点之间的距离。标定的目标是找到一组相机参数,使得这个误差最小。
- 初始估计:使用直接线性变换(DLT)或其他方法得到相机参数的初始估计。
- 优化:通过迭代优化方法(如Levenberg-Marquardt算法)调整相机参数,以最小化所有标定图像上的总重投影误差。
- 畸变校正:考虑畸变系数对图像点位置的影响,进一步优化这些系数以提高标定精度。
整个过程需要用户提供一组已知世界坐标系中位置的对象点(通常使用棋盘格的角点)和这些点在图像上的对应位置。通过分析这些点之间的几何关系,cv2.calibrateCamera
能够计算出相机的内在参数和畸变系数,以及每张图像的视角(通过旋转和平移向量表示)。
[::-1]
- 这是Python中的切片操作,用于反转序列。在这个上下文中,它被用来反转
shape
元组的元素顺序。 :
表示选择序列中的所有元素,而-1
作为步长值指示从后向前选择,即反向。- 因此,如果
gray.shape
返回(rows, columns)
,那么gray.shape[::-1]
将返回(columns, rows)
。
使用场景
在图像处理和计算机视觉中,图像的尺寸经常需要以(width, height)
的格式指定,而NumPy数组的shape
属性则返回(height, width)
格式的尺寸。因此,gray.shape[::-1]
常用于将图像的尺寸从NumPy数组的形式转换为更通用的形式,特别是在调用需要(width, height)
格式尺寸的OpenCV函数时。
例如,当使用cv2.calibrateCamera
函数进行相机标定时,需要指定图像的尺寸。由于OpenCV期望的图像尺寸格式是(width, height)
,而gray.shape
返回的是(height, width)
,所以使用gray.shape[::-1]
来适配这个要求。
2.双目标定
分别对双目的每个相机标定获得的外参通过代换推导得到双目相机中两个摄像头之间的相对位置关系。最终分别得到二者相对同一坐标系的旋转矩阵R和平移矩阵T能够使两个相机重合的过程。
立体校正的目的就是,利用立体标定所获得的参数将实际非共面行对准的两幅图像,校正成共面行对准。当两个图像平面是完全共面行对准时,立体匹配的效率更高且计算立体视差是最简单的。因为当两个图像平面是完全共面行对准时,立体匹配从二维搜索降至一维搜索,并且可以过滤掉无匹配点。但是,在现实的双目立体视觉系统中,是不存在完全的共面行对准的两个摄像机图像平面的,所以我们要进行立体校正(共面行对准是指:两摄像机图像平面在同一平面上,且同一点投影到两个摄像机图像平面时,应该在两个像素坐标系的同一行)
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