Files
gps-denied-onboard/docs/01_solution/01_solution_draft_perplexity.md
T
2025-11-03 21:47:21 +02:00

42 KiB
Raw Blame History

UAV Aerial Image Geolocalization System: Solution Draft

Executive Summary

This document presents a comprehensive solution for determining GPS coordinates of aerial image centers and objects within images captured by fixed-wing UAVs flying at altitudes up to 1km over eastern/southern Ukraine. The system leverages structure-from-motion (SfM), visual odometry, and satellite image cross-referencing to achieve sub-50-meter accuracy for 80% of images while maintaining registration rates above 95%.


1. Problem Analysis

1.1 Key Constraints & Challenges

  • No onboard GPS/GNSS receiver (system must infer coordinates)
  • Fixed downward-pointing camera (non-stabilized, subject to aircraft pitch/roll)
  • Up to 3000 images per flight at 100m nominal spacing (variable due to aircraft dynamics)
  • Altitude ≤ 1km with resolution up to 6252×4168 pixels
  • Sharp turns possible causing image overlaps <5% or complete loss
  • Outliers possible: 350m drift between consecutive images (aircraft tilt)
  • Time constraint: <2 seconds processing per image
  • Real-world requirement: Google Maps validation with <10% outliers

1.2 Reference Dataset Analysis

The provided 29 sample images show:

  • Flight distance: ~2.26 km ground path
  • Image spacing: 66-202m (mean 119m), indicating ~100-200m altitude
  • Coverage area: ~1.1 km × 1.6 km
  • Geographic region: Eastern Ukraine (east of Dnipro, Kherson/Zaporozhye area)
  • Terrain: Mix of agricultural fields and scattered vegetation

1.3 Acceptance Criteria Summary

Criterion Target
80% of images within 50m error Required
60% of images within 20m error Required
Handle 350m outlier drift Graceful degradation
Image Registration Rate >95%
Mean Reprojection Error <1.0 pixels
Processing time/image <2 seconds
Outlier rate (satellite check) <10%
User interaction fallback For unresolvable 20%

2. State-of-the-Art Solutions

2.1 Current Industry Standards

A. OpenDroneMap (ODM)

  • Strengths: Open-source, parallelizable, proven at scale (2500+ images)
  • Pipeline: OpenSfM (feature matching/tracking) → OpenMVS (dense reconstruction) → GDAL (georeferencing)
  • Weaknesses: Requires GCPs for absolute georeferencing; computational cost (recommends 128GB RAM); doesn't handle GPS-denied scenarios without external anchors
  • Typical accuracy: Meter-level without GCPs; cm-level with GCPs

B. COLMAP

  • Strengths: Incremental SfM with robust bundle adjustment; excellent reprojection error (typically <0.5px)
  • Application: Academic gold standard; proven on large multi-view datasets
  • Limitations: Requires good initial seed pair; can fail with low overlap; computational cost for online processing
  • Relevance: Core algorithm suitable as backbone for this application

C. AliceVision/Meshroom

  • Strengths: Modular photogrammetry framework; feature-rich; GPU-accelerated
  • Features: Robust feature matching, multi-view stereo, camera tracking
  • Challenge: Designed for batch processing, not real-time streaming

D. ORB-SLAM3

  • Strengths: Real-time monocular SLAM; handles rolling-shutter distortions; extremely fast
  • Relevant to: Aerial video streams; can operate at frame rates
  • Limitation: No absolute georeferencing without external anchors; drifts over long sequences

E. GPS-Denied Visual Localization (GNSS-Denied Methods)

  • Deep Learning Approaches: CLIP-based satellite-aerial image matching achieving 39m location error, 15.9° heading error at 100m altitude
  • Hierarchical Methods: Coarse semantic matching + fine-grained feature refinement; tolerates oblique views
  • Advantage: Works with satellite imagery as reference

2.2 Feature Detector/Descriptor Comparison

Algorithm Detection Speed Matching Speed Features Robustness Best For
SIFT Slow Medium Scattered Excellent Reference, small scale
AKAZE Fast Fast Moderate Very Good Real-time, scale variance
ORB Very Fast Very Fast High Good Real-time, embedded systems
SuperPoint Medium Fast Learned Excellent Modern DL pipelines

Recommendation: Hybrid approach using AKAZE for speed + SuperPoint for robustness in difficult scenes


3. Proposed Architecture Solution

3.1 High-Level System Design

┌─────────────────────────────────────────────────────────────────┐
│                    UAV IMAGE STREAM                              │
│              (Sequential, ≤100m spacing, 100-200m alt)           │
└──────────────────────────┬──────────────────────────────────────┘
                           │
        ┌──────────────────┴──────────────────┐
        │                                      │
        ▼                                      ▼
