deteksi-badan-new/app2.py

213 lines
7.3 KiB
Python

from flask import Flask, render_template, Response, request, jsonify, send_file
from flask_socketio import SocketIO
import cv2
import json
import mediapipe as mp
import numpy as np
from scipy.spatial import procrustes
import base64
import os
app = Flask(__name__)
socketio = SocketIO(app)
mp_pose = mp.solutions.pose
mp_drawing = mp.solutions.drawing_utils
image_name = "Camel"
image = None
# Extract landmarks from JSON data
landmarks_from_json = []
the_landmarks = None
dataset = {"name": "", "ket": ""}
similarity = 0
all_data = []
def load_image_and_landmarks(image_name):
global image, landmarks_from_json, the_landmarks, all_data
landmarks_from_json = [] # Clear previous landmarks
# Load JSON data
with open('data_yoga.json') as f:
data = json.load(f)
all_data = data
# Load the image and landmarks
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'])
dataset["name"] = the_data['name']
dataset["ket"] = the_data['ket']
# Define the function to calculate the color based on similarity
def calculate_color(similarity):
if similarity < 70:
return (0, 0, 255) # Red
else:
normalized_similarity = (similarity - 55) / 45 # Normalize between 0 and 1 for values 71 to 100
red = int((1 - normalized_similarity) * 255)
green = int(normalized_similarity * 255)
return (0, green, red)
def resample_landmarks(landmarks, target_length):
idxs = np.linspace(0, len(landmarks) - 1, target_length).astype(int)
return [landmarks[i] for i in idxs]
def calculate_similarity(landmarks1, landmarks2):
if not landmarks1 or not landmarks2:
return 0
len1 = len(landmarks1)
len2 = len(landmarks2)
# Resample landmarks to ensure they have the same number of points
if len1 != len2:
if len1 < len2:
landmarks2 = resample_landmarks(landmarks2, len1)
else:
landmarks1 = resample_landmarks(landmarks1, len2)
# Convert to numpy arrays
landmarks1 = np.array(landmarks1)
landmarks2 = np.array(landmarks2)
# Normalize landmarks by removing the mean
norm_landmarks1 = landmarks1 - np.mean(landmarks1, axis=0)
norm_landmarks2 = landmarks2 - np.mean(landmarks2, axis=0)
# Perform Procrustes analysis to align the shapes
_, mtx1, mtx2 = procrustes(norm_landmarks1, norm_landmarks2)
# Calculate the Euclidean distances between corresponding landmarks
dists = np.linalg.norm(mtx1 - mtx2, axis=1)
# Calculate the similarity as the inverse of the average distance
avg_dist = np.mean(dists)
similarity = max(0, 1 - avg_dist)
# Scale the similarity to a percentage
similarity_percentage = similarity * 100
return similarity_percentage
def draw_landmarks(image, landmarks):
global similarity
annotated_image = image.copy()
for landmark in landmarks:
landmark_x = int(landmark['coordinates'][0] * annotated_image.shape[1])
landmark_y = int(landmark['coordinates'][1] * annotated_image.shape[0])
cv2.circle(annotated_image, (landmark_x, landmark_y), 5, (0, 255, 0), -1)
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
def generate_frames():
global similarity
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
image_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
image_rgb.flags.writeable = False
results = pose.process(image_rgb)
image_rgb.flags.writeable = True
image_bgr = cv2.cvtColor(image_rgb, cv2.COLOR_RGB2BGR)
the_color = calculate_color(similarity)
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=4, circle_radius=2),
mp_drawing.DrawingSpec(color=(the_color), thickness=4, circle_radius=2),
)
landmarks_from_webcam = []
for lm in results.pose_landmarks.landmark:
landmarks_from_webcam.append([lm.x, lm.y])
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)
ret, buffer = cv2.imencode('.jpg', image_bgr)
frame = buffer.tobytes()
yield (b'--frame\r\n'
b'Content-Type: image/jpeg\r\n\r\n' + frame + b'\r\n')
cap.release()
@app.route('/')
def index():
image_name = request.args.get('image_name', 'Camel')
previous = None
next = None
load_image_and_landmarks(image_name)
current_index = 0
for index, data in enumerate(all_data):
if data['name'] == image_name:
current_index = index
break
if current_index == 0:
previous = all_data[-1]['name']
else:
previous = all_data[current_index - 1]['name']
if current_index == len(all_data) - 1:
next = all_data[0]['name']
else:
next = all_data[current_index + 1]['name']
annotated_image = draw_landmarks(image, the_landmarks)
_, buffer = cv2.imencode('.jpg', annotated_image)
img_str = base64.b64encode(buffer).decode('utf-8')
return render_template('index2.html', img_str=img_str, previous=previous, next=next)
@app.route('/video_feed')
def video_feed():
return Response(generate_frames(), mimetype='multipart/x-mixed-replace; boundary=frame')
@app.route('/getdata', methods=['GET'])
def getdata():
return jsonify(all_data)
@app.route('/similarity', methods=['GET'])
def get_similarity():
global similarity
return {'similarity': similarity, 'data': dataset}
@app.route('/pose_dataset')
def pose_dataset():
load_image_and_landmarks("Camel")
return render_template('pose_dataset.html', data=all_data)
@app.route('/show_image')
def show_image():
image_path = request.args.get('image_path')
if image_path and os.path.exists(image_path):
return send_file(image_path, mimetype='image/jpeg')
else:
return "Image not found", 404
if __name__ == '__main__':
socketio.run(app, debug=True)