<div align="center">

# FlowNet

**Estabilización de video con estimaciones de movimiento global destiladas con deep learning**

[English](README.md) · [Español](README.es.md) · [🌐 Página del proyecto](https://dan178a.github.io/FlowNet_Video_Stabilization/)

![Python](https://img.shields.io/badge/Python-3.11-3776AB?logo=python&logoColor=white)
![PyTorch](https://img.shields.io/badge/PyTorch-2.4-EE4C2C?logo=pytorch&logoColor=white)
![CUDA](https://img.shields.io/badge/CUDA-12.4-76B900?logo=nvidia&logoColor=white)
![License](https://img.shields.io/badge/License-Apache_2.0-blue.svg)

</div>

---

FlowNet estabiliza video tembloroso grabado a mano estimando el **movimiento global de la cámara** con una red neuronal de flujo óptico destilada, convierte ese flujo en una **trayectoria afín de cámara**, la suaviza con un optimizador de programación cuadrática (QP) y finalmente refina el resultado con una pasada de alineamiento **fotométrico multi-escala**.

## ✨ Resultados

**Entrada (temblorosa) vs. Salida (estabilizada)** — izquierda: original, derecha: estabilizado.

| Clip de celular a mano | Movimiento sintético |
| :---: | :---: |
| ![Demo muestra](docs/media/demo_sample.gif) | ![Demo tembloroso](docs/media/demo_shaky.gif) |

Fotogramas estabilizados de una secuencia más larga:

<p align="center">
  <img src="docs/media/grid_sample.png" width="90%" alt="Fotogramas estabilizados"/>
</p>

## 🧠 Cómo funciona

```
frames temblorosos ──► PWC-Net global (destilado) ──► coeficientes afines del flujo
                                                              │
                                     trayectoria acumulada de la cámara (afín)
                                                              │
                                suavizado QP de la trayectoria (con recorte)
                                                              │
                             refinamiento fotométrico multi-escala
                                                              │
                                                       video estabilizado
```

1. **Estimación de movimiento global** — una variante destilada de PWC-Net (`GLNoWarp4YTBB`) estima el flujo óptico denso entre fotogramas consecutivos. El flujo se comprime con una **parametrización basada en DCT** (`Utils/DCTUtility.py`), de modo que el movimiento global de la cámara queda capturado por un puñado de coeficientes.
2. **Trayectoria afín de cámara** — los coeficientes afines por fotograma (`Utils/AffineUtility.py`) se acumulan en una trayectoria de cámara que se suaviza con un **optimizador QP** (`PathStabilizers/StdPathStabilizerQP.py`), garantizando un solapamiento mínimo (`--maxAffineCrop`) entre el fotograma original y el deformado.
3. **Deformación (warping)** — los coeficientes estabilizados se invierten y se aplican con `grid_sample` por lotes, siguiendo automáticamente la región válida (sin bordes).
4. **Refinamiento fotométrico** — un estabilizador fotométrico multi-escala (`Stabilizers/MSPhotometric.py`) ajusta correcciones polinómicas de bajo orden sobre una ventana deslizante (paso bajo DCT, ponderación gaussiana) para eliminar el temblor residual que la trayectoria afín no puede modelar.
5. **Composición** — `Stabilizers/ComposedStabilizer.py` encadena ambas pasadas: `GNetAffine` → `MSPhotometric`.

El modelo de flujo preentrenado viene incluido en el repo (`GlobalFlowNets/trainedModels/GFlowNet.pth`), así que no hace falta entrenar nada para estabilizar tus propios videos.

## 🚀 Primeros pasos

### Requisitos

- Python 3.11
- GPU con CUDA (el modelo corre en modo `.cuda()`)
- CUDA 12.4 (o adapta la línea de instalación de `torch` a tu versión)

### Instalación

```bash
git clone https://github.com/Dan178A/FlowNet_Video_Stabilization.git
cd FlowNet_Video_Stabilization

python -m venv venv
venv\Scripts\activate            # Windows  (en Linux: source venv/bin/activate)

pip install -r requirements.txt
```

> Si tu versión de CUDA es distinta de 12.4, primero instala PyTorch con el wheel correspondiente desde [pytorch.org](https://pytorch.org/get-started/locally/) y luego ejecuta `pip install -r requirements.txt`.

### Estabilizar un video

```bash
python stabilizeVideo.py --inpVideoPath inputs/sample.avi --outVideoPath outputs/estabilizado.avi
```

Opciones:

| Flag | Por defecto | Descripción |
| --- | --- | --- |
| `--inpVideoPath` | `inputs/VID_...mp4` | Ruta al video tembloroso de entrada |
| `--outVideoPath` | `outputs/VID_...mp4` | Dónde guardar el video estabilizado |
| `--maxAffineCrop` | `0.8` | Solapamiento mínimo que se conserva tras el recorte (más bajo = estabilización más agresiva, recorte mayor) |

La salida se escribe a la misma tasa de fotogramas de la entrada.

## 📁 Estructura del proyecto

```
FlowNet_Video_Stabilization/
├── stabilizeVideo.py            # Punto de entrada CLI
├── GlobalFlowNets/              # Red de movimiento global destilada
│   ├── GlobalPWCNets.py         #   fábrica del modelo (getGlobalPWCModel)
│   ├── PWCBase.py / PWCNet.py   #   backbone PWC-Net
│   ├── FlowLosses.py            #   funciones de pérdida de entrenamiento
│   └── trainedModels/           #   GFlowNet.pth + config.json
├── Stabilizers/                 # Pasadas de estabilización
│   ├── ComposedStabilizer.py    #   pipeline GNetAffine + MSPhotometric
│   ├── JoinedAdaptiveGNetStabilizer.py  # flujo → trayectoria afín → warp
│   └── MSPhotometric.py         #   refinamiento fotométrico multi-escala
├── PathStabilizers/
│   └── StdPathStabilizerQP.py   # Suavizado QP de la trayectoria de cámara
├── Utils/                       # DCT, afines, recorte, E/S de video
├── inputs/  outputs/            # videos de demostración
└── docs/                        # página del proyecto (GitHub Pages) + media
```

## 📄 Licencia

Publicado bajo la [Licencia Apache 2.0](LICENSE).

<div align="center">
<a href="README.md"><img alt="Read in English" src="https://img.shields.io/badge/Read_in-English-yellow?style=for-the-badge"></a>
</div>