Merge branch 'feature/counter' into feature/userInfo
Showing
16 changed files
with
209 additions
and
107 deletions
views/squatPage/sound/0.wav
0 → 100644
No preview for this file type
views/squatPage/sound/1.wav
0 → 100644
No preview for this file type
views/squatPage/sound/2.wav
0 → 100644
No preview for this file type
views/squatPage/sound/3.wav
0 → 100644
No preview for this file type
views/squatPage/sound/4.wav
0 → 100644
No preview for this file type
views/squatPage/sound/5.wav
0 → 100644
No preview for this file type
views/squatPage/sound/6.wav
0 → 100644
No preview for this file type
views/squatPage/sound/7.wav
0 → 100644
No preview for this file type
views/squatPage/sound/8.wav
0 → 100644
No preview for this file type
views/squatPage/sound/9.wav
0 → 100644
No preview for this file type
views/squatPage/sound/bad.mp3
0 → 100644
No preview for this file type
views/squatPage/squat.css
0 → 100644
1 | +@import url("https://fonts.googleapis.com/css?family=Poppins:200,300,400,500,600,700,800,900&display=swap"); | ||
2 | + | ||
3 | +button { | ||
4 | + margin: 10px; | ||
5 | + margin-bottom: 20px; | ||
6 | +} | ||
7 | + | ||
8 | +.w-btn { | ||
9 | + position: relative; | ||
10 | + border: none; | ||
11 | + display: inline-block; | ||
12 | + padding: 15px 30px; | ||
13 | + border-radius: 15px; | ||
14 | + font-family: "paybooc-Light", sans-serif; | ||
15 | + box-shadow: 0 15px 35px rgba(0, 0, 0, 0.2); | ||
16 | + text-decoration: none; | ||
17 | + font-weight: 600; | ||
18 | + transition: 0.25s; | ||
19 | +} | ||
20 | + | ||
21 | +.w-btn-outline { | ||
22 | + position: relative; | ||
23 | + padding: 15px 30px; | ||
24 | + border-radius: 15px; | ||
25 | + font-family: "paybooc-Light", sans-serif; | ||
26 | + box-shadow: 0 15px 35px rgba(0, 0, 0, 0.2); | ||
27 | + text-decoration: none; | ||
28 | + font-weight: 600; | ||
29 | + transition: 0.25s; | ||
30 | +} | ||
31 | + | ||
32 | +.w-btn-indigo { | ||
33 | + background-color: aliceblue; | ||
34 | + color: #2e2f30; | ||
35 | +} | ||
36 | + | ||
37 | +.w-btn-indigo-outline { | ||
38 | + border: 3px solid aliceblue; | ||
39 | + color: #2e2f30; | ||
40 | +} | ||
41 | + | ||
42 | +.w-btn-indigo-outline:hover { | ||
43 | + color: #2e2f30; | ||
44 | + background: aliceblue; | ||
45 | +} | ||
46 | + | ||
47 | +.Title { | ||
48 | + font-size : 100px; | ||
49 | + font-family: fantasy; | ||
50 | + color : aliceblue; | ||
51 | + margin-top: 15%; | ||
52 | + text-align: center; | ||
53 | +} | ||
54 | + | ||
55 | +.click_title { | ||
56 | + font-size : 40px; | ||
57 | + font-family: fantasy; | ||
58 | + color : aliceblue; | ||
59 | + margin-top: 40px; | ||
60 | + margin-bottom: 20px; | ||
61 | + text-align: center; | ||
62 | + transition: 500ms; | ||
63 | +} | ||
64 | + | ||
65 | +.label-container { | ||
66 | + visibility: hidden; | ||
67 | +} | ||
68 | + | ||
69 | +.hidden { | ||
70 | + visibility: hidden; | ||
71 | +} | ||
72 | + | ||
73 | +.visible { | ||
74 | + visibility: visible; | ||
75 | +} | ||
76 | + | ||
77 | +.circle { | ||
78 | + margin: 20px; | ||
79 | + width: 100px; | ||
80 | + height: 100px; | ||
81 | + background-color: aliceblue; | ||
82 | + color: #2e2f30; | ||
83 | + text-align: center; | ||
84 | + border-radius: 50%; | ||
85 | + line-height: 100px; | ||
86 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
views/squatPage/squat.html
0 → 100644
1 | +<!DOCTYPE html> | ||
2 | +<html lang="ko"> | ||
3 | + <head> | ||
4 | + <meta charset="UTF-8"> | ||
5 | + <meta http-equiv="X-UA-Compatible" content="IE=edge"> | ||
6 | + <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
7 | + <link rel="stylesheet" href="squat.css"> | ||
8 | + <title>Squat Page</title> | ||
9 | + </head> | ||
10 | + <body bgcolor= "#353535"> | ||
11 | + <div id="title" class="Title"> | ||
12 | + Squat Page | ||
13 | + <center> | ||
14 | + <button class="w-btn w-btn-indigo" type="button" onclick="init()">WEBCAM START</button> | ||
15 | + <div> | ||
16 | + <canvas id="canvas"></canvas> | ||
17 | + <iframe | ||
18 | + id="youtube" | ||
19 | + class="hidden" | ||
20 | + width="560" height="400" | ||
21 | + src="https://www.youtube.com/embed/9WhpAVOSyl8?start=22" | ||
22 | + title="YouTube video player" | ||
23 | + frameborder="0" | ||
24 | + allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture" allowfullscreen> | ||
25 | + </iframe> | ||
26 | + </div> | ||
27 | + <div id="counter" class="circle"></div> | ||
28 | + </center> | ||
29 | + </div> | ||
30 | + <div id="label-container" class="label-container"></div> | ||
31 | + <script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.3.1/dist/tf.min.js"></script> | ||
32 | + <script src="https://cdn.jsdelivr.net/npm/@teachablemachine/pose@0.8/dist/teachablemachine-pose.min.js"></script> | ||
33 | + <script src="./squat.js"></script> | ||
34 | + </body> | ||
35 | +</html> |
1 | -<!DOCTYPE html> | 1 | +// More API functions here: |
2 | -<html lang="en"> | 2 | +// https://github.com/googlecreativelab/teachablemachine-community/tree/master/libraries/pose |
3 | -<head> | 3 | +// the link to your model provided by Teachable Machine export panel |
4 | - <meta charset="UTF-8"> | 4 | +const URL = "https://teachablemachine.withgoogle.com/models/xymjZj4q-/"; // 임시 URI - stand , squart, bent(허리 굽은 자세) 학습. |
5 | - <meta http-equiv="X-UA-Compatible" content="IE=edge"> | 5 | +let model, webcam, ctx, labelContainer, maxPredictions; |
6 | - <meta name="viewport" content="width=device-width, initial-scale=1.0"> | ||
7 | - <title>Squart Page</title> | ||
8 | -</head> | ||
9 | -<body> | ||
10 | - <div>온라인 헬스 케어 서비스 (스쿼트)</div> | ||
11 | -<div> | ||
12 | - <script src = "./squart.js"></script> | ||
13 | - <sapn id = "user_count">0</sapn> | ||
14 | -</div> | ||
15 | -<button type="button" onclick="init()">Start</button> | ||
16 | -<div><canvas id="canvas"></canvas></div> | ||
17 | 6 | ||
18 | -<div id="label-container"></div> | 7 | +// 상태 : 서있는 상태로 초기화 |
19 | -<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs@1.3.1/dist/tf.min.js"></script> | 8 | +let status = "stand" ; |
20 | -<script src="https://cdn.jsdelivr.net/npm/@teachablemachine/pose@0.8/dist/teachablemachine-pose.min.js"></script> | 9 | +// 갯수 count |
21 | -<script type="text/javascript"> | 10 | +let count = 0; |
22 | - // More API functions here: | 11 | +var counter = document.getElementById("counter"); |
23 | - // https://github.com/googlecreativelab/teachablemachine-community/tree/master/libraries/pose | 12 | +counter.textContent = count; |
13 | +counter.className = "hidden"; | ||
24 | 14 | ||
25 | - // the link to your model provided by Teachable Machine export panel | 15 | +async function init() { |
26 | - const URL = "https://teachablemachine.withgoogle.com/models/xymjZj4q-/"; // 임시 URI - stand , squart, bent(허리 굽은 자세) 학습. | 16 | + const modelURL = URL + "model.json"; |
27 | - let model, webcam, ctx, labelContainer, maxPredictions; | 17 | + const metadataURL = URL + "metadata.json"; |
28 | 18 | ||
29 | - async function init() { | 19 | + var target = document.getElementById("youtube"); |
30 | - const modelURL = URL + "model.json"; | 20 | + target.className = "visible"; |
31 | - const metadataURL = URL + "metadata.json"; | ||
32 | 21 | ||
33 | - // load the model and metadata | 22 | + var target2 = document.getElementById("title"); |
34 | - // Refer to tmImage.loadFromFiles() in the API to support files from a file picker | 23 | + target2.className = "click_title"; |
35 | - // Note: the pose library adds a tmPose object to your window (window.tmPose) | ||
36 | - model = await tmPose.load(modelURL, metadataURL); | ||
37 | - maxPredictions = model.getTotalClasses(); | ||
38 | 24 | ||
39 | - // Convenience function to setup a webcam | 25 | + counter.className = "circle"; |
40 | - const size = 200; | 26 | + |
41 | - const flip = true; // whether to flip the webcam | 27 | + // load the model and metadata |
42 | - webcam = new tmPose.Webcam(size, size, flip); // width, height, flip | 28 | + // Refer to tmImage.loadFromFiles() in the API to support files from a file picker |
43 | - await webcam.setup(); // request access to the webcam | 29 | + // Note: the pose library adds a tmPose object to your window (window.tmPose) |
44 | - await webcam.play(); | 30 | + model = await tmPose.load(modelURL, metadataURL); |
45 | - window.requestAnimationFrame(loop); | 31 | + maxPredictions = model.getTotalClasses(); |
46 | - | 32 | + // Convenience function to setup a webcam |
47 | - // append/get elements to the DOM | 33 | + const size = 400; |
48 | - const canvas = document.getElementById("canvas"); | 34 | + const flip = true; // whether to flip the webcam |
49 | - canvas.width = size; canvas.height = size; | 35 | + webcam = new tmPose.Webcam(size, size, flip); // width, height, flip |
50 | - ctx = canvas.getContext("2d"); | 36 | + await webcam.setup(); // request access to the webcam |
51 | - labelContainer = document.getElementById("label-container"); | 37 | + await webcam.play(); |
52 | - for (let i = 0; i < maxPredictions; i++) { // and class labels | 38 | + webcam.style |
53 | - labelContainer.appendChild(document.createElement("div")); | 39 | + window.requestAnimationFrame(loop); |
54 | - } | 40 | + // append/get elements to the DOM |
41 | + const canvas = document.getElementById("canvas"); | ||
42 | + canvas.width = size; canvas.height = size; | ||
43 | + ctx = canvas.getContext("2d"); | ||
44 | + labelContainer = document.getElementById("label-container"); | ||
45 | + for (let i = 0; i < maxPredictions; i++) { // and class labels | ||
46 | + labelContainer.appendChild(document.createElement("div")); | ||
55 | } | 47 | } |
48 | +} | ||
56 | 49 | ||
57 | - async function loop(timestamp) { | 50 | +async function loop(timestamp) { |
58 | - webcam.update(); // update the webcam frame | 51 | + webcam.update(); // update the webcam frame |
59 | - await predict(); | 52 | + await predict(); |
60 | - window.requestAnimationFrame(loop); | 53 | + window.requestAnimationFrame(loop); |
61 | - } | 54 | +} |
62 | - // 상태 | ||
63 | - let status = "stand" ; | ||
64 | - // 갯수 count | ||
65 | - let count = 0; | ||
66 | - // 잘못된 경우 count | ||
67 | - let wrong_count = 0; | ||
68 | 55 | ||
69 | - async function predict() { | 56 | +async function predict() { |
70 | - // Prediction #1: run input through posenet | 57 | + // Prediction #1: run input through posenet |
71 | - // estimatePose can take in an image, video or canvas html element | 58 | + // estimatePose can take in an image, video or canvas html element |
72 | - const { pose, posenetOutput } = await model.estimatePose(webcam.canvas); | 59 | + const { pose, posenetOutput } = await model.estimatePose(webcam.canvas); |
73 | - // Prediction 2: run input through teachable machine classification model | 60 | + // Prediction 2: run input through teachable machine classification model |
74 | - const prediction = await model.predict(posenetOutput); | 61 | + const prediction = await model.predict(posenetOutput); |
75 | 62 | ||
76 | - if (prediction[0].probability.toFixed(2) > 0.9) // 서있는 상태 | 63 | + if (prediction[0].probability.toFixed(2) > 0.9) { // 서있는 상태 |
77 | - { | 64 | + if (status == "squat"){ // 전에 스쿼트 상태였다면, 일어날 때 카운트를 하나 올려줘야 함. |
78 | - if (status == "squart") | 65 | + count++; |
79 | - { | 66 | + var audio = new Audio('./sound/' + count%10 + '.wav'); |
80 | - count++; | 67 | + audio.play(); |
81 | - console.log(`올바른 스쿼트 : ${count}`) | 68 | + counter.textContent = count; |
82 | - } | 69 | + console.log(count); |
83 | - status = "stand"; | ||
84 | } | 70 | } |
85 | - else if (prediction[1].probability.toFixed(2) > 1.00) // 스쿼트 자세 | 71 | + status = "stand" |
86 | - { | 72 | + } else if (prediction[1].probability.toFixed(2) == 1.00) { // 스쿼트 자세 |
87 | - status = "squart"; | 73 | + status = "squat" |
88 | - } | 74 | + } else if (prediction[2].probability.toFixed(2) == 1.00) { // 굽은 자세(잘못된 케이스) |
89 | - else if (prediction[2].probability.toFixed(2) == 1.00) // 굽은 자세(잘못된 케이스) | 75 | + if (status == "squart" || status == "stand") { // 굽은 자세로 잘못 수행하면, 소리 나도록 |
90 | - { | 76 | + var audio = new Audio('./sound/bad.mp3'); |
91 | - if (status == "squart" || status == "stand") // 굽은 자세로 잘못 수행하면, | 77 | + audio.play(); |
92 | - { | ||
93 | - wrong_count++; | ||
94 | - console.log(`잘못된 자세 : ${wrong_count}`) | ||
95 | - } | ||
96 | - status = "bent"; | ||
97 | - } | ||
98 | - | ||
99 | - for (let i = 0; i < maxPredictions; i++) { | ||
100 | - const classPrediction = | ||
101 | - prediction[i].className + ": " + prediction[i].probability.toFixed(2); | ||
102 | - labelContainer.childNodes[i].innerHTML = classPrediction; | ||
103 | } | 78 | } |
79 | + status = "bent" | ||
80 | + } | ||
104 | 81 | ||
105 | - // finally draw the poses | 82 | + for (let i = 0; i < maxPredictions; i++) { |
106 | - drawPose(pose); | 83 | + const classPrediction = |
84 | + prediction[i].className + ": " + prediction[i].probability.toFixed(2); | ||
85 | + labelContainer.childNodes[i].innerHTML = classPrediction; | ||
107 | } | 86 | } |
108 | 87 | ||
109 | - function drawPose(pose) { | 88 | + // finally draw the poses |
110 | - if (webcam.canvas) { | 89 | + drawPose(pose); |
111 | - ctx.drawImage(webcam.canvas, 0, 0); | 90 | +} |
112 | - // draw the keypoints and skeleton | 91 | + |
113 | - if (pose) { | 92 | +function drawPose(pose) { |
114 | - const minPartConfidence = 0.5; | 93 | + if (webcam.canvas) { |
115 | - tmPose.drawKeypoints(pose.keypoints, minPartConfidence, ctx); | 94 | + ctx.drawImage(webcam.canvas, 0, 0); |
116 | - tmPose.drawSkeleton(pose.keypoints, minPartConfidence, ctx); | 95 | + // draw the keypoints and skeleton |
117 | - } | 96 | + if (pose) { |
97 | + const minPartConfidence = 0.5; | ||
98 | + tmPose.drawKeypoints(pose.keypoints, minPartConfidence, ctx); | ||
99 | + tmPose.drawSkeleton(pose.keypoints, minPartConfidence, ctx); | ||
118 | } | 100 | } |
119 | } | 101 | } |
120 | -</script> | ||
121 | - | ||
122 | -</body> | ||
123 | -</html> | ||
... | \ No newline at end of file | ... | \ No newline at end of file |
102 | +} | ||
... | \ No newline at end of file | ... | \ No newline at end of file | ... | ... |
healthcare-with-webcam @ 381096f7
1 | +Subproject commit 381096f776f0756063d2f9e77ceaca7d5fc7fcdc |
-
Please register or login to post a comment