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