好的,我们来详细探讨手眼标定的相关内容,包括概述、原理、常用方法汇总以及C++代码实战。
(二)手眼标定——概述+原理+常用方法汇总+代码实战(C++)
1. 概述
手眼标定(Hand-Eye Calibration) 是机器人视觉领域的一项关键技术,旨在确定机器人末端执行器(手)与相机(眼)之间的空间变换关系。其核心目标是解决以下问题:
- 眼在手外(Eye-to-Hand):相机固定于场景中,标定相机坐标系到机器人基坐标系的变换。
- 眼在手上(Eye-in-Hand):相机安装在机器人末端,标定相机坐标系到末端执行器坐标系的变换。
标定精度直接影响机器人抓取、视觉引导等任务的准确性,是机器人感知与控制的基础环节。
2. 原理
手眼标定的数学模型基于齐次变换矩阵。假设:
- $T_{\\text{base}}^{\\text{end}}$:机器人基坐标系到末端坐标系的变换(由机器人控制器提供)。
- $T_{\\text{cam}}^{\\text{obj}}$:相机坐标系到标定板坐标系的变换(由相机标定得到)。
- $X$:待求的手眼变换矩阵(末端坐标系到相机坐标系)。
对于眼在手上系统,运动过程中满足: $$ T_{\\text{base}}^{\\text{end}} \\cdot X \\cdot T_{\\text{cam}}^{\\text{obj}} = T_{\\text{base}}^{\\text{obj}} $$ 推导得经典方程: $$ A \\cdot X = X \\cdot B $$ 其中:
- $A = T_{\\text{end}_i}^{\\text{end}_j}$(两次运动的末端相对变换)。
- $B = T_{\\text{cam}_i}^{\\text{cam}_j}$(两次运动的相机相对变换)。
通过多组 $(A, B)$ 数据求解 $X$,即可完成标定。
3. 常用方法汇总
| 1. 旋转向量法 | 分解旋转和平移,先求解旋转矩阵再计算平移向量 | 计算简单,对噪声敏感 |
| 2. 四元数法 | 使用四元数表示旋转,优化旋转误差 | 数值稳定性好,适合大角度运动 |
| 3. 矩阵方程法 | 构造超定方程组 $AX = XB$,通过SVD分解求解 | 精度高,通用性强 |
| 4. 非线性优化法 | 将问题转化为优化问题(如Levenberg-Marquardt),最小化重投影误差 | 抗噪声能力强,计算复杂 |
| 5. 九点法(经典) | 移动标定板至9个不同位置,采集数据求解 | 操作简便,工业常用 |
4. 代码实战(C++)
以下以矩阵方程法为例,使用OpenCV和Eigen库实现眼在手上系统标定:
#include <opencv2/opencv.hpp>
#include <Eigen/Dense>
#include <vector>
using namespace std;
using namespace cv;
using namespace Eigen;
// 定义齐次变换矩阵结构体
struct Transform {
Matrix3d R;
Vector3d t;
Matrix4d H() const {
Matrix4d H = Matrix4d::Identity();
H.block<3,3>(0,0) = R;
H.block<3,1>(0,3) = t;
return H;
}
};
// 求解手眼标定矩阵X: AX = XB
Transform handEyeCalibration(const vector<Transform>& A_motions, const vector<Transform>& B_motions) {
int n = A_motions.size();
MatrixXd M(6*n, 6); // 构造方程矩阵
for (int i = 0; i < n; ++i) {
Matrix3d RA = A_motions[i].R;
Vector3d tA = A_motions[i].t;
Matrix3d RB = B_motions[i].R;
Vector3d tB = B_motions[i].t;
// 构造旋转部分方程: kron(I, RA) – kron(RB^T, I)
MatrixXd blockRot = MatrixXd::Zero(9, 9);
blockRot.block<3,3>(0,0) = RA – RB(0,0)*Matrix3d::Identity();
// …(完整构造9×9块,此处简化)
// 构造平移部分方程: (I – RA) * tX = tA – RB * tX ?(实际需展开)
// 此处简化为线性方程形式
M.block<6,6>(6*i, 0) << RA – Matrix3d::Identity(), -skewSymmetric(tA),
Matrix3d::Zero(), RA – Matrix3d::Identity();
}
// SVD分解求解
JacobiSVD<MatrixXd> svd(M, ComputeThinU | ComputeThinV);
VectorXd x = svd.solve(VectorXd::Zero(6*n)); // 右侧为0向量
// 提取结果
Transform X;
X.R = AngleAxisd(x(0), Vector3d(x(1), x(2), x(3))).toRotationMatrix(); // 旋转向量转矩阵
X.t << x(3), x(4), x(5);
return X;
}
// 测试示例
int main() {
vector<Transform> A, B;
// 填充模拟数据(实际需从机器人/相机读取)
for (int i = 0; i < 10; ++i) {
Transform a, b;
a.R = AngleAxisd(i*0.1, Vector3d::UnitZ()).toRotationMatrix();
a.t << 0.1*i, 0, 0;
b.R = AngleAxisd(i*0.05, Vector3d::UnitX()).toRotationMatrix();
b.t << 0, 0.2*i, 0;
A.push_back(a);
B.push_back(b);
}
Transform X = handEyeCalibration(A, B);
cout << "Calibration Result:\\nRotation:\\n" << X.R << "\\nTranslation:\\n" << X.t << endl;
return 0;
}
5. 关键步骤说明
6. 注意事项
- 运动要求:机器人需进行充分旋转和平移运动,避免退化配置(如纯平移)。
- 噪声处理:可加入RANSAC剔除异常点。
- 标定板精度:相机标定精度直接影响手眼标定结果。
通过上述流程,可高效完成手眼系统的标定,为机器人视觉任务奠定基础。
网硕互联帮助中心





评论前必须登录!
注册