# How Deep-Live-Cam Processes Multiple Faces and Pairs Source-to-Target Faces

> Discover how Deep-Live-Cam processes multiple faces with simple one-to-one swapping, a 'many faces' default source mode, or explicit 'map-faces' source-to-target pairings from its repository.

- Repository: [Kenneth Estanislao/Deep-Live-Cam](https://github.com/hacksider/Deep-Live-Cam)
- Tags: deep-dive
- Published: 2026-03-01

---

**Deep-Live-Cam handles multiple faces through three distinct modes—simple one-to-one swapping, "many faces" mode that applies a default source to every detected target, and "map-faces" mode that uses explicit source-to-target pairings stored in `source_target_map`.**

Deep-Live-Cam (hacksider/Deep-Live-Cam) is an open-source real-time face swapping application that supports complex multi-face scenarios. The system can detect an arbitrary number of faces in a target frame and intelligently pair them with source faces using either automatic defaults or user-defined mappings. This article examines the source code architecture in [`modules/processors/frame/face_swapper.py`](https://github.com/hacksider/Deep-Live-Cam/blob/main/modules/processors/frame/face_swapper.py) to explain exactly how the application manages detection, pairing, and execution across different operational modes.

## Understanding the Three Face Processing Modes

The application logic branches based on two global flags defined in [`modules/globals.py`](https://github.com/hacksider/Deep-Live-Cam/blob/main/modules/globals.py): `many_faces` and `map_faces`. These flags determine which detection and pairing strategy executes inside `process_frame_v2`.

### Simple Mode (One-to-One)

In **simple mode**, the system detects a single source face from the CLI `--source` argument and a single target face from the current frame. The swapper creates exactly one pair and applies the transformation once per frame. This is the default behavior when both `many_faces` and `source_target_map` are disabled.

### Many Faces Mode (Default Source to All Targets)

When the global flag `many_faces` is set to **True**, Deep-Live-Cam calls `get_many_faces()` from [`modules/face_analyser.py`](https://github.com/hacksider/Deep-Live-Cam/blob/main/modules/face_analyser.py) instead of `get_one_face()`. This returns a list of all detected faces in the frame. The system then retrieves a **default source face** (via `default_source_face()` from the first map entry) and pairs it with every detected target face. This mode is toggled from the UI via the *"Swap every detected face, not just the primary one"* switch or by passing `--many-faces` on the command line.

### Map-Faces Mode (Explicit Many-to-Many)

**Map-faces mode** activates when `source_target_map` (or its simplified variant `simple_map`) is populated. This structure contains explicit dictionaries mapping specific source faces to specific target faces. The system supports two sub-variants:
- **One-to-one explicit**: Each map entry contains one source and one specific target
- **Default source with many targets**: When `many_faces` is active alongside a map, the system uses the default source for all mapped targets

## Face Detection Architecture in Deep-Live-Cam

Face detection is handled by [`modules/face_analyser.py`](https://github.com/hacksider/Deep-Live-Cam/blob/main/modules/face_analyser.py), which wraps the InsightFace library. The core detection helper in [`face_swapper.py`](https://github.com/hacksider/Deep-Live-Cam/blob/main/face_swapper.py) branches based on the global configuration:

```python
def get_faces_optimized(frame: Frame, use_cache: bool = True) -> Optional[List[Face]]:
    if modules.globals.many_faces:
        return get_many_faces(frame)      # Returns list of all detected faces

    else:
        face = get_one_face(frame)
        return [face] if face else None

```

The `get_many_faces()` function invokes the underlying InsightFace analyzer on the entire frame, returning all detected face embeddings and bounding boxes. When `many_faces` is False, the system uses `get_one_face()`, which typically returns the largest or most centered face in the frame.

## Source-to-Target Pairing Algorithm

The pairing logic resides in `process_frame_v2` within [`modules/processors/frame/face_swapper.py`](https://github.com/hacksider/Deep-Live-Cam/blob/main/modules/processors/frame/face_swapper.py). The algorithm constructs a list of tuples called `source_target_pairs`, then iterates through them to perform swaps.

### Pair Construction Logic

The code evaluates three conditions in sequence to build the pairing list:

1. **Map-faces with many-faces enabled**: Uses `default_source_face()` for every entry in `source_target_map`
2. **Map-faces without many-faces**: Uses one-to-one mappings from the map structure
3. **Simple many-faces**: Applies the default source to every face returned by `get_many_faces()`
4. **Simple single-face**: Uses the pre-loaded source face with the single detected target

```python
source_target_pairs = []

# 1️⃣ Map-faces mode with many_faces flag

if source_target_map and modules.globals.many_faces:
    source_face = default_source_face()
    for map_data in source_target_map:
        target_face = map_data.get("target", {}).get("face")
        if target_face:
            source_target_pairs.append((source_face, target_face))

# 2️⃣ Map-faces mode one-to-one

elif source_target_map:
    for map_data in source_target_map:
        source_face = map_data["source"]["face"]
        target_face = map_data["target"]["face"]
        source_target_pairs.append((source_face, target_face))

# 3️⃣ Simple mode many faces

elif modules.globals.many_faces:
    source_face = default_source_face()
    detected_faces = get_many_faces(processed_frame)
    for target_face in detected_faces:
        source_target_pairs.append((source_face, target_face))

# 4️⃣ Simple mode single face

else:
    source_face = pre_loaded_source_face
    target_face = get_one_face(processed_frame)
    if source_face and target_face:
        source_target_pairs.append((source_face, target_face))

```

Once assembled, the swapper executes sequential transformations:

```python
for source_face, target_face in source_target_pairs:
    current_swap_target = swap_face(source_face, target_face, current_swap_target)

```

## Creating and Managing Face Maps

Deep-Live-Cam provides two mechanisms for populating `source_target_map`: manual UI mapping and automatic video analysis.

### Image-to-Image Mapping

Users select a source image and target image in the interface ([`modules/ui.py`](https://github.com/hacksider/Deep-Live-Cam/blob/main/modules/ui.py)), then click *"Add mapping"*. The system extracts face embeddings using [`modules/face_analyser.py`](https://github.com/hacksider/Deep-Live-Cam/blob/main/modules/face_analyser.py) and stores the pairing in `modules.globals.source_target_map` as a list of dictionaries containing `source` and `target` face objects.

### Video Mapping with Clustering

For video targets, the function `get_unique_faces_from_target_video()` extracts face embeddings across all frames, clusters them using `find_cluster_centroids`, and assigns a source face to each cluster centroid. The resulting structure stores target faces per frame index in `source_target_map[i]['target_faces_in_frame']`. During processing, the system matches detected faces to the nearest centroid using `find_closest_centroid`.

### Simplified Maps

The `simplify_maps()` function converts the full map into parallel lists (`source_faces` and `target_embeddings`). When `simple_map` is active, the algorithm uses nearest-neighbor matching against these simplified embeddings rather than the full map structure.

## Runtime Execution Flow

The complete data flow from configuration to output involves:

| Step | Component | Action |
|------|-----------|--------|
| **Configuration** | [`modules/core.py`](https://github.com/hacksider/Deep-Live-Cam/blob/main/modules/core.py) | Parses CLI arguments (`--many-faces`, `--map-faces`, `--analyse-video`) and sets flags in [`modules/globals.py`](https://github.com/hacksider/Deep-Live-Cam/blob/main/modules/globals.py) |
| **Detection** | [`modules/face_analyser.py`](https://github.com/hacksider/Deep-Live-Cam/blob/main/modules/face_analyser.py) | Executes `get_many_faces()` or `get_one_face()` based on the `many_faces` boolean |
| **Pairing** | [`face_swapper.py`](https://github.com/hacksider/Deep-Live-Cam/blob/main/face_swapper.py) | Executes `process_frame_v2` to build `source_target_pairs` using map or default logic |
| **Swapping** | [`face_swapper.py`](https://github.com/hacksider/Deep-Live-Cam/blob/main/face_swapper.py) | Iterates pairs and calls `swap_face()` for each source-target combination |
| **Post-processing** | [`face_swapper.py`](https://github.com/hacksider/Deep-Live-Cam/blob/main/face_swapper.py) | Applies sharpening and interpolation via `apply_post_processing()` |
| **Output** | `process_frames` | Writes to disk or streams live through `process_video()` or `process_image()` |

### Command Line Examples

Enable many-faces mode for automatic swapping onto every detected face:

```bash
python run.py --source path/to/source.jpg \
              --target path/to/video.mp4 \
              --many-faces

```

Generate and use a face map for explicit pairing:

```bash

# Analyze target video to build clusters

python run.py --target path/to/video.mp4 --analyse-video

# Run swap using generated map

python run.py --source path/to/source.jpg --target path/to/video.mp4 --map-faces

```

### Programmatic Usage

Control the processing pipeline directly from Python:

```python
from modules import globals, processors
from modules.face_analyser import get_many_faces

# Enable many-faces mode

globals.many_faces = True

# Load pre-built map (normally generated by UI)

globals.source_target_map = [
    {"source": {"face": src_face_obj}, "target": {"face": tgt_face_obj}}
]

# Process numpy array

result = processors.frame.core.process_frame_v2(frame_np)

```

## Summary

- **Three operational modes** control detection scope: simple (single face), many-faces (all faces with default source), and map-faces (explicit pairings).
- **Detection routing** occurs in `get_faces_optimized()`, which selects between `get_one_face()` and `get_many_faces()` based on `modules.globals.many_faces`.
- **Pair construction** happens inside `process_frame_v2` in [`modules/processors/frame/face_swapper.py`](https://github.com/hacksider/Deep-Live-Cam/blob/main/modules/processors/frame/face_swapper.py), supporting both automatic defaults and user-defined `source_target_map` structures.
- **Video analysis** uses clustering (`find_cluster_centroids`) to identify unique faces across frames, enabling persistent identity mapping throughout a video sequence.
- **UI and CLI** both manipulate the same global flags in [`modules/globals.py`](https://github.com/hacksider/Deep-Live-Cam/blob/main/modules/globals.py), ensuring consistent behavior across interface modes.

## Frequently Asked Questions

### How does Deep-Live-Cam choose which source face to use when multiple faces are detected?

When `many_faces` mode is active without an explicit map, the system calls `default_source_face()` from [`modules/face_analyser.py`](https://github.com/hacksider/Deep-Live-Cam/blob/main/modules/face_analyser.py), which returns the face from the first entry in the source map or the primary source image. This single source face is then paired with every detected target face in the frame. In map-faces mode, the specific source face defined in each map entry is used instead.

### What is the difference between `source_target_map` and `simple_map` in the codebase?

`source_target_map` is a list of dictionaries containing full face objects and metadata, supporting complex many-to-many relationships and per-frame video mappings. `simple_map` is a processed variant created by `simplify_maps()` that contains parallel lists of source faces and target embeddings, optimized for nearest-neighbor matching using `find_closest_centroid()`. The simple map reduces lookup overhead during real-time processing.

### Can Deep-Live-Cam maintain consistent face swapping for the same person across different frames in a video?

Yes, when using **map-faces mode** with video analysis. The function `get_unique_faces_from_target_video()` extracts embeddings across all frames, clusters them into unique identities using `find_cluster_centroids`, and assigns a consistent source face to each cluster. During playback, `process_frame_v2` matches detected faces to these centroids, ensuring the same source face swaps onto the same target identity throughout the video sequence.

### Where is the face detection backend implemented in the source code?

The detection backend is implemented in [`modules/face_analyser.py`](https://github.com/hacksider/Deep-Live-Cam/blob/main/modules/face_analyser.py), which wraps the InsightFace library. This module provides `get_one_face()` for single-face detection and `get_many_faces()` for multi-face detection. The detection results (face embeddings and bounding boxes) are then consumed by [`modules/processors/frame/face_swapper.py`](https://github.com/hacksider/Deep-Live-Cam/blob/main/modules/processors/frame/face_swapper.py) to execute the actual swapping logic.