12 KiB
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 categoryupdate_category_color(category_name, bgr_tuple)- Update BGR color for a categoryupdate_raw_map_intensity(intensity_value)- Update raw map intensity (0-255) for indices 32-255get_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
MfdStateinternally 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)
- 7 category rows (Occlusion through Cat C3):
- 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)
- Callback signature:
show_frame(frame)- Queue frame for display (thread-safe)get_mfd_lut()- Return current 256×3 RGB LUT from internal MfdStaterun()- Start Tkinter main loopstop()- Stop viewer and destroy window
Parameter Update Flow:
- User interacts with slider/button
- Internal callback
_on_intensity_changed,_on_color_button_clicked, or_on_raw_map_changed - Updates internal
MfdStateinstance → rebuilds LUT - Calls external
on_mfd_param_changedcallback (if provided) - 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
SfpViewerWithParamsover old simple viewer - Creates callback
on_mfd_param_changed(param_type, name, value)to:- Log parameter change
- Get updated LUT from viewer via
viewer.get_mfd_lut() - Update module's LUT via
module.update_mfd_lut(new_lut)
- Fallback to old
SfpViewerif new viewer import fails - Enhanced run loop to support viewers with/without duration parameter
Callback Integration:
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):
python -m VideoReceiverSFP --sim-dir dumps --fps 2 --duration 60 --verbose
Network Mode (listening for UDP):
python -m VideoReceiverSFP --host 127.0.0.1 --port 55556 --duration 120 --verbose
With Image Type Filter (MFD only):
python -m VideoReceiverSFP --sim-dir dumps --image-type MFD --fps 2 --duration 60 --verbose
Adjusting MFD Parameters in GUI
-
Category Intensity: Drag slider (0-255) next to category name
- 0 = black (invisible)
- 255 = full intensity
- Affects all pixels in that category
-
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
-
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
-
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
AppStateclass; VideoReceiverSFP uses localMfdStateinstance 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:
- ✅ Viewer opens with MFD parameters panel on right
- ✅ All 7 category controls + raw map control present
- ✅ Color indicators show initial white for categories, black for Occlusion/Reserved
- ✅ Sliders update intensity in real-time
- ✅ Color buttons open picker dialog
- ✅ Changes trigger LUT rebuild and logging
- ✅ Module receives updated LUT via callback
- ✅ Simulation mode works with dumps folder
- ✅ Network mode ready for UDP sender (tested with payload dumps)
Test Command:
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.