DEV Community

Cover image for Face Swap in Python: Batch Swap One Face onto Templates
AI Engine
AI Engine

Posted on Originally published at ai-engine.net

Face Swap in Python: Batch Swap One Face onto Templates

Personalized avatar packs and themed profile pictures need the same thing: one user's face placed on many template images. This tutorial builds that in Python. You give the script a selfie and a folder of templates, and it saves one swapped image per template, with no GPU and no model to install.

All the code was run against the live Face Swap API, and the results shown are its real output.

Before and after pairs for two templates with the source face swapped in

The batch script

You need pip install requests, a RapidAPI key, a selfie.jpg and a templates/ folder of JPG images.

from concurrent.futures import ThreadPoolExecutor
from pathlib import Path

import requests

BASE = "https://deepfake-face-swap-ai.p.rapidapi.com"
HEADERS = {
    "x-rapidapi-host": "deepfake-face-swap-ai.p.rapidapi.com",
    "x-rapidapi-key": "YOUR_API_KEY",
}
WORKERS = 4


def swap_face(source_path, target_path):
    """Swap the face from source_path onto target_path, return the result URL."""
    with open(source_path, "rb") as source, open(target_path, "rb") as target:
        response = requests.post(
            f"{BASE}/swap-face",
            headers=HEADERS,
            files={
                "source_image": ("source.jpg", source, "image/jpeg"),
                "target_image": ("target.jpg", target, "image/jpeg"),
            },
            timeout=120,
        )
    response.raise_for_status()
    return response.json()["image_url"]


def has_face(image_path):
    """Return True if the image contains at least one face."""
    with open(image_path, "rb") as image:
        response = requests.post(
            f"{BASE}/detect-faces",
            headers=HEADERS,
            files={"image": ("image.jpg", image, "image/jpeg")},
            timeout=60,
        )
    return response.ok and response.json().get("total_faces", 0) > 0


def process_template(selfie, template, output_dir):
    if not has_face(template):
        return template.name, "skipped: no face"
    url = swap_face(selfie, template)
    output = output_dir / template.name
    output.write_bytes(requests.get(url, timeout=60).content)
    return template.name, f"saved {output}"


def swap_onto_templates(selfie, template_dir, output_dir):
    output_dir = Path(output_dir)
    output_dir.mkdir(exist_ok=True)
    templates = sorted(Path(template_dir).glob("*.jpg"))
    with ThreadPoolExecutor(max_workers=WORKERS) as pool:
        jobs = [
            pool.submit(process_template, selfie, template, output_dir)
            for template in templates
        ]
        return [job.result() for job in jobs]


if __name__ == "__main__":
    for name, status in swap_onto_templates("selfie.jpg", "templates", "output"):
        print(f"{name}: {status}")
Enter fullscreen mode Exit fullscreen mode

has_face skips any template with no face, so the batch carries on, and four worker threads run the swaps side by side.

Real results

One selfie and six templates: five portraits and one photo with no face, to test the skip.

casual.jpg: saved output/casual.jpg
no_face.jpg: skipped: no face
office.jpg: saved output/office.jpg
outdoor.jpg: saved output/outdoor.jpg
sofa.jpg: saved output/sofa.jpg
suit.jpg: saved output/suit.jpg
Enter fullscreen mode Exit fullscreen mode

Each result keeps the template's pose, clothes, glasses and lighting, and takes the face from the selfie.

Using image URLs

If your images are already hosted, send the URLs as form fields:

import requests

response = requests.post(
    "https://deepfake-face-swap-ai.p.rapidapi.com/swap-face",
    headers={
        "x-rapidapi-host": "deepfake-face-swap-ai.p.rapidapi.com",
        "x-rapidapi-key": "YOUR_API_KEY",
    },
    data={
        "source_url": "https://images.pexels.com/photos/614810/pexels-photo-614810.jpeg?w=800",
        "target_url": "https://images.pexels.com/photos/2182970/pexels-photo-2182970.jpeg?w=800",
    },
    timeout=120,
)
print(response.json())
Enter fullscreen mode Exit fullscreen mode
{'image_url': 'https://images.ai-engine.net/face-swap-ai/6ae31bb6-6517-4f79-a481-47982e2afdd5.jpg', 'width': 800, 'height': 1200, 'size_bytes': 131991}
Enter fullscreen mode Exit fullscreen mode

Production tips

  • Copy each result to your own storage, as the script does.
  • Handle HTTP 422: a template with no face returns No face detected in target image.
  • Use front-facing or three-quarter portraits as templates for a natural result.

Use it with consent

Only swap the face of someone who has agreed to it, which is the natural flow when users upload their own selfie. Use templates you have the rights to, tell people when an image has been generated, and never use face swap to impersonate anyone.

Test photos come from Pexels. Full tutorial with before and after images: Face swap in Python on ai-engine.net.

Grab a key from the Face Swap API page and point the script at your own templates.

Top comments (0)