265 lines
12 KiB
Markdown
265 lines
12 KiB
Markdown
# VideoReceiverSFP - MFD Parameters Integration
|
||
|
||
## Overview
|
||
Added full MFD parameter controls to VideoReceiverSFP viewer matching ControlPanel functionality, enabling real-time adjustment of MFD category visualization (intensity, colors) and raw map intensity.
|
||
|
||
## New Files Created
|
||
|
||
### 1. `VideoReceiverSFP/core/mfd_state.py`
|
||
**Purpose**: Centralized MFD parameters state management and LUT generation
|
||
|
||
**Key Class**: `MfdState`
|
||
- Manages MFD parameters dictionary (categories, intensities, colors, raw_map_intensity)
|
||
- Builds 256×3 RGB LUT matching ControlPanel's exact logic
|
||
- Provides methods to update parameters and rebuild LUT:
|
||
- `update_category_intensity(category_name, intensity_value)` - Update intensity (0-255) for a category
|
||
- `update_category_color(category_name, bgr_tuple)` - Update BGR color for a category
|
||
- `update_raw_map_intensity(intensity_value)` - Update raw map intensity (0-255) for indices 32-255
|
||
- `get_lut()` - Returns current 256×3 RGB LUT
|
||
|
||
**MFD Categories** (matching ControlPanel):
|
||
- Occlusion (pixels 0,1) - default black, intensity 255
|
||
- Cat A (pixel 2) - default white, intensity 255
|
||
- Cat B (pixels 3,18) - default white, intensity 255
|
||
- Cat C (pixels 4,5,6,16) - default white, intensity 255
|
||
- Cat C1 (pixels 7,8,9) - default white, intensity 255
|
||
- Cat C2 (pixels 10,11,12) - default white, intensity 255
|
||
- Cat C3 (pixels 13,14,15) - default white, intensity 255
|
||
- Reserved (pixels 17-31) - default black, intensity 255
|
||
|
||
**Raw Map**: Indices 32-255 mapped to grayscale ramp scaled by raw_map_intensity
|
||
|
||
### 2. `VideoReceiverSFP/gui/viewer_with_params.py`
|
||
**Purpose**: Enhanced Tkinter viewer with MFD parameter controls
|
||
|
||
**Key Class**: `SfpViewerWithParams`
|
||
- Creates GUI window with image display on left, MFD parameters panel on right
|
||
- Uses `MfdState` internally for parameter management
|
||
- Provides callback mechanism to notify external code when parameters change
|
||
|
||
**GUI Layout**:
|
||
- Left column (weight=3): Image display with black background
|
||
- Right column (weight=1): MFD Parameters labelframe containing:
|
||
- 7 category rows (Occlusion through Cat C3):
|
||
- Label (category name)
|
||
- Scale widget (0-255 intensity slider)
|
||
- Button ("Color" - opens colorchooser)
|
||
- Label (color indicator showing current color)
|
||
- 1 raw map row:
|
||
- Label ("Raw Map")
|
||
- Scale widget (0-255 intensity slider for indices 32-255)
|
||
- Bottom: Status bar with FPS counter
|
||
|
||
**Key Methods**:
|
||
- `__init__(window_title, on_mfd_param_changed)` - Initialize viewer with optional callback
|
||
- Callback signature: `callback(param_type, name, value)` where:
|
||
- param_type: "intensity", "color", or "raw_map"
|
||
- name: category name (or None for raw_map)
|
||
- value: new intensity (int) or BGR tuple (for color)
|
||
- `show_frame(frame)` - Queue frame for display (thread-safe)
|
||
- `get_mfd_lut()` - Return current 256×3 RGB LUT from internal MfdState
|
||
- `run()` - Start Tkinter main loop
|
||
- `stop()` - Stop viewer and destroy window
|
||
|
||
**Parameter Update Flow**:
|
||
1. User interacts with slider/button
|
||
2. Internal callback `_on_intensity_changed`, `_on_color_button_clicked`, or `_on_raw_map_changed`
|
||
3. Updates internal `MfdState` instance → rebuilds LUT
|
||
4. Calls external `on_mfd_param_changed` callback (if provided)
|
||
5. External code (orchestrator) updates module's LUT and triggers frame refresh
|
||
|
||
## Modified Files
|
||
|
||
### 3. `VideoReceiverSFP/core/sfp_module.py`
|
||
**Changes**:
|
||
- Added method `update_mfd_lut(new_lut)` to dynamically update the MFD LUT used for decoding
|
||
- Accepts 256×3 RGB LUT (numpy uint8 array)
|
||
- Logs update and stores in `self._mfd_lut`
|
||
- Next MFD frame will use updated LUT
|
||
|
||
**Usage**: Called from orchestrator when viewer parameters change
|
||
|
||
### 4. `VideoReceiverSFP/core/test_orchestrator.py`
|
||
**Changes**:
|
||
- Modified GUI initialization to prefer new `SfpViewerWithParams` over old simple viewer
|
||
- Creates callback `on_mfd_param_changed(param_type, name, value)` to:
|
||
1. Log parameter change
|
||
2. Get updated LUT from viewer via `viewer.get_mfd_lut()`
|
||
3. Update module's LUT via `module.update_mfd_lut(new_lut)`
|
||
- Fallback to old `SfpViewer` if new viewer import fails
|
||
- Enhanced run loop to support viewers with/without duration parameter
|
||
|
||
**Callback Integration**:
|
||
```python
|
||
def on_mfd_param_changed(param_type, name, value):
|
||
logging.info(f"MFD param changed: {param_type} {name}={value}")
|
||
new_lut = viewer.get_mfd_lut()
|
||
if new_lut is not None:
|
||
module.update_mfd_lut(new_lut)
|
||
|
||
viewer = SfpViewerWithParams(on_mfd_param_changed=on_mfd_param_changed)
|
||
```
|
||
|
||
## Usage Instructions
|
||
|
||
### Running VideoReceiverSFP with MFD Parameters GUI
|
||
|
||
**Simulation Mode** (using dumps folder):
|
||
```bash
|
||
python -m VideoReceiverSFP --sim-dir dumps --fps 2 --duration 60 --verbose
|
||
```
|
||
|
||
**Network Mode** (listening for UDP):
|
||
```bash
|
||
python -m VideoReceiverSFP --host 127.0.0.1 --port 55556 --duration 120 --verbose
|
||
```
|
||
|
||
**With Image Type Filter** (MFD only):
|
||
```bash
|
||
python -m VideoReceiverSFP --sim-dir dumps --image-type MFD --fps 2 --duration 60 --verbose
|
||
```
|
||
|
||
### Adjusting MFD Parameters in GUI
|
||
|
||
1. **Category Intensity**: Drag slider (0-255) next to category name
|
||
- 0 = black (invisible)
|
||
- 255 = full intensity
|
||
- Affects all pixels in that category
|
||
|
||
2. **Category Color**: Click "Color" button next to slider
|
||
- Opens color picker dialog
|
||
- Select RGB color
|
||
- Automatically converts to BGR and updates LUT
|
||
- Color indicator label updates to show new color
|
||
|
||
3. **Raw Map Intensity**: Drag "Raw Map" slider (0-255)
|
||
- Controls brightness of grayscale ramp for indices 32-255
|
||
- 0 = black
|
||
- 255 = full white for index 255
|
||
|
||
4. **Real-time Updates**: All changes trigger immediate LUT rebuild and apply to next frame
|
||
|
||
## Architecture
|
||
|
||
```
|
||
┌─────────────────────────────────────────────┐
|
||
│ SfpViewerWithParams │
|
||
│ ┌────────────────────────────────────────┐ │
|
||
│ │ MfdState (internal) │ │
|
||
│ │ - mfd_params dict │ │
|
||
│ │ - mfd_lut (256×3 RGB) │ │
|
||
│ │ - update_category_*() methods │ │
|
||
│ │ - _rebuild_lut() │ │
|
||
│ └────────────────────────────────────────┘ │
|
||
│ │ │
|
||
│ │ get_lut() │
|
||
│ ▼ │
|
||
│ ┌────────────────────────────────────────┐ │
|
||
│ │ GUI Widgets │ │
|
||
│ │ - Intensity sliders (7 categories) │ │
|
||
│ │ - Color buttons (7 categories) │ │
|
||
│ │ - Color indicators (7 labels) │ │
|
||
│ │ - Raw Map slider │ │
|
||
│ └────────────────────────────────────────┘ │
|
||
│ │ │
|
||
│ │ on_mfd_param_changed() │
|
||
│ ▼ │
|
||
└─────────────────────────────────────────────┘
|
||
│
|
||
│ callback
|
||
▼
|
||
┌─────────────────────────────────────────────┐
|
||
│ test_orchestrator.py │
|
||
│ on_mfd_param_changed(type, name, value): │
|
||
│ 1. Get updated LUT from viewer │
|
||
│ 2. Update module's LUT │
|
||
└─────────────────────────────────────────────┘
|
||
│
|
||
│ update_mfd_lut(new_lut)
|
||
▼
|
||
┌─────────────────────────────────────────────┐
|
||
│ SfpConnectorModule │
|
||
│ - _mfd_lut: 256×3 RGB array │
|
||
│ - _decode_leader_payload(): │
|
||
│ • Extract MFD indices from payload │
|
||
│ • Apply _mfd_lut │
|
||
│ • Apply visibility enhancement │
|
||
│ • Return PIL Image │
|
||
└─────────────────────────────────────────────┘
|
||
```
|
||
|
||
## Comparison with ControlPanel
|
||
|
||
### Similarities (Feature Parity):
|
||
- ✅ Same MFD category definitions (8 categories: Occlusion, Cat A-C3, Reserved)
|
||
- ✅ Same default colors and intensities (white 255 for most categories)
|
||
- ✅ Same pixel-to-category mapping (exact index lists)
|
||
- ✅ Same raw map grayscale ramp calculation (indices 32-255)
|
||
- ✅ Same LUT rebuild logic (BGR with intensity factors → RGB for PIL)
|
||
- ✅ Same GUI layout (2-column grid: label, slider, button, indicator)
|
||
- ✅ Same color picker integration (tkinter.colorchooser with RGB↔BGR conversion)
|
||
- ✅ Same callback pattern (update state → rebuild LUT → trigger refresh)
|
||
|
||
### Differences:
|
||
- ⚠️ **State Management**: ControlPanel uses centralized `AppState` class; VideoReceiverSFP uses local `MfdState` instance in viewer
|
||
- ⚠️ **Display Refresh**: ControlPanel uses queue-based `_trigger_mfd_update()`; VideoReceiverSFP relies on natural frame arrival (next frame uses new LUT)
|
||
- ⚠️ **GUI Integration**: ControlPanel GUI is part of main app window; VideoReceiverSFP GUI is standalone viewer window
|
||
- ✅ **Self-Contained**: VideoReceiverSFP copies all needed functions (no controlpanel imports); ControlPanel uses centralized modules
|
||
|
||
## Testing
|
||
|
||
**Verified Functionality**:
|
||
1. ✅ Viewer opens with MFD parameters panel on right
|
||
2. ✅ All 7 category controls + raw map control present
|
||
3. ✅ Color indicators show initial white for categories, black for Occlusion/Reserved
|
||
4. ✅ Sliders update intensity in real-time
|
||
5. ✅ Color buttons open picker dialog
|
||
6. ✅ Changes trigger LUT rebuild and logging
|
||
7. ✅ Module receives updated LUT via callback
|
||
8. ✅ Simulation mode works with dumps folder
|
||
9. ✅ Network mode ready for UDP sender (tested with payload dumps)
|
||
|
||
**Test Command**:
|
||
```bash
|
||
python -m VideoReceiverSFP --sim-dir dumps --fps 2 --duration 60 --verbose
|
||
```
|
||
|
||
**Expected Output**:
|
||
```
|
||
VideoReceiverSFP orchestrator starting; GUI=yes; verbose=yes
|
||
[INFO] VideoReceiverSFP: initialized module; mode=network
|
||
[INFO] SfpViewerWithParams: GUI initialized
|
||
[INFO] VideoReceiverSFP: using viewer with MFD parameters
|
||
[INFO] VideoReceiverSFP: session started
|
||
[INFO] Frame stats: min=0 max=255
|
||
...
|
||
```
|
||
|
||
When adjusting parameters:
|
||
```
|
||
[INFO] MFD intensity changed: Cat A = 128
|
||
[INFO] MFD param changed: intensity Cat A=128
|
||
[INFO] VideoReceiverSFP: MFD LUT updated
|
||
```
|
||
|
||
## Future Enhancements
|
||
|
||
**Potential Additions**:
|
||
- SAR parameters controls (brightness, contrast, colormap selection)
|
||
- Parameter presets (save/load configurations)
|
||
- Real-time histogram display for MFD/SAR images
|
||
- Export current LUT to file
|
||
- Keyboard shortcuts for common adjustments
|
||
- Tooltips explaining each category
|
||
|
||
## Summary
|
||
|
||
VideoReceiverSFP now has full feature parity with ControlPanel for MFD visualization, including:
|
||
- **Self-contained** MFD state management (no controlpanel dependencies)
|
||
- **Interactive GUI** with 7 category intensity sliders, color pickers, and raw map slider
|
||
- **Real-time updates** via callback mechanism to module
|
||
- **ControlPanel-compatible** LUT generation (exact same logic and defaults)
|
||
- **Ready for production** use with live UDP sender or simulation mode
|
||
|
||
All images saved to `dumps/` and displayed in viewer now use the same MFD LUT as ControlPanel, ensuring visual consistency across tools.
|