129 lines
4.5 KiB
Python
129 lines
4.5 KiB
Python
import cv2
|
|
import json
|
|
import mediapipe as mp
|
|
import numpy as np
|
|
from scipy.spatial import distance
|
|
|
|
# Load JSON data
|
|
with open('data_yoga.json') as f:
|
|
data = json.load(f)
|
|
|
|
image_name = "Camel"
|
|
image = None
|
|
|
|
# Extract landmarks from JSON data
|
|
landmarks_from_json = []
|
|
the_landmarks = None
|
|
|
|
|
|
# Load the image
|
|
for the_data in data:
|
|
if the_data['name'] == image_name:
|
|
for lm in the_data['landmarks']:
|
|
landmarks_from_json.append([lm['coordinates'][0], lm['coordinates'][1]])
|
|
the_landmarks = the_data['landmarks']
|
|
image = cv2.imread(the_data['image_name'])
|
|
|
|
# Initialize MediaPipe pose module
|
|
mp_pose = mp.solutions.pose
|
|
mp_drawing = mp.solutions.drawing_utils
|
|
|
|
# Function to calculate similarity between two sets of landmarks
|
|
def calculate_similarity(landmarks1, landmarks2):
|
|
if not landmarks1 or not landmarks2:
|
|
return 0
|
|
# Normalize landmarks
|
|
norm_landmarks1 = np.array(landmarks1) - np.mean(landmarks1, axis=0)
|
|
norm_landmarks2 = np.array(landmarks2) - np.mean(landmarks2, axis=0)
|
|
# Calculate the distance between corresponding landmarks
|
|
dists = [distance.euclidean(lm1, lm2) for lm1, lm2 in zip(norm_landmarks1, norm_landmarks2)]
|
|
# Calculate similarity as the inverse of the average distance
|
|
similarity = 1 / (1 + np.mean(dists))
|
|
return similarity * 100
|
|
|
|
# Draw landmarks and connections on the image
|
|
def draw_landmarks(image, landmarks):
|
|
annotated_image = image.copy()
|
|
|
|
for landmark in landmarks:
|
|
# Extract landmark coordinates
|
|
landmark_x = int(landmark['coordinates'][0] * annotated_image.shape[1])
|
|
landmark_y = int(landmark['coordinates'][1] * annotated_image.shape[0])
|
|
# Draw a circle at the landmark position
|
|
cv2.circle(annotated_image, (landmark_x, landmark_y), 5, (0, 255, 0), -1)
|
|
# Add text with the body part label
|
|
cv2.putText(annotated_image, landmark['body'], (landmark_x, landmark_y), cv2.FONT_HERSHEY_SIMPLEX, 0.5,
|
|
(255, 255, 255), 1)
|
|
|
|
# Draw connections between landmarks
|
|
connections = mp_pose.POSE_CONNECTIONS
|
|
for connection in connections:
|
|
start_idx = connection[0]
|
|
end_idx = connection[1]
|
|
if 0 <= start_idx < len(landmarks) and 0 <= end_idx < len(landmarks):
|
|
start_landmark = landmarks[start_idx]['coordinates']
|
|
end_landmark = landmarks[end_idx]['coordinates']
|
|
start_x = int(start_landmark[0] * annotated_image.shape[1])
|
|
start_y = int(start_landmark[1] * annotated_image.shape[0])
|
|
end_x = int(end_landmark[0] * annotated_image.shape[1])
|
|
end_y = int(end_landmark[1] * annotated_image.shape[0])
|
|
cv2.line(annotated_image, (start_x, start_y), (end_x, end_y), (0, 255, 0), 2)
|
|
|
|
return annotated_image
|
|
|
|
|
|
|
|
# Annotate and display the image
|
|
annotated_image = draw_landmarks(image, the_landmarks)
|
|
cv2.imshow('Image with Landmarks and Connections', annotated_image)
|
|
|
|
# Open webcam
|
|
cap = cv2.VideoCapture(0)
|
|
|
|
with mp_pose.Pose(min_detection_confidence=0.5, min_tracking_confidence=0.5) as pose:
|
|
while cap.isOpened():
|
|
ret, frame = cap.read()
|
|
if not ret:
|
|
break
|
|
|
|
# Convert the BGR image to RGB
|
|
image_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
|
|
image_rgb.flags.writeable = False
|
|
|
|
# Process the image and detect the pose
|
|
results = pose.process(image_rgb)
|
|
|
|
# Convert the RGB image back to BGR
|
|
image_rgb.flags.writeable = True
|
|
image_bgr = cv2.cvtColor(image_rgb, cv2.COLOR_RGB2BGR)
|
|
|
|
# Draw the pose annotation on the image
|
|
if results.pose_landmarks:
|
|
mp_drawing.draw_landmarks(
|
|
image_bgr,
|
|
results.pose_landmarks,
|
|
mp_pose.POSE_CONNECTIONS,
|
|
mp_drawing.DrawingSpec(color=(0, 255, 0), thickness=2, circle_radius=2),
|
|
mp_drawing.DrawingSpec(color=(0, 0, 255), thickness=2, circle_radius=2),
|
|
)
|
|
|
|
# Extract landmarks
|
|
landmarks_from_webcam = []
|
|
for lm in results.pose_landmarks.landmark:
|
|
landmarks_from_webcam.append([lm.x, lm.y])
|
|
|
|
# Calculate similarity
|
|
similarity = calculate_similarity(landmarks_from_json, landmarks_from_webcam)
|
|
cv2.putText(image_bgr, f'Similarity: {similarity:.2f}%', (10, 30), cv2.FONT_HERSHEY_SIMPLEX, 1, (0, 255, 0), 2)
|
|
|
|
# Display the image
|
|
cv2.imshow('Webcam Pose', image_bgr)
|
|
|
|
if cv2.waitKey(10) & 0xFF == ord('q'):
|
|
break
|
|
|
|
# Release resources
|
|
cap.release()
|
|
cv2.destroyAllWindows()
|
|
cv2.waitKey(1)
|