4
0
mirror of https://github.com/nerfstudio-project/nerfstudio.git synced 2026-11-10 18:17:31 +08:00
nerfstudio/tests/process_data/test_misc.py
Paul Wais 5c73766653
SFM: sfm-based depth, some breadcrumbs for pycolmap (#1457)
* save

* save

* more cleanup

* save

* save

* update phototourism

* save

* works

* works

* cleanup

* cleanup

* lint

* python3 default

* cleanup
2023-02-25 21:10:53 -08:00

64 lines
2.0 KiB
Python

"""
Test misc data utils
"""
import numpy as np
from pyquaternion import Quaternion
from scipy.spatial.transform import Rotation
# TODO(1480) use pycolmap instead of colmap_parsing_utils
# import pycolmap
from nerfstudio.data.utils.colmap_parsing_utils import qvec2rotmat
def test_scalar_first_scalar_last_quaternions():
"""Many nerfstudio datasets use quaternions for pose rotations. Some use
scalar-first format and others use scalar-last. However internally
nerfstudio uses rotation *matrices* / projection matrices. This test
helps document differences in quaternion encodings & conversion to
rotation matrices.
FMI see call sites in nerfstudio where the various libraries are used. You
might also consult this detailed reference:
* "Why and How to Avoid the Flipped Quaternion Multiplication"
Sommer et al.
https://arxiv.org/abs/1801.07478
"""
# Pick an arbitrary euler rotation; note that different communities
# also use different rotation axes (e.g. Euler vs Tait-Bryan ...)
rot = Rotation.from_euler("xyz", np.array([10.0, 20.0, 30.0]), degrees=True)
# scalar-last
xyzw = rot.as_quat()
assert np.allclose(xyzw, np.array([0.03813458, 0.18930786, 0.23929834, 0.95154852]))
# scalar-first
wxyz = xyzw[[3, 0, 1, 2]]
assert np.allclose(wxyz, np.array([0.95154852, 0.03813458, 0.18930786, 0.23929834]))
# Expected Rotation matrix
# fmt: off
R_expected = np.array( # pylint: disable=invalid-name
[
[ 0.81379768, -0.44096961, 0.37852231],
[ 0.46984631, 0.88256412, 0.01802831],
[-0.34202014, 0.16317591, 0.92541658]
]
)
# fmt: on
# Record3D / scipy
R = Rotation.from_quat(xyzw).as_matrix()
assert np.allclose(R, R_expected)
# Nuscenes / pyquaternion
R = Quaternion(wxyz).rotation_matrix
assert np.allclose(R, R_expected)
# COLMAP
# TODO(1480) use pycolmap
# R = pycolmap.qvec_to_rotmat(wxyz)
R = qvec2rotmat(wxyz)
assert np.allclose(R, R_expected)