本文最后更新于: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协议 。转载请注明出处!