Official implementation of SyncLight: Single-Edit Multi-View Relighting.
Authors: David Serrano-Lozano, Anand Bhattad, Luis Herranz, Jean-François Lalonde, Javier Vazquez-Corral
SyncLight relights a set of multi-view images consistently from a single light edit. Given a reference image, additional viewpoints, and a target lightmap, the model generates all views under the specified lighting using a multi-view diffusion model (Latent Bridge Matching with MVDream-style 3D attention).
git clone https://github.com/CVC-Color/synclight
cd synclight
pip install -e .Python 3.10+ and a CUDA-capable GPU are required. For CPU-only inference use --device cpu (slow).
Download the pretrained weights and place them in ckpt/:
ckpt/
config.yaml # already included
synclight.ckpt # download separately
Download link: [TODO]
A lightmap is a numpy array of shape (H, W, 4) with float32 values:
| Channel | Meaning | Range |
|---|---|---|
| 0 | Light activation (0 = off, 1 = on) | 0 or 1 |
| 1 | Lightness L (normalized) | −1 to 1 |
| 2 | Color a (normalized) | −1 to 1 |
| 3 | Color b (normalized) | −1 to 1 |
L, a, b follow the CIE LAB color space with normalization:
L_norm = L/50 − 1where L ∈ [0, 100]a_norm = a/128where a ∈ [−128, 127]b_norm = b/128
Use the interactive lightmap editor:
python lightmap_creator.py --image path/to/reference.pngControls:
- Left-click / drag — place a circular light source
- Scribble mode — click-drag to draw a freeform light
- Right-click — delete a light
- Scroll — resize selected light
- ab picker — click the color picker panel to set hue
- Temperature slider — set warm/cool color temperature
- Save NPY button — write the lightmap to disk
The editor saves a .npy file and a preview .png in the current directory.
python gradio_demo.py --model_weights ckpt/ --device cuda --port 7860Open http://localhost:7860. Load example images from the sidebar or upload your own images and a lightmap.
python test.py \
--image_paths input_images/example_1_0_ref.png \
input_images/example_1_1.png \
input_images/example_1_2.png \
--lightmap_path input_images/example_1_0_lightmap.npy \
--model_weights ckpt/ \
--output_dir outputs/ \
--num_inference_steps 1 \
--device cudaOutput images are saved to outputs/output_0.jpg, output_1.jpg, etc. — one per input view.
Options:
| Flag | Default | Description |
|---|---|---|
--image_paths |
required | Input images (reference first, then additional views) |
--lightmap_path |
required | Path to .npy lightmap |
--model_weights |
required | Path to weights directory |
--output_dir |
./outputs |
Output directory |
--num_inference_steps |
1 |
Diffusion steps (1 is fast and works well) |
--device |
cuda |
cuda or cpu |
--torch_dtype |
bfloat16 |
bfloat16 or float32 |
import numpy as np
from PIL import Image
from src.synclight.inference import evaluate, get_model
model = get_model("ckpt/", device="cuda")
images = [Image.open(p).convert("RGB") for p in image_paths]
lightmap = np.load("lightmap.npy").astype("float32") # (H, W, 4)
outputs = evaluate(model, images, lightmap_image=lightmap, num_sampling_steps=1)
# outputs: list of PIL Images, one per input viewsynclight/
├── src/synclight/ # Core library
│ ├── models/
│ │ ├── lbm/ # LBM diffusion model
│ │ ├── unets/ # MVDream UNet with 3D attention
│ │ ├── vae/ # VAE wrapper
│ │ └── embedders/ # Conditioners (lightmap concat)
│ └── inference/ # Inference utilities
├── ckpt/
│ └── config.yaml # Model config
├── input_images/ # Example inputs
├── outputs/ # Default output directory
├── gradio_demo.py # Interactive web demo
├── lightmap_creator.py # Interactive lightmap editor
└── test.py # Command-line inference script
@article{serrano2025synclight,
title={SyncLight: Single-Edit Multi-View Relighting},
author={Serrano-Lozano, David and Bhattad, Anand and Herranz, Luis and Lalonde, Jean-Fran\c{c}ois and Vazquez-Corral, Javier},
journal={arXiv preprint arXiv:2601.16981},
year={2025}
}This work builds on the Latent Bridge Matching framework by Jasper AI and the MVDream multi-view diffusion architecture.
Apache 2.0