File size: 8,121 Bytes
70e9024
 
 
 
c060c9e
70e9024
c060c9e
0152ef9
 
70e9024
0152ef9
70e9024
 
 
c060c9e
0152ef9
 
 
 
c060c9e
0152ef9
 
c060c9e
 
 
 
 
 
f531490
 
c060c9e
0152ef9
 
 
c060c9e
 
 
f531490
 
c060c9e
0152ef9
 
 
 
c060c9e
0152ef9
 
 
 
c060c9e
0152ef9
 
 
 
f531490
 
c060c9e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
0152ef9
c060c9e
0152ef9
70e9024
 
0152ef9
c060c9e
 
f531490
c060c9e
 
 
f531490
 
 
c060c9e
0152ef9
c060c9e
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
f531490
 
c060c9e
 
0152ef9
c060c9e
 
 
 
 
 
 
 
 
0152ef9
f531490
c060c9e
 
 
 
 
0152ef9
c060c9e
 
 
 
 
 
 
 
 
f531490
 
0152ef9
 
 
 
 
 
f531490
0152ef9
 
 
 
 
f531490
 
 
 
 
0152ef9
f531490
0152ef9
f531490
70e9024
 
c060c9e
70e9024
 
0152ef9
f531490
 
 
0152ef9
 
f531490
0152ef9
f531490
0152ef9
 
c060c9e
70e9024
f531490
c060c9e
0152ef9
 
 
 
 
 
70e9024
f531490
0152ef9
 
 
 
 
c060c9e
 
0152ef9
f531490
 
 
 
 
c060c9e
f531490
 
 
 
c060c9e
f531490
 
 
 
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
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
import os
import cv2
import mediapipe as mp
import streamlit as st
from PIL import Image
import numpy as np
import face_recognition
import pandas as pd
from datetime import datetime

# Initialize MediaPipe
mp_face_detection = mp.solutions.face_detection
mp_drawing = mp.solutions.drawing_utils

# Function to create user database directory if it doesn't exist
def initialize_database():
    if not os.path.exists("database"):
        os.makedirs("database")
    if not os.path.exists("database/records.csv"):
        df = pd.DataFrame(columns=['name', 'image_path', 'encoding', 'date_added'])
        df.to_csv("database/records.csv", index=False)

# Function to compute face encoding
def get_face_encoding(image):
    rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    encodings = face_recognition.face_encodings(rgb_image)
    if encodings:
        return encodings[0]
    return None

# Function to add face to database
def add_to_database(image, name):
    initialize_database()
    
    # Get face encoding
    encoding = get_face_encoding(image)
    if encoding is None:
        return None, "No face detected in the image"
    
    # Save image to database folder
    timestamp = datetime.now().strftime("%Y%m%d_%H%M%S")
    image_path = f"database/{name}_{timestamp}.jpg"
    cv2.imwrite(image_path, image)
    
    # Update records
    df = pd.read_csv("database/records.csv")
    new_record = pd.DataFrame({
        'name': [name],
        'image_path': [image_path],
        'encoding': [encoding.tolist()],
        'date_added': [datetime.now().strftime("%Y-%m-%d %H:%M:%S")]
    })
    df = pd.concat([df, new_record], ignore_index=True)
    df.to_csv("database/records.csv", index=False)
    return image_path, "Successfully added to database"

def find_best_match(face_encoding, known_encodings, known_names, tolerance=0.6):
    """
    Find the best match for a face encoding among known encodings
    Returns name and confidence score of the best match, or None if no match found
    """
    if not known_encodings or not known_names:
        return None, 0
    
    # Calculate face distances
    face_distances = face_recognition.face_distance(known_encodings, face_encoding)
    
    if len(face_distances) > 0:
        best_match_index = np.argmin(face_distances)
        best_match_distance = face_distances[best_match_index]
        
        # Convert distance to confidence score (0-100%)
        confidence = (1 - best_match_distance) * 100
        
        # Only return match if distance is below tolerance
        if best_match_distance <= tolerance:
            return known_names[best_match_index], confidence
    
    return None, 0

