参考转载 http://www.cnblogs.com/singlex/p/3DPointRotate.html

基本概念

1 空间点绕轴旋转公式&程序

空间点绕轴旋转公式&程序(C++)

关键词:空间旋转、旋转轴

用途:相机位姿估计、无人机位姿估计、3D游戏、3D建模

文章类型:概念、公式总结(本文不带推倒过程,若想了解公式是如何推出来的请搜索文献),C++函数展示

@Author:VShawn(singlex@foxmail.com)

写在前面的一些概念

右手系

关于这个概念,搞3D的人应该都懂,而像我这样做图像处理的可能就对这个知道的比较少了。右手系这个概念其实很简单,看图就懂了。在坐标系中,右手摆成下图的样子,当拇指指向X轴食指指向Y轴时,中指指向了Z轴,满足这个条件的坐标系就是右手系。本文所有概念都在右手系下进行讨论。

右手系

旋转90°到底是怎么转

当我要让一个点,绕Y轴转动了90°,并且用程序计算出了旋转结果,为了验证这个点是否旋转正确,我们需要知道这个90°是怎么转的。在网上搜索了挺多文章,都没有对这个东西进行明确的定义,那么这里给出我的总结。从原点(0,0,0)往Y轴方向看,此时视野中的坐标系降维到二维坐标系XOZ,那么让点绕O点顺时针转90°,即为正确的旋转结果。

问题一:XYZ空间内某点绕X、Y、Z轴旋转一次

这个问题比较简单,网上已经有较多总结:设旋转前坐标为,旋转后坐标为

1.绕Z轴旋转γ角

首先给出向量表示:(行向量与列向量,左乘右乘,差负号)

然后是公式表示:

最后是代码表示

//将空间点绕Z轴旋转

//输入参数 x y为空间点原始x y坐标

//thetaz为空间点绕Z轴旋转多少度,角度制范围在-180到180

//outx outy为旋转后的结果坐标

void codeRotateByZ(double x,double y,double thetaz,double& outx, double& outy)

{

    double x1 = x;//将变量拷贝一次,保证&x == &outx这种情况下也能计算正确

    double y1 = y;

    double rz = thetaz * CV_PI / 180;

    outx = cos(rz) * x1 - sin(rz) * y1;

    outy = sin(rz) * x1 + cos(rz) * y1;

}

2.绕Y轴旋转β角

首先给出向量表示:

然后是公式表示:

最后是代码表示

//将空间点绕Y轴旋转

//输入参数 x z为空间点原始x z坐标

//thetay为空间点绕Y轴旋转多少度,角度制范围在-180到180

//outx outz为旋转后的结果坐标

void codeRotateByY(double x,double z,double thetay,double& outx, double& outz)

{

    double x1 = x;

    double z1 = z;

    double ry = thetay * CV_PI / 180;

    outx = cos(ry) * x1 + sin(ry) * z1;

    outz = cos(ry) * z1 - sin(ry) * x1;

}

  

3.绕X轴旋转α角

首先给出向量表示:

然后是公式表示:

最后是代码表示

//将空间点绕X轴旋转

//输入参数 y z为空间点原始y z坐标

//thetax为空间点绕X轴旋转多少度,角度制范围在-180到180

//outy outz为旋转后的结果坐标

void codeRotateByX(double y,double z,double thetax,double& outy, double& outz)

{

    double y1 = y;//将变量拷贝一次,保证&y == &y这种情况下也能计算正确

    double z1 = z;

    double rx = thetax * CV_PI / 180;

    outy = cos(rx) * y1 - sin(rx) * z1;

    outz = cos(rx) * z1 + sin(rx) * y1;

}

  

问题二:空间点绕任意轴旋转

首先,需要定义"任意轴"的单位向量,例如X轴可以用向量来表示。

那么假设旋转轴的单位向量为,旋转前坐标为,旋转后坐标为,旋转角为,于是有:

