Spaces:
Runtime error
Runtime error
File size: 6,758 Bytes
925cf9e 01812af 1ed5218 925cf9e 01812af 925cf9e 01812af 925cf9e 01812af 925cf9e 01812af 925cf9e 01812af 925cf9e 01812af 925cf9e 01812af 925cf9e 01812af 925cf9e 01812af 925cf9e 01812af 925cf9e 01812af 925cf9e 01812af 925cf9e 01812af 925cf9e 01812af 925cf9e 01812af 925cf9e 01812af 925cf9e 01812af 925cf9e 01812af 925cf9e 01812af 925cf9e 01812af 925cf9e 01812af 925cf9e 01812af 1ed5218 01812af 925cf9e 01812af 925cf9e 01812af 925cf9e 01812af 5b34140 01812af 5b34140 925cf9e 5b34140 01812af 925cf9e 01812af 925cf9e 5b34140 01812af 5b34140 925cf9e 01812af 5b34140 925cf9e 5b34140 925cf9e 5b34140 925cf9e 01812af 5b34140 01812af 5b34140 925cf9e 5b34140 925cf9e |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 |
import streamlit as st
import cv2 as cv
import numpy as np
import mediapipe as mp
import tempfile
# Initialize MediaPipe Pose
mp_pose = mp.solutions.pose
pose = mp_pose.Pose()
# Function to rotate an image around its center
def rotate_image(image, angle):
h, w = image.shape[:2]
center = (w // 2, h // 2)
rot_matrix = cv.getRotationMatrix2D(center, angle, 1.0)
rotated_image = cv.warpAffine(image, rot_matrix, (w, h), flags=cv.INTER_LINEAR)
return rotated_image
# Function to overlay the image with rotation following arm direction
def overlay_image_alpha_rotated(img, img_overlay, pos, alpha_mask, angle):
x, y = pos
# Rotate the overlay image in the opposite direction
img_overlay_rotated = rotate_image(img_overlay, -angle) # Negate the angle
alpha_mask_rotated = rotate_image(alpha_mask, -angle) # Negate the angle
# Calculate the new position after rotation
h, w = img_overlay_rotated.shape[:2]
new_pos = (x - w // 2, y - h // 2)
# Image ranges
y1, y2 = max(0, new_pos[1]), min(img.shape[0], new_pos[1] + h)
x1, x2 = max(0, new_pos[0]), min(img.shape[1], new_pos[0] + w)
# Overlay ranges
y1o, y2o = max(0, -new_pos[1]), min(h, img.shape[0] - new_pos[1])
x1o, x2o = max(0, -new_pos[0]), min(w, img.shape[1] - new_pos[0])
# Exit if nothing to overlay
if y1 >= y2 or x1 >= x2 or y1o >= y2o or x1o >= x2o:
return
# Blend overlay within the determined ranges
img_crop = img[y1:y2, x1:x2]
img_overlay_crop = img_overlay_rotated[y1o:y2o, x1o:x2o]
alpha = alpha_mask_rotated[y1o:y2o, x1o:x2o, np.newaxis]
alpha_inv = 1.0 - alpha
img_crop[:] = alpha * img_overlay_crop + alpha_inv * img_crop
# Function to handle JPG images without alpha channel
def add_alpha_channel(image):
b_channel, g_channel, r_channel = cv.split(image)
alpha_channel = np.ones(b_channel.shape, dtype=b_channel.dtype) * 255 # Creating a fully opaque alpha channel
return cv.merge((b_channel, g_channel, r_channel, alpha_channel))
# Function to detect pose and overlay image following arm direction
def poseDetector(frame, overlay_img):
# Convert the image to RGB as MediaPipe expects RGB images
frame_rgb = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
# Process the image and get the pose landmarks
results = pose.process(frame_rgb)
if results.pose_landmarks:
# Extract relevant landmarks
right_wrist = results.pose_landmarks.landmark[mp_pose.PoseLandmark.RIGHT_WRIST]
left_wrist = results.pose_landmarks.landmark[mp_pose.PoseLandmark.LEFT_WRIST]
right_elbow = results.pose_landmarks.landmark[mp_pose.PoseLandmark.RIGHT_ELBOW]
left_elbow = results.pose_landmarks.landmark[mp_pose.PoseLandmark.LEFT_ELBOW]
# Convert landmark positions to pixel coordinates
h, w, _ = frame.shape
right_wrist_coord = (int(right_wrist.x * w), int(right_wrist.y * h))
left_wrist_coord = (int(left_wrist.x * w), int(left_wrist.y * h))
right_elbow_coord = (int(right_elbow.x * w), int(right_elbow.y * h))
left_elbow_coord = (int(left_elbow.x * w), int(left_elbow.y * h))
# Calculate the length of the hand region (between wrist and elbow)
right_hand_length = int(np.sqrt((right_wrist_coord[0] - right_elbow_coord[0])**2 + (right_wrist_coord[1] - right_elbow_coord[1])**2) * 0.5)
left_hand_length = int(np.sqrt((left_wrist_coord[0] - left_elbow_coord[0])**2 + (left_wrist_coord[1] - left_elbow_coord[1])**2) * 0.5)
# Calculate the angle of the hand for rotation
right_angle = np.degrees(np.arctan2(right_wrist_coord[1] - right_elbow_coord[1], right_wrist_coord[0] - right_elbow_coord[0]))
left_angle = np.degrees(np.arctan2(left_wrist_coord[1] - left_elbow_coord[1], left_wrist_coord[0] - left_elbow_coord[0]))
# Ensure the hand length is positive before resizing
if right_hand_length > 0:
# Resize overlay image to fit the hand length
right_overlay_resized = cv.resize(overlay_img, (right_hand_length, right_hand_length))
# Adjust position to overlay the image at the wrist
right_position = right_wrist_coord
# Overlay the image on the right hand with rotation following the arm direction
alpha_mask = right_overlay_resized[:, :, 3] / 255.0
overlay_image_alpha_rotated(frame, right_overlay_resized[:, :, :3], right_position, alpha_mask, right_angle)
if left_hand_length > 0:
# Resize overlay image to fit the hand length
left_overlay_resized = cv.resize(overlay_img, (left_hand_length, left_hand_length))
# Adjust position to overlay the image at the wrist
left_position = left_wrist_coord
# Overlay the image on the left hand with rotation following the arm direction
alpha_mask = left_overlay_resized[:, :, 3] / 255.0
overlay_image_alpha_rotated(frame, left_overlay_resized[:, :, :3], left_position, alpha_mask, left_angle)
return frame
# Streamlit interface
def main():
st.title("Webcam Pose Detection with Tattoo Overlay")
# Sidebar for file upload
st.sidebar.header("Upload Tattoo Image and Video")
uploaded_tattoo_img = st.sidebar.file_uploader("Upload Tattoo Image", type=["png", "jpg", "jpeg"])
uploaded_video = st.sidebar.file_uploader("Upload Video File", type=["mp4", "mov", "avi"])
if uploaded_tattoo_img and uploaded_video:
# Load the uploaded tattoo image
file_bytes = np.frombuffer(uploaded_tattoo_img.read(), np.uint8)
tattoo_img = cv.imdecode(file_bytes, cv.IMREAD_UNCHANGED)
# If the image is in JPG format (no alpha channel), add an alpha channel
if tattoo_img.shape[2] == 3: # Check if image has only 3 channels (BGR)
tattoo_img = add_alpha_channel(tattoo_img)
# Checkbox to start the processing
run = st.checkbox('Run')
if run:
# Temporary file to store the uploaded video
tfile = tempfile.NamedTemporaryFile(delete=False)
tfile.write(uploaded_video.read())
# Video capture
cap = cv.VideoCapture(tfile.name)
stframe = st.empty()
while cap.isOpened():
ret, frame = cap.read()
if not ret:
break
# Perform pose detection and overlay
frame = poseDetector(frame, tattoo_img)
# Convert the frame to RGB for display in Streamlit
frame = cv.cvtColor(frame, cv.COLOR_BGR2RGB)
stframe.image(frame, channels="RGB")
cap.release()
if __name__ == "__main__":
main()
|