HybrIK
HybrIK copied to clipboard
Great job! A quick question about SMPL joint angles?
When running inferences in the wild, how do I extract the joint angles from pose_output? I see the joint positions in the object, but not the rotation angles? Is it embedded in the SMPL object? I would love to evaluate the accuracy of the joint twist angles as your paper states that you are able to decompose.
Again, great job! This is the first paper that I have seen that can decompose all 3 joint angles using inference.
Thanks!
@brainleacher Maybe you need quaternion to angle conversion? https://github.com/Jeff-sjtu/HybrIK/blob/8a798c9d427f1867032d063b5647d6705f4a1265/scripts/demo_image.py#L108
So hopefully this helps:
#!/usr/bin/env python3
from math import radians, degrees, cos, sin, atan2, asin, pow, floor
class Quaternion:
def __init__(self, x: float, y: float, z: float, w: float) -> None:
if round(pow(x, 2) + pow(y, 2) + pow(z, 2) + pow(w, 2), 1) == 1:
self.x = x
self.y = y
self.z = z
self.w = w
else:
raise ValueError(
"Invalid quaternion values: x={}, y={}, z={}, w={}".format(
x,
y,
z,
w
)
)
@classmethod
def from_euler(cls,
phi: float, theta: float, psi: float,
precision: int) -> 'Quaternion':
"""Creates an quaternion by euler angles and returns it
Args:
phi (float): Rotation angle around the X axis
theta (float): Rotation angle around the Y axis
psi (float): Rotation angle around the Y axis
precision (int): Round the results to 'precision' digits after the decimal point
Returns:
Quaternion: Created quaternion (x, y, z, w)
>>> str(Quaternion.from_euler(-90, -180, 90, 12))
'(0.5, -0.5, -0.5, 0.5)'
.. _Source:
https://www.meccanismocomplesso.org/en/hamiltons-quaternions-and-3d-rotation-with-python
"""
# x axis rotation angle
cos_phi_half = cos(radians(phi) / 2)
sin_phi_half = sin(radians(phi) / 2)
# y axis rotation angle
cos_theta_half = cos(radians(theta) / 2)
sin_theta_half = sin(radians(theta) / 2)
# z axis rotation angle
cos_psi_half = cos(radians(psi) / 2)
sin_psi_half = sin(radians(psi) / 2)
# Calculation
return cls(
x = float(round(sin_phi_half * cos_theta_half * cos_psi_half - cos_phi_half * sin_theta_half * sin_psi_half, precision)),
y = float(round(cos_phi_half * sin_theta_half * cos_psi_half + sin_phi_half * cos_theta_half * sin_psi_half, precision)),
z = float(round(cos_phi_half * cos_theta_half * sin_psi_half - sin_phi_half * sin_theta_half * cos_psi_half, precision)),
w = float(round(cos_phi_half * cos_theta_half * cos_psi_half + sin_phi_half * sin_theta_half * sin_psi_half, precision))
)
def to_euler(self) -> tuple[float, float, float]:
"""Exports an quaternion as an euler angle tuple
Returns:
tuple[float, float, float]: (x, y, z)
>>> str(Quaternion.from_euler(-90, -180, 90, 12).to_euler())
(90.0, 0.0, -90.0)
.. _Source:
https://www.meccanismocomplesso.org/en/hamiltons-quaternions-and-3d-rotation-with-python
"""
# x axis rotation angle
t0 = 2 * (self.w * self.x + self.y * self.z)
t1 = 1 - 2 * (self.x * self.x + self.y * self.y)
x = atan2(t0, t1)
# y axis rotation angle
t2 = 2 * (self.w * self.y - self.z * self.x)
t2 = 1 if t2 > 1 else t2
t2 = -1 if t2 < -1 else t2
y = asin(t2)
# y axis rotation angle
t3 = 2 * (self.w * self.z + self.x * self.y)
t4 = 1 - 2 * (self.y * self.y + self.z * self.z)
z = atan2(t3, t4)
return degrees(x), degrees(y), degrees(z)
def __str__(self) -> str:
return "(" + ", ".join(
(
str(self.x),
str(self.y),
str(self.z),
str(self.w)
)
) + ")"
Edit: Fixed the check in Quaternion.__init__()
and added rounding parameter to Quaternion.from_euler()
Example usage:
q = Quaternion(float(-0.000002366145), float(-0.000047797843), float(0.000008500623), float(-1))
print(q)
print(q.to_euler())
q = Quaternion.from_euler(-90, -180, 90, precision = 12)
print(q)
print(q.to_euler())
'Euler' means roatations by angles instead of quaternions.
Thanks @vivi90 , I actually prefer to look at the quaternions rather than the Euler angles. Where are the quaternions burried in the pose_output object (either in rotational axis and rotation angle form, or the 4x4 matrix?) Thanks!
Hi @brainleacher, you can refer to this line to obtain the output quaternions.