-
Notifications
You must be signed in to change notification settings - Fork 0
/
index.html
117 lines (99 loc) · 4.08 KB
/
index.html
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
<!DOCTYPE html>
<html>
<head>
<title>Push Up Counter </title>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-core"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-converter"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs-backend-webgl"></script>
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/pose-detection"></script>
</head>
<body>
<video style="position: fixed; height: 100vh; width: 100%; object-fit: fill; top:0; left:0; z-index: 1;" id="video"></video>
<div id="notVisible" style="display: none; position: fixed; background-color: red; height: 100%; width: 100%; top:0; left:0; opacity: 0.2; z-index: 1;"></div>
<div id="visible" style="display: none; position: fixed; background-color: green; height: 100%; width: 100%; top:0; left:0; opacity: 0.2; z-index: 1"></div>
<div id="pushUpCount" style="position: fixed; z-index: 2; right: 0; top:0; border-left: 3px solid green; border-bottom: 3px solid green; background-color: white; color: black; width: 100px; height: 100px; text-align: center; font-size: 75px; border-radius: 0 0 0 30px" >0</div>
</body>
<script>
var detector;
const video = document.getElementById("video")
navigator.mediaDevices
.getUserMedia({
audio: false,
video: {
facingMode: "user"
}
})
.then(stream => {
video.srcObject = stream
video.onloadedmetadata = () => {
video.play()
}
})
setup();
async function setup() {
const detectorConfig = {
modelType: poseDetection.movenet.modelType.MULTIPOSE_LIGHTNING,
enableTracking: true,
trackerType: poseDetection.TrackerType.BoundingBox
};
detector = await poseDetection.createDetector(poseDetection.SupportedModels.MoveNet, detectorConfig);
video.onloadeddata = async (event) => {
detect();
};
}
var totalPushUps = 0;
var poseUp = false;
var poseDown = false;
async function detect() {
try {
const poses = await detector.estimatePoses(video);
let total = 0;
let pose = poses[0].keypoints;
var allPointsVisible = true;
for(let i=5; i<=10; i++) {
if(pose[i].score <= 0.3) {
allPointsVisible = false;
}
}
if(allPointsVisible) {
document.getElementById("notVisible").style.display = "none";
document.getElementById("visible").style.display = "block";
let averageWristToElbowDistance = (dist(pose[9].x, pose[9].y, pose[7].x, pose[7].y) + dist(pose[10].x, pose[10].y, pose[8].x, pose[8].y))/2;
let averageElbowToShoulderDistance = (dist(pose[5].x, pose[5].y, pose[7].x, pose[7].y) + dist(pose[6].x, pose[6].y, pose[8].x, pose[8].y))/2;
let averageShoulderHeight = (pose[5].y + pose[6].y)/2;
let averageElbowHeight = (pose[7].y + pose[8].y)/2;
if(match(averageWristToElbowDistance, averageElbowToShoulderDistance, 0.01)) {
poseUp = true;
}
if(match(averageElbowHeight, averageShoulderHeight, 0.25)) {
poseDown = true;
}
if(poseUp && poseDown) {
totalPushUps++;
document.getElementById("pushUpCount").innerHTML = totalPushUps;
poseUp = false;
poseDown = false;
}
requestAnimationFrame(detect);
} else {
document.getElementById("notVisible").style.display = "block";
document.getElementById("visible").style.display = "none";
requestAnimationFrame(detect);
}
} catch(e) {
requestAnimationFrame(detect);
}
}
function dist(x1, y1, x2, y2) {
return Math.sqrt((x2-x1)*(x2-x1) + (y2-y1)*(y2-y1))
}
function match(a, b, percent) {
let boundGap1 = a - (percent*a);
let boundGap2 = a + (percent*a);
if(b >= boundGap1 && b <= boundGap2) {
return true;
}
return false;
}
</script>
</html>