Real-Time Face Swapping Implementation for Live Webcam Processing in Deep Live Cam
Deep Live Cam achieves real-time face swapping by running three concurrent pipelines—capture, detection, and processing—that minimize latency through frame dropping and thread decoupling.
Deep Live Cam is an open-source application that performs real-time face swapping for live webcam processing using a multi-threaded architecture built on InsightFace and OpenCV. The implementation separates camera input, face detection, and frame rendering into independent workers that communicate via thread-safe queues and shared state, allowing the UI to maintain approximately 30 FPS output even during heavy inference loads.
The Three-Pipeline Architecture
The live preview system orchestrates three distinct threads to maintain smooth performance. This design isolates the computationally expensive face detection step from the rendering loop, preventing frame stalls and ensuring responsive webcam feedback.
Capture Pipeline: Low-Latency Frame Acquisition
The VideoCapturer class in modules/video_capture.py wraps OpenCV's VideoCapture interface to feed raw frames into a bounded queue. It continuously pulls images from the camera and pushes them into a thread-safe buffer.
cap = VideoCapturer(camera_index)
cap.start(PREVIEW_DEFAULT_WIDTH, PREVIEW_DEFAULT_HEIGHT, 60) # Target 60 FPS input
With a queue size strictly limited to 2, stale frames are automatically discarded. This forced dropping ensures that downstream processors always work with the most recent image rather than accumulating backlog, keeping latency minimal.
Detection Pipeline: Face Analysis Thread
Running in parallel, the _detection_thread_func in modules/ui.py (line 56) continuously analyzes the latest frame stored in latest_frame_holder[0]. It delegates face detection to modules/face_analyser.py, selecting between single or multiple face detection based on global configuration.
if modules.globals.many_faces:
many = get_many_faces(frame)
detection_result['many_faces'] = many
else:
face = get_one_face(frame)
detection_result['target_face'] = face
Results are cached in a thread-safe dictionary (detection_result), effectively decoupling the 15-30ms detection latency from the main rendering loop. This means the UI never waits for face analysis to complete before displaying a frame.
Processing Pipeline: The Swapping Core
The _processing_thread_func in modules/ui.py (line 66) executes the actual face replacement. It retrieves cached detection results and calls swap_face from modules/processors/frame/face_swapper.py to perform the inference.
if modules.globals.many_faces and cached_many_faces:
for t_face in cached_many_faces:
result = frame_processor.swap_face(source_image, t_face, result)
else:
result = frame_processor.swap_face(source_image, cached_target_face, temp_frame)
After swapping, the frame passes through optional post-processing before being pushed to the UI queue.
InsightFace Model Integration
The core face swapping logic relies on an ONNX model loaded via the InsightFace library. In modules/processors/frame/face_swapper.py, the swap_face function orchestrates model inference:
FACE_SWAPPER = insightface.model_zoo.get_model(model_path,
providers=providers_config)
swapped_frame_raw = face_swapper.get(frame, target_face, source_face, paste_back=True)
The model file (inswapper_128_fp16.onnx) is automatically downloaded during initialization via pre_check and conditional_download. Execution providers are selected dynamically based on the runtime environment:
- CoreMLExecutionProvider for Apple Silicon (set via
IS_APPLE_SILICON) - CUDAExecutionProvider for NVIDIA GPUs
- CPU fallback for unsupported hardware
Post-Processing and Rendering
After the raw swap operation, frames undergo enhancement through apply_post_processing in face_swapper.py. The pipeline supports several GPU-accelerated operations defined in modules/gpu_processing.py:
- Sharpening (
gpu_sharpen) enhances edge definition in the swapped region - Temporal interpolation (
gpu_add_weighted) blends frames with previous outputs to smooth motion - Mouth masking and Poisson blending create seamless boundaries between the swapped face and target head
The webcam_preview function in modules/ui.py (line 36) assembles these three threads and manages the Tkinter rendering loop. It pulls completed frames from the processing queue, converts them using gpu_cvt_color, and renders them via PIL.Image and CTkImage. An optional FPS overlay can be displayed to monitor performance.
Implementation Example
To launch a live webcam preview programmatically with a custom source face:
import modules.globals as G
from modules.ui import webcam_preview
import customtkinter as ctk
# Configure the source image (the face to swap in)
G.source_path = "samples/source.jpg"
G.map_faces = False # Use single source mode
# Initialize the GUI root window
root = ctk.CTk()
root.title("Deep Live Cam – Live Swap")
# Start preview for camera index 0
webcam_preview(root, camera_index=0)
root.mainloop()
All global toggles—including many_faces, sharpness, enable_interpolation, and poisson_blend—are defined in modules/globals.py and can be modified before launching the preview.
Performance Optimizations
Bounded Queues: The VideoCapturer uses a queue size of 2 to drop stale frames when processing cannot keep pace with the camera's 60 FPS input, ensuring the pipeline always processes the latest available image.
Hardware Acceleration: GPU processing utilities in modules/gpu_processing.py provide optimized CUDA and Metal paths for color conversion, resizing, sharpening, and blending operations.
Thread Isolation: By running face detection in a separate thread, the rendering loop maintains consistent frame rates even when InsightFace inference spikes above 30 milliseconds.
Summary
- Deep Live Cam implements real-time face swapping through three concurrent threads: capture, detection, and processing.
- The
VideoCapturerinmodules/video_capture.pymaintains low latency by dropping stale frames from its bounded queue. - Face detection runs independently in
_detection_thread_func, caching results indetection_resultto avoid blocking the rendering pipeline. - The actual swap operation uses the
inswapper_128_fp16.onnxInsightFace model loaded inmodules/processors/frame/face_swapper.py. - Optional post-processing includes sharpening, temporal interpolation, and Poisson blending for visual quality.
- Platform-specific execution providers (CoreML, CUDA) are selected automatically via configuration in
modules/globals.py.
Frequently Asked Questions
How does Deep Live Cam maintain low latency during live webcam processing?
Deep Live Cam uses a bounded queue with a maximum size of 2 in the VideoCapturer class, which automatically drops stale frames when processing slows down. Additionally, face detection runs in a dedicated thread (_detection_thread_func in modules/ui.py), ensuring that heavy inference taking 15-30ms never blocks the UI rendering loop.
What AI model does Deep Live Cam use for face swapping?
The application uses the inswapper_128_fp16.onnx model from the InsightFace model zoo. This ONNX model is loaded via insightface.model_zoo.get_model() in modules/processors/frame/face_swapper.py and supports hardware acceleration through CoreML on Apple Silicon and CUDA on NVIDIA GPUs.
Can Deep Live Cam swap multiple faces simultaneously in real-time?
Yes. When modules.globals.many_faces is enabled, the detection thread caches multiple faces using get_many_faces from modules/face_analyser.py. The processing thread then iterates through all detected faces in cached_many_faces, applying the swap operation to each target face within the same frame before rendering.
How do I start the webcam preview programmatically?
Import webcam_preview from modules.ui and call it with a CustomTkinter root window and camera index. Ensure you set modules.globals.source_path to your source image before launching. The function handles thread creation and the Tkinter after loop automatically, pulling frames from the processing queue and displaying them at approximately 30 FPS.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →