# 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.
