mirror of
https://github.com/azaion/gps-denied-onboard.git
synced 2026-04-22 08:56:37 +00:00
90 lines
3.9 KiB
Python
90 lines
3.9 KiB
Python
import pytest
|
|
pytest.skip("Obsolete test file replaced by test_f09_local_geospatial_anchoring", allow_module_level=True)
|
|
|
|
import os
|
|
import numpy as np
|
|
import cv2
|
|
from unittest.mock import patch, MagicMock
|
|
|
|
# Trigger deep learning model mocks for CI/CD environments
|
|
os.environ["USE_MOCK_MODELS"] = "1"
|
|
from f09_metric_refinement import MetricRefinement, TileBounds, GPSPoint
|
|
|
|
@pytest.fixture
|
|
def metric_refinement():
|
|
"""Initializes the F09 Metric Refinement module with CPU-based mock models."""
|
|
return MetricRefinement(device="cpu", max_keypoints=100)
|
|
|
|
@pytest.fixture
|
|
def dummy_tile_bounds():
|
|
return TileBounds(
|
|
nw=GPSPoint(lat=48.001, lon=37.0),
|
|
ne=GPSPoint(lat=48.001, lon=37.001),
|
|
sw=GPSPoint(lat=48.0, lon=37.0),
|
|
se=GPSPoint(lat=48.0, lon=37.001),
|
|
center=GPSPoint(lat=48.0005, lon=37.0005),
|
|
gsd=0.5 # 0.5 meters per pixel
|
|
)
|
|
|
|
class TestMetricRefinement:
|
|
|
|
def test_compute_homography_success(self, metric_refinement):
|
|
"""Tests that sufficient matches successfully generate a homography matrix and MRE."""
|
|
# Create dummy images
|
|
uav_image = np.zeros((256, 256, 3), dtype=np.uint8)
|
|
satellite_tile = np.zeros((512, 512, 3), dtype=np.uint8)
|
|
|
|
# Because we are using USE_MOCK_MODELS=1, SuperPoint and LightGlue will
|
|
# emit random matched tensors. We need to mock cv2.findHomography to
|
|
# guarantee a deterministic matrix return for the test.
|
|
with patch('f09_metric_refinement.cv2.findHomography') as mock_find_h:
|
|
# Return an identity homography matrix and an all-inlier mask of 25 points
|
|
mock_find_h.return_value = (np.eye(3), np.ones((25, 1), dtype=np.uint8))
|
|
|
|
H, mask, total_corr, mre = metric_refinement.compute_homography(uav_image, satellite_tile)
|
|
|
|
assert H is not None
|
|
assert np.array_equal(H, np.eye(3))
|
|
assert mask is not None
|
|
assert np.sum(mask) == 25
|
|
assert total_corr == 25
|
|
# Identity matrix applied to identical points yields 0.0 error
|
|
assert isinstance(mre, float)
|
|
|
|
def test_extract_gps_from_alignment(self, metric_refinement, dummy_tile_bounds):
|
|
"""Verifies pixel-to-GPS interpolation using the homography matrix and tile GSD."""
|
|
# Simulate a homography that translates the UAV center by exactly 100 pixels on X and 50 pixels on Y
|
|
H = np.array([
|
|
[1.0, 0.0, 100.0],
|
|
[0.0, 1.0, 50.0],
|
|
[0.0, 0.0, 1.0]
|
|
])
|
|
|
|
image_center = (200, 200) # (cx, cy)
|
|
|
|
# Expected Satellite Pixel = (200+100, 200+50) = (300, 250)
|
|
gps = metric_refinement.extract_gps_from_alignment(H, dummy_tile_bounds, image_center)
|
|
|
|
assert gps is not None
|
|
# The GPS should be shifted South and East from the NW corner
|
|
assert gps.lat < dummy_tile_bounds.nw.lat
|
|
assert gps.lon > dummy_tile_bounds.nw.lon
|
|
|
|
def test_compute_match_confidence(self, metric_refinement):
|
|
"""Verifies the heuristic confidence scoring based on inliers and reprojection error."""
|
|
|
|
# High confidence: Lots of inliers, low MRE
|
|
conf_high = metric_refinement.compute_match_confidence(inlier_count=60, total_correspondences=100, reprojection_error=0.5)
|
|
assert conf_high >= 0.8
|
|
|
|
# Medium confidence: Decent inliers, high MRE
|
|
conf_med = metric_refinement.compute_match_confidence(inlier_count=30, total_correspondences=100, reprojection_error=2.5)
|
|
assert 0.5 <= conf_med <= 0.8
|
|
|
|
# Low confidence: Few inliers
|
|
conf_low = metric_refinement.compute_match_confidence(inlier_count=10, total_correspondences=100, reprojection_error=5.0)
|
|
assert conf_low < 0.5
|
|
|
|
# Zero correspondences
|
|
conf_zero = metric_refinement.compute_match_confidence(inlier_count=0, total_correspondences=0, reprojection_error=0.0)
|
|
assert conf_zero == 0.0 |