# Averaging Quaternions

1. Nov 28, 2014

### twoski

I am trying to implement animation smoothing for a given set of keyframes. Some keyframes have "jitter" which i have to remove through my own algorithms. I am using the Unity game engine which has its own quaternion classes and such.

I looked into it, and using an Exponential Moving Average seems like a good idea. This approach works well for removing positional jitter, however when i use it with quaternions it causes some errors with rotations.

I am currently converting quaternions to euler angles, averaging, then converting back. However this doesn't seem to work. It causes my models to rotate in the wrong directions.

Here is the code i use:

Code (Text):

void UpdateRotationEMA(int i, Quaternion q)
{
if (transforms[i] != null)
{
if (frameList[i] != null)
{
Vector3 pos = AvgPos(frameList[i], q.eulerAngles); //T1

transforms[i].rotation = Quaternion.Euler(pos);
frameList[i] = pos;
}
else
{
transforms[i].rotation = q;
frameList[i] = q.eulerAngles;
}
}
}
Vector3 AvgPos(Vector3 lastPos, Vector3 pos)
{
return (emaAlpha * pos + ((1f - emaAlpha) * lastPos));
}
Can anyone spot any obvious bugs?

2. Nov 28, 2014

### Staff: Mentor

Perhaps you can get it to print the input and the averaged output to see what's going on. Could the algorithm be averaging the angles too?

3. Nov 28, 2014

### twoski

I wasn't sure if this was the proper method - should i be converting my quaternions to euler angles, then averaging those? Or am i meant to just average the quaternions?

4. Nov 29, 2014

### twoski

I think my problems are stemming from a situation like this:

Angle 1: 10, 0, 0.
Angle 2: 350, 0, 0.

The distance between 10 and 350 is 20. This is pretty clear.

However, by doing:

(0.2 * Angle1 + ((0.8) * Angle2))

We get a new angle which is 282, 0, 0. This is totally wrong since it goes the wrong direction!

5. Nov 29, 2014

### twoski

This seems like a step in the right direction.

Code (Text):

Vector3 AvgPos(Vector3 lastPos, Vector3 pos)
{
Vector3 init = (emaAlpha * pos + ((1f - emaAlpha) * lastPos));

if (init == pos)
{
return init;
}

Vector3 res = init;
Vector3 delta = pos - init;

if (Mathf.Abs(pos.x - lastPos.x) > 180f)
{
res.x = pos.x - delta.x;
}

if (Mathf.Abs(pos.y - lastPos.y) > 180f)
{
res.y = pos.y - delta.y;
}

if (Mathf.Abs(pos.z - lastPos.z) > 180f)
{
res.z = pos.z - delta.z;
}

res.x = res.x % 360f;
res.y = res.y % 360f;
res.z = res.z % 360f;

return res;
}
Still, my skeletons are rotating weirdly.

6. Nov 29, 2014

### Staff: Mentor

I don't know much about what you're trying to do but am talking from the experience of debugging programs.

So are you trying to move an object from once place to the next smoothly without changing it orientation? Or change it in a natural and smooth way?

I found this NASA pdf talking about how to average quaternions and also about subtle errors you may encounter:

http://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/20070017872.pdf

Here's another reference:

http://www.mathworks.com/matlabcentral/fileexchange/40098-tolgabirdal-averaging-quaternions

7. Nov 29, 2014

### Staff: Mentor

8. Nov 29, 2014

### twoski

Hmm that looks correct, however i am trying to do an exponential moving average which is slightly different from the way they are doing it.

9. Nov 29, 2014

### Stephen Tashi

Clarify the meaning of "jitter".

Thinking of hand drawn animation, I can imagine a sequence of keyframes that are supposed portray a globe turning. Perhaps some of them inadvertently show the globe moving a little from side to side, so the animation that interpolates images between the keyframes shows the globe vibrating as well as rotating.

How were the keyframes generated? Is a keyframe a set of parameters or an actual image?

10. Nov 29, 2014

### twoski

Ok keyframes was misleading as an example, i'm using raw input from a kinect. Essentially, i have the last frame, and the current frame. Both have a rotation value.

I want to calculate the exponential moving average of these values, however in order to do so i need to convert to euler i think. The problem with using an exponential moving average for this is that euler angles go from 0 to 360 then start at 0 again, so if 2 angles are, say, 350 and 10, the exponential moving average of these will be incorrect using the function i posted.

Intuitively, we know that the difference is 20 degrees. Given this value is there a way to find out the exponential moving average?

11. Nov 30, 2014

### Stephen Tashi

I've glanced at pages about using quaternions for animation and seen interpolation recommended - something like a spline. Supposedly interpolation between quaternion values produces smoother results than interpolating between Euler angles. Is interpolation relevant to what you are doing?

I don't know what an "exponential moving average" is. The meaning of "moving average" is familiar, but what is being averaged? What is being exponentiated?

12. Nov 30, 2014

### twoski

I am showcasing different methods of animation smoothing, i've already implemented quaternion lerping so now i'm trying to show a different method.

Here is the definition: http://en.wikipedia.org/wiki/Moving_average#Exponential_moving_average

The exponential moving average is easy to implement for vectors, however in my case we need to account for the fact that the vectors are euler angles and can go from 0 to 350 in 10 degrees rather than 350 degrees.

13. Nov 30, 2014

### Stephen Tashi

The way I think of moving averages computed from a sequence of data points is that they don't form a curve that goes through the points. So smoothing with moving average is not "interpolation". Is it your intention that your smoothed animation never exactly matches the keyframes?

14. Nov 30, 2014

### twoski

The main goal is to remove jitter, if the animation is slightly off then that just gives me one more talking point for when i showcase the different styles of smoothing.

15. Nov 30, 2014

### Stephen Tashi

I second jedishfu's suggestion to check the code that does the exponential average, if you haven't done that yet.

Have you done any "sanity" tests? Does animation look right if you apply the method to something that just stays in the same constant position?

16. Nov 30, 2014

### twoski

I have done debug prints, however the easiest way to see what was going on was by looking at the raw data in action.

You can see that it's rotating joints in the wrong direction which results in the sporadic flipping of the middle girl.

It only happens when an angle goes from a low number to a very high number, like the scenarios i have described.