DeepSwapFace · Face Swap Video & Image CLI

A small, readable face swap tool for video and stills, built on InsightFace + ONNX Runtime.

No Colab notebook, no 40-node ComfyUI graph to debug. One Python file, two models, one command.

# video
python swap.py --source face.jpg --target clip.mp4 --output out.mp4

# image
python swap.py --source face.jpg --target group.jpg --output out.jpg --all-faces

⚠️ Ethical use & disclaimer

This is a technical tool for research, VFX prototyping, and identity-preservation experiments.

By downloading or using it you agree that:

  • Consent is mandatory. You must have explicit permission from every person whose likeness you process, and from anyone whose face you insert.
  • No deception. Do not use it to impersonate, defraud, harass, or create non-consensual intimate imagery. In many jurisdictions (EU AI Act, US state deepfake laws, China's deep synthesis regulations) publishing synthetic media of real people without disclosure is illegal.
  • You are liable. The software is provided "as is", without warranty of any kind. The authors accept no responsibility for misuse.
  • Model licences apply. inswapper_128.onnx from InsightFace is released for non-commercial research use only. Check the upstream licence before any commercial deployment.

🚀 Quickstart

1. Install

python -m venv .venv && source .venv/bin/activate
pip install -r requirements.txt

Requires Python 3.10+. CPU is enough; a GPU is roughly 10–30× faster.

2. Get the models

mkdir -p models ~/.insightface/models
# face detector + recognition (buffalo_l, ~289 MB)
curl -L -o /tmp/buffalo_l.zip \
  https://github.com/deepinsight/insightface/releases/download/v0.7/buffalo_l.zip
unzip -q /tmp/buffalo_l.zip -d ~/.insightface/models/buffalo_l

# the swap model (~529 MB)
curl -L -o models/inswapper_128.onnx \
  https://huggingface.co/ezioruan/inswapper_128.onnx/resolve/main/inswapper_128.onnx

The models are not mirrored in this repo — inswapper_128.onnx is non-commercial research-only and stays with its upstream host.

3. Swap a video

python swap.py --source examples/source-01.jpg \
               --target examples/demo-clip.mp4 \
               --output out.mp4 \
               --det-size 320

4. Swap a still

python swap.py --source examples/source-01.jpg \
               --target examples/target-01.jpg \
               --output out.jpg

🧩 CLI options

Flag Default Description
--source required Image containing the face to insert
--target required Image or video to put that face into
--output output.jpg Output path (use .mp4 for video)
--model models/inswapper_128.onnx Path to the swap model
--source-face 0 Which source face to use (left-to-right order)
--target-face 0 Which target face to replace
--all-faces off Swap every face detected in the target
--det-size 640 Detector input size; 320 is ~2× faster on video
--every 1 Video only: swap every Nth frame, reuse the result in between
--max-frames 0 Video only: stop after N frames (0 = whole clip)
--execution-provider CPUExecutionProvider Set to CUDAExecutionProvider for GPU

🎬 Video example

Input clip (synthetic slow zoom, 24 frames @ 8 fps) → swapped with this script, default settings except --det-size 320:

Input Output

Identity check on the decoded output frames — ArcFace cosine similarity of the result face vs the source face:

Frame source ↔ target (before) source ↔ result (after)
0 -0.071 0.822
12 -0.082 0.846
23 -0.058 0.828

The identity stays stable across the clip because detection runs per frame and the swap target is resolved by the same left-to-right rule each time.


🖼️ Still-image examples

Four pairs generated with the released model, then verified the same way.

1 · Colour portrait → vintage studio photo

example 1

before -0.036 → after 0.893

2 · Same source, different target

example 2

before 0.107 → after 0.855

3 · Role-reversed pair

example 3

before 0.068 → after 0.851

4 · Reverse direction again

example 4

before 0.068 → after 0.820

Reproduce any of them:

python swap.py --source examples/source-01.jpg \
               --target examples/target-01.jpg \
               --output /tmp/check.jpg

⏱️ Performance

Measured on a 2 vCPU / 1.9 GB RAM cloud instance, CPUExecutionProvider:

Workload Result
Still, 960×1696, det-size 640 ~27 s (cold start ~50 s incl. model load)
Still, peak RSS ~1.6 GB
Video, 378×600, det-size 320 4.2 s per frame (24 frames → 100 s)

A modern GPU (CUDA EP) brings a single frame down to well under a second.

Rule of thumb on CPU: frames × 4s. Pass --every 2 or --every 3 when you need speed more than smoothness.


🔬 How it works

  1. Detect — SCRFD (det_10g.onnx) finds face boxes and 5-point landmarks, once per frame.
  2. Align — faces are warped to the canonical 112×112 template.
  3. Embed — ArcFace (w600k_r50.onnx) produces a 512-d identity vector for the source face.
  4. Swap — inswapper_128.onnx maps the source identity onto the target's aligned crop.
  5. Paste back — the 128×128 result is inverse-warped into the full-resolution frame, so framing, lighting gradient and background are preserved.
  6. Encode — frames are written back at the source fps.

The swapped region is inherently 128×128 — that is the model's bottleneck, not the script's. Faces smaller than ~80 px will look soft.


🚧 Known limitations

  • No temporal smoothing. Each frame is swapped independently, so identity can flicker under fast head motion or partial occlusion. Adding a tracker / stabilising pass is the obvious next step.
  • Yaw / profile views degrade badly; the model is trained mostly on frontal faces.
  • Heavy occlusion (masks, hands, hair) leaves artefacts at the seam.
  • Glasses and beards are not transferred — you keep the target's accessories.
  • Skin-tone mismatch between very different sources produces a visible edge.
  • Multiple faces need --all-faces or an explicit --target-face index; ordering is left-to-right by bounding box, so it can jump if people cross.
  • Audio is dropped. The video writer does not mux audio; re-attach it with ffmpeg: ffmpeg -i out.mp4 -i original.mp4 -c copy -map 0:v -map 1:a final.mp4.

📜 Credits & licences

Code in this repository: MIT.

Example imagery is public-domain / no-known-restrictions material from Wikimedia Commons, used unmodified as inputs:

  • source-01 — Cornelia Montgomery, 3/4 face portrait, Library of Congress via Wikimedia Commons, Public domain
  • target-01 — Studio portrait of a young man, Internet Archive book images, No known copyright restrictions
  • third portrait (Portrait photograph of Rose Stahl), Wikimedia Commons, Public domain
  • demo-clip.mp4 — synthetic slow zoom generated from target-01 for testing purposes

Upstream projects:

  • InsightFace — detector, recognition model and inswapper_128 (non-commercial research licence)
  • ONNX Runtime — inference
  • OpenCV — image/video I/O and warping

🙏 Acknowledgements

This project is sponsored by deepswapface.ai — they cover the compute used to build and benchmark the examples in this repository.

If you would rather not set up a local environment, they run a hosted version of the same workflow:

→ https://deepswapface.ai


📄 Citation

@misc{deepswapface_cli,
  title  = {DeepSwapFace: a minimal face swap CLI for video and images},
  author = {deepswapface.ai contributors},
  year   = {2026},
  url    = {https://deepswapface.ai}
}
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support