经典手眼标定算法之Tsai-Lenz的OpenCV实现

经典手眼标定算法之Tsai-Lenz的OpenCV实现本文主要是讲解经典手眼标定问题中的TSAI-LENZ文献方法,参考文献为“ANewTechniqueforFullyAutonomousandEfficient3DRoboticsHand/EyeCalibration”,并且实现了基于OpenCV的C++代码程序,code可去CSDN资源下载。

大家好,又见面了,我是你们的朋友全栈君。

       本文主要是讲解经典手眼标定问题中的TSAI-LENZ 文献方法,参考文献为“A New Technique for Fully Autonomous and Efficient 3D Robotics Hand/Eye Calibration”,并且实现了基于OpenCV的C++代码程序,code可去CSDN资源下载,MATLAB版本作者为苏黎世理工的Christian Wengert,也可在此处下载。


手眼标定问题描述

       在机器人校准测量、机器人手眼协调以及机器人辅助测量等领域,都要求知道机器人执行器末端(抓取臂)坐标系和传感器(比如用来测量三维空间中目标位置和方向并固定在机器人手上的摄像机)坐标系之间的相互关系,确定这种转换关系在机器人领域就是通常所说的手眼标定。

       将手眼标定系统如下图所示,其中 H g i j H_{gij} Hgij​为机器人执行器末端坐标系之间相对位置姿态的齐次变换矩阵; H c i j H_{cij} Hcij​为摄像机坐标系之间相对位置姿态的齐次变换矩阵; H c g H_{cg} Hcg​为像机与机器人执行器末端之间的相对位置姿态齐次矩阵。

手眼标定系统

       经过坐标系变换, H g i j H_{gij} Hgij​、 H c i j H_{cij} Hcij​和 H c g H_{cg} Hcg​满足如下关系:
