云计算百科
云计算领域专业知识百科平台

手眼标定:原理详解与C++实战

好的,我们来详细探讨手眼标定的相关内容,包括概述、原理、常用方法汇总以及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. 关键步骤说明
  • 数据采集:机器人末端移动至不同位姿,同时采集标定板在相机中的位姿。
  • 相对变换计算:计算相邻位姿间的相对变换 $A_i$(末端)和 $B_i$(相机)。
  • 方程构造:将 $A_i X = X B_i$ 展开为线性方程组。
  • SVD求解:通过奇异值分解求最小二乘解,得到 $X$。
  • 结果验证:计算标定误差(如重投影误差)评估精度。

  • 6. 注意事项
    • 运动要求:机器人需进行充分旋转和平移运动,避免退化配置(如纯平移)。
    • 噪声处理:可加入RANSAC剔除异常点。
    • 标定板精度:相机标定精度直接影响手眼标定结果。

    通过上述流程,可高效完成手眼系统的标定,为机器人视觉任务奠定基础。

    赞(0)
    未经允许不得转载:网硕互联帮助中心 » 手眼标定:原理详解与C++实战
    分享到: 更多 (0)

    评论 抢沙发

    评论前必须登录!