x′=(vx⋅vx⋅(1−cosθ)+cosθ)⋅x+(vx⋅vy⋅(1−cosθ)−vz⋅sinθ)⋅y+(vx⋅vz⋅(1−cosθ)+vy⋅sinθ)⋅zy′=(vx⋅vy⋅(1−cosθ)+vz⋅sinθ)⋅x+(vy⋅vy⋅(1−cosθ)+cosθ)⋅y+(vy⋅vz⋅(1−cosθ)−vx⋅sinθ)⋅zz′=(vx⋅vz⋅(1−cosθ)−vy⋅sinθ)⋅x+(vy⋅vz⋅(1−cosθ)+vx⋅sinθ)⋅y+(vz⋅vz⋅(1−cosθ)+cosθ)⋅z(10)(11)(12)(10)x′=(vx⋅vx⋅(1−cosθ)+cosθ)⋅x+(vx⋅vy⋅(1−cosθ)−vz⋅sinθ)⋅y+(vx⋅vz⋅(1−cosθ)+vy⋅sinθ)⋅z(11)y′=(vx⋅vy⋅(1−cosθ)+vz⋅sinθ)⋅x+(vy⋅vy⋅(1−cosθ)+cosθ)⋅y+(vy⋅vz⋅(1−cosθ)−vx⋅sinθ)⋅z(12)z′=(vx⋅vz⋅(1−cos⁡θ)−vy⋅sin⁡θ)⋅x+(vy⋅vz⋅(1−cos⁡θ)+vx⋅sin⁡θ)⋅y+(vz⋅vz⋅(1−cos⁡θ)+cos⁡θ)⋅z

计算时照着公式代入即可。

最后给出代码实现:

//定义返回结构体

struct Point3f

{

    Point3f(double _x,double _y,double _z)

    {

        x = _x;

        y = _y;

        z = _z;

    }

    double x;

    double y;

    double z;

};

//点绕任意向量旋转,右手系

//输入参数old_x,old_y,old_z为旋转前空间点的坐标

//vx,vy,vz为旋转轴向量

//theta为旋转角度角度制,范围在-180到180

//返回值为旋转后坐标点

Point3f RotateByVector(double old_x,double old_y,double old_z,double vx,double vy,double vz,double theta)

{

    double r = theta * CV_PI / 180;

    double c = cos(r);

    double s = sin(r);

    double new_x = (vx*vx*(1 - c) + c) * old_x + (vx*vy*(1 - c) - vz*s) * old_y + (vx*vz*(1 - c) + vy*s) * old_z;

    double new_y = (vy*vx*(1 - c) + vz*s) * old_x + (vy*vy*(1 - c) + c) * old_y + (vy*vz*(1 - c) - vx*s) * old_z;

    double new_z = (vx*vz*(1 - c) - vy*s) * old_x + (vy*vz*(1 - c) + vx*s) * old_y + (vz*vz*(1 - c) + c) * old_z;

    return Point3f(new_x, new_y, new_z);

}

 

问题三:空间点绕xyz轴连续旋转

前面的问题比较基础,到这个问题就需要一点空间想象力了。

首先我假设一个点绕x、y、z轴旋转90°,最终它会落在哪里?这个答案不是唯一的,因为旋转的顺序将会影响到最终的结果。

以点(1,2,3)为例

A 我让它首先绕x轴转90°,再绕y轴转90°,再绕z轴转90°。

double x = 1, y = 2, z = 3;

codeRotateByX(y, z, 90, y, z);

codeRotateByY(x, z, -90, x, z);

codeRotateByZ(x, y, -90, x, y);

cout << endl << "   (1,2,3) -> (" << x << ',' << y << ',' << z << ")" << endl << endl;

旋转结果是:

B 这一次我让它首先绕z轴转90°,再绕y轴转90°,最后绕z轴转90°。

double x = 1, y = 2, z = 3;

codeRotateByZ(x, y, -90, x, y);

codeRotateByY(x, z, -90, x, z);

codeRotateByX(y, z, 90, y, z);

cout << endl << "   (1,2,3) -> (" << x << ',' << y << ',' << z << ")" << endl << endl;

这次的结果是:

