在四元数旋转上应用镜像效果的有效方法?

时间:2015-09-07 12:02:12

标签: math 3d quaternions

四元数表示旋转 - 它们不包含有关缩放或镜像的信息。但是仍然可以反映旋转的效果。

考虑在x-y平面上的镜像(我们也可以将其称为沿z轴的镜像)。围绕在x-y平面上镜像的x轴的旋转将被否定。同样围绕y轴旋转。但是,围绕z轴的旋转将保持不变。

另一个例子:在x-y平面上镜像的轴(1,1,1)周围旋转90º会使(-1,1,-1)周围旋转-90°。为了帮助直觉,如果您可以想象轴的描绘和指示旋转的圆形箭头,则镜像该可视化指示新旋转应该是什么。

我找到了一种计算旋转镜像的方法,如下所示:

  • 获取四元数的角度轴表示。
  • 对于轴x,y和z中的每一个。
    • 如果沿该轴缩放为负(镜像):
      • 取消角度和轴。
  • 从修改后的角度和轴获取更新的四元数。

这仅支持沿主轴x,y和z的镜像,因为这就是我所需要的。它适用于任意旋转。

然而,从四元数到角轴的转换以及从角轴到四元数的转换是昂贵的。我想知道是否有一种方法可以直接在四元数上进行转换,但是我对四元数数学的理解还不足以让我自己去任何地方。

(由于计算效率方法的重要性,发布在StackOverflow而非数学相关论坛。)

5 个答案:

答案 0 :(得分:8)

我花了很长时间才弄清楚这个问题的明确答案,所以我将它张贴在这里作为记录。

简介

正如在其他答案中所指出的,镜像效果不能表示为旋转。然而,给定从坐标系C1到坐标系C2的旋转R1to2,我们可能有兴趣在将相同的镜像效果应用于C1和C2 时有效地计算等效旋转(例如,我正面临着将左手坐标系中给出的输入四元数转换为表示相同旋转但在右手坐标系中的四元数的问题。

就旋转矩阵而言,可以认为如下:

 curl --data-binary @your_image.png "https://gateway-a.watsonplatform.net/calls/image/ImageGetRankedImageKeywords?imagePostMode=raw&apikey=d3a529b15ac9ebe550a51006815xxxxxx"

此处,R_mirroredC1_to_mirroredC2 = M_mirrorC2 * R_C1_to_C2 * M_mirrorC1 R_C1_to_C2都代表有效的轮换,因此在处理四元数时,如何从R_mirroredC1_to_mirroredC2高效计算q_mirroredC1_to_mirroredC2

解决方案

以下假定q_C1_to_C2

  • 如果C1和C2沿X轴镜像(即q_C1_to_C2=[w,x,y,z])则M_mirrorC1=M_mirrorC2=diag_3x3(-1,1,1)
  • 如果C1和C2沿Y轴镜像(即q_mirroredC1_to_mirroredC2=[w,x,-y,-z])则M_mirrorC1=M_mirrorC2=diag_3x3(1,-1,1)
  • 如果C1和C2沿Z轴镜像(即q_mirroredC1_to_mirroredC2=[w,-x,y,-z])则M_mirrorC1=M_mirrorC2=diag_3x3(1,1,-1)

当考虑C1和C2的不同镜像轴时,我们有以下内容:

  • 如果C1沿X轴镜像,C2沿Y轴镜像(即q_mirroredC1_to_mirroredC2=[w,-x,-y,z]& M_mirrorC1=diag_3x3(-1,1,1))则M_mirrorC2=diag_3x3(1,-1,1)
  • 如果C1沿X轴镜像,C2沿Z轴镜像(即q_mirroredC1_to_mirroredC2=[z,y,x,w]& M_mirrorC1=diag_3x3(-1,1,1))则M_mirrorC2=diag_3x3(1,1,-1)

  • 如果C1沿Y轴镜像,C2沿X轴镜像(即q_mirroredC1_to_mirroredC2=[-y,z,-w,x]& M_mirrorC1=diag_3x3(1,-1,1))则M_mirrorC2=diag_3x3(-1,1,1)

  • 如果C1沿Y轴镜像,C2沿Z轴镜像(即q_mirroredC1_to_mirroredC2=[z,-y,-x,w]& M_mirrorC1=diag_3x3(1,-1,1))则M_mirrorC2=diag_3x3(1,1,-1)

  • 如果C1沿Z轴镜像,C2沿X轴镜像(即q_mirroredC1_to_mirroredC2=[x,w,z,y]& M_mirrorC1=diag_3x3(1,1,-1))则M_mirrorC2=diag_3x3(-1,1,1)

  • 如果C1沿Z轴镜像,C2沿Y轴镜像(即q_mirroredC1_to_mirroredC2=[y,z,w,x]& M_mirrorC1=diag_3x3(1,1,-1))则M_mirrorC2=diag_3x3(1,-1,1)

测试程序

这是一个基于OpenCV的小型c ++程序来测试所有这些:

q_mirroredC1_to_mirroredC2=[x,w,-z,-y]

答案 1 :(得分:1)

我们可以在3D中检查所有旋转和反射的集合,这称为Orthogonal group O(3)。它可以是具有行列式+1或-1的正交矩阵集。所有旋转都具有行列式+1并且纯反射具有确定-1。 O(3)中的另一个成员在点(x,y,z)中的反转 - >( - x,-y,-z)这在3D中具有det -1,我们将在稍后讨论。如果我们在组中组合两个变换,则乘以它们的决定因素。因此两个旋转组合给出另一个旋转(+ 1 * +1 = +1),旋转与反射相结合给出反射(+ 1 * -1 = -1)并且两个反射组合给出旋转(-1 * -1) = +1)。

