|
import cv2 |
|
import numpy as np |
|
from PIL import Image |
|
from PIL import ImageColor |
|
import mediapipe as mp |
|
import time |
|
import gradio as gr |
|
import glob |
|
|
|
width_, height_ = 144, 96 |
|
|
|
drawing_flag = False |
|
sleepy_time = time.time() |
|
|
|
output_frames = [] |
|
|
|
|
|
def is_hex(hexq): |
|
if hexq[0] == '#' and len(hexq) == 7 and hexq[1:7].isalnum(): |
|
return True |
|
else: |
|
return False |
|
|
|
|
|
def hex2rgb(hex): |
|
if is_hex(hex): |
|
return ImageColor.getcolor(hex, "RGB") |
|
else: |
|
return (0, 0, 0) |
|
|
|
|
|
def find_hands(brain, img): |
|
if img is not None: |
|
img_rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB) |
|
results = brain.process(img_rgb) |
|
all_hands = [] |
|
h, w, _ = img.shape |
|
if results.multi_hand_landmarks: |
|
for hand_type, hand_lms in zip(results.multi_handedness, |
|
results.multi_hand_landmarks): |
|
hand = {} |
|
lm_list = [] |
|
for lm in hand_lms.landmark: |
|
px, py, pz = int(lm.x * w), int(lm.y * h), int( |
|
lm.z * w) |
|
lm_list.append([px, py, pz]) |
|
|
|
hand["lm_list"] = lm_list |
|
hand["type"] = hand_type.classification[0].label |
|
all_hands.append(hand) |
|
return all_hands |
|
|
|
else: |
|
return 0 |
|
|
|
|
|
def is_drawing(index, thumb): |
|
npindex = np.array((index[0], index[1])) |
|
npthumb = np.array((thumb[0], thumb[1])) |
|
if np.linalg.norm(npindex - npthumb) < 20: |
|
return True |
|
else: |
|
return False |
|
|
|
|
|
def save(landmarks): |
|
if landmarks[8][1] < landmarks[6][1]: |
|
if landmarks[12][1] < landmarks[10][1]: |
|
if landmarks[16][1] < landmarks[14][1]: |
|
if landmarks[20][1] < landmarks[18][1]: |
|
return True |
|
else: |
|
return False |
|
|
|
|
|
def clear(landmarks): |
|
if landmarks[4][1] < landmarks[3][1] < landmarks[2][1] < landmarks[8][1]: |
|
return True |
|
else: |
|
return False |
|
|
|
|
|
def show(video, dominant_hand, hex_color): |
|
cam = cv2.VideoCapture(video) |
|
width = cam.get(cv2.CAP_PROP_FRAME_WIDTH) |
|
height = cam.get(cv2.CAP_PROP_FRAME_HEIGHT) |
|
|
|
detector = mp.solutions.hands.Hands(min_detection_confidence=0.8) |
|
|
|
paper = np.zeros((int(height), int(width), 3), dtype=np.uint8) |
|
paper.fill(255) |
|
|
|
color = hex2rgb(hex_color) |
|
past_holder = () |
|
palette = cv2.imread('palette_small.jpg') |
|
|
|
page_num = 0 |
|
|
|
global sleepy_time |
|
|
|
while cam.isOpened(): |
|
x, rgb_image = cam.read() |
|
rgb_image_f = cv2.flip(rgb_image, 1) |
|
|
|
hands = find_hands(detector, rgb_image_f) |
|
|
|
if x: |
|
try: |
|
if hands: |
|
hand1 = hands[0] if hands[0]["type"] == dominant_hand else hands[1] |
|
lm_list1 = hand1["lm_list"] |
|
handedness = hand1["type"] |
|
|
|
if handedness == dominant_hand: |
|
idx_coords = lm_list1[8][0], lm_list1[8][1] |
|
|
|
cv2.circle(rgb_image_f, idx_coords, 5, color, cv2.FILLED) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if len(past_holder) and drawing_flag: |
|
cv2.line(paper, past_holder, idx_coords, color, 5) |
|
cv2.line(rgb_image_f, past_holder, idx_coords, color, 5) |
|
|
|
|
|
cv2.circle(rgb_image_f, idx_coords, 5, color, cv2.FILLED) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if clear(lm_list1) and time.time() - sleepy_time > 3: |
|
paper = np.zeros((height, width, 3), dtype=np.uint8) |
|
paper.fill(255) |
|
print("page cleared") |
|
sleepy_time = time.time() |
|
|
|
past_holder = idx_coords |
|
|
|
if is_drawing(idx_coords, lm_list1[4]): |
|
drawing_flag = True |
|
else: |
|
drawing_flag = False |
|
|
|
except: |
|
pass |
|
|
|
finally: |
|
if True: |
|
presenter = cv2.resize(rgb_image_f, (width_, height_)) |
|
h, w, _ = rgb_image_f.shape |
|
paper[0:height_, w - width_: w] = presenter |
|
|
|
else: |
|
break |
|
|
|
paper = cv2.cvtColor(paper, cv2.COLOR_RGB2BGR) |
|
im = Image.fromarray(paper) |
|
output_frames.append(paper) |
|
im.save("paper%s.png" % page_num) |
|
page_num += 1 |
|
|
|
img_array = [] |
|
for filename in glob.glob('*.png'): |
|
imggg = cv2.imread(filename) |
|
img_array.append(imggg) |
|
|
|
video_output = cv2.VideoWriter('any.webm', cv2.VideoWriter_fourcc(*'VP80'), 30, (640, 480)) |
|
|
|
for i in range(len(img_array)): |
|
video_output.write(img_array[i]) |
|
video_output.release() |
|
|
|
return 'any.webm' |
|
|
|
title = 'Air Draw' |
|
desc = 'A mediapipe hands wrapper for drawing in the air. Position your fingers in a "drawing" form to draw, and open up your hand to lift the "pen" from the "paper". Use a "thumbs up" gesture to clear the drawing paper.' |
|
iface = gr.Interface( |
|
fn=show, |
|
inputs=[ |
|
gr.inputs.Video(source="webcam", label="Record yourself drawing in the air!"), |
|
gr.inputs.Radio(['Right', 'Left'], label="Dominant Hand"), |
|
gr.inputs.Textbox(placeholder="#355C7D", label="Hex Color") |
|
], |
|
outputs='video', |
|
title=title, |
|
description=desc) |
|
|
|
iface.launch(share=True, enable_queue=True) |
|
|