显然,不同的旋转顺序导致了结果的不同,因此在处理空间内绕轴旋转的问题时,我们需要严格定义每次旋转的顺序,否则会导致错误的答案。

2 求解三个轴的旋转角/欧拉角/姿态角旋转公式&程序

根据相机旋转矩阵求解三个轴的旋转角/欧拉角/姿态角

关键词:旋转矩阵 旋转角 欧拉角 姿态角

用途:相机位姿估计、无人机位姿估计、各种位姿估计

文章类型:概念、公式总结(本文不带推倒过程,若想了解公式是如何推出来的请自习搜索文献),C++函数展示

前言

相机标定后得出了旋转矩阵,而后应该怎么通过旋转矩阵表示相机姿态这一问题估计困扰过每一位研究这一问题的新同学,那么本文就给出我的一种做法,帮助大家少走歪路。当然有什么好的想法,或者更牛的办法也欢迎留言交流斧正。当然,公式的推倒就不要找我了,参考文献比我厉害多了

公式

有旋转矩阵

那么可求出各轴旋转角:

Z轴:

Y轴

X轴

注:atan2为C++中函数,atan2(y,x)的做法:当 x 的绝对值比 y 的绝对值大时使用 atan(y/x);反之使用 atan(x/y)。这样就保证了数值稳定性。

上面公式的意思是,相机坐标系想要转到与世界坐标系完全平行(即xc平行于xw,yc平行于yw,zc平行于zw,且他们的方向都是相同的),需要旋转3次,设原始相机坐标系为C0。

1、C0绕其z轴旋转,得到新的坐标系C1;

2、C1绕其y轴旋转,得到新的坐标系C2(注意旋转轴为C1的y轴,而非C0的y轴);

3、C2绕其x轴旋转,得到新的坐标系C3。此时C3与世界坐标系W完全平行。

特别注意:旋转顺序为z y x,切记不能调换。

C++程序

代码就比较简单了

r11-r33从旋转矩阵中提出,为double型变量。

//计算出相机坐标系的三轴旋转欧拉角,旋转后可以转出世界坐标系。

//旋转顺序为z、y、x

const double PI = 3.141592653;

double thetaz = atan2(r21, r11) / PI * 180;

double thetay = atan2(-1 * r31, sqrt(r32*r32 + r33*r33)) / PI * 180;

double thetax = atan2(r32, r33) / PI * 180;

参考文献

Computing Euler angles from a rotation matrix. Gregory G. Slabaugh

http://www.staff.city.ac.uk/~sbbh653/publications/euler.pdf

3 子坐标系C在父坐标系W中的旋转问题

子坐标系C在父坐标系W中的旋转问题

关键词:空间旋转、旋转轴、刚体旋转          用途:相机位姿估计、无人机位姿估计

本文接上一篇《空间点绕轴旋转公式&程序(C++)》,继续讨论空间内的旋转问题,可能会用到上一篇中定义的函数。

问题四:空间内的坐标系旋转(相机坐标系在世界坐标系中的旋转)

好了,现在问题越来越复杂了,这次的问题涉及两个坐标系:世界坐标系W与相机坐标系C。

做过相机标定或者研究过相机模型的人对这两个坐标系应该是相当熟悉的了,对于不了解这方面的同学可以这样理解:

  1. 世界坐标系就是前文一直在用着的坐标系,它规定了所有东西的绝对坐标。

  2. 相机坐标系是人眼或者是相机看物体的一个坐标系,它能够表示我观测的这个物体距离我有多远,方向角是多少。(其z轴为视线正中线)

下图中的O即为相机坐标系原点,也就是人眼的位置,OZc表示的是当前视线的方向,

Ow则是世界坐标系原点。

于是我们的问题就是,人站在某点拍摄世界坐标系的原点Ow(下标w表示该坐标是在世界坐标系中的),拍摄出的原点正好落在图像中心,现在我通过某种方法(解PNP问题)计算出Ow在相机坐标系下的坐标为(下标c表示该坐标定义在相机坐标系内),求相机或者说是人位于世界坐标系的哪里。

