mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-04-23 00:46:37 +00:00
68 lines
3.1 KiB
Python
68 lines
3.1 KiB
Python
import pytest
|
|
import numpy as np
|
|
import math
|
|
from h07_image_rotation_utils import ImageRotationUtils
|
|
|
|
@pytest.fixture
|
|
def rot_utils():
|
|
return ImageRotationUtils()
|
|
|
|
class TestImageRotationUtils:
|
|
|
|
def test_normalize_angle(self, rot_utils):
|
|
"""Verifies angle normalization to the standard 0-360 degree range."""
|
|
assert rot_utils.normalize_angle(360.0) == 0.0
|
|
assert rot_utils.normalize_angle(405.0) == 45.0
|
|
assert rot_utils.normalize_angle(-90.0) == 270.0
|
|
assert rot_utils.normalize_angle(-450.0) == 270.0
|
|
assert rot_utils.normalize_angle(45.0) == 45.0
|
|
|
|
def test_rotate_image(self, rot_utils):
|
|
"""Verifies basic image rotation using OpenCV affine transformations."""
|
|
img = np.zeros((10, 10), dtype=np.uint8)
|
|
img[0, 0] = 255
|
|
|
|
# 0 degree rotation should return an exact copy
|
|
rot_0 = rot_utils.rotate_image(img, 0.0)
|
|
np.testing.assert_array_equal(rot_0, img)
|
|
|
|
# Standard rotation should preserve dimensions
|
|
rotated = rot_utils.rotate_image(img, 90.0, center=(4.5, 4.5))
|
|
assert rotated.shape == (10, 10)
|
|
|
|
def test_kabsch_zero_rotation(self, rot_utils):
|
|
"""Verifies identical point clouds return exactly 0.0 degrees."""
|
|
points = np.array([[0, 0], [10, 0], [0, 10], [10, 10]], dtype=np.float64)
|
|
angle = rot_utils.calculate_rotation_from_points(points, points)
|
|
assert np.isclose(angle, 0.0)
|
|
|
|
def test_kabsch_known_rotation(self, rot_utils):
|
|
"""Verifies correct angle extraction for standard geometric rotations (90 and 180 deg)."""
|
|
src_points = np.array([[10, 10], [20, 10], [10, 20], [20, 20]], dtype=np.float64)
|
|
|
|
# 90 degrees Counter-Clockwise mapping: (x, y) -> (-y, x)
|
|
dst_points_90 = np.array([[-10, 10], [-10, 20], [-20, 10], [-20, 20]], dtype=np.float64)
|
|
angle_90 = rot_utils.calculate_rotation_from_points(src_points, dst_points_90)
|
|
assert np.isclose(angle_90, 90.0)
|
|
|
|
# 180 degrees mapping: (x, y) -> (-x, -y)
|
|
dst_points_180 = np.array([[-10, -10], [-20, -10], [-10, -20], [-20, -20]], dtype=np.float64)
|
|
angle_180 = rot_utils.calculate_rotation_from_points(src_points, dst_points_180)
|
|
assert np.isclose(angle_180, 180.0)
|
|
|
|
def test_kabsch_with_translation(self, rot_utils):
|
|
"""Verifies SVD strictly isolates rotation and ignores translation via mean centering."""
|
|
src_points = np.array([[0, 0], [10, 0], [0, 10]], dtype=np.float64)
|
|
|
|
# Manually apply a 45 degree rotation AND a massive [100, 50] translation
|
|
angle_rad = math.radians(45.0)
|
|
cos_a, sin_a = math.cos(angle_rad), math.sin(angle_rad)
|
|
R = np.array([[cos_a, -sin_a], [sin_a, cos_a]])
|
|
dst_points = np.dot(src_points, R.T) + np.array([100.0, 50.0])
|
|
|
|
angle = rot_utils.calculate_rotation_from_points(src_points, dst_points)
|
|
assert np.isclose(angle, 45.0)
|
|
|
|
def test_kabsch_insufficient_points(self, rot_utils):
|
|
"""Verifies safety return when less than 2 points are provided."""
|
|
assert rot_utils.calculate_rotation_from_points(np.array([[0, 0]]), np.array([[10, 10]])) == 0.0 |