Akshayram1's picture
Update app.py
c060c9e verified
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)}")