vkgs-sim / tests /test_rig.py
kimjunhan's picture
Add files using upload-large-folder tool
4c75661 verified
Raw History Blame Contribute Delete
3.38 kB
"""카메라 리그 μˆ˜ν•™. numpy κ°€ ν•„μš”ν•˜λ―€λ‘œ μ»¨ν…Œμ΄λ„ˆμ—μ„œ λˆλ‹€."""
import math
import pytest
np = pytest.importorskip("numpy")
from nusim.data.index import CameraCalib, Frame
from nusim.data.rig import camera_pose, quat_to_matrix, rt_to_matrix
def test_identity_quaternion():
assert np.allclose(quat_to_matrix((1.0, 0.0, 0.0, 0.0)), np.eye(3))
def test_quaternion_is_orthonormal():
rng = np.random.default_rng(0)
for _ in range(50):
q = rng.normal(size=4)
q /= np.linalg.norm(q)
r = quat_to_matrix(tuple(q))
assert np.allclose(r.T @ r, np.eye(3), atol=1e-12)
assert abs(np.linalg.det(r) - 1.0) < 1e-12
def test_quaternion_90deg_about_z():
# (w,x,y,z) = (cos45, 0, 0, sin45) β†’ zμΆ• +90도
s = math.sqrt(0.5)
r = quat_to_matrix((s, 0.0, 0.0, s))
assert np.allclose(r @ np.array([1.0, 0, 0]), [0, 1, 0], atol=1e-12)
def test_degenerate_quaternion_returns_identity():
# μ •κ·œν™” λΆˆκ°€λŠ₯ν•œ μž…λ ₯에 NaN 을 λ‚΄λ†“λŠ” λŒ€μ‹  ν•­λ“±ν–‰λ ¬λ‘œ μ•ˆμ „ν•˜κ²Œ λ–¨μ–΄μ Έμ•Ό ν•œλ‹€
assert np.allclose(quat_to_matrix((0.0, 0.0, 0.0, 0.0)), np.eye(3))
def _pose():
f = Frame(0, "x.jpg", (100.0, 200.0, 0.0), (math.sqrt(0.5), 0.0, 0.0, math.sqrt(0.5)), True)
c = CameraCalib(
translation=(1.7, 0.0, 1.5),
rotation=(0.5, -0.5, 0.5, -0.5),
intrinsic=((1266.4, 0.0, 816.3), (0.0, 1266.4, 491.5), (0.0, 0.0, 1.0)),
width=1600, height=900,
)
return camera_pose(f, c, "CAM_FRONT")
def test_w2c_inverts_c2w():
p = _pose()
assert np.allclose(p.w2c @ p.c2w, np.eye(4), atol=1e-12)
def test_camera_is_offset_from_ego_origin():
p = _pose()
# ego κ°€ (100,200,0) 에 +90λ„λ‘œ μ„œ 있고 카메라가 μ „λ°© 1.7 m, 높이 1.5 m μ΄λ―€λ‘œ
# μ „μ—­ μ’Œν‘œμ—μ„œλŠ” ego 의 +y λ°©ν–₯으둜 1.7 m λ°€λ € μžˆμ–΄μ•Ό ν•œλ‹€.
assert np.allclose(p.position, [100.0, 201.7, 1.5], atol=1e-9)
def test_projection_is_vulkan_clip_space():
p = _pose()
proj = p.projection(znear=0.1, zfar=100.0)
# znear 에 μžˆλŠ” 점은 z_ndc=0, zfar λŠ” 1 이어야 ν•œλ‹€ (OpenGL 의 -1..1 이 μ•„λ‹ˆλ‹€)
for z, expect in ((0.1, 0.0), (100.0, 1.0)):
v = proj @ np.array([0.0, 0.0, z, 1.0])
assert abs(v[2] / v[3] - expect) < 1e-6
def test_projection_matches_pixel_projection():
# 카메라 +y λŠ” 'μ•„λž˜'(OpenCV)이고 Vulkan NDC 도 y κ°€ μ•„λž˜λ‘œ + 라 λ’€μ§‘κΈ°κ°€ μ—†μ–΄μ•Ό ν•œλ‹€.
# μž„μ˜μ˜ 점을 K 둜 픽셀에 νˆ¬μ˜ν•œ 결과와 NDC κ°€ μ •ν™•νžˆ μΌμΉ˜ν•˜λŠ”μ§€ λ³Έλ‹€.
p = _pose()
proj = p.projection()
for pt in ([0.0, 1.0, 10.0], [3.0, -2.0, 25.0], [-5.0, 0.5, 7.0]):
x, y, z = pt
u = p.K[0, 0] * x / z + p.K[0, 2]
v = p.K[1, 1] * y / z + p.K[1, 2]
c = proj @ np.array([x, y, z, 1.0])
ndc = c[:2] / c[3]
assert np.allclose(ndc, [2 * u / p.width - 1, 2 * v / p.height - 1], atol=1e-9)
# μ•„λž˜μͺ½ 점(+y)은 NDC μ—μ„œλ„ + μ—¬μ•Ό ν•œλ‹€
c = proj @ np.array([0.0, 1.0, 10.0, 1.0])
assert c[1] / c[3] > 0
def test_fov_matches_nuscenes_front_camera():
h, v = _pose().fov_deg()
assert 63.0 < h < 66.0 # nuScenes CAM_FRONT 은 μ•½ 64도
assert 38.0 < v < 42.0
def test_rt_to_matrix():
m = rt_to_matrix(np.eye(3), (1.0, 2.0, 3.0))
assert np.allclose(m[:3, 3], [1, 2, 3])
assert m[3, 3] == 1.0