本文最后更新于:14 天前
相对位姿测量算法
【基于空间多点】
- 相对位姿估计的基本问题 - 已知:相机内参数;多个空间上的特征点(非共面)在目标坐标系(3D)和相平面坐标系(2D)坐标。
- 输出:目标坐标系相对相机坐标系的位置和姿态。
  
- 基本思想示意  
- 线性求解 - 对每一个特征点,均有:  
- 对每一个特征点,均有:  
- 展开第一行  
- 类似展开第二、第三行:  
- 消去$Z_c$  
- 上二式右侧分母移到左边,得:  
- 整理为矩阵形式  
- 对于每一个点都可以形成如上两个方程,对于多个点,可进行堆叠,并记成矩阵形式:  
- 有六个或以上特征点且非共面时,可求解:  
- 上面求出的只有11个参数,且多一个/t3. 最后一个变量可利用如下约束求出  
- 线性求解总结 - 利用矩阵的QR分解,得到最终的旋转矩阵非奇异矩阵P的正交三角分解:P=QR, 其中Q(维数n*s): 正交阵; R :上三角阵 - 证明思路:对P 中各向量进行正交化  
 
【扩展】
- 根据旋转矩阵计算旋转角 - 相机坐标系想要转到与世界坐标系完全平行(即坐标轴完全平行,且方向相同),需要旋转3次,设原始相机坐标系为C0 
 1、 C0绕其Z轴旋转,得到新的坐标系C1;
 2、 C1绕其Y轴旋转,得到新的坐标系C2(注意旋转轴为C1的Y轴,而非C0的Y轴);
 3、 C2绕其X轴旋转,得到新的坐标系C3。此时C3与世界坐标系完全平行。 
- Rodrigues旋转  
- 空间的任何一个旋转,可表达为一个向量绕旋转轴旋转给定角度。可用四元数表达:  
 
 
【基于平面多特征点】
- 基本问题 - 已知:相机内参数;多个平面上的特征点在目标坐标系(3D)和相平面坐标系(2D)坐标。 - 输出:目标坐标系相对相机坐标系的位置和姿态。 

- 平面特征点相对位姿估计——线性求解 - 设$Z_t=0$(特征共面), 则对每一个特征点,均有:  
- 得到两个方程  
- 未知数线性求解  
- 对于每一个点都可以形成如上两个方程,对于>=4个点,可使用类似PnP方法求得解:  
 
【总结】
- 在已知至少六个空间点三维点坐标的条件下,可通过点的图像坐标及相对位姿估计算法计算相对位姿。
- 在已知至少四个平面点三维点坐标的条件下,可通过点的图像坐标及相对位姿估计算法计算相对位姿。
代码演示
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# @Time    : 2019/2/26 21:25
# @Author  : Seven
# @File    : PositionMeasurement.py
# @Software: PyCharm
# function : 实现位姿测量算法
import cv2
import numpy as np
import glob
# 加载相机标定的数据
with np.load('C.npz') as X:
    mtx, dist, _, _ = [X[i] for i in ('mtx', 'dist', 'rvecs', 'tvecs')]
def draw(img, corners, imgpts):
    """
    在图片上画出三维坐标轴
    :param img: 图片原数据
    :param corners: 图像平面点坐标点
    :param imgpts: 三维点投影到二维图像平面上的坐标
    :return:
    """
    corner = tuple(corners[0].ravel())
    cv2.line(img, corner, tuple(imgpts[0].ravel()), (255, 0, 0), 5)
    cv2.line(img, corner, tuple(imgpts[1].ravel()), (0, 255, 0), 5)
    cv2.line(img, corner, tuple(imgpts[2].ravel()), (0, 0, 255), 5)
    return img
# 初始化目标坐标系的3D点
objp = np.zeros((6 * 7, 3), np.float32)
objp[:, :2] = np.mgrid[0:7, 0:6].T.reshape(-1, 2)
# 初始化三维坐标系
axis = np.float32([[3, 0, 0], [0, 3, 0], [0, 0, -3]]).reshape(-1, 3)  # 坐标轴
# 加载打包所有图片数据
images = glob.glob('image/*.jpg')
for fname in images:
    img = cv2.imread(fname)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    # 找到图像平面点坐标点
    ret, corners = cv2.findChessboardCorners(gray, (7, 6), None)
    if ret:
        # PnP计算得出旋转向量和平移向量
        _, rvecs, tvecs, _ = cv2.solvePnPRansac(objp, corners, mtx, dist)
        print("旋转变量", rvecs)
        print("平移变量", tvecs)
        # 计算三维点投影到二维图像平面上的坐标
        imgpts, jac = cv2.projectPoints(axis, rvecs, tvecs, mtx, dist)
        # 把坐标显示图片上
        img = draw(img, corners, imgpts)
        cv2.imshow('img', img)
        cv2.waitKey(500)
cv2.destroyAllWindows()运行结果

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!