KaTeX parse error: Unknown column alignment: * at position 77: …{\begin{array}{*̲{20}{c}} {
{R_…

       将上式展开,可以得到手眼标定的基本方程:
KaTeX parse error: Unknown column alignment: * at position 24: …{\begin{array}{*̲{20}{c}} {
{R_…

       因此,手眼标定问题也就转化为从上述方程组中求解出 R c g R_{cg} Rcg​和 T c g T_{cg} Tcg​,下面就按照TSAI文献所述求解该方程组。


“两步法”手眼标定

       一般用“两步法”求解基本方程,即先从基本方程上式求解出 R c g R_{cg} Rcg​,再代入下式求解出 T c g T_{cg} Tcg​。在TSAI文献中引入旋转轴-旋转角系统来描述旋转运动来进行求解该方程组,具体的公式推导可以查看原始文献,这里只归纳计算步骤,不明白的地方可阅读文献,计算步骤如下:

Step1:利用罗德里格斯变换将旋转矩阵转换为旋转向量

KaTeX parse error: Unknown column alignment: * at position 24: …{\begin{array}{*̲{20}{c}} {
{r_…

Step2:向量归一化

KaTeX parse error: Unknown column alignment: * at position 24: …{\begin{array}{*̲{20}{c}} {\be…

Step3:修正的罗德里格斯参数表示姿态变化

KaTeX parse error: Unknown column alignment: * at position 24: …{\begin{array}{*̲{20}{c}} {
{P_…

Step4:计算初始旋转向量 P c g ′ P_{cg}^\prime Pcg′​

s k e w ( P g i j + P c i j ) P c g ′ = P c i j − P g i j skew\left( {
{P_{gij}} + {P_{cij}}} \right){P_{cg}}^\prime = {P_{cij}}- {P_{gij}}
skew(Pgij​+Pcij​)Pcg​′=Pcij​−Pgij​

       其中,skew为反对称运算,假设一个三维向量 V = [ v x ; v y ; v z ] V=[v_x;v_y;v_z] V=[vx​;vy​;vz​],其反对称矩阵为:
KaTeX parse error: Unknown column alignment: * at position 46: …{\begin{array}{*̲{20}{c}} {\be…

Step5:计算旋转向量 P c g P_{cg} Pcg​

P c g = 2 P c g ′ 1 + ∣ P c g ′ ∣ 2 {P_{cg}} = \frac{
{2{P_{cg}}^\prime }}{
{\sqrt {1 + {
{\left| {
{P_{cg}}^\prime } \right|}^2}} }}
Pcg​=1+∣∣​Pcg​′∣∣​2
​
2Pcg​′
​

Step6:计算旋转矩阵 R c g R_{cg} Rcg​

R c g = ( 1 − ∣ P c g ∣ 2 2 ) I + 1 2 ( P c g P c g T + 4 − ∣ P c g ∣ 2 s k e w ( P c g ) ) {R_{cg}} = \left( {1 – \frac{
{
{
{\left| {
{P_{cg}}} \right|}^2}}}{2}} \right)I + \frac{1}{2}\left( {
{P_{cg}}{P_{cg}}^T + \sqrt {4 – {
{\left| {
{P_{cg}}} \right|}^2}} skew\left( {
{P_{cg}}} \right)} \right)
Rcg​=(1−2∣Pcg​∣2​)I+21​(Pcg​Pcg​T+4−∣Pcg​∣2
​
skew(Pcg​)
)

Step7:计算平移向量 T c g T_{cg} Tcg​

( R g i j − I ) T c g = R c g T c i j − T g i j \left( {
{R_{gij}} – I} \right){T_{cg}} = {R_{cg}}{T_{cij}} – {T_{gij}}
(Rgij​−I)Tcg​=Rcg​Tcij​−Tgij​


算法源代码

       根据上述基本计算步骤,在利用OpenCV 2.0开源库的基础上,编写Tsai手眼标定方法的c++程序,其实现函数代码如下:

void Tsai_HandEye(Mat& Hcg, vector<Mat> Hgij, vector<Mat> Hcij)
{ 
   
	CV_Assert(Hgij.size() == Hcij.size());
	int nStatus = Hgij.size();

	Mat Rgij(3, 3, CV_64FC1);
	Mat Rcij(3, 3, CV_64FC1);

	Mat rgij(3, 1, CV_64FC1);
	Mat rcij(3, 1, CV_64FC1);

	double theta_gij;
	double theta_cij;

	Mat rngij(3, 1, CV_64FC1);
	Mat rncij(3, 1, CV_64FC1);

	Mat Pgij(3, 1, CV_64FC1);
	Mat Pcij(3, 1, CV_64FC1);

	Mat tempA(3, 3, CV_64FC1);
	Mat tempb(3, 1, CV_64FC1);

	Mat A;
	Mat b;
	Mat pinA;

	Mat Pcg_prime(3, 1, CV_64FC1);
	Mat Pcg(3, 1, CV_64FC1);
	Mat PcgTrs(1, 3, CV_64FC1);

	Mat Rcg(3, 3, CV_64FC1);
	Mat eyeM = Mat::eye(3, 3, CV_64FC1);
		
	Mat Tgij(3, 1, CV_64FC1);
	Mat Tcij(3, 1, CV_64FC1);

	Mat tempAA(3, 3, CV_64FC1);
	Mat tempbb(3, 1, CV_64FC1);

	Mat AA;
	Mat bb;
	Mat pinAA;

	Mat Tcg(3, 1, CV_64FC1);

	for (int i = 0; i < nStatus; i++)
	{ 
   
		Hgij[i](Rect(0, 0, 3, 3)).copyTo(Rgij);
		Hcij[i](Rect(0, 0, 3, 3)).copyTo(Rcij);

		Rodrigues(Rgij, rgij);
		Rodrigues(Rcij, rcij);

		theta_gij = norm(rgij);
		theta_cij = norm(rcij);

		rngij = rgij / theta_gij;
		rncij = rcij / theta_cij;

		Pgij = 2 * sin(theta_gij / 2)*rngij;
		Pcij = 2 * sin(theta_cij / 2)*rncij;

		tempA = skew(Pgij + Pcij);
		tempb = Pcij - Pgij;

		A.push_back(tempA);
		b.push_back(tempb);
	}

	//Compute rotation
	invert(A, pinA, DECOMP_SVD);

	Pcg_prime = pinA * b;
	Pcg = 2 * Pcg_prime / sqrt(1 + norm(Pcg_prime) * norm(Pcg_prime));
	PcgTrs = Pcg.t();	
	Rcg = (1 - norm(Pcg) * norm(Pcg) / 2) * eyeM + 0.5 * (Pcg * PcgTrs + sqrt(4 - norm(Pcg)*norm(Pcg))*skew(Pcg));

	//Compute Translation 
	for (int i = 0; i < nStatus; i++)
	{ 
   
		Hgij[i](Rect(0, 0, 3, 3)).copyTo(Rgij);
		Hcij[i](Rect(0, 0, 3, 3)).copyTo(Rcij);
		Hgij[i](Rect(3, 0, 1, 3)).copyTo(Tgij);
		Hcij[i](Rect(3, 0, 1, 3)).copyTo(Tcij);


		tempAA = Rgij - eyeM;
		tempbb = Rcg * Tcij - Tgij;

		AA.push_back(tempAA);
		bb.push_back(tempbb);
	}

	invert(AA, pinAA, DECOMP_SVD);
	Tcg = pinAA * bb;

	Rcg.copyTo(Hcg(Rect(0, 0, 3, 3)));
	Tcg.copyTo(Hcg(Rect(3, 0, 1, 3)));
	Hcg.at<double>(3, 0) = 0.0;
	Hcg.at<double>(3, 1) = 0.0;
	Hcg.at<double>(3, 2) = 0.0;
	Hcg.at<double>(3, 3) = 1.0;

}

Mat skew(const Mat A) //Compute the skew symmetric matrix.
{ 
   
	CV_Assert(A.cols == 1 && A.rows == 3);
	Mat B(3, 3, CV_64FC1);

	B.at<double>(0, 0) = 0.0;
	B.at<double>(0, 1) = -A.at<double>(2, 0);
	B.at<double>(0, 2) = A.at<double>(1, 0);

	B.at<double>(1, 0) = A.at<double>(2, 0);
	B.at<double>(1, 1) = 0.0;
	B.at<double>(1, 2) = -A.at<double>(0, 0);

	B.at<double>(2, 0) = -A.at<double>(1, 0);
	B.at<double>(2, 1) = A.at<double>(0, 0);
	B.at<double>(2, 2) = 0.0;

	return B;
}
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/132187.html原文链接:https://javaforall.net

赞 (0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • stm32中的u8定义在哪里_c语言中u8和u16是啥

    stm32中的u8定义在哪里_c语言中u8和u16是啥初学STM32编程时,经常见到数据类型定义的符号:u8、u16等,51都是自己定义数据类型的简写符号,STM32是哪里定义的呢?今天没事就看了看系统头文件,数据类型的定义在其中的3个头文件里:(1)stdint.h(摘取定义部分)/* *’signed’isredundantbelow,exceptfor’signedchar’andif *thetypedefis…

    2022年10月7日
  • VMware虚拟机安装详细教程

    VMware虚拟机安装详细教程VMware安装好之后,下载好我们要安装的操作系统的镜像文件后此处安装的为centos7版本需要下载镜像的小伙伴可去我的资源处下载,就可以开始安装了。进入主页选择创建新的虚拟机这里选择自定义安装,下一步即可。可以根据需要选择版本选择完成后,下一步选择安装程序映像文件,浏览到自己下载的镜像文件,下一步即可自定义虚拟机名称,以及虚拟机存储在主机的路径,下一步即可根据需要配置处…

    2022年5月18日
  • yarn详细入门教程「建议收藏」

    yarn详细入门教程「建议收藏」简介Yarn是Facebook,Google,Exponent和Tilde开发的一款新的JavaScript包管理工具。就像我们可以从官方文档了解那样,它的目的是解决这些团队使用npm面临的少数问题,即:1.安装的时候无法保证速度/一致性2.安全问题,因为npm安装时允许运行代码Yarn同样是一个从npm注册源获取模块的新的CLI客户端。注册的方

    2022年6月5日
  • 服务器的文件不能修改器,荒野行动gg修改器脚本安装文件运行出错「建议收藏」

    服务器的文件不能修改器,荒野行动gg修改器脚本安装文件运行出错「建议收藏」PrivateDeclareFunctionCreateDirectoryLib”kernel32″Alias”CreateDirectoryA”(ByVallpPathNameAsString,lpSecurityAttributesAsSECURITY_ATTRIBUTES)AsLongPrivateTypeSECURITY_ATTRIBUTESnLengthAsLonglpSecurityD…

    2022年9月5日
  • ZBrush中必须记住的常用快捷键

    ZBrush中必须记住的常用快捷键ZBrush是一款数字雕刻和绘画软件,它以强大的功能和直观的工作流程彻底改变了整个三维雕刻行业。强大的功能离不开便捷的操作,为此ZBrush提供了一系列常用操作快捷键,熟练掌握这些快捷键

    2022年8月2日
  • c语言和java哪个好学_学java前要学C语言吗?java和C语言哪个好学?

    c语言和java哪个好学_学java前要学C语言吗?java和C语言哪个好学?在编程世界,只要一提到java,总会有人联想到C语言,仿佛这两者之间有着一种密不可分的联系,那么也会有外行人在选择学习编程时,会有类似于学java前是否需要学习C语言呢?或者说java和C语言哪个会比较好学?等等之类的问题。其实大家会有这样的问题倒也不奇怪,因为学习C语言就是在学习Java,因为C语言中至少80%的语法知识都被Java继承了。Java刚开始的前半部分,如数据类型、变量、流…

    2022年7月7日

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号