我们可以将O(3)限制为具有行列式+1的那些以形成Special Orthogonal Group SO(3)。这只包含旋转。

现在,单位四元数的集合是SO(3)的双重覆盖,这意味着两个单位四元数对应于每个旋转。准确地说,如果a+b i+c j+d k是单位四元数,那么a-b i-c j-d k表示相同的旋转,您可以将其视为围绕向量(b,c,d)的旋转与旋转相同by-ø在向量周围(-b,-c,-d)。

请注意,所有单位四元数都有行列式+1,因此没有一个对应于纯反射。这就是您不能使用四元数来表示反射的原因。

您可以做的是使用反演。现在反转后跟反转是一个旋转。例如,在x = 0和反转中反射,与在y = 0中反射并在z = 0中反射相同。这与围绕x轴旋转180º相同。您可以对任何反射执行相同的过程。

我们可以使用法线向量 n =(a,b,c)来定义通过原点的平面。

给出该平面中向量 v (x,y,z)的reflection

v - 2( v n )/( n n n

=(x,y,z) - 2(a x + b y + c z)/(a ^ 2 + b ^ 2 + c ^ 2)(a,b,c)

特别是x-y平面具有法线(0,0,1),因此反射是

(x,y,z) - 2 z(0,0,1)=(x,y,-z)

Quaternions and spatial rotation从轴角公式得到四元数的公式很好。

p = cos(ø/ 2)+(x i + y j + z k )sin(ø/ 2)< / p>

这是一个四元数W + X i + Y j + Z k ,W = cos(ø/ 2),X = x sin(ø/ 2),Y = y sin(ø/ 2),Z = z sin(ø/ 2)

改变旋转方向将翻转半角的sin,但保持cos不变,给出

p'= cos(ø/ 2) - (x i + y j + z k )sin(ø/ 2)

现在我们考虑在x-y平面上反映相应的矢量给出

q = cos(ø/ 2)+(x i + y j - z k )sin(ø/ 2)< / p>

我们可能想要改变旋转方向

q'= cos(ø/ 2)+( - x i - y j + z k )sin(ø/ 2) )

= W - X i - Y j + Z k

我认为这与你的答案相对应。

我们可以将其推广到单位长度正常(a,b,c)的一般平面中的反射。设d为点积(a,b,c)。(x,y,z)。 (x,y,z)的反思是

(x,y,z) - 2 d(a,b,c)=(x - 2 d a,y - 2 d b,z - 2 d c)

的旋转四元数

q = cos(ø/ 2) - ((x - 2 da) i +((y - 2 db) j +(z - 2 dc) k )sin(ø/ 2)

q = cos(ø/ 2) - (x i + y j + z k )sin(ø/ 2)   + 2 d sin(ø/ 2)(a i + b j + c k

= W - X i - Y j - Z k + 2 d(X,Y,Z)。(a,b ,c)(a i + b j + c k

答案 2 :(得分:1)

请注意,镜像不是旋转,因此通常您不能将其烘焙到四元数中(尽管如此,我可能很好地误解了您的问题)。镜像变换矩阵的3x3分量是

M = I-2(n*nT) 

其中I是身份3x3矩阵,n是镜像平面的法线表示为3x1矩阵,nT是n作为1x3矩阵(因此n * nT是3x(1x1)x3 = 3x3矩阵)。

现在,如果四元数q你想要反映&#39;是最后一次转换,另一方面的最后一次转换只是M * q(同样,这将是一般的3x3矩阵,通常不能表示为四元数)

答案 3 :(得分:1)

有一些更容易和程序员导向的方式来思考这个问题。假设您想要在坐标系中反转z轴(即将z轴翻转为-z)。现在将四元数视为滚动,俯仰和偏航方面的方向向量。当您翻转z轴时,请注意滚动和俯仰的符号已反转,但偏航的符号保持不变。

现在,您可以使用以下代码将Euler角度转换为四元数(我将此代码放入维基百科),找到对四元数的净效果:

static Quaterniond toQuaternion(double pitch, double roll, double yaw)
{
    Quaterniond q;
    double t0 = std::cos(yaw * 0.5f);
    double t1 = std::sin(yaw * 0.5f);
    double t2 = std::cos(roll * 0.5f);
    double t3 = std::sin(roll * 0.5f);
    double t4 = std::cos(pitch * 0.5f);
    double t5 = std::sin(pitch * 0.5f);

    q.w() = t0 * t2 * t4 + t1 * t3 * t5;
    q.x() = t0 * t3 * t4 - t1 * t2 * t5;
    q.y() = t0 * t2 * t5 + t1 * t3 * t4;
    q.z() = t1 * t2 * t4 - t0 * t3 * t5;
    return q;
}

使用基本三角学,sin(-x) = -sin(x)cos(-x) = cos(x)。将此应用于上面的代码,您可以看到t3和t5的符号将会翻转。这将导致x和y的符号翻转。

所以当你反转z轴时,

Q'(w, x, y, z) = Q(w, -x, -y, z)

同样,您可以找出轴反转的任何其他组合,并发现对四元数的影响。

PS:如果有人想知道为什么有人会需要这个...我需要上面来转换来自控制无人机的MavLink / Pixhawk系统的四元数。源系统使用NED坐标系,但像Unreal这样的常用3D环境使用NEU坐标系,需要将z轴转换为-z才能正确使用四元数。

答案 4 :(得分:0)

对于通过网络搜索来到这里并正在寻找数学的人,那么:

反射

使用四元数反射点'p'通过平面ax + + + cz = 0:

n = 0+(a,b,c)
p = 0+(x,y,z)

其中'n'是单位bivector(或者如果你愿意,可以是纯四元数)

p'= npn

然后p'是反射点。

如果你用第二个反射'm'作曲:

p'= mnpnm =(mn)p(mn)^ *

是轮换。

旋转和反射符合预期。

统一缩放

由于标量产品通勤并且可以因子分解,那么如果我们有单位四元数'Q'的旋转或单位bivector'b'(或任何组合)的反射乘以某个非零标度值' s'导致s ^ 2的均匀缩放。并且由于(sqrt(s0)* sqrt(s1))^ 2 = s0 * s1,这些均匀缩放值按预期组成。

然而,这一点可能没有意义,因为在代码中我们希望能够假设单位幅度值来降低运行时复杂性。