change similarity function

This commit is contained in:
kicap 2024-07-20 06:50:06 +08:00
parent 2e7c0ed8bc
commit de3c441033
7 changed files with 2152 additions and 552 deletions

View File

Before

Width:  |  Height:  |  Size: 211 KiB

After

Width:  |  Height:  |  Size: 211 KiB

View File

Before

Width:  |  Height:  |  Size: 193 KiB

After

Width:  |  Height:  |  Size: 193 KiB

40
app.py
View File

@ -4,7 +4,7 @@ import cv2
import json
import mediapipe as mp
import numpy as np
from scipy.spatial import distance
from scipy.spatial import procrustes,distance
import base64
import os
@ -52,14 +52,42 @@ def calculate_color(similarity):
green = int(normalized_similarity * 255)
return (0, green, red)
# def calculate_similarity(landmarks1, landmarks2):
# if not landmarks1 or not landmarks2:
# return 0
# norm_landmarks1 = np.array(landmarks1) - np.mean(landmarks1, axis=0)
# norm_landmarks2 = np.array(landmarks2) - np.mean(landmarks2, axis=0)
# dists = [distance.euclidean(lm1, lm2) for lm1, lm2 in zip(norm_landmarks1, norm_landmarks2)]
# similarity = 1 / (1 + np.mean(dists))
# return similarity * 100
def calculate_similarity(landmarks1, landmarks2):
if not landmarks1 or not landmarks2:
return 0
norm_landmarks1 = np.array(landmarks1) - np.mean(landmarks1, axis=0)
norm_landmarks2 = np.array(landmarks2) - np.mean(landmarks2, axis=0)
dists = [distance.euclidean(lm1, lm2) for lm1, lm2 in zip(norm_landmarks1, norm_landmarks2)]
similarity = 1 / (1 + np.mean(dists))
return similarity * 100
# 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

212
app2.py Normal file
View File

@ -0,0 +1,212 @@
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)

1900
data_yoga copy.json Normal file

File diff suppressed because it is too large Load Diff

View File