这个问题,当相机坐标系跟世界坐标系完全平行(指两对坐标系的三个轴都相互对应平行)的时候很简单,无需考虑旋转,相机的位置就是。实际上,只要相机坐标系的三根轴与世界的三轴平行(这种平行不需要保证一一对应),这个问题都很好解决。比如下面几幅图的情况(黄点为世界坐标系原点Ow),只要知道世界坐标系的原点Ow在相机坐标系中的坐标,就可以很容易计算出相机的位置。

 

然而,一旦出现了下面的情况,那么问题就不那么好解决了。

比如说相机的状态是这样:

你就很难通过相机坐标系下的Ow坐标,计算出相机在世界坐标系下的位置。因为其中涉及到了相机坐标系在世界坐标系中的旋转问题。

那么如何求解这个问题呢,事实上,在上文中通过某种方法(解PNP问题)求出原点Ow在相机坐标系下的坐标的同时,我们也获得了相机坐标系的旋转矩阵(没错,就是求相机的外参数矩阵:旋转矩阵r&平移矩阵t),这个"某种方法"我将在其他文章中给大家展示。平移矩阵t可以告诉世界坐标系原点Ow在相机坐标系中的坐标,我们暂且假设为点P=(x0,y0,z0),向量OcP为Oc指向Ow的向量。而旋转矩阵r,可以求出三个欧拉角【具体如何计算参考《根据相机旋转矩阵求解三个轴的旋转角/欧拉角》】。当相机坐标系C按照z轴、y轴、x轴的顺序旋转以上角度后变成坐标系C3,C3将与世界坐标系W完全平行。此时如果知道Ow在C3系中的坐标,自然就知道了Oc在世界坐标系W中的坐标。

显然,相机坐标系经历了三次旋转后,原点Oc位置会保持不变,而点P跟随坐标系进行了三次旋转,那么向量OcP不再指向Ow。

为了抵消旋转的作用,每次对坐标轴旋转后,我们需要对点P进行反向旋转,使得坐标系C3中的向量OcP依然能指向Ow。

于是得到解决问题的步骤:

第一次旋转:

原始相机坐标系C绕z轴旋转了变为C1系,此时P=P0=(x0,y0,z0),那么单独将P点绕z轴旋转,得到P1=(x1,y1,z1),为C1系中Ow的坐标。

第二次旋转:

C1绕y轴旋转了变为C2系,此时P1=(x1,y1,z1),那么将P1点绕y轴旋转,得到P2=(x2,y2,z2),为C2系中Ow的坐标。

第三次旋转:

C2绕x轴旋转了变为C3系,此时P2=(x2,y2,z2),那么将P2点绕x轴旋转,得到P3=(x3,y3,z3),为C3系中Ow的坐标。

于是世界坐标系中,相机的位置坐标为(-x3,-y3,-z3)。

至于程序就很简单了,只需要调用几次《空间点绕轴旋转公式&程序(C++)》中的函数即可。

最后,本文的成果用在了《相机位姿估计1:根据四个特征点估计相机姿态》中。

作者:VShawn 出处:http://www.cnblogs.com/singlex/