┌──────────────────────────┐      ┌──────────────────────────┐
│  FEATURE EXTRACTION      │      │  INITIALIZATION MODULE   │
│  ────────────────────    │      │  ──────────────────      │
│  • AKAZE keypoint detect │      │  • Assume starting GPS   │
│  • Multi-scale pyramids  │      │  • Initial camera params │
│  • Descriptor computation│      │  • Seed pair selection   │
└──────────────┬───────────┘      └──────────────┬───────────┘
               │                                  │
               │         ┌────────────────────────┘
               │         │
               ▼         ▼
        ┌──────────────────────────┐
        │  SEQUENTIAL MATCHING     │
        │  ────────────────────    │
        │  • N-to-N+1 matching     │
        │  • Epipolar constraint   │
        │  • RANSAC outlier reject │
        │  • Essential matrix est. │
        └──────────────┬───────────┘
                       │
              ┌────────┴────────┐
              │                 │
         YES  ▼                 ▼  NO/DIFFICULT
        ┌──────────────┐  ┌──────────────┐
        │ COMPUTE POSE │  │ FALLBACK:    │
        │ ────────────│  │ • Try N→N+2  │
        │ • 8-pt alg  │  │ • Try global │
        │ • Triangulate  • Try satellite  │
        │ • BA update │  │ • Ask user   │
        └──────┬───────┘  └──────┬───────┘
               │                 │
               └────────┬────────┘
                        │
                        ▼
        ┌──────────────────────────────┐
        │  BUNDLE ADJUSTMENT (Local)   │
        │  ──────────────────────────  │
        │  • Windowed optimization     │
        │  • Levenberg-Marquardt       │
        │  • Refine poses + 3D points  │
        │  • Covariance estimation     │
        └──────────────┬───────────────┘
                       │
                       ▼
        ┌──────────────────────────────┐
        │  GEOREFERENCING              │
        │  ────────────────────────    │
        │  • Satellite image matching  │
        │  • GCP integration (if avail)│
        │  • WGS84 transformation      │
        │  • Accuracy assessment       │
        └──────────────┬───────────────┘
                       │
                       ▼
        ┌──────────────────────────────┐
        │  OUTPUT & VALIDATION         │
        │  ────────────────────────    │
        │  • Image center GPS coords   │
        │  • Object/feature coords     │
        │  • Confidence intervals      │
        │  • Outlier flagging          │
        │  • Google Maps cross-check   │
        └──────────────────────────────┘

3.2 Core Algorithmic Components

3.2.1 Initialization Phase

Input: Starting GPS coordinate (or estimated from first visible landmarks)

Process:

  1. Load first image, extract AKAZE features at multiple scales
  2. Establish camera intrinsic parameters:
    • If known: use factory calibration or pre-computed values
    • If unknown: assume standard pinhole model with principal point at image center
    • Estimate focal length from image resolution: ~2.5-3.0 × image width (typical aerial lens)
  3. Define initial local coordinate system:
    • Origin at starting GPS coordinate
    • Z-axis up, XY horizontal
    • Project all future calculations to WGS84 at end

Output: Camera matrix K, initial camera pose (R₀, t₀)

3.2.2 Sequential Image-to-Image Matching

Algorithm: Incremental SfM with temporal ordering constraint

