DEV Community

Edgaras
Edgaras

Posted on

2 1

Face Recognition with Python and FaceNet

This guide demonstrates how to use facenet-pytorch to implement a tool for detecting face similarity. Built on the FaceNet model, which generates high-quality face embeddings, the tool compares a target image with multiple pictures to identify the most similar face. Here the process to get started.
**
Key Tools and Libraries**

  1. PyTorch: For deep learning operations.
  2. FaceNet-PyTorch: Provides pre-trained models for face detection and embedding.
  3. Pillow (PIL): For image manipulation.
  4. Matplotlib: For visualizing results.

We'll use two main models:

  • MTCNN: For detecting faces.
  • InceptionResnetV1: For extracting face embeddings.

Initialization

import torch
from facenet_pytorch import MTCNN, InceptionResnetV1
from PIL import Image
import requests
from io import BytesIO
import matplotlib.pyplot as plt

# Initialize the MTCNN module for face detection and the InceptionResnetV1 module for face embedding.
mtcnn = MTCNN(image_size=160, keep_all=True)
resnet = InceptionResnetV1(pretrained='vggface2').eval()
Enter fullscreen mode Exit fullscreen mode

Function Definitions

1. Load Image and Extract Embedding:
This function loads an image from a URL, detects the face, and computes the embedding.

def get_embedding_and_face(image_path):
    """Load an image, detect the face, and return the embedding and face."""
    try:
        response = requests.get(image_path)
        response.raise_for_status()
        content_type = response.headers.get('Content-Type')
        if 'image' not in content_type:
            raise ValueError(f"URL does not point to an image: {content_type}")
        image = Image.open(BytesIO(response.content)).convert("RGB")
    except Exception as e:
        print(f"Error loading image from {image_path}: {e}")
        return None, None

    faces, probs = mtcnn(image, return_prob=True)
    if faces is None or len(faces) == 0:
        return None, None

    embedding = resnet(faces[0].unsqueeze(0))
    return embedding, faces[0]
Enter fullscreen mode Exit fullscreen mode

2. Convert Tensor to Image:
This function prepares a tensor for visualization.

def tensor_to_image(tensor):
    """Convert a normalized tensor to a valid image array."""
    image = tensor.permute(1, 2, 0).detach().numpy()
    image = (image - image.min()) / (image.max() - image.min())
    image = (image * 255).astype('uint8')
    return image
Enter fullscreen mode Exit fullscreen mode

3. Find the Most Similar Face:
This function compares the embeddings of the target image with the candidates.

def find_most_similar(target_image_path, candidate_image_paths):
    """Find the most similar image to the target image from a list of candidate images."""
    target_emb, target_face = get_embedding_and_face(target_image_path)
    if target_emb is None:
        raise ValueError("No face detected in the target image.")

    highest_similarity = float('-inf')
    most_similar_face = None
    most_similar_image_path = None

    candidate_faces = []
    similarities = []

    for candidate_image_path in candidate_image_paths:
        candidate_emb, candidate_face = get_embedding_and_face(candidate_image_path)
        if candidate_emb is None:
            similarities.append(None)
            candidate_faces.append(None)
            continue

        similarity = torch.nn.functional.cosine_similarity(target_emb, candidate_emb).item()
        similarities.append(similarity)
        candidate_faces.append(candidate_face)

        if similarity > highest_similarity:
            highest_similarity = similarity
            most_similar_face = candidate_face
            most_similar_image_path = candidate_image_path

    # Visualization
    plt.figure(figsize=(12, 8))

    # Display target image
    plt.subplot(2, len(candidate_image_paths) + 1, 1)
    plt.imshow(tensor_to_image(target_face))
    plt.title("Target Image")
    plt.axis("off")

    # Display most similar image
    if most_similar_face is not None:
        plt.subplot(2, len(candidate_image_paths) + 1, 2)
        plt.imshow(tensor_to_image(most_similar_face))
        plt.title("Most Similar")
        plt.axis("off")

    # Display all candidate images with similarity scores
    for idx, (candidate_face, similarity) in enumerate(zip(candidate_faces, similarities)):
        plt.subplot(2, len(candidate_image_paths) + 1, idx + len(candidate_image_paths) + 2)
        if candidate_face is not None:
            plt.imshow(tensor_to_image(candidate_face))
            plt.title(f"Score: {similarity * 100:.2f}%")
        else:
            plt.title("No Face")
        plt.axis("off")

    plt.tight_layout()
    plt.show()

    if most_similar_image_path is None:
        raise ValueError("No faces detected in the candidate images.")

    return most_similar_image_path, highest_similarity
Enter fullscreen mode Exit fullscreen mode

Usage

URLs of the images to compare:

image_url_target = 'https://d1mnxluw9mpf9w.cloudfront.net/media/7588/4x3/1200.jpg'
candidate_image_urls = [
    'https://beyondthesinglestory.wordpress.com/wp-content/uploads/2021/04/elon_musk_royal_society_crop1.jpg',
    'https://cdn.britannica.com/56/199056-050-CCC44482/Jeff-Bezos-2017.jpg',
    'https://cdn.britannica.com/45/188745-050-7B822E21/Richard-Branson-2003.jpg'
]

most_similar_image, similarity_score = find_most_similar(image_url_target, candidate_image_urls)
print(f"The most similar image is: {most_similar_image}")
print(f"Similarity score: {similarity_score * 100:.2f}%")
Enter fullscreen mode Exit fullscreen mode

Result

Image description

Conclusion

This example demonstrates the power of facenet-pytorch for facial recognition tasks. By combining face detection and embedding, we can create tools for various applications, such as identity verification, or content filtering.

Do your career a big favor. Join DEV. (The website you're on right now)

It takes one minute, it's free, and is worth it for your career.

Get started

Community matters

Top comments (0)

👋 Kindness is contagious

Discover a treasure trove of wisdom within this insightful piece, highly respected in the nurturing DEV Community enviroment. Developers, whether novice or expert, are encouraged to participate and add to our shared knowledge basin.

A simple "thank you" can illuminate someone's day. Express your appreciation in the comments section!

On DEV, sharing ideas smoothens our journey and strengthens our community ties. Learn something useful? Offering a quick thanks to the author is deeply appreciated.

Okay