多个四元数的"平均"?

jon*_*han 44 math quaternions

我正在尝试在我的OpenGL程序中从矩阵切换到四元数以进行骨架动画,但我遇到了一个问题:

给定一些单位四元数,我需要得到一个四元数,当用于变换向量时,将给出一个向量,该向量是由每个四元数单独转换的向量的平均值.(使用矩阵我只需将矩阵加在一起并除以矩阵数)

小智 46

与计算机图形行业的普遍看法相反,存在一种直接的算法来解决这个问题,该算法来自航空航天工业,其稳健,准确且简单.它以平均四元数加上(大)常数因子的线性运行.

设Q = [a_1*q_1 a_2*q_2 ... a_n*q_n]

其中a_i是第i个四元数的权重,q_i是被平均的第i个四元数,作为列向量.因此Q是4xN矩阵.

对应于Q*Q ^ T的最大特征值的归一化特征向量是加权平均值.由于Q*Q ^ T是自伴的,并且至少可以获得解决该特征问题的正半确定,快速且稳健的方法.计算矩阵 - 矩阵乘积是随着平均元素数量的增长而增长的唯一步骤.

请参阅2007年"指导,控制和动力学杂志"中的技术说明,该杂志是本方法和其他方法的摘要.在现代,我上面引用的方法对实现可靠性和鲁棒性进行了很好的权衡,并且已经在1978年的教科书中发表了!

  • @GabeHalsmer:这不是*真的.如果四元数足够相似,那么统一代码是合适的(它不是平均加上负四元数检查).参考文献提供了一种完全不同的解决方案,适用于所有四元数,但计算成本却高得多. (9认同)
  • 这个答案有错误吗?我会将 $a_i ^ {1/2}$ 放入您的公式中,以便 $QQ^\intercal$ 恢复 $a_i$。我这么说是因为我在链接 http://www.acsu.buffalo.edu/~johnc/ave_quat07.pdf 的 eq 12 中没有看到权重的平方 (2认同)

Nat*_*one 14

不幸的是,这并不是非常简单,但它是可能的.这是一份解释其背后数学的白皮书:http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/20070017872_2007014421.pdf

查看Unity3D Wiki页面(带代码):http://wiki.unity3d.com/index.php/Averaging_Quaternions_and_Vectors

这篇文章也是:http://forum.unity3d.com/threads/86898-Average-quaternions


Gou*_*uda 11

这是 MATLAB函数的实现,我用它来平均四元数的方向估计.将MATLAB转换为任何其他语言是很简单的,除了这种特殊方法(Markley 2007)需要计算特征向量和特征值.有许多库(包括Eigen C++)可以为您完成此任务.

您可以阅读文件的说明/标题,以查看原始论文中的数学.

来自http://www.mathworks.com/matlabcentral/fileexchange/40098-tolgabirdal-averaging-quaternions的 matlab文件:

% by Tolga Birdal
% Q is an Mx4 matrix of quaternions. weights is an Mx1 vector, a weight for
% each quaternion.
% Qavg is the weightedaverage quaternion
% This function is especially useful for example when clustering poses
% after a matching process. In such cases a form of weighting per rotation
% is available (e.g. number of votes), which can guide the trust towards a
% specific pose. weights might then be interpreted as the vector of votes 
% per pose.
% Markley, F. Landis, Yang Cheng, John Lucas Crassidis, and Yaakov Oshman. 
% "Averaging quaternions." Journal of Guidance, Control, and Dynamics 30, 
% no. 4 (2007): 1193-1197.
function [Qavg]=quatWAvgMarkley(Q, weights)

% Form the symmetric accumulator matrix
A=zeros(4,4);
M=size(Q,1);
wSum = 0;

for i=1:M
    q = Q(i,:)';
    w_i = weights(i);
    A=w_i.*(q*q')+A; % rank 1 update
    wSum = wSum + w_i;
end

% scale
A=(1.0/wSum)*A;

% Get the eigenvector corresponding to largest eigen value
[Qavg, ~]=eigs(A,1);

end
Run Code Online (Sandbox Code Playgroud)

  • 为什么你需要`for i = 1:M`循环?难道你不能只加权`Q`的值,然后计算'A = Q'*Q`? (2认同)
  • @fdermishin:是的,我对此进行了测试,并产生了相同的值,误差约为10 ^ -15。另外,它可能快得多。这是代码:`Q =(weights。* Q)./ sum(weights); A =转置(Q)* Q;` (2认同)

jon*_*han 5

我尝试按照此处的建议对四元数进行 Slerping,但这对我想要做的事情不起作用(模型扭曲),所以我只是最终通过每个四元数转换向量,然后求平均值(直到我能找到更好的解决方案)。


小智 5

这是我在 Python 中对 Tolga Birdal 算法的实现:

import numpy as np

def quatWAvgMarkley(Q, weights):
    '''
    Averaging Quaternions.

    Arguments:
        Q(ndarray): an Mx4 ndarray of quaternions.
        weights(list): an M elements list, a weight for each quaternion.
    '''

    # Form the symmetric accumulator matrix
    A = np.zeros((4, 4))
    M = Q.shape[0]
    wSum = 0

    for i in range(M):
        q = Q[i, :]
        w_i = weights[i]
        A += w_i * (np.outer(q, q)) # rank 1 update
        wSum += w_i

    # scale
    A /= wSum

    # Get the eigenvector corresponding to largest eigen value
    return np.linalg.eigh(A)[1][:, -1]
Run Code Online (Sandbox Code Playgroud)

  • 作为附录,您可以使用 `np.linalg.eigh(np.einsum('ij,ik,i->...jk', q, q, w))[1][:, -1] 来完成此操作`,对于大型四元数集来说,速度要快数百倍。累加器的缩放全部在特征值中(不是正交特征向量)并且可以省略。 (7认同)