For image N in sequence:
  1. Extract AKAZE features from image N
  2. Match features with image N-1 using KNN with Lowe's ratio test
  3. RANSAC with 8-point essential matrix estimation:
     - Iterate: sample 8 point correspondences
     - Solve: SVD-based essential matrix E computation
     - Score: inlier count (epipolar constraint |p'ᵀEp| < ε)
     - Keep: best E with >50 inliers
  4. If registration fails (inliers <50 or insufficient quality):
     - Attempt N to N+2 matching (skip frame)
     - If still failing: request user input or flag as uncertain
  5. Decompose E to camera pose (R, t) with triangulation validation
  6. Triangulate 3D points from matched features
  7. Perform local windowed bundle adjustment (last 5 images)
  8. Compute image center GPS via local-to-global transformation

Key Parameters:

  • AKAZE threshold: adaptive based on image quality
  • Matching distance ratio: 0.7 (Lowe's test)
  • RANSAC inlier threshold: 1.0 pixels
  • Minimum inliers for success: 50 points
  • Maximum reprojection error in BA: 1.5 pixels

3.2.3 Pose Estimation & Triangulation

5-Point Algorithm (Stewenius et al.):

  • Minimal solver for 5 point correspondences
  • Returns up to 4 solutions for essential matrix
  • Selects solution with maximum triangulated points in front of cameras
  • Complexity: O(5) vs O(8) for 8-point, enabling RANSAC speed

Triangulation:

  • Linear triangulation using DLT (Direct Linear Transform)
  • For each matched feature pair: solve 4×4 system via SVD
  • Filter: reject points with:
    • Reprojection error > 1.5 pixels
    • Behind either camera
    • Altitude inconsistent with flight dynamics

3.2.4 Bundle Adjustment (Windowed)

Formulation:

minimize Σ ||p_i^(img) - π(X_i, P_cam)||² + λ·||ΔP_cam||²

where:
- p_i^(img): observed pixel position
- X_i: 3D point coordinate
- P_cam: camera pose parameters
- π(): projection function
- λ: regularization weight

Algorithm: Sparse Levenberg-Marquardt with Schur complement

  • Window size: 5-10 consecutive images (trade-off between accuracy and speed)
  • Iteration limit: 10 (convergence typically in 3-5)
  • Damping: adaptive μ (starts at 10⁻⁶)
  • Covariance computation: from information matrix inverse

Complexity: O(w³) where w = window size → ~0.3s for w=10 on modern CPU

3.2.5 Georeferencing Module

Challenge: Converting local 3D structure to WGS84 coordinates

Approach 1 - Satellite Image Matching (Primary):

  1. Query Google Maps Static API for area around estimated location
  2. Scale downloaded satellite imagery to match expected ground resolution
  3. Extract ORB/SIFT features from satellite image
  4. Match features between UAV nadir image and satellite image
  5. Compute homography transformation (if sufficient overlap)
  6. Estimate camera center GPS from homography
  7. Validate: check consistency with neighboring images

Approach 2 - GCP Integration (When available):

  1. If user provides 4+ manually-identified GCPs in images with known coords:
    • Use GCPs to establish local-to-global transformation
    • 6-DOF rigid transformation (4 GCPs minimum)
    • Refine with all available GCPs using least-squares
  2. Transform all local coordinates via this transformation

Approach 3 - IMU/INS Integration (If available):

  1. If UAV provides gyro/accelerometer data:
    • Integrate IMU measurements to constrain camera orientation
    • Use IMU to detect anomalies (sharp turns, tilt)
    • Fuse with visual odometry using Extended Kalman Filter (EKF)
    • Improves robustness during low-texture sequences

Uncertainty Quantification:

  • Covariance matrix σ² from bundle adjustment
  • Project uncertainty to GPS coordinates via Jacobian
  • Compute 95% confidence ellipse for each image center
  • Typical values: σ ≈ 20-50m initially, improves with satellite anchor

3.2.6 Fallback & Outlier Detection

Outlier Detection Strategy:

  1. Local consistency check:
    • Compute velocity between consecutive images
    • Flag if velocity changes >50% between successive intervals
    • Expected velocity: ~10-15 m/s ground speed
  2. Satellite validation:
    • After full flight processing: retrieve satellite imagery
    • Compare UAV image against satellite image at claimed coordinates
    • Compute cross-correlation; flag if <0.3
  3. Loop closure detection:
    • If imagery from later in flight matches earlier imagery: flag potential error
    • Use place recognition (ORB vocabulary tree) to detect revisits
  4. User feedback loop:
    • Display flagged uncertain frames to operator
    • Allow manual refinement for <20% of images
    • Re-optimize trajectory using corrected anchor points

Graceful Degradation (350m outlier scenario):

  • Detect outlier via velocity threshold
  • Attempt skip-frame matching (N to N+2, N+3)
  • If fails, insert "uncertainty zone" marker
  • Continue from next successfully matched pair
  • Later satellite validation will flag this region for manual review

4. Architecture: Detailed Module Specifications

4.1 System Components

Component 1: Image Preprocessor

Input: Raw JPEG/PNG from UAV
Output: Normalized, undistorted image ready for feature extraction

Operations:
├─ Load image (max 6252×4168)
├─ Apply lens distortion correction (if calibration available)
├─ Normalize histogram (CLAHE for uniform feature detection)
├─ Optional: Downsample for <2s latency (e.g., 3000×2000 if >4000×3000)
├─ Compute image metadata (filename, timestamp)
└─ Cache for access by subsequent modules

Component 2: Feature Detector

Input: Preprocessed image
Output: Keypoints + descriptors

Algorithm: AKAZE with multi-scale pyramids
├─ Pyramid levels: 4-6 (scale factor 1.2)
├─ FAST corner threshold: adaptive (target 500-1000 keypoints)
├─ BRIEF descriptor: rotation-aware, 256 bits
├─ Feature filtering:
│  ├─ Remove features in low-texture regions (variance <10)
│  ├─ Enforce min separation (8px) to avoid clustering
│  └─ Sort by keypoint strength (use top 2000)
└─ Output: vector<KeyPoint>, Mat descriptors (Nx256 uint8)

Component 3: Feature Matcher

Input: Features from Image N-1, Features from Image N
Output: Vector of matched point pairs (inliers only)

Algorithm: KNN matching with Lowe's ratio test + RANSAC
├─ BruteForceMatcher (Hamming distance for AKAZE)
├─ KNN search: k=2
├─ Lowe's ratio test: d1/d2 < 0.7
├─ RANSAC 5-point algorithm:
│  ├─ Iterations: min(4000, 10000 - 100*inlier_count)
│  ├─ Inlier threshold: 1.0 pixels
│  ├─ Minimum inliers: 50 (lower to 30 for skip-frame matching)
│  └─ Success: inlier_ratio > 0.4
├─ Triangulation validation (reject behind camera)
└─ Output: vector<DMatch>, Mat points3D (Mx3)

Component 4: Pose Solver

Input: Essential matrix E from RANSAC, matched points
Output: Rotation matrix R, translation vector t

Algorithm: E decomposition
├─ SVD decomposition of E
├─ Extract 4 candidate (R, t) pairs
├─ Triangulate points for each candidate
├─ Select candidate with max points in front of both cameras
├─ Recover scale using calibration (altitude constraint)
├─ Output: 4x4 transformation matrix T = [R t; 0 1]

Component 5: Triangulator

Input: Keypoints from image 1, image 2; poses P1, P2; calib K
Output: 3D point positions, mask of valid points

Algorithm: Linear triangulation (DLT)
├─ For each point correspondence (p1, p2):
│  ├─ Build 4×4 matrix from epipolar lines
│  ├─ SVD → solve for 3D point X
│  ├─ Validate: |p1 - π(X,P1)| < 1.5px AND |p2 - π(X,P2)| < 1.5px
│  ├─ Validate: X_z > 50m (min safe altitude above ground)
│  └─ Validate: X_z < 1500m (max altitude constraint)
└─ Output: Mat points3D (Mx3 float32), Mat validMask (Mx1 uchar)

Component 6: Bundle Adjuster

Input: Poses [P0...Pn], 3D points [X0...Xm], observations
Output: Refined poses, 3D points, covariance matrices

Algorithm: Sparse Levenberg-Marquardt with windowing
├─ Window size: 5 images (or fewer at flight start)
├─ Optimization variables:
│  ├─ Camera poses: 6 DOF per image (Rodrigues rotation + translation)
│  └─ 3D points: 3 coordinates per point
├─ Residuals: reprojection error in both images
├─ Iterations: max 10 (typically converges in 3-5)
├─ Covariance:
│  ├─ Compute Hessian inverse (information matrix)
│  ├─ Extract diagonal for per-parameter variances
│  └─ Per-image uncertainty: sqrt(diag(Cov[t]))
└─ Output: refined poses, points, Mat covariance (per image)

Component 7: Satellite Georeferencer

Input: Current image, estimated center GPS (rough), local trajectory
Output: Refined GPS coordinates, confidence score

Algorithm: Satellite image matching
├─ Query Google Maps API:
│  ├─ Coordinates: estimated_gps ± 200m
│  ├─ Resolution: match UAV image resolution (1-2m GSD)
│  └─ Zoom level: 18-20
├─ Image preprocessing:
│  ├─ Scale satellite image to ~same resolution as UAV image
│  ├─ Convert to grayscale
│  └─ Equalize histogram
├─ Feature matching:
│  ├─ Extract ORB features from both images
│  ├─ Match with BruteForceMatcher
│  ├─ Apply RANSAC homography (min 10 inliers)
│  └─ Compute inlier ratio
├─ Homography analysis:
│  ├─ If inlier_ratio > 0.2:
│  │  ├─ Extract 4 corners from UAV image via inverse homography
│  │  ├─ Map to satellite image coordinates
│  │  ├─ Compute implied GPS shift
│  │  └─ Apply shift to current pose estimate
│  └─ else: keep local estimate, flag as uncertain
├─ Confidence scoring:
│  ├─ score = inlier_ratio × mutual_information_normalized
│  └─ Threshold: score > 0.3 for "high confidence"
└─ Output: refined_gps, confidence (0.0-1.0), residual_px

Component 8: Outlier Detector

Input: Trajectory sequence [GPS_0, GPS_1, ..., GPS_n]
Output: Outlier flags, re-processed trajectory

Algorithm: Multi-stage detection
├─ Stage 1 - Velocity anomaly:
│  ├─ Compute inter-image distances: d_i = |GPS_i - GPS_{i-1}|
│  ├─ Compute velocity: v_i = d_i / Δt (Δt typically 0.5-2s)
│  ├─ Expected: 10-20 m/s for typical UAV
│  ├─ Flag if: v_i > 30 m/s OR v_i < 1 m/s
│  └─ Acceleration anomaly: |v_i - v_{i-1}| > 15 m/s
├─ Stage 2 - Satellite consistency:
│  ├─ For each flagged image:
│  │  ├─ Retrieve satellite image at claimed GPS
│  │  ├─ Compute cross-correlation with UAV image
│  │  └─ If corr < 0.25: mark as outlier
│  └─ Reprocess outlier image:
│       ├─ Try skip-frame matching (to N±2, N±3)
│       ├─ Try global place recognition
│       └─ Request user input if all fail
├─ Stage 3 - Loop closure:
│  ├─ Check if image matches any earlier image (Hamming dist <50)
│  └─ If match detected: assess if consistent with trajectory
└─ Output: flags, corrected_trajectory, uncertain_regions

Component 9: User Interface Module

Input: Flight trajectory, flagged uncertain regions
Output: User corrections, refined trajectory

Features:
├─ Web interface or desktop app
├─ Map display (Google Maps embedded):
│  ├─ Show computed trajectory
│  ├─ Overlay satellite imagery
│  ├─ Highlight uncertain regions (red)
│  ├─ Show confidence intervals (error ellipses)
│  └─ Display reprojection errors
├─ Image preview:
│  ├─ Click trajectory point to view corresponding image
│  ├─ Show matched keypoints and epipolar lines
│  ├─ Display feature matching quality metrics
│  └─ Show neighboring images in sequence
├─ Manual correction:
│  ├─ Drag trajectory point to correct location (via map click)
│  ├─ Mark GCPs manually (click point in image, enter GPS)
│  ├─ Re-run optimization with corrected anchors
│  └─ Export corrected trajectory as GeoJSON/CSV
└─ Reporting:
    ├─ Summary statistics (% within 50m, 20m, etc.)
    ├─ Outlier report with reasons
    ├─ Satellite validation results
    └─ Export georeferenced image list with coordinates

4.2 Data Flow & Processing Pipeline

Phase 1: Offline Initialization (before flight or post-download)

Input: Full set of N images, starting GPS coordinate
├─ Load all images into memory/fast storage (SSD)
├─ Detect features in all images (parallelizable: N CPU threads)
├─ Store features on disk for quick access
└─ Estimate camera calibration (if not known)
Time: ~1-3 minutes for 1000 images on 16-core CPU

Phase 2: Sequential Processing (online or batch)

For i = 1 to N-1:
├─ Load images[i] and images[i+1]
├─ Match features
├─ RANSAC pose estimation
├─ Triangulate 3D points
├─ Local bundle adjustment (last 5 frames)
├─ Satellite georeferencing
├─ Store: GPS[i+1], confidence[i+1], covariance[i+1]
└─ [< 2 seconds per iteration]
Time: 2N seconds = ~30-60 minutes for 1000 images

Phase 3: Post-Processing (after full trajectory)

├─ Global bundle adjustment (optional: full flight with key-frame selection)
├─ Loop closure optimization (if detected)
├─ Outlier detection and flagging
├─ Satellite validation (batch retrieve imagery, compare)
├─ Export results with metadata
└─ Generate report with accuracy metrics
Time: ~5-20 minutes

Phase 4: Manual Review & Correction (if needed)

├─ User reviews flagged uncertain regions
├─ Manually corrects up to 20% of trajectory as needed
├─ Re-optimizes with corrected anchors
└─ Final export
Time: 10-60 minutes depending on complexity

5. Testing Strategy

2. Detailed Test Categories

2.1 Unit Tests (Level 1)

UT-1: Feature Extraction (AKAZE)

Purpose: Verify keypoint detection and descriptor computation
Test Data: Synthetic images with known features (checkerboard patterns)
Test Cases:
  ├─ UT-1.1: Basic feature detection
  │   Input: 1024×768 synthetic image with checkerboard
  │   Expected: ≥500 keypoints detected
  │   Pass: count ≥ 500
  │
  ├─ UT-1.2: Scale invariance
  │   Input: Same scene at 2x scale
  │   Expected: Keypoints at proportional positions
  │   Pass: correlation of positions > 0.9
  │
  ├─ UT-1.3: Rotation robustness
  │   Input: Image rotated ±30°
  │   Expected: Descriptors match original + rotated
  │   Pass: match rate > 80%
  │
  ├─ UT-1.4: Multi-scale handling
  │   Input: Image with features at multiple scales
  │   Expected: Features detected at all scales (pyramid)
  │   Pass: ratio of scales [1:1.2:1.44:...] verified
  │
  └─ UT-1.5: Performance constraint
      Input: FullHD image (1920×1080)
      Expected: <500ms feature extraction
      Pass: 95th percentile < 500ms

UT-2: Feature Matching

Purpose: Verify robust feature correspondence
Test Data: Pairs of synthetic/real images with known correspondence
Test Cases:
  ├─ UT-2.1: Basic matching
  │   Input: Two images from synthetic scene (90% overlap)
  │   Expected: ≥95% of ground-truth features matched
  │   Pass: match_rate ≥ 0.95
  │
  ├─ UT-2.2: Outlier rejection (Lowe's ratio test)
  │   Input: Synthetic pair + 50% false features
  │   Expected: False matches rejected
  │   Pass: false_match_rate < 0.1
  │
  ├─ UT-2.3: Low overlap scenario
  │   Input: Two images with 20% overlap
  │   Expected: Still matches ≥20 points
  │   Pass: min_matches ≥ 20
  │
  └─ UT-2.4: Performance
      Input: FullHD images, 1000 features each
      Expected: <300ms matching time
      Pass: 95th percentile < 300ms

UT-3: Essential Matrix Estimation

Purpose: Verify 5-point/8-point algorithms for camera geometry
Test Data: Synthetic correspondences with known relative pose
Test Cases:
  ├─ UT-3.1: 8-point algorithm
  │   Input: 8+ point correspondences
  │   Expected: Essential matrix E with rank 2
  │   Pass: min_singular_value(E) < 1e-6
  │
  ├─ UT-3.2: 5-point algorithm
  │   Input: 5 point correspondences
  │   Expected: Up to 4 solutions generated
  │   Pass: num_solutions ∈ [1, 4]
  │
  ├─ UT-3.3: RANSAC convergence
  │   Input: 100 correspondences, 30% outliers
  │   Expected: Essential matrix recovery despite outliers
  │   Pass: inlier_ratio ≥ 0.6
  │
  └─ UT-3.4: Chirality constraint
      Input: Multiple (R,t) solutions from decomposition
      Expected: Only solution with points in front of cameras selected
      Pass: selected_solution verified via triangulation

UT-4: Triangulation (DLT)

Purpose: Verify 3D point reconstruction from image correspondences
Test Data: Synthetic scenes with known 3D geometry
Test Cases:
  ├─ UT-4.1: Accuracy
  │   Input: Noise-free point correspondences
  │   Expected: Reconstructed X matches ground truth
  │   Pass: RMSE < 0.1cm on 1m scene
  │
  ├─ UT-4.2: Outlier handling
  │   Input: 10 valid + 2 invalid correspondences
  │   Expected: Invalid points detected (behind camera/far)
  │   Pass: valid_mask accuracy > 95%
  │
  ├─ UT-4.3: Altitude constraint
  │   Input: Points with z < 50m (below aircraft)
  │   Expected: Points rejected
  │   Pass: altitude_filter works correctly
  │
  └─ UT-4.4: Batch performance
      Input: 500 point triangulations
      Expected: <100ms total
      Pass: 95th percentile < 100ms

UT-5: Bundle Adjustment

Purpose: Verify pose and 3D point optimization
Test Data: Synthetic multi-view scenes
Test Cases:
  ├─ UT-5.1: Convergence
  │   Input: 5 frames with noisy initial poses
  │   Expected: Residual decreases monotonically
  │   Pass: final_residual < 0.001 * initial_residual
  │
  ├─ UT-5.2: Covariance computation
  │   Input: Optimized poses and points
  │   Expected: Covariance matrix positive-definite
  │   Pass: all_eigenvalues > 0
  │
  ├─ UT-5.3: Window size effect
  │   Input: Same problem with window sizes [3, 5, 10]
  │   Expected: Larger windows → better residuals
  │   Pass: residual_5 < residual_3, residual_10 < residual_5
  │
  └─ UT-5.4: Performance scaling
      Input: Window size [5, 10, 15, 20]
      Expected: Time ~= O(w^3)
      Pass: quadratic fit accurate (R² > 0.95)

2.2 Integration Tests (Level 2)

IT-1: Sequential Pipeline

Purpose: Verify image-to-image processing chain
Test Data: Real aerial image sequences (5-20 images)
Test Cases:
  ├─ IT-1.1: Feature flow
  │   Features extracted from img₁ → tracked to img₂ → matched
  │   Expected: Consistent tracking across images
  │   Pass: ≥70% features tracked end-to-end
  │
  ├─ IT-1.2: Pose chain consistency
  │   Poses P₁, P₂, P₃ computed sequentially
  │   Expected: P₃ = P₂ ∘ P₂₋₁ (composition consistency)
  │   Pass: pose_error < 0.1° rotation, 5cm translation
  │
  ├─ IT-1.3: Trajectory smoothness
  │   Velocity computed between poses
  │   Expected: Smooth velocity profile (no jumps)
  │   Pass: velocity_std_dev < 20% mean_velocity
  │
  └─ IT-1.4: Memory usage
      Process 100-image sequence
      Expected: Constant memory (windowed processing)
      Pass: peak_memory < 2GB

IT-2: Satellite Georeferencing

Purpose: Verify local-to-global coordinate transformation
Test Data: Synthetic/real images with known satellite reference
Test Cases:
  ├─ IT-2.1: Feature matching with satellite
  │   Input: Aerial image + satellite reference
  │   Expected: ≥10 matched features between viewpoints
  │   Pass: match_count ≥ 10
  │
  ├─ IT-2.2: Homography estimation
  │   Matched features → homography matrix
  │   Expected: Valid transformation (3×3 matrix)
  │   Pass: det(H) ≠ 0, condition_number < 100
  │
  ├─ IT-2.3: GPS transformation accuracy
  │   Apply homography to image corners
  │   Expected: Computed GPS ≈ known reference GPS
  │   Pass: error < 100m (on test data)
  │
  └─ IT-2.4: Confidence scoring
      Compute inlier_ratio and MI (mutual information)
      Expected: score = inlier_ratio × MI ∈ [0, 1]
      Pass: high_confidence for obvious matches

IT-3: Outlier Detection Chain

Purpose: Verify multi-stage outlier detection
Test Data: Synthetic trajectory with injected outliers
Test Cases:
  ├─ IT-3.1: Velocity anomaly detection
  │   Inject 350m jump at frame N
  │   Expected: Detected as outlier
  │   Pass: outlier_flag = True
  │
  ├─ IT-3.2: Recovery mechanism
  │   After outlier detection
  │   Expected: System attempts skip-frame matching (N→N+2)
  │   Pass: recovery_successful = True
  │
  ├─ IT-3.3: False positive rate
  │   Normal sequence with small perturbations
  │   Expected: <5% false outlier flagging
  │   Pass: false_positive_rate < 0.05
  │
  └─ IT-3.4: Consistency across stages
      Multiple detection stages should agree
      Pass: agreement_score > 0.8

2.3 System Tests (Level 3)

ST-1: Accuracy Criteria

Purpose: Verify system meets ±50m and ±20m accuracy targets
Test Data: Real aerial image sequences with ground-truth GPS
Test Cases:
  ├─ ST-1.1: 50m accuracy target
  │   Input: 500-image flight
  │   Compute: % images within 50m of ground truth
  │   Expected: ≥80%
  │   Pass: accuracy_50m ≥ 0.80
  │
  ├─ ST-1.2: 20m accuracy target
  │   Same flight data
  │   Expected: ≥60% within 20m
  │   Pass: accuracy_20m ≥ 0.60
  │
  ├─ ST-1.3: Mean absolute error
  │   Compute: MAE over all images
  │   Expected: <40m typical
  │   Pass: MAE < 50m
  │
  └─ ST-1.4: Error distribution
      Expected: Error approximately Gaussian
      Pass: K-S test p-value > 0.05

ST-2: Registration Rate

Purpose: Verify ≥95% of images successfully registered
Test Data: Real flights with various conditions
Test Cases:
  ├─ ST-2.1: Baseline registration
  │   Good overlap, clear features
  │   Expected: >98% registration rate
  │   Pass: registration_rate ≥ 0.98
  │
  ├─ ST-2.2: Challenging conditions
  │   Low texture, variable lighting
  │   Expected: ≥95% registration rate
  │   Pass: registration_rate ≥ 0.95
  │
  ├─ ST-2.3: Sharp turns scenario
  │   Images with <10% overlap
  │   Expected: Fallback mechanisms trigger, ≥90% success
  │   Pass: fallback_success_rate ≥ 0.90
  │
  └─ ST-2.4: Consecutive failures
      Track max consecutive unregistered images
      Expected: <3 consecutive failures
      Pass: max_consecutive_failures ≤ 3

ST-3: Reprojection Error

Purpose: Verify <1.0 pixel mean reprojection error
Test Data: Real flight data after bundle adjustment
Test Cases:
  ├─ ST-3.1: Mean reprojection error
  │   After BA optimization
  │   Expected: <1.0 pixel
  │   Pass: mean_reproj_error < 1.0
  │
  ├─ ST-3.2: Error distribution
  │   Histogram of per-point errors
  │   Expected: Tightly concentrated <2 pixels
  │   Pass: 95th_percentile < 2.0 px
  │
  ├─ ST-3.3: Per-frame consistency
  │   Error should not vary dramatically
  │   Expected: Consistent across frames
  │   Pass: frame_error_std_dev < 0.3 px
  │
  └─ ST-3.4: Outlier points
      Very large reprojection errors
      Expected: <1% of points with error >3 px
      Pass: outlier_rate < 0.01

ST-4: Processing Speed

Purpose: Verify <2 seconds per image
Test Data: Full flight sequences on target hardware
Test Cases:
  ├─ ST-4.1: Average latency
  │   Mean processing time per image
  │   Expected: <2 seconds
  │   Pass: mean_latency < 2.0 sec
  │
  ├─ ST-4.2: 95th percentile latency
  │   Worst-case images (complex scenes)
  │   Expected: <2.5 seconds
  │   Pass: p95_latency < 2.5 sec
  │
  ├─ ST-4.3: Component breakdown
  │   Feature extraction: <0.5s
  │   Matching: <0.3s
  │   RANSAC: <0.2s
  │   BA: <0.8s
  │   Satellite: <0.3s
  │   Pass: Each component within budget
  │
  └─ ST-4.4: Scaling with problem size
      Memory usage, CPU usage vs. image resolution
      Expected: Linear scaling
      Pass: O(n) complexity verified

ST-5: Robustness - Outlier Handling

Purpose: Verify graceful handling of 350m outlier drifts
Test Data: Synthetic/real data with injected outliers
Test Cases:
  ├─ ST-5.1: Single 350m outlier
  │   Inject outlier at frame N
  │   Expected: Detected, trajectory continues
  │   Pass: system_continues = True
  │
  ├─ ST-5.2: Multiple outliers
  │   3-5 outliers scattered in sequence
  │   Expected: All detected, recovery attempted
  │   Pass: detection_rate ≥ 0.8
  │
  ├─ ST-5.3: False positive rate
  │   Normal trajectory, no outliers
  │   Expected: <5% false flagging
  │   Pass: false_positive_rate < 0.05
  │
  └─ ST-5.4: Recovery latency
      Time to recover after outlier
      Expected: ≤3 frames
      Pass: recovery_latency ≤ 3 frames

ST-6: Robustness - Sharp Turns

Purpose: Verify handling of <5% image overlap scenarios
Test Data: Synthetic sequences with sharp angles
Test Cases:
  ├─ ST-6.1: 5% overlap matching
  │   Two images with 5% overlap
  │   Expected: Minimal matches or skip-frame
  │   Pass: system_handles_gracefully = True
  │
  ├─ ST-6.2: Skip-frame fallback
  │   Direct N→N+1 fails, tries N→N+2
  │   Expected: Succeeds with N→N+2
  │   Pass: skip_frame_success_rate ≥ 0.8
  │
  ├─ ST-6.3: 90° turn handling
  │   Images at near-orthogonal angles
  │   Expected: Degeneracy detected, logged
  │   Pass: degeneracy_detection = True
  │
  └─ ST-6.4: Trajectory consistency
      Consecutive turns: check velocity smoothness
      Expected: No velocity jumps > 50%
      Pass: velocity_consistency verified

2.4 Field Acceptance Tests (Level 4)

FAT-1: Real UAV Flight Trial #1 (Baseline)

Scenario: Nominal flight over agricultural field
┌────────────────────────────────────────┐
│ Conditions:                             │
│ • Clear weather, good sunlight          │
│ • Flat terrain, sparse trees            │
│ • 300m altitude, 50m/s speed            │
│ • 800 images, ~15 min flight            │
└────────────────────────────────────────┘

Pass Criteria:
  ✓ Accuracy: ≥80% within 50m
  ✓ Accuracy: ≥60% within 20m
  ✓ Registration rate: ≥95%
  ✓ Processing time: <2s/image
  ✓ Satellite validation: <10% outliers
  ✓ Reprojection error: <1.0px mean

Success Metrics:
  • MAE (mean absolute error): <40m
  • RMS error: <45m
  • Max error: <200m
  • Trajectory coherence: smooth (no jumps)

FAT-2: Real UAV Flight Trial #2 (Challenging)

Scenario: Flight with more complex terrain
┌────────────────────────────────────────┐
│ Conditions:                             │
│ • Mixed urban/agricultural              │
│ • Buildings, vegetation, water bodies   │
│ • Variable altitude (250-400m)          │
│ • Includes 1-2 sharp turns              │
│ • 1200 images, ~25 min flight           │
└────────────────────────────────────────┘

Pass Criteria:
  ✓ Accuracy: ≥75% within 50m (relaxed from 80%)
  ✓ Accuracy: ≥50% within 20m (relaxed from 60%)
  ✓ Registration rate: ≥92% (relaxed from 95%)
  ✓ Processing time: <2.5s/image avg
  ✓ Outliers detected: <15% (relaxed from 10%)
  
Fallback Validation:
  ✓ User corrected <20% of uncertain images
  ✓ After correction, accuracy meets FAT-1 targets

FAT-3: Real UAV Flight Trial #3 (Edge Case)

Scenario: Low-texture flight (challenging for features)
┌────────────────────────────────────────┐
│ Conditions:                             │
│ • Sandy/desert terrain or water         │
│ • Minimal features                      │
│ • Overcast/variable lighting            │
│ • 500-600 images, ~12 min flight        │
└────────────────────────────────────────┘

Pass Criteria:
  ✓ System continues (no crash): YES
  ✓ Graceful degradation: Flags uncertainty
  ✓ User can correct and improve: YES
  ✓ Satellite anchor helps recovery: YES

Success Metrics:
  • >80% of images tagged "uncertain"
  • After user correction: meets standard targets
  • Demonstrates fallback mechanisms working

3. Test Environment Setup

Hardware Requirements

CPU: 16+ cores (Intel Xeon / AMD Ryzen)
RAM: 64GB minimum (32GB acceptable for <1500 images)
Storage: 1TB SSD (for raw images + processing)
GPU: Optional (CUDA 11.8+ for 5-10x acceleration)
Network: For satellite API queries (can be cached)

Software Requirements

OS: Ubuntu 20.04 LTS or macOS 12+
Build: CMake 3.20+, GCC 9+ or Clang 11+
Dependencies: OpenCV 4.8+, Eigen 3.4+, GDAL 3.0+
Testing: GoogleTest, Pytest
CI/CD: GitHub Actions or Jenkins

Test Data Management

Synthetic Data: Generated via Blender (checked into repo)
Real Data: External dataset storage (S3/local SSD)
Ground Truth: Maintained in CSV format with metadata
Versioning: Git-LFS for binary image data

4. Test Execution Plan

Phase 1: Unit Testing (Weeks 1-6)

Sprint 1-2: UT-1 (Feature detection) - 2 week
Sprint 3-4: UT-2 (Feature matching) - 2 weeks
Sprint 5-6: UT-3, UT-4, UT-5 (Geometry) - 2 weeks

Continuous: Run full unit test suite every commit
Coverage target: >90% code coverage

Phase 2: Integration Testing (Weeks 7-12)

Sprint 7-9: IT-1 (Sequential pipeline) - 3 weeks
Sprint 10-11: IT-2, IT-3 (Georef, Outliers) - 2 weeks
Sprint 12: System integration - 1 week

Continuous: Integration tests run nightly

Phase 3: System Testing (Weeks 13-18)

Sprint 13-14: ST-1, ST-2 (Accuracy, Registration) - 2 weeks
Sprint 15-16: ST-3, ST-4 (Error, Speed) - 2 weeks
Sprint 17-18: ST-5, ST-6 (Robustness) - 2 weeks

Load testing: 1000-3000 image sequences
Stress testing: Edge cases, memory limits

Phase 4: Field Acceptance (Weeks 19-30)

Week 19-22: FAT-1 (Baseline trial)
  • Coordinate 1-2 baseline flights
  • Validate system on real data
  • Adjust parameters as needed

Week 23-26: FAT-2 (Challenging trial)
  • More complex scenarios
  • Test fallback mechanisms
  • Refine user interface

Week 27-30: FAT-3 (Edge case trial)
  • Low-texture scenarios
  • Validate robustness
  • Final adjustments

Post-trial: Generate comprehensive report

5. Acceptance Criteria Summary

Criterion Target Test Pass/Fail
Accuracy@50m ≥80% FAT-1 ≥80% pass
Accuracy@20m ≥60% FAT-1 ≥60% pass
Registration Rate ≥95% ST-2 ≥95% pass
Reprojection Error <1.0px mean ST-3 <1.0px pass
Processing Speed <2.0s/image ST-4 p95<2.5s pass
Robustness (350m outlier) Handled ST-5 Continue pass
Sharp turns (<5% overlap) Handled ST-6 Skip-frame pass
Satellite validation <10% outliers FAT-1-3 <10% pass

6. Success Metrics

Green Light Criteria (Ready for production):

  • All unit tests pass (100%)
  • All integration tests pass (100%)
  • All system tests pass (100%)
  • FAT-1 and FAT-2 pass acceptance criteria
  • FAT-3 shows graceful degradation
  • <10% code defects discovered in field trials
  • Performance meets SLA consistently

Yellow Light Criteria (Conditional deployment):

  • ⚠ 85-89% of acceptance criteria met
  • ⚠ Minor issues in edge cases
  • ⚠ Requires workaround documentation
  • ⚠ Re-test after fixes

Red Light Criteria (Do not deploy):

  • <85% of acceptance criteria met
  • Critical failures in core functionality
  • Safety/security concerns
  • Cannot meet latency or accuracy targets