File size: 5,072 Bytes
0f813fa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f06634b
 
 
 
0f813fa
 
 
 
f06634b
 
 
 
 
 
0f813fa
 
f06634b
 
 
 
0f813fa
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f06634b
0f813fa
f06634b
 
 
 
 
 
 
 
 
 
0f813fa
f06634b
 
 
 
 
 
 
 
0f813fa
f06634b
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
import face_recognition
import numpy as np
import pickle
from mtcnn import MTCNN
from PIL import Image
import cv2
import faiss
import imgaug.augmenters as iaa
import os
import gradio as gr

def detect_and_align_face(image_path):
    detector = MTCNN()
    image = cv2.imread(image_path)
    image_rgb = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    detections = detector.detect_faces(image_rgb)
    
    if len(detections) == 0:
        raise ValueError("No face detected in the image.")
    
    detection = detections[0]
    x, y, width, height = detection['box']
    keypoints = detection['keypoints']
    face = image_rgb[y:y+height, x:x+width]
    
    left_eye = keypoints['left_eye']
    right_eye = keypoints['right_eye']
    delta_x = right_eye[0] - left_eye[0]
    delta_y = right_eye[1] - left_eye[1]
    angle = np.arctan2(delta_y, delta_x) * (180.0 / np.pi)
    
    center = ((x + x + width) // 2, (y + y + height) // 2)
    rot_matrix = cv2.getRotationMatrix2D(center, angle, scale=1.0)
    aligned_image = cv2.warpAffine(image_rgb, rot_matrix, (image_rgb.shape[1], image_rgb.shape[0]))
    aligned_face = aligned_image[y:y+height, x:x+width]
    
    return Image.fromarray(aligned_face)

def load_encodings(file_path):
    with open(file_path, "rb") as file:
        data = pickle.load(file)
    return np.array(data["encodings"]), data["labels"]

def save_encodings(encodings, labels, file_path):
    data = {"encodings": encodings, "labels": labels}
    with open(file_path, "wb") as file:
        pickle.dump(data, file)

def create_faiss_index(known_encodings):
    dimension = known_encodings.shape[1]
    index = faiss.IndexFlatL2(dimension)
    index.add(known_encodings)
    return index

def encode_face(image):
    img_array = np.array(image)
    encodings = face_recognition.face_encodings(img_array)
    return encodings[0] if encodings else None

def augment_image(image, num_augmented=5):
    image = np.array(image)
    aug = iaa.Sequential([
        iaa.Fliplr(0.5),  # horizontal flips
        iaa.Affine(rotate=(-25, 25)),  # rotation
        iaa.AdditiveGaussianNoise(scale=(0, 0.05*255)),  # noise
        iaa.Multiply((0.8, 1.2)),  # brightness
        iaa.GaussianBlur(sigma=(0.0, 1.0))  # blur
    ])
    augmented_images = [Image.fromarray(aug(image=image)) for _ in range(num_augmented)]
    return augmented_images

def update_dataset_with_verified_image(image, encodings_file, label, num_augmented=5):
    known_encodings, known_labels = load_encodings(encodings_file)
    augmented_images = augment_image(image, num_augmented=num_augmented)
    images_to_encode = [image] + augmented_images
    for img in images_to_encode:
        img_array = np.array(img)
        encoding = face_recognition.face_encodings(img_array)
        if encoding:
            known_encodings = np.append(known_encodings, [encoding[0]], axis=0)
            known_labels.append(label)
    save_encodings(known_encodings, known_labels, encodings_file)

def verify_face_with_faiss(image, encodings_file, similarity_threshold=70, num_augmented=5):
    aligned_face = image.convert("RGB")
    target_encodings = face_recognition.face_encodings(np.array(aligned_face))
    
    if not target_encodings:
        return False, "No face detected in the provided image. Please try with another image."
    
    target_encoding = target_encodings[0].reshape(1, -1)
    
    known_encodings, known_labels = load_encodings(encodings_file)
    
    if len(known_encodings) == 0:
        return False, "No known faces in the database. Please add some faces first."
    
    known_encodings = np.array(known_encodings)
    
    index = create_faiss_index(known_encodings)
    
    distances, indices = index.search(target_encoding, 1)
    
    best_match_index = indices[0][0]
    best_similarity_percentage = (1 - distances[0][0]) * 100
    
    is_match = best_similarity_percentage >= similarity_threshold
    
    if is_match:
        matched_label = known_labels[best_match_index]
        update_dataset_with_verified_image(image, encodings_file, matched_label, num_augmented=num_augmented)
        return True, f"Match found: {matched_label}, Similarity: {best_similarity_percentage:.2f}%"
    else:
        return False, "No match found."

# Gradio Interface Function
def gradio_interface(image, similarity_threshold=70):
    if image is None:
        return "Error: No image provided. Please upload an image or take one using the webcam."
    
    encodings_file = "./face_encoding.pkl"
    
    try:
        result, message = verify_face_with_faiss(image, encodings_file, similarity_threshold=similarity_threshold)
        return message
    except Exception as e:
        return f"An error occurred: {str(e)}"

# Gradio Interface Setup
iface = gr.Interface(
    fn=gradio_interface, 
    inputs=[gr.Image(type="pil"), gr.Slider(0, 100, value=70, label="Similarity Threshold")], 
    outputs="text", 
    title="Face Recognition with MTCNN and FAISS",
    description="Upload an image to see if it matches any face in the database."
)

iface.launch(share=True)