10.19 쿼터니언에서 회전 행렬로의 변환

10.19 쿼터니언에서 회전 행렬로의 변환

1. 변환의 동기

쿼터니언은 회전을 효율적으로 저장하고 합성하기에 적합하지만, 점이나 벡터의 변환에서는 회전 행렬이 더 효율적이다. 따라서 단위 쿼터니언을 회전 행렬로 변환하여 후속 점 변환에 활용하는 패턴이 표준이다.

2. 변환 공식

단위 쿼터니언 \mathbf{q} = (q_w, q_x, q_y, q_z)가 주어졌을 때, 대응하는 회전 행렬은 다음과 같다.

\mathbf{R}(\mathbf{q}) = \begin{bmatrix} 1 - 2(q_y^2 + q_z^2) & 2(q_x q_y - q_w q_z) & 2(q_x q_z + q_w q_y) \\ 2(q_x q_y + q_w q_z) & 1 - 2(q_x^2 + q_z^2) & 2(q_y q_z - q_w q_x) \\ 2(q_x q_z - q_w q_y) & 2(q_y q_z + q_w q_x) & 1 - 2(q_x^2 + q_y^2) \end{bmatrix}

이는 단위 노름 조건 q_w^2 + q_x^2 + q_y^2 + q_z^2 = 1하에서 정확히 회전 행렬이다.

3. 행렬 원소의 명명

이 행렬을 \mathbf{R} = [r_{ij}]로 표기하고 각 원소를 분리하여 보면 다음과 같다.

3.1 대각 원소

r_{11} = 1 - 2(q_y^2 + q_z^2)

r_{22} = 1 - 2(q_x^2 + q_z^2)

r_{33} = 1 - 2(q_x^2 + q_y^2)

3.2 비대각 원소

r_{12} = 2(q_x q_y - q_w q_z), \quad r_{21} = 2(q_x q_y + q_w q_z)

r_{13} = 2(q_x q_z + q_w q_y), \quad r_{31} = 2(q_x q_z - q_w q_y)

r_{23} = 2(q_y q_z - q_w q_x), \quad r_{32} = 2(q_y q_z + q_w q_x)

4. 변환의 유도

이 공식은 회전 공식 \mathbf{v}' = \mathbf{q}\mathbf{v}\mathbf{q}^*의 명시적 전개로부터 얻을 수 있다. 회전 공식이 벡터에 대해 선형이므로 \mathbf{v}' = \mathbf{R}(\mathbf{q})\mathbf{v}의 형태로 표현된다.

4.1 첫 번째 열의 유도

회전된 단위 벡터 \hat{\mathbf{e}}_x를 계산한다. \mathbf{v} = (1, 0, 0)을 회전 공식에 대입하면

\mathbf{R}(\mathbf{q})\hat{\mathbf{e}}_x = \mathbf{q}(0, 1, 0, 0)\mathbf{q}^*

이를 단계적으로 계산하면 첫 번째 열이 얻어진다.

\mathbf{R}(\mathbf{q})_{[:,1]} = \begin{bmatrix}1 - 2(q_y^2 + q_z^2) \\ 2(q_x q_y + q_w q_z) \\ 2(q_x q_z - q_w q_y)\end{bmatrix}

이는 회전된 x축의 좌표이다.

4.2 두 번째 열과 세 번째 열

\hat{\mathbf{e}}_y\hat{\mathbf{e}}_z에 대해서도 같은 방법으로 두 번째와 세 번째 열이 얻어진다.

5. 단위 노름 조건 활용

위의 공식은 단위 노름 조건 q_w^2 + q_x^2 + q_y^2 + q_z^2 = 1을 사용하여 일부 항을 단순화한 형태이다. 예를 들어

1 - 2(q_y^2 + q_z^2) = q_w^2 + q_x^2 - q_y^2 - q_z^2

이는 q_w^2 + q_x^2 + q_y^2 + q_z^2 = 1로부터 1 - 2q_y^2 - 2q_z^2 = q_w^2 + q_x^2 - q_y^2 - q_z^2이다.

6. 일반 형태 (단위 노름 조건 없이)

단위 노름 조건을 가정하지 않은 일반 형태는 다음과 같다.

