contact_lens / app.py
Medvira's picture
Update app.py
6d1e1df verified
import os
import sys
import traceback
import gradio as gr
import cv2 as cv
import numpy as np
import time
import mediapipe as mp
from mediapipe.tasks import python
from mediapipe.tasks.python import vision
from utils import blinkRatio,LEFT_EYE,RIGHT_EYE,LEFT_IRIS,RIGHT_IRIS
def custom_excepthook(type, value, tb):
traceback.print_exception(type, value, tb)
sys.__excepthook__(type, value, tb)
sys.excepthook = custom_excepthook
def list_overlay_images(directory):
return [f for f in os.listdir(directory) if f.endswith('.png')]
def process_frame(frame, overlay, results, frame_timestamp_ms=None, task='image', alpha=None):
if results.face_landmarks:
rgba_frame = cv.cvtColor(frame, cv.COLOR_BGR2RGBA)
height, width = rgba_frame.shape[:2]
zero_overlay = np.zeros_like(rgba_frame)
mesh_points = np.array([np.multiply([p.x, p.y],
[width, height]).astype(int) for p in results.face_landmarks[0]])
iris_mask_left = np.zeros(rgba_frame.shape, dtype=np.uint8)
iris_mask_right = np.zeros(rgba_frame.shape, dtype=np.uint8)
_, re_ratio, le_ratio = blinkRatio(frame, mesh_points, RIGHT_EYE, LEFT_EYE)
(l_cx, l_cy), l_radius = cv.minEnclosingCircle(mesh_points[LEFT_IRIS])
(r_cx, r_cy), r_radius = cv.minEnclosingCircle(mesh_points[RIGHT_IRIS])
center_left = (int(l_cx), int(l_cy))
center_right = (int(r_cx), int(r_cy))
cv.circle(iris_mask_left, center_left, int(l_radius), (255, 0, 0, 255), -1, cv.LINE_AA)
cv.circle(iris_mask_right, center_right, int(r_radius), (255, 0, 0, 255), -1, cv.LINE_AA)
bbx_size_l = int((l_radius * 2) / 2)
bbx_size_r = int((r_radius * 2) / 2)
resized_overlay_l = cv.resize(overlay, (bbx_size_l * 2, bbx_size_l * 2), interpolation=cv.INTER_CUBIC)
resized_overlay_r = cv.resize(overlay, (bbx_size_r * 2, bbx_size_r * 2), interpolation=cv.INTER_CUBIC)
y1_r = center_right[1] - bbx_size_r
y2_r = center_right[1] + bbx_size_r
x1_r = center_right[0] - bbx_size_r
x2_r = center_right[0] + bbx_size_r
y1_l = center_left[1] - bbx_size_l
y2_l = center_left[1] + bbx_size_l
x1_l = center_left[0] - bbx_size_l
x2_l = center_left[0] + bbx_size_l
if (resized_overlay_l.shape == zero_overlay[y1_l:y2_l, x1_l:x2_l].shape) & (le_ratio < 5.0) & (le_ratio > 2.0):
zero_overlay[y1_l:y2_l, x1_l:x2_l] = resized_overlay_l
if (resized_overlay_r.shape == zero_overlay[y1_r:y2_r, x1_r:x2_r].shape) & (re_ratio < 5.0) & (re_ratio > 2.0):
zero_overlay[y1_r:y2_r, x1_r:x2_r] = resized_overlay_r
eye_mask_left = np.zeros(rgba_frame.shape, dtype=np.uint8)
eye_mask_right = np.zeros(rgba_frame.shape, dtype=np.uint8)
cv.fillPoly(eye_mask_left, [mesh_points[LEFT_EYE]], (255, 0, 0, 255))
cv.fillPoly(eye_mask_right, [mesh_points[RIGHT_EYE]], (255, 0, 0, 255))
zero_overlay[np.where((iris_mask_left[:, :, 3] > 0) & (eye_mask_left[:, :, 3] == 0))] = 0
zero_overlay[np.where((iris_mask_right[:, :, 3] > 0) & (eye_mask_right[:, :, 3] == 0))] = 0
rgba_frame = cv.addWeighted(rgba_frame, 1, zero_overlay, alpha, 0)
return rgba_frame
def process_image(input_image, overlay_file, alpha=0.3):
model_path = os.path.join(os.getcwd(),'face_landmarker.task')
BaseOptions = mp.tasks.BaseOptions
FaceLandmarker = mp.tasks.vision.FaceLandmarker
FaceLandmarkerOptions = mp.tasks.vision.FaceLandmarkerOptions
VisionRunningMode = mp.tasks.vision.RunningMode
options = FaceLandmarkerOptions(
base_options=BaseOptions(model_asset_path=model_path),
running_mode=VisionRunningMode.IMAGE)
with FaceLandmarker.create_from_options(options) as landmarker:
overlay_file = overlay_file + '.png'
overlay_path = os.path.join(os.getcwd(),'overlays', overlay_file)
overlay = cv.imread(overlay_path, cv.IMREAD_UNCHANGED)
frame = np.array(input_image)
if frame.dtype != np.uint8:
frame = (frame * 255).astype(np.uint8)
rgb_frame = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
mp_frame = mp.Image(image_format=mp.ImageFormat.SRGB, data=rgb_frame)
results = landmarker.detect(mp_frame)
processed_frame = process_frame(frame=frame, overlay=overlay, results=results, alpha=alpha)
return cv.cvtColor(processed_frame, cv.COLOR_BGR2RGB)
def process_video(input_video, overlay_file, alpha=0.3, output_format='mp4', output_frame_rate=30):
model_path = os.path.join(os.getcwd(), 'face_landmarker.task')
BaseOptions = mp.tasks.BaseOptions
FaceLandmarker = mp.tasks.vision.FaceLandmarker
FaceLandmarkerOptions = mp.tasks.vision.FaceLandmarkerOptions
VisionRunningMode = mp.tasks.vision.RunningMode
options = FaceLandmarkerOptions(
base_options=BaseOptions(model_asset_path=model_path),
running_mode=VisionRunningMode.VIDEO)
with FaceLandmarker.create_from_options(options) as landmarker:
overlay_file = overlay_file + '.png'
overlay_path = os.path.join(os.getcwd(), 'overlays', overlay_file)
overlay = cv.imread(overlay_path, cv.IMREAD_UNCHANGED)
cap = cv.VideoCapture(input_video)
output_path = os.path.join(os.getcwd(), f'video_processed.{output_format}')
if overlay is not None and cap.isOpened():
fps = int(output_frame_rate) if output_frame_rate > 0 else cap.get(cv.CAP_PROP_FPS)
h, w = None, None
new_h, new_w = None, None
frame_idx = 0
fourcc = cv.VideoWriter_fourcc(*'mp4v' if output_format == 'mp4' else 'MJPG')
out = cv.VideoWriter(output_path, fourcc, fps, (new_w, new_h))
start_time = time.time()
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
if h is None or w is None:
h, w, _ = frame.shape
new_h = 800
new_w = int((w / h) * new_h)
out = cv.VideoWriter(output_path, fourcc, fps, (new_w, new_h)) # Initialize output writer with correct size
frame = cv.resize(frame, (new_w, new_h), interpolation=cv.INTER_NEAREST)
if frame.dtype != np.uint8:
frame = (frame * 255).astype(np.uint8)
rgb_frame = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
mp_frame = mp.Image(image_format=mp.ImageFormat.SRGB, data=rgb_frame)
timestamp = int(frame_idx * 1000 / fps) # Convert frame index to milliseconds
results = landmarker.detect_for_video(mp_frame, timestamp)
processed_frame = process_frame(frame=frame, overlay=overlay, results=results, alpha=alpha)
processed_frame = cv.cvtColor(processed_frame, cv.COLOR_RGBA2BGR)
out.write(processed_frame)
frame_idx += 1
cap.release()
out.release()
end_time = time.time()
execution_time = end_time - start_time
print(f"Execution time: {execution_time} seconds")
return output_path
def process_webcam(frame, overlay_file, alpha=0.3, min_detection_confidence=0.5, min_tracking_confidence=0.5):
BaseOptions = mp.tasks.BaseOptions
FaceLandmarker = mp.tasks.vision.FaceLandmarker
FaceLandmarkerOptions = mp.tasks.vision.FaceLandmarkerOptions
FaceLandmarkerResult = mp.tasks.vision.FaceLandmarkerResult
VisionRunningMode = mp.tasks.vision.RunningMode
model_path = os.path.join(os.getcwd(), 'face_landmarker.task')
overlay_file = overlay_file + '.png'
overlay_path = os.path.join(os.getcwd(), overlay_file)
overlay = cv.imread(overlay_path, cv.IMREAD_UNCHANGED)
global latest_results
latest_results = None
def return_result(result: FaceLandmarkerResult, output_image: mp.Image, timestamp_ms: int):
global latest_results
latest_results = result
options = FaceLandmarkerOptions(
base_options=BaseOptions(model_asset_path=model_path),
running_mode=VisionRunningMode.LIVE_STREAM,
result_callback=return_result)
with FaceLandmarker.create_from_options(options) as landmarker:
timestamp_ms = int(time.time() * 1000) # Current time in milliseconds
mp_image = mp.Image(image_format=mp.ImageFormat.SRGB, data=frame)
landmarker.detect_async(mp_image, timestamp_ms)
while latest_results is None:
time.sleep(0.01) # Wait for the result to be available
processed_frame = process_frame(frame, overlay, latest_results, alpha)
return processed_frame
overlay_dir = os.path.join(os.getcwd(),'overlays')
overlay_files = list_overlay_images(overlay_dir)
overlay_choices = [x.split('.png')[0] for x in overlay_files]
overlay_file = gr.Dropdown(choices=overlay_choices, value='Blue', label="Select a color")
image_interface = gr.Interface(
process_image,
[gr.Image(height=500,label="Upload Image"),
gr.Dropdown(choices=overlay_choices, value='Blue', label="Select a color")],
gr.Image(height=500),
)
video_interface = gr.Interface(
process_video,
[gr.Video(height=500,label="Upload Video"),
gr.Dropdown(choices=overlay_choices, value='Blue', label="Select a color")],
gr.Video(height=500,label="Processed Video"),
)
webcam_interface = gr.Interface(
process_webcam,
[gr.Image(sources=["webcam"], streaming=True),
gr.Dropdown(choices=overlay_choices, value='Blue', label="Select a color")],
"image",
live=True
)
demo = gr.TabbedInterface([image_interface,video_interface],['Image','Video'])
demo.launch()