components assesment #2

add 2.15_components_assesment.md step
This commit is contained in:
Oleksandr Bezdieniezhnykh
2025-11-29 12:04:51 +02:00
parent 2037870f67
commit ef75cc5877
20 changed files with 557 additions and 1205 deletions
@@ -13,7 +13,7 @@ class IImageRotationManager(ABC):
pass
@abstractmethod
def try_rotation_steps(self, flight_id: str, image: np.ndarray, satellite_tile: np.ndarray) -> Optional[RotationResult]:
def try_rotation_steps(self, flight_id: str, frame_id: int, image: np.ndarray, satellite_tile: np.ndarray, tile_bounds: TileBounds, timestamp: datetime) -> Optional[RotationResult]:
pass
@abstractmethod
@@ -25,7 +25,7 @@ class IImageRotationManager(ABC):
pass
@abstractmethod
def update_heading(self, flight_id: str, heading: float) -> bool:
def update_heading(self, flight_id: str, frame_id: int, heading: float, timestamp: datetime) -> bool:
pass
@abstractmethod
@@ -41,29 +41,29 @@ class IImageRotationManager(ABC):
pass
@abstractmethod
def try_chunk_rotation_steps(self, chunk_images: List[np.ndarray], satellite_tile: np.ndarray) -> Optional[RotationResult]:
def try_chunk_rotation_steps(self, chunk_images: List[np.ndarray], satellite_tile: np.ndarray, tile_bounds: TileBounds) -> Optional[RotationResult]:
pass
```
## Component Description
### Responsibilities
- Handle UAV image rotation preprocessing for LiteSAM
- **Critical**: LiteSAM fails if images rotated >45°, requires preprocessing
- Handle UAV image rotation preprocessing
- **Critical**: LiteSAM (F09 Metric Refinement) fails if images rotated >45°, requires preprocessing
- Perform 30° step rotation sweeps (12 rotations: 0°, 30°, 60°, ..., 330°)
- Track UAV heading angle across flight
- Calculate precise rotation angle from homography point correspondences
- Detect sharp turns requiring rotation sweep
- Pre-rotate images to known heading for subsequent frames
- **Chunk rotation operations (rotate all images in chunk)**
- **Chunk rotation sweeps for LiteSAM matching**
- **Chunk rotation sweeps (delegates matching to F09 Metric Refinement)**
### Scope
- Image rotation operations
- Image rotation operations (pure rotation, no matching)
- UAV heading tracking and history
- Sharp turn detection
- Rotation sweep coordination with LiteSAM matching
- Precise angle calculation from homography
- Rotation sweep coordination (rotates images, delegates matching to F09 Metric Refinement)
- Precise angle calculation from homography (extracted from F09 results)
- **Chunk-level rotation (all images rotated by same angle)**
## API Methods
@@ -103,9 +103,9 @@ np.ndarray # Rotated image (same dimensions)
---
### `try_rotation_steps(flight_id: str, image: np.ndarray, satellite_tile: np.ndarray) -> Optional[RotationResult]`
### `try_rotation_steps(flight_id: str, frame_id: int, image: np.ndarray, satellite_tile: np.ndarray, tile_bounds: TileBounds, timestamp: datetime) -> Optional[RotationResult]`
**Description**: Performs 30° rotation sweep, trying LiteSAM match for each rotation.
**Description**: Performs 30° rotation sweep, rotating image at each step and delegating matching to F09 Metric Refinement.
**Called By**:
- Internal (when requires_rotation_sweep() returns True)
@@ -114,8 +114,11 @@ np.ndarray # Rotated image (same dimensions)
**Input**:
```python
flight_id: str
frame_id: int # Frame identifier for heading persistence
image: np.ndarray # UAV image
satellite_tile: np.ndarray # Satellite reference tile
tile_bounds: TileBounds # GPS bounds and GSD of satellite tile (for F09)
timestamp: datetime # Timestamp for heading persistence
```
**Output**:
@@ -132,23 +135,23 @@ RotationResult:
```
For angle in [0°, 30°, 60°, 90°, 120°, 150°, 180°, 210°, 240°, 270°, 300°, 330°]:
rotated_image = rotate_image_360(image, angle)
result = LiteSAM.align_to_satellite(rotated_image, satellite_tile)
result = F09.align_to_satellite(rotated_image, satellite_tile, tile_bounds)
if result.matched and result.confidence > threshold:
precise_angle = calculate_precise_angle(result.homography, angle)
update_heading(flight_id, precise_angle)
update_heading(flight_id, frame_id, precise_angle, timestamp)
return RotationResult(matched=True, initial_angle=angle, precise_angle=precise_angle, ...)
return None # No match found
```
**Processing Flow**:
1. For each 30° step:
- Rotate image
- Call F09 Metric Refinement (LiteSAM)
- Rotate image via rotate_image_360()
- Call F09 Metric Refinement.align_to_satellite(rotated_image, satellite_tile, tile_bounds)
- Check if match found
2. If match found:
- Calculate precise angle from homography
- Update UAV heading
- Return result
- Calculate precise angle from homography via calculate_precise_angle()
- Update UAV heading via update_heading()
- Return RotationResult
3. If no match:
- Return None (triggers progressive search expansion)
@@ -228,7 +231,7 @@ Optional[float]: Heading angle in degrees (0-360), or None if not initialized
---
### `update_heading(flight_id: str, heading: float) -> bool`
### `update_heading(flight_id: str, frame_id: int, heading: float, timestamp: datetime) -> bool`
**Description**: Updates UAV heading angle after successful match.
@@ -239,7 +242,9 @@ Optional[float]: Heading angle in degrees (0-360), or None if not initialized
**Input**:
```python
flight_id: str
frame_id: int # Frame identifier for database persistence
heading: float # New heading angle (0-360)
timestamp: datetime # Timestamp for database persistence
```
**Output**:
@@ -251,7 +256,7 @@ bool: True if updated successfully
1. Normalize angle to 0-360 range
2. Add to heading history (last 10 headings)
3. Update current_heading for flight
4. Persist to database (optional)
4. **Persist to database**: Call F03 Flight Database.save_heading(flight_id, frame_id, heading, timestamp)
**Test Cases**:
1. **Update heading**: Sets new heading
@@ -365,17 +370,18 @@ List[np.ndarray] # Rotated images (same dimensions)
---
### `try_chunk_rotation_steps(chunk_images: List[np.ndarray], satellite_tile: np.ndarray) -> Optional[RotationResult]`
### `try_chunk_rotation_steps(chunk_images: List[np.ndarray], satellite_tile: np.ndarray, tile_bounds: TileBounds) -> Optional[RotationResult]`
**Description**: Performs 30° rotation sweep on entire chunk, trying LiteSAM match for each rotation.
**Description**: Performs 30° rotation sweep on entire chunk, rotating all images at each step and delegating matching to F09 Metric Refinement.
**Called By**:
- F11 Failure Recovery Coordinator (chunk LiteSAM matching with rotation)
- F11 Failure Recovery Coordinator (chunk matching with rotation)
**Input**:
```python
chunk_images: List[np.ndarray] # Chunk images
satellite_tile: np.ndarray # Reference satellite tile
tile_bounds: TileBounds # GPS bounds and GSD of satellite tile (for F09)
```
**Output**:
@@ -392,7 +398,7 @@ RotationResult:
```
For angle in [0°, 30°, 60°, 90°, 120°, 150°, 180°, 210°, 240°, 270°, 300°, 330°]:
rotated_chunk = rotate_chunk_360(chunk_images, angle)
result = LiteSAM.align_chunk_to_satellite(rotated_chunk, satellite_tile)
result = F09.align_chunk_to_satellite(rotated_chunk, satellite_tile, tile_bounds)
if result.matched and result.confidence > threshold:
precise_angle = calculate_precise_angle(result.homography, angle)
return RotationResult(matched=True, initial_angle=angle, precise_angle=precise_angle, ...)
@@ -401,17 +407,17 @@ return None # No match found
**Processing Flow**:
1. For each 30° step:
- Rotate all chunk images
- Call F09 Metric Refinement.align_chunk_to_satellite()
- Rotate all chunk images via rotate_chunk_360()
- Call F09 Metric Refinement.align_chunk_to_satellite(rotated_chunk, satellite_tile, tile_bounds)
- Check if match found
2. If match found:
- Calculate precise angle from homography
- Calculate precise angle from homography via calculate_precise_angle()
- Return RotationResult
3. If no match:
- Return None
**Performance**:
- 12 rotations × chunk LiteSAM (~60ms) = ~720ms
- 12 rotations × chunk matching via F09 (~60ms) = ~720ms
- Acceptable for chunk matching (async operation)
**Test Cases**:
@@ -425,18 +431,19 @@ return None # No match found
### Test 1: First Frame Rotation Sweep
1. First frame arrives (no heading set)
2. requires_rotation_sweep() → True
3. try_rotation_steps() → rotates 12 times
4. Match found at 60° step
5. calculate_precise_angle() → 62.3°
6. update_heading(62.3°)
7. Subsequent frames use 62.3° heading
3. try_rotation_steps(flight_id, frame_id=1, image, satellite_tile, tile_bounds, timestamp=now()) → rotates 12 times
4. F09 Metric Refinement called for each rotation
5. Match found at 60° step
6. calculate_precise_angle() → 62.3°
7. update_heading(flight_id, frame_id=1, heading=62.3°, timestamp=now())
8. Subsequent frames use 62.3° heading
### Test 2: Normal Frame Processing
1. Heading known (90°)
2. requires_rotation_sweep() → False
3. Pre-rotate image to 90°
4. LiteSAM match succeeds with small delta (+2.5°)
5. update_heading(92.5°)
5. update_heading(flight_id, frame_id=237, heading=92.5°, timestamp=now())
### Test 3: Sharp Turn Detection
1. UAV heading 45°
@@ -446,17 +453,19 @@ return None # No match found
5. Perform rotation sweep → find match at 120° step
### Test 4: Tracking Loss Recovery
1. LiteSAM fails to match (no overlap after turn)
1. F09 Metric Refinement fails to match (no overlap after turn)
2. requires_rotation_sweep() → True
3. try_rotation_steps() with all 12 rotations
4. Match found → heading updated
3. try_rotation_steps(flight_id, frame_id, image, satellite_tile, tile_bounds, timestamp) with all 12 rotations
4. F09 called for each rotation step
5. Match found → heading updated
### Test 5: Chunk Rotation Sweeps
1. Build chunk with 10 images (unknown orientation)
2. try_chunk_rotation_steps() with satellite tile
3. Match found at 120° step
4. Precise angle calculated (122.5°)
5. Verify all images rotated consistently
2. try_chunk_rotation_steps(chunk_images, satellite_tile, tile_bounds) with all 12 rotations
3. F09 Metric Refinement called for each rotation
4. Match found at 120° step
5. Precise angle calculated (122.5°)
6. Verify all images rotated consistently
## Non-Functional Requirements
@@ -479,9 +488,12 @@ return None # No match found
## Dependencies
### Internal Components
- **F09 Metric Refinement**: For LiteSAM matching during rotation sweep and chunk matching
- **F09 Metric Refinement**: For matching during rotation sweep (align_to_satellite, align_chunk_to_satellite). F06 rotates images, F09 performs the actual matching.
- **H07 Image Rotation Utils**: For image rotation and angle calculations
- **F12 Route Chunk Manager**: For chunk image retrieval
- **F03 Flight Database**: For heading persistence
**Note**: `TileBounds` data model is imported from F09 Metric Refinement.
### External Dependencies
- **opencv-python**: Image rotation (`cv2.warpAffine`)