\mathbf{R}(\mathbf{q}) = \begin{bmatrix} q_w^2 + q_x^2 - q_y^2 - q_z^2 & 2(q_x q_y - q_w q_z) & 2(q_x q_z + q_w q_y) \\ 2(q_x q_y + q_w q_z) & q_w^2 - q_x^2 + q_y^2 - q_z^2 & 2(q_y q_z - q_w q_x) \\ 2(q_x q_z - q_w q_y) & 2(q_y q_z + q_w q_x) & q_w^2 - q_x^2 - q_y^2 + q_z^2 \end{bmatrix}

이 형태는 일반 쿼터니언(단위 노름이 아닐 수 있는)에 대해서도 유효하지만, 결과는 일반적으로 회전 행렬이 아니다(스케일 효과 포함). 단위 쿼터니언에서만 정확한 회전 행렬을 산출한다.

7. 변환 알고리즘

쿼터니언에서 회전 행렬로의 변환을 의사 코드로 표현하면 다음과 같다.

function quaternion_to_matrix(q):
    qw, qx, qy, qz = q.w, q.x, q.y, q.z
    
    # 사전 계산
    qx2 = qx * qx
    qy2 = qy * qy
    qz2 = qz * qz
    qxy = qx * qy
    qxz = qx * qz
    qyz = qy * qz
    qwx = qw * qx
    qwy = qw * qy
    qwz = qw * qz
    
    R = matrix(3, 3)
    R[0, 0] = 1 - 2 * (qy2 + qz2)
    R[0, 1] = 2 * (qxy - qwz)
    R[0, 2] = 2 * (qxz + qwy)
    R[1, 0] = 2 * (qxy + qwz)
    R[1, 1] = 1 - 2 * (qx2 + qz2)
    R[1, 2] = 2 * (qyz - qwx)
    R[2, 0] = 2 * (qxz - qwy)
    R[2, 1] = 2 * (qyz + qwx)
    R[2, 2] = 1 - 2 * (qx2 + qy2)
    
    return R

8. 효율적 구현

8.1 사전 계산

위의 의사 코드에서 자주 사용되는 곱(예: q_x q_y, q_w q_z 등)을 사전 계산하여 재사용한다. 이는 중복 계산을 피한다.

8.2 계산 비용

총 약 12 곱셈, 12 덧셈/뺄셈이 필요하다. 이는 매우 효율적이며, 매 변환마다 부담이 작다.

8.3 SIMD 최적화

행렬 라이브러리는 SIMD 명령으로 더욱 가속할 수 있다.

9. 변환 결과의 검증

9.1 직교성 검증

\mathbf{R}^T\mathbf{R} = \mathbf{I}

이는 입력 쿼터니언이 단위 노름이면 자동으로 만족된다. 부동 소수점 오차의 임계값 내에서 확인할 수 있다.

9.2 행렬식 검증

\det(\mathbf{R}) = +1

마찬가지로 입력 쿼터니언이 단위 노름이면 만족된다.

9.3 회전 동일성

쿼터니언으로 점을 직접 회전한 결과와 행렬로 회전한 결과가 같아야 한다.

\mathbf{q}\mathbf{v}\mathbf{q}^* = \mathbf{R}(\mathbf{q})\mathbf{v}

이 동등성은 변환 공식의 정의로부터 자동으로 보장된다.

10. 변환의 응용

10.1 점 변환

쿼터니언으로 자세를 저장하고, 점 변환 시에는 회전 행렬로 변환하여 사용한다.

R = quaternion_to_matrix(q)
v_rotated = R * v

10.2 메쉬 변환

3D 메쉬의 모든 정점에 같은 회전을 적용할 때, 한 번의 변환으로 행렬을 얻고 모든 정점에 적용한다.

10.3 카메라 변환

카메라 자세가 쿼터니언으로 저장되지만, 픽셀 사영에는 회전 행렬이 사용된다.

10.4 시각화

3D 시각화 라이브러리(OpenGL, Vulkan, DirectX)는 일반적으로 회전 행렬을 사용한다. 쿼터니언 자세를 이러한 라이브러리에 전달하기 전에 변환한다.

10.5 동역학 시뮬레이션

물리 시뮬레이션 엔진은 강체의 자세를 다양한 형태로 저장한다. 쿼터니언 표현에서 회전 행렬로의 변환이 자주 필요하다.

11. 단위 쿼터니언이 아닌 경우의 처리

입력 쿼터니언이 단위 노름이 아니면, 변환된 행렬이 정확한 회전 행렬이 아닐 수 있다. 두 가지 처리 방법이 있다.

11.1 사전 정규화

변환 전에 쿼터니언을 정규화한다.

