facial_model / app /final_facial_model.py
Haryiank's picture
Upload 14 files
c08f9a0 verified
import cv2
import joblib
import time
import json
from microexpression_tracker import track_microexpressions, get_lip_engagement
from collections import Counter
import mediapipe as mp
import numpy as np
# --- Load microexpression calibration ---
with open('user_calibration.json', 'r') as f:
calibration_ref = json.load(f)
# --- Load your ELM model and scaler ---
# (Commented out for now)
# elm_model = joblib.load("src/model_fer.pkl")
# scaler = joblib.load("src/scaler_fer.pkl")
IMG_SIZE = 96 # use same as in training
SESSION_DURATION = 15 # seconds
EYE_AWAY_THRESHOLD = 20
HEAD_TURN_THRESHOLD = 20
def preprocess_for_model(frame):
img = cv2.resize(frame, (IMG_SIZE, IMG_SIZE))
img = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
img = img.astype(np.float32) / 255.0
img = img.flatten().reshape(1, -1)
return img
cap = cv2.VideoCapture(0)
print("\n📸 Welcome! Press SPACE to start stress & engagement analysis.")
while True:
ret, frame = cap.read()
if not ret:
continue
cv2.putText(frame, "Press SPACE to start", (60, 60), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2)
cv2.imshow("Webcam", frame)
if cv2.waitKey(1) & 0xFF == 32:
break
print("\n🟡 Session started. Look at the screen for 15 seconds.")
session_start = time.time()
mp_face_mesh = mp.solutions.face_mesh
face_mesh = mp_face_mesh.FaceMesh(static_image_mode=False, max_num_faces=1)
eye_away_count = 0
head_turn_count = 0
engagement_predictions = [] # Not used if ELM is commented out, but kept for completeness
lip_engagement_predictions = []
while time.time() - session_start < SESSION_DURATION:
ret, frame = cap.read()
if not ret:
continue
# --- Microexpression detection ---
micro, face_bbox, multiple_faces = track_microexpressions(frame, face_mesh, calibration_ref)
# --- Lip engagement detection ---
h, w, _ = frame.shape
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results = face_mesh.process(frame_rgb)
lip_engagement = "No Face"
if results.multi_face_landmarks:
landmarks = [(lm.x, lm.y) for lm in results.multi_face_landmarks[0].landmark]
lip_engagement = get_lip_engagement(landmarks)
lip_engagement_predictions.append(lip_engagement)
if face_bbox:
cv2.rectangle(frame, (face_bbox[0], face_bbox[1]), (face_bbox[2], face_bbox[3]), (0,255,0), 2)
else:
lip_engagement_predictions.append("No Face")
landmarks = None
if micro["eye_away"]:
eye_away_count += 1
if micro["head_turn"]:
head_turn_count += 1
if multiple_faces:
cv2.putText(frame, "Multiple faces detected!", (20, 450), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,0,255), 3)
elapsed = int(time.time() - session_start)
cv2.putText(frame, f"Time left: {SESSION_DURATION-elapsed}s", (20, 50), cv2.FONT_HERSHEY_SIMPLEX, 1, (255,255,255), 2)
cv2.putText(frame, f"Engagement: {lip_engagement}", (20, 130), cv2.FONT_HERSHEY_SIMPLEX, 1, (0,255,0), 2)
cv2.imshow('SafeSpace Session', frame)
print(f"Frame: {len(lip_engagement_predictions)} | Engagement: {lip_engagement}")
if cv2.waitKey(1) & 0xFF == ord('q'):
break
cap.release()
cv2.destroyAllWindows()
# --- Summarize Lip Engagement Results (Safe & Robust) ---
lip_counts = Counter(lip_engagement_predictions)
# Remove "No Face" for reporting majority, if present
lip_counts_no_face = Counter({k: v for k, v in lip_counts.items() if k != "No Face"})
lip_total = sum(lip_counts_no_face.values())
if lip_total > 0:
for label in ["Engaged", "Partially Engaged", "Not Engaged"]:
print(f"Engagement {label}: {lip_counts_no_face.get(label,0)} frames ({(lip_counts_no_face.get(label,0)/lip_total)*100:.1f}%)")
lip_majority_label = lip_counts_no_face.most_common(1)[0][0]
else:
print("No valid engagement predictions to summarize.")
lip_majority_label = "No Face"
# --- Microexpression-based feedback ---
if 10 < eye_away_count < 20 and 10 < head_turn_count < 20:
print(f"\nEye distraction detected some times in session.")
print(f"Head turn detected some times in session.")
if eye_away_count > EYE_AWAY_THRESHOLD:
print(f"\nEye distraction detected many times in session.")
if head_turn_count > HEAD_TURN_THRESHOLD:
print(f"Head turn detected many times in session.")
# --- Final Hybrid Result (using only lips & microexpression, as ELM is off) ---
hybrid_result = lip_majority_label
# Apply microexpression override
if eye_away_count > EYE_AWAY_THRESHOLD or head_turn_count > HEAD_TURN_THRESHOLD:
if hybrid_result == "Engaged":
hybrid_result = "Partially Engaged"
elif hybrid_result == "Partially Engaged":
hybrid_result = "Not Engaged"
print(f"\n✅ Final Conclusion (with Microexpressions): {hybrid_result}")