@ -812,548 +812,8 @@
}
]
},
{
"image_name": "gerakan/SidePlank.jpg",
"name": "Side Plank",
"ket": "Side Plank adalah pose yoga yang bagus untuk pria yang ingin merasakan kekuatan saat berlatih yoga. Karena yoga lebih dari sekadar peregangan, pose ini sebenarnya cukup menantang bagi banyak pria untuk menjadi stabil sehingga merupakan tantangan sempurna untuk membangun kekuatan dan keseimbangan.<br>Mulailah dengan Pose Papan netral dengan kaki bersentuhan<br>Akar dengan kuat ke tangan kanan Anda dan tuangkan beban Anda ke sisi kanan tubuh Anda<br>Gulingkan ke sisi kelingking kaki kanan Anda dan susun kaki kiri Anda di atas kaki kanan Anda<br>Turunkan tubuh ke lantai dengan tangan dan kaki, lalu angkat pinggul menjauh dari matras<br>Regangkan lengan kiri Anda ke langit<br>Tahan beberapa kali napas dalam-dalam lalu ganti sisi",
"landmarks": [
{
"body": "nose",
"coordinates": [
0.7098162174224854,
0.4569375216960907,
-0.43993350863456726
]
},
{
"body": "left_eye_inner",
"coordinates": [
0.7251797318458557,
0.47123992443084717,
-0.4204886555671692
]
},
{
"body": "left_eye",
"coordinates": [
0.7261665463447571,
0.47927266359329224,
-0.4205434322357178
]
},
{
"body": "left_eye_outer",
"coordinates": [
0.7271681427955627,
0.4877326190471649,
-0.42069318890571594
]
},
{
"body": "right_eye_inner",
"coordinates": [
0.7234879732131958,
0.4508434236049652,
-0.4142134487628937
]
},
{
"body": "right_eye",
"coordinates": [
0.7235473394393921,
0.44637542963027954,
-0.4142872393131256
]
},
{
"body": "right_eye_outer",
"coordinates": [
0.72352534532547,
0.4414880871772766,
-0.4142611026763916
]
},
{
"body": "left_ear",
"coordinates": [
0.7266677021980286,
0.5080437660217285,
-0.27510419487953186
]
},
{
"body": "right_ear",
"coordinates": [
0.7228119373321533,
0.4497060477733612,
-0.24739260971546173
]
},
{
"body": "mouth_left",
"coordinates": [
0.6963652968406677,
0.47936636209487915,
-0.38349977135658264
]
},
{
"body": "mouth_right",
"coordinates": [
0.6949125528335571,
0.4527930021286011,
-0.3757424056529999
]
},
{
"body": "left_shoulder",
"coordinates": [
0.6616856455802917,
0.5975712537765503,
-0.14586275815963745
]
},
{
"body": "right_shoulder",
"coordinates": [
0.6592086553573608,
0.4010165333747864,
-0.14102506637573242
]
},
{
"body": "left_elbow",
"coordinates": [
0.6435102224349976,
0.7407686710357666,
-0.1331832855939865
]
},
{
"body": "right_elbow",
"coordinates": [
0.6343681216239929,
0.2664838135242462,
-0.13378147780895233
]
},
{
"body": "left_wrist",
"coordinates": [
0.6483306884765625,
0.8784486055374146,
-0.312683641910553
]
},
{
"body": "right_wrist",
"coordinates": [
0.6353558301925659,
0.1287083625793457,
-0.29510271549224854
]
},
{
"body": "left_pinky",
"coordinates": [
0.6662757992744446,
0.8944035768508911,
-0.3472563624382019
]
},
{
"body": "right_pinky",
"coordinates": [
0.6349470615386963,
0.08301430940628052,
-0.3394726514816284
]
},
{
"body": "left_index",
"coordinates": [
0.6702272891998291,
0.8951166868209839,
-0.39849695563316345
]
},
{
"body": "right_index",
"coordinates": [
0.6397250294685364,
0.0813528299331665,
-0.3793392777442932
]
},
{
"body": "left_thumb",
"coordinates": [
0.6614180207252502,
0.893438458442688,
-0.3408251702785492
]
},
{
"body": "right_thumb",
"coordinates": [
0.6385964751243591,
0.09477406740188599,
-0.3216344714164734
]
},
{
"body": "left_hip",
"coordinates": [
0.4968375861644745,
0.6325719356536865,
0.013312475755810738
]
},
{
"body": "right_hip",
"coordinates": [
0.4600812792778015,
0.5501070618629456,
-0.013295695185661316
]
},
{
"body": "left_knee",
"coordinates": [
0.3700864613056183,
0.7610329985618591,
-0.027371346950531006
]
},
{
"body": "right_knee",
"coordinates": [
0.3484456241130829,
0.7027431726455688,
-0.06001186743378639
]
},
{
"body": "left_ankle",
"coordinates": [
0.23582607507705688,
0.8720247745513916,
0.09060442447662354
]
},
{
"body": "right_ankle",
"coordinates": [
0.21887026727199554,
0.8373360633850098,
0.04682646319270134
]
},
{
"body": "left_heel",
"coordinates": [
0.21965157985687256,
0.8809549808502197,
0.09259264916181564
]
},
{
"body": "right_heel",
"coordinates": [
0.2048492431640625,
0.8526101112365723,
0.0474533811211586
]
},
{
"body": "left_foot_index",
"coordinates": [
0.19632641971111298,
0.9135346412658691,
-0.10043893754482269
]
},
{
"body": "right_foot_index",
"coordinates": [
0.18483410775661469,
0.8908615112304688,
-0.13688577711582184
]
}
]
},
{
"image_name": "gerakan/Dolphin.jpg",
"name": "Dolphin",
"ket": "Pose yoga hebat lainnya untuk membangun kekuatan dan kelenturan, Pose Lumba-lumba memperkuat dan meregangkan dada dan bahu sekaligus menciptakan panjang di bagian belakang kaki.<br>Mulailah dengan posisi merangkak dengan bahu bertumpu pada pergelangan tangan dan pinggul bertumpu pada lutut<br>Turunkan lengan bawah Anda ke lantai dan sejajarkan siku di bawah bahu Anda<br>Turunkan dengan kuat ke lengan bawah Anda dan selipkan jari-jari kaki Anda ke bawah<br>Angkat lutut dari lantai dan regangkan kaki ke arah lurus<br>Arahkan tulang duduk Anda ke arah langit dan panjangkan seluruh tubuh punggung Anda<br>Terus turunkan tubuh ke lengan bawah dan tekan lantai menjauh saat Anda meleburkan dada ke arah paha<br> Tahan beberapa kali napas dalam-dalam sebelum melepaskannya kembali secara perlahan",
"landmarks": [
{
"body": "nose",
"coordinates": [
0.6843224167823792,
0.7867915630340576,
0.007792915217578411
]
},
{
"body": "left_eye_inner",
"coordinates": [
0.6982460021972656,
0.7978988885879517,
0.023978769779205322
]
},
{
"body": "left_eye",
"coordinates": [
0.6998078227043152,
0.7972776889801025,
0.02383337914943695
]
},
{
"body": "left_eye_outer",
"coordinates": [
0.7018256187438965,
0.7967249751091003,
0.023737428709864616
]
},
{
"body": "right_eye_inner",
"coordinates": [
0.7009738087654114,
0.7966487407684326,
-0.02601107768714428
]
},
{
"body": "right_eye",
"coordinates": [
0.7043293714523315,
0.7947158813476562,
-0.026141010224819183
]
},
{
"body": "right_eye_outer",
"coordinates": [
0.7080330848693848,
0.7928115725517273,
-0.02617897465825081
]
},
{
"body": "left_ear",
"coordinates": [
0.7163191437721252,
0.7732642889022827,
0.12233810126781464
]
},
{
"body": "right_ear",
"coordinates": [
0.7212889194488525,
0.770534873008728,
-0.10985520482063293
]
},
{
"body": "mouth_left",
"coordinates": [
0.681481122970581,
0.7661354541778564,
0.048803988844156265
]
},
{
"body": "mouth_right",
"coordinates": [
0.6851271390914917,
0.7642875909805298,
-0.01917620562016964
]
},
{
"body": "left_shoulder",
"coordinates": [
0.6901950240135193,
0.678408145904541,
0.24474893510341644
]
},
{
"body": "right_shoulder",
"coordinates": [
0.7028524279594421,
0.6920257806777954,
-0.21413485705852509
]
},
{
"body": "left_elbow",
"coordinates": [
0.6924396753311157,
0.8409109115600586,
0.4287886619567871
]
},
{
"body": "right_elbow",
"coordinates": [
0.7083194851875305,
0.8894730806350708,
-0.2994592487812042
]
},
{
"body": "left_wrist",
"coordinates": [
0.790278434753418,
0.8663578033447266,
0.4406212866306305
]
},
{
"body": "right_wrist",
"coordinates": [
0.8122759461402893,
0.8971265554428101,
-0.07922858744859695
]
},
{
"body": "left_pinky",
"coordinates": [
0.8207050561904907,
0.8718618750572205,
0.45191624760627747
]
},
{
"body": "right_pinky",
"coordinates": [
0.8562626838684082,
0.8964477777481079,
-0.09679531306028366
]
},
{
"body": "left_index",
"coordinates": [
0.8259179592132568,
0.862907886505127,
0.43286991119384766
]
},
{
"body": "right_index",
"coordinates": [
0.8538448214530945,
0.8585608005523682,
-0.10031750053167343
]
},
{
"body": "left_thumb",
"coordinates": [
0.8150687217712402,
0.8554471731185913,
0.4281766414642334
]
},
{
"body": "right_thumb",
"coordinates": [
0.8399573564529419,
0.8561289310455322,
-0.07788088172674179
]
},
{
"body": "left_hip",
"coordinates": [
0.5260228514671326,
0.38588520884513855,
0.18303664028644562
]
},
{
"body": "right_hip",
"coordinates": [
0.5276482105255127,
0.38163620233535767,
-0.18260757625102997
]
},
{
"body": "left_knee",
"coordinates": [
0.3823971748352051,
0.6091682314872742,
0.17168764770030975
]
},
{
"body": "right_knee",
"coordinates": [
0.3792652189731598,
0.6195148229598999,
-0.14887301623821259
]
},
{
"body": "left_ankle",
"coordinates": [
0.2077355533838272,
0.7839767932891846,
0.2007771134376526
]
},
{
"body": "right_ankle",
"coordinates": [
0.18811026215553284,
0.7911090850830078,
-0.13209345936775208
]
},
{
"body": "left_heel",
"coordinates": [
0.18081320822238922,
0.8039306402206421,
0.19741442799568176
]
},
{
"body": "right_heel",
"coordinates": [
0.16176638007164001,
0.8074171543121338,
-0.13716663420200348
]
},
{
"body": "left_foot_index",
"coordinates": [
0.259407639503479,
0.8775787353515625,
0.11939527839422226
]
},
{
"body": "right_foot_index",
"coordinates": [
0.2452431619167328,
0.8928111791610718,
-0.25604158639907837
]
}
]
},
{
"image_name": "gerakan/Crow.jpg",
"name": "Crow",

View File

@ -208,7 +208,7 @@
console.log(data);
var similarity = data.similarity;
if (similarity <80) {
if (similarity <90) {
counter = 0
}else{
counter = counter + 1
@ -234,9 +234,9 @@
}, 2000);
// set interval 70 second and change pose
setInterval(function () {
window.location.href="{{ url_for('index', image_name=next) }}";
}, 70000);
// setInterval(function () {
// window.location.href="{{ url_for('index', image_name=next) }}";
// }, 70000);
</script>
</body>