import gradio as gr from flask import Flask, Response import cv2 import numpy as np import mediapipe as mp import matplotlib.pyplot as plt import math from IPython import display # -------------------- MAX_ANGLE = 10 # -------------------- # -------------------- # -------------------- # -------------------- def distanceCalculate(p): p1 = p[0] p2 = p[1] dis = ((p2[0] - p1[0]) ** 2 + (p2[1] - p1[1]) ** 2) ** 0.5 return dis # -------------------- def angleLinePoints(p): p1 = p[0] p2 = p[1] # p1_x = p1[0] p1_y = p1[1] p2_x = p2[0] p2_y = p2[1] # d_x = p2_x - p1_x d_y = p2_y - p1_y # angle_radians = np.arctan(d_y/d_x) angle_degrees = math.degrees(angle_radians) return angle_degrees # -------------------- def process_image(image): if isinstance(image, str): image = cv2.imread(image) # (B, G, R) = cv2.split(image) mp_face_mesh = mp.solutions.face_mesh face_mesh = mp_face_mesh.FaceMesh( static_image_mode=True, max_num_faces=1, refine_landmarks=True, min_detection_confidence=0.5) result = face_mesh.process(cv2.cvtColor(image, cv2.COLOR_BGR2RGB)) height, width, _ = image.shape mesh_points= np.array([np.multiply([p.x, p.y], [width, height]).astype(int) for p in result.multi_face_landmarks[0].landmark]) # Landmark mapping landmarks = { 'topToBottom': [10, 152], 'leftToRight': [234, 454], 'rightEyeIris': [473, 474, 475, 476, 477], 'leftEyeIris': [468, 469, 470, 471, 472], 'outerRightEyebrowUpper': 70, 'outerLeftEyebrowUpper': 300, 'silhouette': [10, 338, 297, 332, 284, 251, 389, 356, 454, 323, 361, 288, 397, 365, 379, 378, 400, 377, 152, 148, 176, 149, 150, 136, 172, 58, 132, 93, 234, 127, 162, 21, 54, 103, 67, 109]} # Iris location (l_cx, l_cy), l_radius = cv2.minEnclosingCircle(mesh_points[landmarks['rightEyeIris']]) (r_cx, r_cy), r_radius = cv2.minEnclosingCircle(mesh_points[landmarks['leftEyeIris']]) center_left_iris = np.array([l_cx, l_cy], dtype=np.int32) center_right_iris = np.array([r_cx, r_cy], dtype=np.int32) # Face dimension width_face_px = distanceCalculate(mesh_points[landmarks['leftToRight']]) height_face_px = distanceCalculate(mesh_points[landmarks['topToBottom']]) # IPD calculation ipd = distanceCalculate([center_left_iris, center_right_iris]) # Photo Quality Check vertical_angle = angleLinePoints(mesh_points[landmarks['topToBottom']]) horizonal_angle = angleLinePoints(mesh_points[landmarks['leftToRight']]) # Rectangle for Card Area x_start = mesh_points[landmarks['outerRightEyebrowUpper']][0] y_start = mesh_points[landmarks['outerRightEyebrowUpper']][1] - 0.6*height_face_px x_end, y_end = mesh_points[landmarks['outerLeftEyebrowUpper']] start_point = (int(x_start), int(y_start)) end_point = (int(x_end), int(y_end)) # overlay = image.copy() alpha = 0.1 beta = (1.0 - alpha) # Plot all the information # plt.imshow(image) # plt.imshow(image_landmarks) for facial_landmarks in result.multi_face_landmarks: for i in range(0, 468): pt1 = facial_landmarks.landmark[i] x = int(pt1.x * width) y = int(pt1.y * height) cv2.circle(image, (x, y), 1, (0,255,0), -1) plt.imshow(cv2.polylines(image, [mesh_points[landmarks['topToBottom']]], 1, (0,255,0), 1)) plt.imshow(cv2.polylines(image, [mesh_points[landmarks['leftToRight']]], 1, (0,255,0), 1)) plt.imshow(cv2.polylines(image, [mesh_points[landmarks['silhouette']]], 1, (0,255,0), 1)) plt.imshow(cv2.line(image, center_left_iris, center_right_iris, (0, 255, 0), 2)) plt.imshow(cv2.line(image, mesh_points[landmarks['outerLeftEyebrowUpper']], mesh_points[landmarks['outerRightEyebrowUpper']], (0, 255, 0), 1)) plt.imshow(cv2.rectangle(image, start_point, end_point, (255,0,0), 1)) plt.imshow(cv2.ellipse(image, center=(int(width/2), int(height/2)), axes=(int(min(width,height)/4),int(min(width,height)/3)), angle=0, startAngle=0, endAngle=360, color=(255,255,255), thickness=4)) plt.imshow(cv2.putText(image, f'IPD: {str(ipd)} [px]', (50,50), cv2.FONT_HERSHEY_PLAIN,1, (0,0,0), 1)) plt.imshow(cv2.putText(image, f'Face Height: {str(height_face_px)} [px]', (50,100), cv2.FONT_HERSHEY_PLAIN,1, (0,0,0),1)) plt.imshow(cv2.putText(image, f'Face Width: {str(width_face_px)} [px]', (50,150), cv2.FONT_HERSHEY_PLAIN,1, (0,0,0), 1)) if abs(horizonal_angle) < MAX_ANGLE: plt.imshow(cv2.putText(image, f'Horizonal Angle: {str(horizonal_angle)} [degrees]', (50,200), cv2.FONT_HERSHEY_PLAIN,1, (0,255,0), 1)) cv2.rectangle(overlay, (0,0), (width, height), (0, 255, 0), -1) image = cv2.addWeighted(overlay, alpha, image, 1 - alpha, 0) elif horizonal_angle < -MAX_ANGLE: plt.imshow(cv2.arrowedLine(image,[int(x_start) - (int(min(width,height)/4)),int(y_start+ height_face_px/2)], [int(x_start), int(y_start+ height_face_px/2)], (0, 255, 0), 4)) plt.imshow(cv2.putText(image, f'Horizonal Angle: {str(horizonal_angle)} [degrees]', (50,200), cv2.FONT_HERSHEY_PLAIN,1, (0,0,255), 1)) cv2.rectangle(overlay, (0,0), (width, height), (0, 0, 255), -1) image = cv2.addWeighted(overlay, alpha, image, 1 - alpha, 0) plt.imshow(image) elif horizonal_angle > MAX_ANGLE: plt.imshow(cv2.arrowedLine(image, [int(x_start), int(y_start+ height_face_px/2)],[int(x_start) - (int(min(width,height)/4)),int(y_start+ height_face_px/2)], (0, 255, 0), 4)) plt.imshow(cv2.putText(image, f'Horizonal Angle: {str(horizonal_angle)} [degrees]', (50,200), cv2.FONT_HERSHEY_PLAIN,1, (0,0,255), 1)) cv2.rectangle(overlay, (0,0), (width, height), (0, 0, 255), -1) image = cv2.addWeighted(overlay, alpha, image, 1 - alpha, 0) plt.imshow(image) if abs(vertical_angle) > (90 - MAX_ANGLE): #[-80, 80] -> okay plt.imshow(cv2.putText(image, f'Vertical Angle: {str(vertical_angle)} [degrees]', (50,250), cv2.FONT_HERSHEY_PLAIN,1, (0,255,0), 1)) else: plt.imshow(cv2.putText(image, f'Vertical Angle: {str(vertical_angle)} [degrees]', (50,250), cv2.FONT_HERSHEY_PLAIN,1, (0,0,255), 1)) # return image # -------------------- # -------------------- # -------------------- # -------------------- def processing_frame(im): image = process_image(im) return image # demo = gr.Interface( processing_frame, gr.Image(source="webcam", streaming=True), "image", live=True ) demo.launch()