# Function to detect faces and perform recognition
def detect_and_recognize_faces(image, output_folder="output"):
    if not os.path.exists(output_folder):
        os.makedirs(output_folder)
    
    # Convert image to RGB
    rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
    
    # Get face locations and encodings
    face_locations = face_recognition.face_locations(rgb_image, model="cnn")
    face_encodings = face_recognition.face_encodings(rgb_image, face_locations)
    
    face_images = []
    face_results = []
    recognition_details = []
    
    # Load database
    try:
        df = pd.read_csv("database/records.csv")
        if not df.empty:
            known_encodings = [np.array(eval(enc)) for enc in df['encoding']]
            known_names = df['name'].tolist()
        else:
            known_encodings = []
            known_names = []
    except Exception as e:
        st.error(f"Error loading database: {str(e)}")
        known_encodings = []
        known_names = []
    
    # Process each detected face
    for idx, (face_location, face_encoding) in enumerate(zip(face_locations, face_encodings)):
        top, right, bottom, left = face_location
        
        # Extract and save face image
        face_image = image[top:bottom, left:right]
        face_images.append(face_image)
        
        face_output_path = os.path.join(output_folder, f"face_{idx+1}.jpg")
        cv2.imwrite(face_output_path, face_image)
        
        # Find best match
        matched_name, confidence = find_best_match(face_encoding, known_encodings, known_names)
        
        if matched_name and confidence > 0:
            result = f"Match: {matched_name}\nConfidence: {confidence:.1f}%"
            color = (36, 255, 12)  # Green for match
        else:
            result = "No match in database"
            color = (0, 0, 255)    # Red for no match
            
        face_results.append(result)
        recognition_details.append({
            'location': (left, top, right, bottom),
            'color': color,
            'text': result.split('\n')[0]
        })
        
    # Draw results on image
    for detail in recognition_details:
        left, top, right, bottom = detail['location']
        # Draw rectangle around face
        cv2.rectangle(image, (left, top), (right, bottom), detail['color'], 2)
        # Draw text above face
        cv2.putText(image, detail['text'], 
                    (left, max(0, top - 10)),
                    cv2.FONT_HERSHEY_SIMPLEX, 0.6, detail['color'], 2)
    
    return image, face_images, face_results

# Streamlit UI
st.title("Face Recognition System")

# Sidebar for database management
st.sidebar.header("Database Management")
upload_for_db = st.sidebar.file_uploader("Add face to database", type=["jpg", "jpeg", "png"], key="db_uploader")
if upload_for_db:
    person_name = st.sidebar.text_input("Enter person's name")
    if st.sidebar.button("Add to Database") and person_name:
        file_bytes = np.asarray(bytearray(upload_for_db.read()), dtype=np.uint8)
        img = cv2.imdecode(file_bytes, 1)
        image_path, message = add_to_database(img, person_name)
        if image_path:
            st.sidebar.success(f"Added {person_name} to database!")
        else:
            st.sidebar.error(message)

# Main interface
st.header("Face Detection and Recognition")
uploaded_file = st.file_uploader("Choose an image for recognition", type=["jpg", "jpeg", "png"], key="recognition_uploader")

if uploaded_file is not None:
    # Load and process image
    file_bytes = np.asarray(bytearray(uploaded_file.read()), dtype=np.uint8)
    image = cv2.imdecode(file_bytes, 1)
    
    with st.spinner("Processing image..."):
        output_folder = "output"
        detected_image, face_images, face_results = detect_and_recognize_faces(image, output_folder)
    
    # Display results
    st.subheader("Recognition Results")
    st.image(cv2.cvtColor(detected_image, cv2.COLOR_BGR2RGB), 
             caption="Processed Image", 
             use_column_width=True)
    
    # Display extracted faces and results
    if face_images:
        st.subheader("Detected Faces")
        cols = st.columns(min(len(face_images), 4))  # Limit to 4 columns max
        for idx, (face, result, col) in enumerate(zip(face_images, face_results, cols)):
            with col:
                st.image(cv2.cvtColor(face, cv2.COLOR_BGR2RGB), 
                        caption=f"Face {idx+1}", 
                        use_column_width=True)
                st.write(result)
    else:
        st.warning("No faces detected in the image.")

# Display database contents
if st.sidebar.checkbox("Show Database Contents"):
    try:
        df = pd.read_csv("database/records.csv")
        display_df = df.drop('encoding', axis=1)  # Don't show encodings
        st.sidebar.dataframe(display_df)
    except:
        st.sidebar.write("Database is empty or not initialized.")

# Add clear database button
if st.sidebar.button("Clear Database"):
    try:
        # Remove all files in database directory
        for file in os.listdir("database"):
            file_path = os.path.join("database", file)
            if os.path.isfile(file_path):
                os.remove(file_path)
        # Reinitialize database
        initialize_database()
        st.sidebar.success("Database cleared successfully!")
    except Exception as e:
        st.sidebar.error(f"Error clearing database: {str(e)}")