q_normalized = q / norm(q)
R = quaternion_to_matrix(q_normalized)

11.2 일반 형태 사용

단위 노름을 가정하지 않은 일반 형태를 사용한다. 이 경우 결과는 회전과 스케일링의 결합이며, 순수 회전이 아니다.

대부분의 경우 사전 정규화가 권장된다.

12. 변환의 변형

12.1 우측 곱 vs. 좌측 곱

회전 행렬을 점에 적용할 때 \mathbf{v}' = \mathbf{R}\mathbf{v} 또는 \mathbf{v}'^T = \mathbf{v}^T\mathbf{R}^T의 두 형태가 가능하다. 이에 따라 회전 행렬의 정의가 다를 수 있다.

12.2 행 우선 vs. 열 우선

행렬의 메모리 배치가 행 우선(C/C++ 기본)이나 열 우선(Fortran/MATLAB 기본)에 따라 변환 결과의 메모리 배치가 다르다. 라이브러리 사용 시 이에 주의한다.

13. 변환의 미분

쿼터니언에서 회전 행렬로의 변환의 미분은 자세 추정과 최적화에서 사용된다.

13.1 자코비안

\frac{\partial \mathbf{R}(\mathbf{q})}{\partial \mathbf{q}}

이는 9×4 자코비안이며, 각 원소가 쿼터니언 성분에 대한 회전 행렬 원소의 편미분이다. 비선형 최적화에서 사용된다.

13.2 닫힌 형태

자코비안의 닫힌 형태는 위의 변환 공식을 직접 미분하여 얻을 수 있다. 각 원소가 쿼터니언 성분의 곱이므로 미분이 단순하다.

14. 변환의 라이브러리 지원

대부분의 회전 라이브러리가 이 변환을 자동으로 처리한다.

14.1 Eigen

Eigen::Quaterniond q(w, x, y, z);
Eigen::Matrix3d R = q.toRotationMatrix();

14.2 NumPy/SciPy

from scipy.spatial.transform import Rotation
R = Rotation.from_quat([x, y, z, w]).as_matrix()

(SciPy는 스칼라 후순 관례를 사용함에 주의)

14.3 ROS의 tf2

tf2::Quaternion q(x, y, z, w);
tf2::Matrix3x3 R(q);

15. 변환의 응용 패턴

쿼터니언과 회전 행렬을 함께 사용하는 일반적 패턴은 다음과 같다.

15.1 패턴 1: 저장은 쿼터니언, 변환은 행렬

자세를 쿼터니언으로 저장하고, 점 변환이 필요할 때마다 회전 행렬로 변환한다. 합성과 보간은 쿼터니언에서 직접 수행한다.

15.2 패턴 2: 캐싱

자세가 자주 변하지 않으면, 회전 행렬을 캐싱하여 점 변환마다 재계산을 피한다.

class Pose:
    def __init__(self, q):
        self.q = q
        self.R_cached = None
    
    def get_matrix(self):
        if self.R_cached is None:
            self.R_cached = quaternion_to_matrix(self.q)
        return self.R_cached

15.3 패턴 3: 즉시 변환

자세를 갱신할 때마다 회전 행렬도 즉시 갱신한다. 점 변환이 매우 빈번한 경우 효율적이다.

16. 결론

쿼터니언에서 회전 행렬로의 변환은 단순하고 효율적인 닫힌 형태 공식으로 수행된다. 약 12 곱셈과 12 덧셈으로 변환이 완료되며, 변환 결과는 정확한 회전 행렬이다(입력이 단위 쿼터니언인 경우). 이 변환은 쿼터니언과 회전 행렬의 장점을 결합한 효율적 응용 패턴의 기반이다.

17. 참고 문헌

  • Hamilton, W. R. (1844). “On Quaternions; or on a New System of Imaginaries in Algebra.” Philosophical Magazine, Vol. 25, 489–495.
  • Diebel, J. (2006). “Representing Attitude: Euler Angles, Unit Quaternions, and Rotation Vectors.” Stanford University Technical Report.
  • Shoemake, K. (1985). “Animating Rotation with Quaternion Curves.” SIGGRAPH Computer Graphics, 19(3), 245–254.
  • Kuipers, J. B. (1999). Quaternions and Rotation Sequences. Princeton University Press.
  • Sola, J. (2017). “Quaternion Kinematics for the Error-State Kalman Filter.” arXiv:1711.02508.

version: 1.0