【计算机视觉】opencv靶标相机姿态解算1之基本概念(空间旋转、旋转轴)相关推荐

  1. 姿态解算基础知识(二)-旋转矢量坐标变换的四元数描述的验证

    姿态解算基础知识(二)-旋转矢量坐标变换的四元数描述的验证 2015-11-14 补充下四元数的知识及上篇博文提到的旋转矢量坐标变换的四元数描述的推导过程. 四元数q可以看出由一个实数和一个三维矢量组 ...

  2. 单目相机三维姿态解算

    单目相机三维姿态解算 Abstract:This passage mainly describes how to solve pose(Yaw,Pitch,Roll)with signal camer ...

  3. Pixhawk代码分析-姿态解算篇A

    姿态解算篇A 基本知识 1.如何实现控制 一个无人机系统的算法主要有两类:姿态检测算法.姿态控制算法.姿态控制.被控对象.姿态检测三个部分构成一个闭环控制系统.被控对象的模型是由其物理系统决定,设计无 ...

  4. STM32实现水下四旋翼(六)传感任务2——姿态解算代码实现(使用角度传感器)

    目录 一. 绪论 二. JY901B与JY-GPSIMU角度传感器介绍 1. 角度传感器简介 2. JY901B的IIC通讯协议 3. JY-GPSIMU的串口通讯协议 三. STM32的IIC与串口 ...

  5. Arduino 与 MPU6050 姿态解算+ PROCESSING

    2019独角兽企业重金招聘Python工程师标准>>> 买的MPU6050自带姿态解算大大减轻了上层处理器所做的工作. 通过熟悉了一下processing之后做了一个小例子更是感觉这 ...

  6. 四轴飞行器1.4 姿态解算和Matlab实时姿态显示

    四轴飞行器1.4 姿态解算和Matlab实时姿态显示 MPU6050数据读取出来后,经过一个星期的努力,姿态解算和在matlab上的实时显示姿态终于完成了. 1:完成matlab的串口,并且实时通过波 ...

  7. 四旋翼姿态解算——梯度下降法理论推导

    转载请注明出处:http://blog.csdn.net/hongbin_xu 或 http://hongbin96.com/ 文章链接:http://blog.csdn.net/hongbin_xu ...

  8. 四旋翼姿态解算——互补滤波算法及理论推导

    转载请注明出处:http://blog.csdn.net/hongbin_xu 或 http://hongbin96.com/ 文章链接:http://blog.csdn.net/hongbin_xu ...

  9. 四旋翼姿态解算——基础理论及推导

    转载请注明出处:http://blog.csdn.net/hongbin_xu 或 http://hongbin96.com/ 文章链接:http://blog.csdn.net/hongbin_xu ...

  10. 四元数姿态解算及多传感器融合详细解析

    代码路径ardupolit/modules/PX4Firmware/src/modules/attitude_estimator_so3/attitude_estimator_so3_main.cpp ...

最新文章

  1. CSS FILTERS:CSS过滤器能够做什么?
  2. mysql DML操作、关联查询、联合查询、聚合函数使用
  3. 【Clickhouse】rsyslog服务器使用clickhouse列数据库存储日志
  4. 一个本科生,只用了两年就拿下诺贝尔奖,拯救了无数糖尿病患者
  5. 整合apache和JBoss,配置虚拟主机
  6. Python分布式爬虫1
  7. 云服务器选ssd还是hdd_SSD和普通硬盘对比?SSD到底好不好?看超变态测试
  8. Matlab中的各种运算符的用法
  9. Atitit.加密算法ati Aes的框架设计v2.2
  10. vfp语言属于第代计算机语言,计算机等级考试VFP教程:第二章VFP语言基础
  11. 根据前序序列和中序序列重建二叉树
  12. 无人机通信无线电开放频段
  13. 分析称惠普赶走前任CEO赫德堪比苹果赶走乔布斯
  14. 提取文件夹中图片名字
  15. 盘点最常用的几款linux服务器管理面板
  16. c函数 postgres_C-语言函数
  17. git操作时Permission denied (publickey).
  18. 黑盒测试和白盒测试优点和缺点
  19. pam_limits(crond:session): unknown limit item ‘noproc‘
  20. java吃货联盟的实训报告_作业:吃货联盟

热门文章

  1. 扫地机器人进水后会出现什么故障_小米扫地机器人吸进水怎么办?小米扫地机器人吸进水解决方法...
  2. 次世代3D建模高低模的搭配方式你知道吗?
  3. 青少年重度抑郁的动态功能连接:与严重程度和症状维度的关系
  4. 蓝桥杯:座次问题(枚举法 回溯) java
  5. 留美学子安全手册,这个可以有
  6. 遭遇Trojan.PSW.OnlineGames、Trojan.HiJack.a、Trojan.PSW.ZhuXian.b等
  7. linux路由器还原,openwrt路由器恢复出厂设置的方法
  8. office word 使用快捷键ctrl c ctrl v提示文件未找到:MathPage.WLL
  9. WERTYU - UVA - 10082
  10. LeetCode - 加一