Real-time underwater image and video enhancement for ROV (Remotely Operated Vehicle) operations. Restores clarity, color, and contrast to degraded underwater footage caused by light absorption, scattering, and turbidity.
Key highlights:
- ~73 FPS at 4K resolution using TensorRT INT8 inference with CUDA graphs
- 5-8x speedup over CPU with GPU-accelerated classical CV pipeline
- Cross-platform desktop GUI, CLI, and Python SDK
- Automatic GPU/CPU fallback with zero-copy GPU memory management
Each frame passes through a configurable stage-based pipeline where enhancement techniques are applied in sequence, with data kept on the GPU across all stages to minimize transfer overhead:
Input Frame → White Balance → CLAHE → Dehazing → Denoising → Sharpening → Enhanced Frame
│ │ │ │ │
Gray-world Adaptive Dark channel BM3D / Unsharp
color cast contrast prior with bilateral mask
correction boost transmission filter
estimation
Two processing modes are available:
- Classical CV pipeline — configurable chain of the stages above, with parameter presets tuned for specific underwater conditions (murky, clear, reef, etc.)
- ML pipeline — adapted and fine-tuned DNnet (Cao et al., 2025) to meet real-time inference requirements, balancing visual quality and performance. Deployed as an INT8-quantized TensorRT engine with CUDA graphs, achieving ~73 FPS at 4K on an RTX 5070 Ti
src/urvis/
├── sdk/
│ ├── pipeline.py # Stage-based enhancement orchestrator
│ ├── device.py # GPU/CPU device abstraction and memory management
│ └── trt_stage.py # TensorRT INT8 inference (CUDA graphs, FP16 I/O, pinned memory)
├── gui/ # PyQt6 desktop application
│ ├── workers/ # Background threads for camera capture and enhancement
│ ├── widgets/ # Live camera tab, batch processing tab, comparison view
│ └── managers/ # TensorRT engine auto-discovery
└── __main__.py # CLI entry point
Design decisions:
- Single GPU upload/download per frame — data stays on GPU across all pipeline stages, eliminating redundant transfers
- Lazy TensorRT initialization — deferred to worker threads so the PyCUDA context binds correctly, not to the GUI thread
- Graceful degradation — each stage independently falls back to CPU if GPU operations fail, keeping the pipeline running
- Protocol-based stages — new enhancement stages plug in without modifying the orchestrator
| Mode | Resolution | Throughput | Hardware |
|---|---|---|---|
| ML (TensorRT INT8) | 3840x2160 (4K) | ~73 FPS | RTX 5070 Ti |
| Classical CV (GPU) | 1920x1080 | 10-15 FPS | RTX 5070 Ti |
| Classical CV (CPU) | 1920x1080 | 2-3 FPS | CPU fallback |
| Component | Technology |
|---|---|
| ML inference | TensorRT 10.15, INT8 quantization, CUDA graphs |
| GPU compute | PyCUDA, CuPy |
| Classical CV | OpenCV, BM3D |
| Desktop GUI | PyQt6 (threaded workers, signal/slot architecture) |
| Packaging | PyInstaller (Windows/Linux standalone executables) |
| CI/CD | GitHub Actions (automated builds on tag/release) |
| Code quality | Ruff, ty, pre-commit hooks |
# Python 3.12 required
python -m venv .venv
source .venv/bin/activate # Windows: .venv\Scripts\activate
pip install -e . # Core + CLI
pip install -e .[gui] # + Desktop GUI
pip install -e .[gpu] # + CuPy GPU acceleration
pip install -e .[dev] # + Dev tools (linting, formatting)python -m urvis.gui- Live Camera Tab — real-time enhancement with preset/model cycling (arrow keys)
- Enhancement Tab — drag-drop batch processing with video preview
# Enhance image
urvis enhance input.jpg --out output.jpg --preset classical
# Enhance video
urvis enhance --video input.mp4 --out output.mp4 --preset turbid_close
# Stream processing (webcam or RTSP)
urvis stream 0 --out stream_enhanced.mp4
urvis stream rtsp://example/stream --out out.mp4
# GPU device selection
urvis enhance input.jpg --device cuda # Force GPU
urvis enhance input.jpg --device auto # Auto-detect (default)from urvis.sdk.pipeline import Pipeline
import cv2
pipeline = Pipeline(preset="classical", device="auto")
enhanced = pipeline.enhance(cv2.imread("input.jpg"))
cv2.imwrite("output.jpg", enhanced)| Preset | Use Case |
|---|---|
classical |
Balanced defaults for most reef scenes |
turbid_close |
Aggressive enhancement for murky, near-field captures |
turbid_soft |
Halo-reduced variant with milder dehaze |
reef_clear |
Subtle corrections for already-clear water |
auto |
Auto-selects based on image statistics (contrast, saturation, color bias) |
fast |
Lightweight chain for real-time scenarios |
URVIS auto-discovers TensorRT .engine files in the models/ directory. To build engines from trained PyTorch models:
- Export model to ONNX
- Convert ONNX to TensorRT with optional INT8 calibration
The GUI lets you cycle through available models with arrow keys during live camera enhancement.
| Variable | Default | Description |
|---|---|---|
URVIS_PRESET |
classical |
Default enhancement preset |
URVIS_GPU_DEVICE |
auto |
Device selection: cpu, cuda, auto |
URVIS_LOG_LEVEL |
INFO |
Logging level |
URVIS_MODEL_PATH |
— | Custom path to TensorRT engine |
GUI_USAGE.md— Desktop application guideGPU_SETUP.md— GPU setup and troubleshootingBUILD_WINDOWS_EXE.md— Building standalone executables
- Fork the repository
- Create a feature branch
- Run
make lintbefore committing - Open a Pull Request
MIT — see LICENSE.
The ML enhancement pipeline builds on DNnet (Cao et al., 2025).