From ba833e4f58d6cc718e5e8145b096282ec156b2fc Mon Sep 17 00:00:00 2001 From: Shreya Ramesh Date: Sun, 12 Nov 2017 22:31:45 -0500 Subject: [PATCH 1/8] line for hand raising exercise --- exercise/public/js/kinect.js | 39 +++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 12 deletions(-) diff --git a/exercise/public/js/kinect.js b/exercise/public/js/kinect.js index 09548ba..f00389c 100755 --- a/exercise/public/js/kinect.js +++ b/exercise/public/js/kinect.js @@ -57,21 +57,17 @@ $(document).ready(function () { document.getElementById("display").style.display = 'none'; }); - // Functions - - function drawCircle(x, y, r, color){ // Not used in current code - ctx1.beginPath(); - ctx1.strokeStyle=color; - ctx1.arc(x, y,r,0,Math.PI*2); - ctx1.stroke(); - } function drawBody(body){ - //drawCircle(50, 50, 10, "green"); jointType = [7,6,5,4,2,8,9,10,11,10,9,8,2,3,2,1,0,12,13,14,15,14,13,12,0,16,17,18,19] //re visit and draw in a line jointType.forEach(function(jointType){ drawJoints(body.joints[jointType].depthX * width, body.joints[jointType].depthY * height); }); + + // Example of hand raising exercise. + var gt_y_test = 250; + draw_height_line(body.joints[8].depthX * width, gt_y_test, body.joints[11].depthY*height); + drawCenterCircle(width/2, height/5, 50, body.joints[2].depthX * width, body.joints[2].depthY * height); ctx1.beginPath(); @@ -93,7 +89,9 @@ $(document).ready(function () { ctx1.fillStyle = "yellow"; ctx1.fill(); } - // Draw Center Circle in ctx1 (canvasSKLT) + + + // Draw center circle - to help user position themselves function drawCenterCircle(x, y, r, nx, ny){ ctx1.beginPath(); if(nx > x-r && nx < x+r && ny > y-r && ny < y+r) @@ -108,10 +106,27 @@ $(document).ready(function () { } + // Line to indicate user reaching some standard or requirement + // Input is start of line, ground truth height, exercise height + // Line is yellow if requirement unfulfilled, green if fulfilled + + function draw_height_line(starting_x, gt_y, ex_y){ + ctx1.beginPath(); + if (hand_y < gt_y){ + ctx1.strokeStyle = "green"; + }else{ + ctx1.strokeStyle = "yellow"; + } + + ctx1.moveTo(shoulder_x, gt_y); + ctx1.lineTo(width, gt_y); + ctx1.stroke(); + ctx1.closePath(); + ctx1.strokeStyle = "black"; + } + function liveupdateCanvas1(bodyFrame, tracingID){ ctx1.clearRect(0, 0, width, height); - //drawCircle(ctx1, 50, 50, 10, "red"); removed if following code line works - //drawCenterCircle(width/2, height/5, 50, body.joints[2].depthX * width, body.joints[2].depthY * height); if (tracingID == -1){ bodyFrame.bodies.some(function(body){ if(body.tracked){ drawBody(body); return(body.tracked);} From 7a3a0f3b393fd0bb4734844633925de9546b6923 Mon Sep 17 00:00:00 2001 From: Shreya Ramesh Date: Sat, 25 Nov 2017 14:56:46 -0500 Subject: [PATCH 2/8] show line marker for squat --- exercise/public/index.html | 91 ++++++----- exercise/public/js/kinect.js | 284 +++++++++++++++++++---------------- 2 files changed, 207 insertions(+), 168 deletions(-) diff --git a/exercise/public/index.html b/exercise/public/index.html index 6afeb5b..d3a22db 100755 --- a/exercise/public/index.html +++ b/exercise/public/index.html @@ -1,50 +1,65 @@ - - - ExerciseCheck Client - - ExerciseCheck Client - - - - + + + ExerciseCheck Client + + ExerciseCheck Client + + + + - - - - + + + + - -

ExerciseCheck

-
-
-
- -
- - - - - -
-
-
- - - -
-
+ +

ExerciseCheck

+
+
+
+ +
+ + + + + +
+
+
+ + + +
+
-
+
- - - - + + + + diff --git a/exercise/public/js/kinect.js b/exercise/public/js/kinect.js index f00389c..5a9e6dc 100755 --- a/exercise/public/js/kinect.js +++ b/exercise/public/js/kinect.js @@ -2,152 +2,176 @@ var socket = io.connect('/'); var clientActive = false; $(document).ready(function () { - var canvasSKLT = document.getElementById('bodyCanvas'); - var ctx1 = canvasSKLT.getContext('2d'); + var canvasSKLT = document.getElementById('bodyCanvas'); + var ctx1 = canvasSKLT.getContext('2d'); - document.getElementById("display").style.display = 'none'; - var colors = ['#ff0000', '#00ff00', '#0000ff', '#ffff00', '#00ffff', '#ff00ff']; + document.getElementById("display").style.display = 'none'; - // Globals: - var radius=9; - var width = canvasSKLT.width; - var height = canvasSKLT.height; + // Globals: + var radius = 9; + var width = canvasSKLT.width; + var height = canvasSKLT.height; - var IntervalID; + var IntervalID; - // Signals + // Signals - // Use bodyFrame from server to update the canvas 1 on client - socket.on('init', function(bodyFrame,systemState){ - clientActive = true; - liveupdateCanvas1(bodyFrame,-1); - document.getElementById("command").value= 'Start'; - document.getElementById("command").style.backgroundColor = ''; - document.getElementById("display").style.display = 'none'; - }); + // Use bodyFrame from server to update the canvas 1 on client + socket.on('init', function (bodyFrame, systemState) { + clientActive = true; + liveupdateCanvas1(bodyFrame, -1); + document.getElementById("command").value = 'Start'; + document.getElementById("command").style.backgroundColor = ''; + document.getElementById("display").style.display = 'none'; + }); - socket.on('rec', function(bodyFrame,systemState, tracingID){ - clientActive = true; - liveupdateCanvas1(bodyFrame,tracingID); - document.getElementById("command").value = 'Stop'; - document.getElementById("command").style.backgroundColor = 'red'; - document.getElementById("display").style.display = 'none'; - }); - - socket.on('disp', function(bufferBodyFrames,systemState, tracingID, activityLabeled){ - clientActive = true; // unlock the button - IntervalID = animateCanvas1(bufferBodyFrames,tracingID); - document.getElementById("command").value = 'Live'; - document.getElementById("command").style.backgroundColor = ''; - if (!activityLabeled) - document.getElementById("display").style.display = 'block'; - }); - - socket.on('live', function(bodyFrame,systemState, tracingID){ - clientActive = true; - clearInterval(IntervalID); - liveupdateCanvas1(bodyFrame,-1); - - document.getElementById("command").value= 'Start'; - document.getElementById("command").style.backgroundColor = ''; - document.getElementById("display").style.display = 'none'; - }); + socket.on('rec', function (bodyFrame, systemState, tracingID) { + clientActive = true; + liveupdateCanvas1(bodyFrame, tracingID); + document.getElementById("command").value = 'Stop'; + document.getElementById("command").style.backgroundColor = 'red'; + document.getElementById("display").style.display = 'none'; + }); - socket.on('serverDataLabeled',function(){ // hid the buttons "Reference","Exercise","Discard" - document.getElementById("display").style.display = 'none'; - }); + socket.on('disp', function (bufferBodyFrames, systemState, tracingID, activityLabeled) { + clientActive = true; // unlock the button + IntervalID = animateCanvas1(bufferBodyFrames, tracingID); + document.getElementById("command").value = 'Live'; + document.getElementById("command").style.backgroundColor = ''; + if (!activityLabeled) + document.getElementById("display").style.display = 'block'; + }); + socket.on('live', function (bodyFrame) { + clientActive = true; + clearInterval(IntervalID); + liveupdateCanvas1(bodyFrame, -1); - function drawBody(body){ - jointType = [7,6,5,4,2,8,9,10,11,10,9,8,2,3,2,1,0,12,13,14,15,14,13,12,0,16,17,18,19] //re visit and draw in a line - jointType.forEach(function(jointType){ - drawJoints(body.joints[jointType].depthX * width, body.joints[jointType].depthY * height); + document.getElementById("command").value = 'Start'; + document.getElementById("command").style.backgroundColor = ''; + document.getElementById("display").style.display = 'none'; }); - - // Example of hand raising exercise. - var gt_y_test = 250; - draw_height_line(body.joints[8].depthX * width, gt_y_test, body.joints[11].depthY*height); - - drawCenterCircle(width/2, height/5, 50, body.joints[2].depthX * width, body.joints[2].depthY * height); - - ctx1.beginPath(); - ctx1.moveTo(body.joints[7].depthX * width, body.joints[7].depthY * height); - jointType.forEach(function(jointType){ - ctx1.lineTo(body.joints[jointType].depthX * width, body.joints[jointType].depthY * height); - ctx1.moveTo(body.joints[jointType].depthX * width, body.joints[jointType].depthY * height); + + socket.on('serverDataLabeled', function () { // hide the buttons "Reference","Exercise","Discard" + document.getElementById("display").style.display = 'none'; }); - ctx1.lineWidth=10; - ctx1.strokeStyle='blue'; - ctx1.stroke(); - ctx1.closePath(); - } - - function drawJoints(cx,cy){ - ctx1.beginPath(); - ctx1.arc(cx,cy,radius,0,Math.PI*2); //radius is a global variable defined at the beginning - ctx1.closePath(); - ctx1.fillStyle = "yellow"; - ctx1.fill(); - } - - - // Draw center circle - to help user position themselves - function drawCenterCircle(x, y, r, nx, ny){ - ctx1.beginPath(); - if(nx > x-r && nx < x+r && ny > y-r && ny < y+r) - ctx1.strokeStyle="green"; - else - ctx1.strokeStyle="red"; - - ctx1.arc(x, y,r,0,Math.PI*2); - ctx1.stroke(); - ctx1.closePath(); - ctx1.strokeStyle="black"; - } - - - // Line to indicate user reaching some standard or requirement - // Input is start of line, ground truth height, exercise height - // Line is yellow if requirement unfulfilled, green if fulfilled - - function draw_height_line(starting_x, gt_y, ex_y){ - ctx1.beginPath(); - if (hand_y < gt_y){ - ctx1.strokeStyle = "green"; - }else{ - ctx1.strokeStyle = "yellow"; + + + function drawBody(body) { + jointType = [7, 6, 5, 4, 2, 8, 9, 10, 11, 10, 9, 8, 2, 3, 2, 1, 0, 12, 13, 14, 15, 14, 13, 12, 0, 16, 17, 18, 19] //re visit and draw in a line + jointType.forEach(function (jointType) { + drawJoints(body.joints[jointType].depthX * width, body.joints[jointType].depthY * height); + }); + + // Example of hand raising exercise. + var line_marker = document.getElementById("line-marker").value; + var gt_y_test; + if (line_marker == 11) { + gt_y_test = 250; + draw_height_line(body.joints[8].depthX * width, gt_y_test, body.joints[line_marker].depthY * height); + } else if (line_marker == 0) { + gt_y_test = 500; + draw_height_line(body.joints[13].depthX * width, gt_y_test, body.joints[line_marker].depthY * height, comparison = 'greater', direction = 'both'); + } + + drawCenterCircle(width / 2, height / 5, 50, body.joints[2].depthX * width, body.joints[2].depthY * height); + + ctx1.beginPath(); + ctx1.moveTo(body.joints[7].depthX * width, body.joints[7].depthY * height); + jointType.forEach(function (jointType) { + ctx1.lineTo(body.joints[jointType].depthX * width, body.joints[jointType].depthY * height); + ctx1.moveTo(body.joints[jointType].depthX * width, body.joints[jointType].depthY * height); + }); + ctx1.lineWidth = 10; + ctx1.strokeStyle = 'blue'; + ctx1.stroke(); + ctx1.closePath(); } - ctx1.moveTo(shoulder_x, gt_y); - ctx1.lineTo(width, gt_y); - ctx1.stroke(); - ctx1.closePath(); - ctx1.strokeStyle = "black"; - } - - function liveupdateCanvas1(bodyFrame, tracingID){ - ctx1.clearRect(0, 0, width, height); - if (tracingID == -1){ - bodyFrame.bodies.some(function(body){ - if(body.tracked){ drawBody(body); return(body.tracked);} - }); + function drawJoints(cx, cy) { + ctx1.beginPath(); + ctx1.arc(cx, cy, radius, 0, Math.PI * 2); //radius is a global variable defined at the beginning + ctx1.closePath(); + ctx1.fillStyle = "yellow"; + ctx1.fill(); } - else { - drawBody(bodyFrame.bodies[tracingID]); + + // Draw center circle - to help user position themselves + function drawCenterCircle(x, y, r, nx, ny) { + ctx1.beginPath(); + if (nx > x - r && nx < x + r && ny > y - r && ny < y + r) + ctx1.strokeStyle = "green"; + else + ctx1.strokeStyle = "red"; + + ctx1.arc(x, y, r, 0, Math.PI * 2); + ctx1.stroke(); + ctx1.closePath(); + ctx1.strokeStyle = "black"; + } + + + // Line to indicate user reaching some standard or requirement + // Input is start of line, ground truth height, exercise height + // Line is yellow if requirement unfulfilled, green if fulfilled + + function draw_height_line(starting_x, gt_y, ex_y, comparison='less', direction='right') { + ctx1.beginPath(); + if (comparison == 'less') { + if (ex_y < gt_y) { + ctx1.strokeStyle = "green"; + } else { + ctx1.strokeStyle = "yellow"; + } + } + else { + if (ex_y > gt_y) { + ctx1.strokeStyle = "green"; + } else { + ctx1.strokeStyle = "yellow"; + } + } + + ctx1.moveTo(starting_x, gt_y); + if (direction == 'both') { + ctx1.lineTo(width, gt_y); + ctx1.lineTo(0, gt_y); + } else if (direction == 'left') { + ctx1.lineTo(0, gt_y); + } else { + ctx1.lineTo(width, gt_y); + } + ctx1.stroke(); + ctx1.closePath(); + ctx1.strokeStyle = "black"; + } + + function liveupdateCanvas1(bodyFrame, tracingID) { + ctx1.clearRect(0, 0, width, height); + if (tracingID == -1) { + bodyFrame.bodies.some(function (body) { + if (body.tracked) { + drawBody(body); + return (body.tracked); + } + }); + } else { + drawBody(bodyFrame.bodies[tracingID]); + } } - } - - function animateCanvas1(bufferBodyFrames,tracingID){ - var i = 0; - var TimerID = setInterval(function(){ - liveupdateCanvas1(bufferBodyFrames[i], tracingID); - i++; - if (i>=bufferBodyFrames.length){i=0;} - },20); - return TimerID; - } -}); + function animateCanvas1(bufferBodyFrames, tracingID) { + var i = 0; + var TimerID = setInterval(function () { + liveupdateCanvas1(bufferBodyFrames[i], tracingID); + i++; + if (i >= bufferBodyFrames.length) { + i = 0; + } + }, 20); + return TimerID; + } +}); /* Reference From 7a923f07b494458154a52ae664b31c756d9eed84 Mon Sep 17 00:00:00 2001 From: Shreya Ramesh Date: Sat, 2 Dec 2017 22:56:25 -0500 Subject: [PATCH 3/8] show speed by joint in display mode --- exercise/index.js | 995 +++++++++++++++++-------------- exercise/public/index.html | 21 +- exercise/public/js/kinect.js | 12 +- exercise/public/js/navigation.js | 50 +- 4 files changed, 586 insertions(+), 492 deletions(-) diff --git a/exercise/index.js b/exercise/index.js index ea6e584..ec3dffe 100755 --- a/exercise/index.js +++ b/exercise/index.js @@ -1,469 +1,550 @@ var Kinect2 = require('kinect2'), - express = require('express'), - app = express(), - server = require('http').createServer(app), - io = require('socket.io').listen(server); - XLSX = require('xlsx'); + express = require('express'), + app = express(), + server = require('http').createServer(app), + io = require('socket.io').listen(server); +XLSX = require('xlsx'); const fs = require('fs'); var kinect = new Kinect2(); var clients = 0; -if(kinect.open()) { - // Server Initiation - server.listen(8000); - console.log('Server listening on port 8000'); - console.log('Point your browser to http://localhost:8000'); - app.use(express.static('public')) - - // Initiation - - // States and sub-state, global variables in server - var systemState = 3, // 3 is the initiation code || 1: recording, 2: display, 0: live, 3: init == live - activityLabeled = false; - - // Data Storage, global variables in server - var bufferTrial= [], // trial is a number of activities, including ground truth (gt) and exercises - bufferBodyFrames =[], gtArray = [], exArray = []; - - // Start Time for the test - var startTime, duration; - var bodyIndex = -1; - - console.log('system init state'); - kinect.openBodyReader(); - - // Connection On: - io.on('connection', function(socket){ - ++clients; - console.log('a user connected'); - // systemState could be 0..3 during connection event, but only 2 needs signal emission - if (systemState == 2) { - socket.emit('disp',bufferBodyFrames,systemState, bodyIndex, activityLabeled); - } - - // State Transition controlled by the client's command - socket.on('command',function(){ - systemState = StateTrans(systemState); - switch (systemState) { // During the transition, prepare the buffer - case 1: // 0->1 or 3->1 Get ready for recording - activityLabeled = false; - bodyIndex = locateBodyTrackedIndex(bufferBodyFrames); - bufferBodyFrames = []; - console.log('System in Recording state'); - startTime = new Date().getTime(); - break; - - case 2: // 1->2, Push the BodyFrames Data to the current trial - duration = ((new Date().getTime() - startTime)/1000).toFixed(2); - kinect.closeBodyReader(); // if closeBodyReader is called twice, the server is down. - bufferBodyFrames.durationsecs = duration; - bufferBodyFrames.duration = duration.toString(); - bufferBodyFrames.bodyIndex = bodyIndex; - bodyIndex = -1; - //console.log(JSON.stringify(bufferBodyFrames)); - bufferTrial.push(bufferBodyFrames); - console.log('system in Result Display state'); // Action - socket.emit('disp',bufferBodyFrames,systemState, bodyIndex, activityLabeled); // activityLabeled should be false because recording is just ended - socket.broadcast.emit('disp',bufferBodyFrames,systemState, bodyIndex, activityLabeled); - break; - - case 0: // 2->0, get the system from Result Disp to Live state. - kinect.openBodyReader();// No Other Specific Actions in this block because it is done by kinect.on() - console.log('system in Live state'); - default: - } - }); - // Speical Buttons: label buttons(3), report button(1), save(1) & curve show(1) - socket.on('dataLabelFromClient',function(num){ // label reference, exercise or discard - testID = bufferTrial.length-1; - if (gtArray[gtArray.length-1] == testID) { gtArray.pop(); } - if (exArray[exArray.length-1] == testID) { exArray.pop(); } - if (num == 1) { gtArray.push(testID); } - else{ if (num == 2) { exArray.push(testID); } } - activityLabeled = true; - socket.emit('serverDataLabeled'); - socket.broadcast.emit('serverDataLabeled'); - }) - - socket.on('analyze',function(){ - console.log('analyze signal received!'); - var chartData = chartAnalyze(bufferTrial,gtArray,exArray); - var barData = barAnalyze(bufferTrial, gtArray, exArray); - socket.emit('report',chartData, barData, gtArray, exArray); +if (kinect.open()) { + // Server Initiation + server.listen(8000); + console.log('Server listening on port 8000'); + console.log('Point your browser to http://localhost:8000'); + app.use(express.static('public')) + + + // States and sub-state, global variables in server + var systemState = 3, // 3 is the initiation code || 1: recording, 2: display, 0: live, 3: init == live + activityLabeled = false; + + // Data Storage, global variables in server + var bufferTrial = [], // trial is a number of activities, including ground truth (gt) and exercises + bufferBodyFrames = [], gtArray = [], exArray = []; + + // Variables used in calculating speed + var startTime, duration; + var bodyIndex = -1; + + console.log('system init state'); + kinect.openBodyReader(); + + // Connection On: + io.on('connection', function (socket) { + ++clients; + console.log('a user connected'); + // systemState could be 0..3 during connection event, but only 2 needs signal emission + if (systemState == 2) { + socket.emit('disp', bufferBodyFrames, systemState, bodyIndex, activityLabeled); + } + + // State Transition controlled by the client's command + socket.on('command', function () { + systemState = StateTrans(systemState); + switch (systemState) { // During the transition, prepare the buffer + case 1: // 0->1 or 3->1 Get ready for recording + activityLabeled = false; + bodyIndex = locateBodyTrackedIndex(bufferBodyFrames); + bufferBodyFrames = []; + console.log('System in Recording state'); + startTime = new Date().getTime(); + break; + + case 2: // 1->2, Push the BodyFrames Data to the current trial + duration = ((new Date().getTime() - startTime)).toFixed(2); + kinect.closeBodyReader(); // if closeBodyReader is called twice, the server is down. + bufferBodyFrames.durationsecs = duration / 1000; + bufferBodyFrames.duration = duration.toString(); + bufferBodyFrames.bodyIndex = bodyIndex; + bodyIndex = -1; + bufferTrial.push(bufferBodyFrames); + console.log('system in Result Display state'); // Action + socket.emit('disp', bufferBodyFrames, systemState, bodyIndex, activityLabeled); // activityLabeled should be false because recording is just ended + socket.broadcast.emit('disp', bufferBodyFrames, systemState, bodyIndex, activityLabeled); + break; + + case 0: // 2->0, get the system from Result Disp to Live state. + kinect.openBodyReader();// No Other Specific Actions in this block because it is done by kinect.on() + console.log('system in Live state'); + default: + } + }); + // Special Buttons: label buttons(3), report button(1), save(1) & curve show(1) + socket.on('dataLabelFromClient', function (num) { // label reference, exercise or discard + testID = bufferTrial.length - 1; + if (gtArray[gtArray.length - 1] == testID) { + gtArray.pop(); + } + if (exArray[exArray.length - 1] == testID) { + exArray.pop(); + } + if (num == 1) { + gtArray.push(testID); + } + else { + if (num == 2) { + exArray.push(testID); + } + } + activityLabeled = true; + socket.emit('serverDataLabeled'); + socket.broadcast.emit('serverDataLabeled'); + }); + + // For showing joint speed with speedometer + socket.on('joint-speed', function (joint_num) { + console.log('inside joint speed socket on'); + var speed = getSpeed(bufferTrial, bufferTrial.length - 1, joint_num); + socket.emit('showing-speed', speed); + }); + + + socket.on('analyze', function () { + console.log('analyze signal received!'); + var chartData = chartAnalyze(bufferTrial, gtArray, exArray); + var barData = barAnalyze(bufferTrial, gtArray, exArray); + socket.emit('report', chartData, barData, gtArray, exArray); + }); + + socket.on('saveRequest', function (filename) { + save2xlsx(bufferTrial, gtArray, exArray, filename); + }); + + socket.on('curveRequest', function (gtInd, exInd, jt, datatype) { + var curveData = curveAnalyze(bufferTrial, gtArray, exArray, gtInd, exInd, jt, datatype); + socket.emit('curveResult', curveData); + }); + + // States + kinect.on('bodyFrame', function (bodyFrame) { + + switch (systemState) { + case 1: //recording: save the data being recorded, give identification to client + socket.emit('rec', bodyFrame, systemState, bodyIndex); + socket.broadcast.emit('rec', bodyFrame, systemState, bodyIndex); + bufferBodyFrames.push(bodyFrame); // save the bodyFrame by pushing it to buffer + break; + + case 2: //display + console.log('system in display state, but system is streaming. Something wrong here.'); + break; + + case 0: //live + bufferBodyFrames = []; + bufferBodyFrames.push(bodyFrame); // clean buffer and push the current bodyFrame to buffer. It is used to find the (1) bodyIndex to track. + socket.emit('live', bodyFrame, systemState) + socket.broadcast.emit('live', bodyFrame, systemState); + break; + + case 3: //3 init + bufferBodyFrames = []; + bufferBodyFrames.push(bodyFrame); + socket.emit('init', bodyFrame, systemState); + socket.broadcast.emit('init', bodyFrame, systemState); + break; + + default: + console.log('System State unknown'); + } + }); + + // disconnect + socket.on('disconnect', function () { + console.log('a user disconnect'); + --clients; + }) }); - socket.on('saveRequest',function(filename){ - save2xlsx(bufferTrial,gtArray,exArray,filename); - }); - - socket.on('curveRequest',function(gtInd,exInd,jt,datatype){ - var curveData = curveAnalyze(bufferTrial,gtArray,exArray,gtInd,exInd,jt,datatype); - socket.emit('curveResult',curveData); - }); - - // States - kinect.on('bodyFrame', function(bodyFrame){ - console.log("new bodyframe received..."); - console.log(JSON.stringify(bodyFrame)) ; - - switch (systemState) { - case 1: //recording: save the data being recorded, give identification to client - socket.emit('rec', bodyFrame, systemState, bodyIndex); - socket.broadcast.emit('rec', bodyFrame, systemState, bodyIndex); - bufferBodyFrames.push(bodyFrame); // save the bodyFrame by pushing it to buffer - break; - - case 2: //display - console.log('system in display state, but system is streaming. Something wrong here.'); - break; - - case 0: //live - bufferBodyFrames = []; - bufferBodyFrames.push(bodyFrame); // clean buffer and push the current bodyFrame to buffer. It is used to find the (1) bodyIndex to track. - socket.emit('live', bodyFrame,systemState) - socket.broadcast.emit('live', bodyFrame,systemState); - break; - - case 3: //3 init - bufferBodyFrames = []; - bufferBodyFrames.push(bodyFrame); - socket.emit('init', bodyFrame, systemState); - socket.broadcast.emit('init', bodyFrame, systemState); - break; - - default: - console.log('System State unknown'); - }//end of switch - }); // end of kinect.on('bodyframe',function) - - // disconnect - socket.on('disconnect',function(){ - console.log('a user disconnect'); - --clients; - }) - }); // end of io.on('connection',function) -}//end of kinect.open() - - -// Functions ---------------------------------------------------------------------- -// Define the legal move between states -function StateTrans(st){ - return (st+1)%3; -} - -function locateBodyTrackedIndex(bufferBodyFrames){ - var ind = -1; - for (var i=0; i<=5; i++){ - if (bufferBodyFrames[0].bodies[i].tracked){ // tracked in the first frame - ind = i; - break; - } - } - return ind; -} - -function typeofTest(bufferTrial,id){ - var type // 0: Hand, 1: Squat - var typeList = ["Hand","Squat"]; - if (getAmplitudeY(bufferTrial,id,0) > 0.15) //Base of spine moves > 0.15m - {type = "Squat";} - else - { type = "Hand";} - return type; -} - -function getRaw(bufferTrial,id,jt,datatype){ - var frames = bufferTrial[id]; - var ind = frames.bodyIndex, time = frames.durationsecs; - var rawdata = [] - for(var i=0; i90) {T_x += -180;} - if (T_y>180) {T_y += -180;} - if (T_z>180) {T_z += -180;} - if (datatype == 3) - {rawdata.push(T_x);} - if (datatype == 4) - {rawdata.push(T_y);} - if (datatype == 5) - {rawdata.push(T_z);} - - } - } - return rawdata; -} - -function getSpeed(bufferTrial,id,jt){ - var frames = bufferTrial[id]; - var ind = frames.bodyIndex, time = frames.durationsecs; - var accumDist = 0, speed = 0; - for(var i=0; i0){ - for(var i=0 ; imaxlength) {maxlength = rawdata.length} - } - } - - if (exInd.length>0){ - for(var i=0 ; imaxlength) {maxlength = rawdata.length} - } - } - var numMarks = 10; - var pads = Math.ceil(maxlength/numMarks); - - for (var i = 0; i 0.15) //Base of spine moves > 0.15m + { + type = "Squat"; + } + else { + type = "Hand"; + } + return type; + } + + function getRaw(bufferTrial, id, jt, datatype) { + var frames = bufferTrial[id]; + var ind = frames.bodyIndex, time = frames.durationsecs; + var rawdata = [] + for (var i = 0; i < frames.length; i++) { + if (datatype == 0) { + rawdata.push(frames[i].bodies[ind].joints[jt].cameraX); + } + if (datatype == 1) { + rawdata.push(frames[i].bodies[ind].joints[jt].cameraY); + } + if (datatype == 2) { + rawdata.push(frames[i].bodies[ind].joints[jt].cameraZ); + } + else { + var x = frames[i].bodies[ind].joints[jt].orientationX; + var y = frames[i].bodies[ind].joints[jt].orientationY; + var z = frames[i].bodies[ind].joints[jt].orientationZ; + var w = frames[i].bodies[ind].joints[jt].orientationW; + + var T_x = 180 + 180 / 3.1416 * Math.atan2(2 * y * z + 2 * x * w, 1 - 2 * x * x - 2 * y * y); // leaning forward/backward + var T_y = 180 / 3.1416 * Math.asin(2 * y * w - 2 * x * z); // turning + var T_z = 180 + 180 / 3.1416 * Math.atan2(2 * x * y + 2 * z * w, 1 - 2 * y * y - 2 * z * z); // leaning left + while (T_x > 90) { + T_x += -180; + } + if (T_y > 180) { + T_y += -180; + } + if (T_z > 180) { + T_z += -180; + } + if (datatype == 3) { + rawdata.push(T_x); + } + if (datatype == 4) { + rawdata.push(T_y); + } + if (datatype == 5) { + rawdata.push(T_z); + } + + } + } + return rawdata; + } + + function getSpeed(bufferTrial, id, jt) { + var frames = bufferTrial[id]; + var ind = frames.bodyIndex; + var time = frames.durationsecs; + var accumDist = 0; + for (var i = 0; i < frames.length - 1; i++) { + if (!frames[i + 1].bodies[ind]) { + continue; + } + var current_joint = frames[i + 1].bodies[ind].joints[jt]; + var prev_joint = frames[i].bodies[ind].joints[jt]; + var distance_x = current_joint.cameraX - prev_joint.cameraX; + var distance_y = current_joint.cameraY - prev_joint.cameraY; + var distance_z = current_joint.cameraZ - prev_joint.cameraZ; + var dist = Math.sqrt(Math.pow(distance_x, 2) + Math.pow(distance_y, 2) + Math.pow(distance_z, 2)); + if (dist) { + accumDist = accumDist + dist; + } + } + return accumDist / time; + } + + function getAmplitudeX(bufferTrial, getSpeedid, jt) { + var ListX = getRaw(bufferTrial, id, jt, 0) + var DistX = (Math.max(...ListX) - Math.min(...ListX + )) + ; + return DistX; + } + + function getAmplitudeY(bufferTrial, id, jt) { + var ListY = getRaw(bufferTrial, id, jt, 1) + var DistY = (Math.max(...ListY) - Math.min(...ListY + )) + ; + return DistY; + } + + function getAmplitudeZ(bufferTrial, id, jt) { + var ListZ = getRaw(bufferTrial, id, jt, 2) + var DistZ = (Math.max(...ListZ) - Math.min(...ListZ + )) + ; + return DistZ; + } + + function getOrientation(bufferTrial, id, jt) { + var RotX = getRaw(bufferTrial, id, jt, 3); + var maxRot = Math.max(...RotX + ), + minRot = Math.min(...RotX + ) + var lean = Math.abs(maxRot - minRot); + return lean; + } + + function save2xlsx(bufferTrial, gtArray, exArray, filename) { + + var wb = new Workbook(); //Create new wb object + for (var i in gtArray) { + var ws_name = "GT_" + (i).toString(); + var ws = sheet_from_bufferTrial(bufferTrial[gtArray[i]], ws_name); + wb.SheetNames.push(ws_name); + wb.Sheets[ws_name] = ws; + } + for (var i in exArray) { + var ws_name = "EX_" + (i).toString(); + var ws = sheet_from_bufferTrial(bufferTrial[exArray[i]], ws_name); + wb.SheetNames.push(ws_name); + wb.Sheets[ws_name] = ws; + } + var wbout = XLSX.write(wb, {bookType: 'xlsx', bookSST: false, type: 'binary'}); //Define workbook type + XLSX.writeFile(wb, filename); //Write workbook + } + + function Workbook() { + if (!(this instanceof Workbook)) return new Workbook(); //Create new instance of workbook type + this.SheetNames = []; + this.Sheets = {}; + } + + function sheet_from_bufferTrial(bufferBodyFrames, ws_name) { + var ws = {}; + var range = {s: {c: 0, r: 0}, e: {c: 275, r: 500}}; + skeleton = 0; //Track which skeleton # it is out of the maximum 6 + for (var i = 0; i < bufferBodyFrames[0].bodies.length; i++) { + if (bufferBodyFrames[0].bodies[i].tracked) { + skeleton = i; + break; + } + } + + for (var R = 0; R < bufferBodyFrames.length; R++) { + var column = 0; // Goes upto 275, i.e. 25 x 11 + for (var C = 0; C < bufferBodyFrames[R].bodies[skeleton].joints.length; C++) { + for (var attributename in bufferBodyFrames[R].bodies[skeleton].joints[C]) { + var cell = {v: bufferBodyFrames[R].bodies[skeleton].joints[C][attributename]}; + if (cell.v == null) continue; + var cell_ref = XLSX.utils.encode_cell({c: column, r: R}); + if (typeof cell.v === 'number') cell.t = 'n'; + else if (typeof cell.v === 'boolean') cell.t = 'b'; + else cell.t = 's'; + ws[cell_ref] = cell; + column++; + } + } + } + ws['!ref'] = XLSX.utils.encode_range(range); + return ws; + } + + function chartAnalyze(bufferTrial, gtArray, exArray) { + var gtLabel = [], exLabel = []; + for (var i in gtArray) { + gtLabel.push("GT_" + (i).toString()); + } + for (var i in exArray) { + exLabel.push("EX_" + (i).toString()); + } + + var chartData = [ + {"Name": "Duration (seconds)",}, + {"Name": "Type",}, + {"Name": "Left Wrist Speed (m/s)"}, + {"Name": "Left Wrist Height Change (m)"}, + {"Name": "Right Wrist Speed (m/s)"}, + {"Name": "Right Wrist Height Change (m)"}, + {"Name": "Pelvic Speed (m/s)"}, + {"Name": "Pelvic Height Change (m)"}, + {"Name": "Trunk Leaning (degrees)"}, + {"Name": "Hip A-P Movement (m)"}, + ]; + // Duration + for (var i in gtArray) { + chartData[0][gtLabel[i]] = bufferTrial[gtArray[i]].duration; + chartData[1][gtLabel[i]] = typeofTest(bufferTrial, gtArray[i]); + chartData[2][gtLabel[i]] = getSpeed(bufferTrial, gtArray[i], 6).toFixed(2); + chartData[3][gtLabel[i]] = getAmplitudeY(bufferTrial, gtArray[i], 6).toFixed(2); + chartData[4][gtLabel[i]] = getSpeed(bufferTrial, gtArray[i], 10).toFixed(2); + chartData[5][gtLabel[i]] = getAmplitudeY(bufferTrial, gtArray[i], 10).toFixed(2); + chartData[6][gtLabel[i]] = getSpeed(bufferTrial, gtArray[i], 0).toFixed(2); + chartData[7][gtLabel[i]] = getAmplitudeY(bufferTrial, gtArray[i], 0).toFixed(2); + chartData[8][gtLabel[i]] = getOrientation(bufferTrial, gtArray[i], 1).toFixed(2); + chartData[9][gtLabel[i]] = getAmplitudeZ(bufferTrial, gtArray[i], 0).toFixed(2); + } + for (var i in exArray) { + chartData[0][exLabel[i]] = bufferTrial[exArray[i]].duration; + chartData[1][exLabel[i]] = typeofTest(bufferTrial, exArray[i]); + chartData[2][exLabel[i]] = getSpeed(bufferTrial, exArray[i], 6).toFixed(2); + chartData[3][exLabel[i]] = getAmplitudeY(bufferTrial, exArray[i], 6).toFixed(2); + chartData[4][exLabel[i]] = getSpeed(bufferTrial, exArray[i], 10).toFixed(2); + chartData[5][exLabel[i]] = getAmplitudeY(bufferTrial, exArray[i], 10).toFixed(2); + chartData[6][exLabel[i]] = getSpeed(bufferTrial, exArray[i], 0).toFixed(2); + chartData[7][exLabel[i]] = getAmplitudeY(bufferTrial, exArray[i], 0).toFixed(2); + chartData[8][exLabel[i]] = getOrientation(bufferTrial, exArray[i], 1).toFixed(2); + chartData[9][exLabel[i]] = getAmplitudeZ(bufferTrial, exArray[i], 0).toFixed(2); + } + return chartData; + } + + function curveAnalyze(bufferTrial, gtArray, exArray, gtInd, exInd, jt, datatype) { + var curveData = {}; + var maxlength = 0; + curveData["numDataSets"] = gtInd.length + exInd.length; + curveData["labels"] = []; + curveData["dataset"] = []; + curveData["xticks"] = []; + if (gtInd.length > 0) { + for (var i = 0; i < gtInd.length; i++) { + curveData.labels.push("Referece_" + gtInd[i].toString()); + var id = gtArray[gtInd[i]]; + var rawdata = getRaw(bufferTrial, id, jt, datatype); + curveData.dataset.push(rawdata); + if (rawdata.length > maxlength) { + maxlength = rawdata.length + } + } + } + + if (exInd.length > 0) { + for (var i = 0; i < exInd.length; i++) { + curveData.labels.push("Exercise_" + exInd[i].toString()); + var id = exArray[exInd[i]]; + var rawdata = getRaw(bufferTrial, id, jt, datatype); + curveData.dataset.push(rawdata); + if (rawdata.length > maxlength) { + maxlength = rawdata.length + } + } + } + var numMarks = 10; + var pads = Math.ceil(maxlength / numMarks); + + for (var i = 0; i < numMarks; i++) { + var timeMark = (i * pads * 0.008342).toFixed(2); + curveData.xticks.push(timeMark.toString()); + for (var j = 1; j < pads; j++) { + curveData.xticks.push(""); + } + } + // "xticks": ["1", "", "", "", "", "6", "", "", "", "", "11"], + + return curveData; + } + + function barAnalyze(bufferTrial, gtArray, exArray) { + var barData = {}; + barData.leftHandSpeed = []; + barData.leftHandHeightChange = []; + barData.rightHandSpeed = []; + barData.rightHandHeightChange = []; + barData.pelvicSpeed = []; + barData.pelvicHeightChange = []; + barData.SpineMidOrientation = []; + barData.SpineBaseMovement = []; + var threshold = { + Speed: 0.005, + HeightChange: 0.005, + Orientation: 1, + }; + var speed_jt6_gt = 0, height_jt6_gt = 0, speed_jt10_gt = 0, height_jt10_gt = 0, + speed_jt0_gt = 0, height_jt0_gt = 0; + var lean_jt1_gt = 0, ampZ_jt0_gt = 0; + for (var i in gtArray) { + speed_jt6_gt = getSpeed(bufferTrial, gtArray[i], 6); + height_jt6_gt += getAmplitudeY(bufferTrial, gtArray[i], 6); + speed_jt10_gt += getSpeed(bufferTrial, gtArray[i], 10); + height_jt10_gt += getAmplitudeY(bufferTrial, gtArray[i], 10); + speed_jt0_gt += getSpeed(bufferTrial, gtArray[i], 0); + height_jt0_gt += getAmplitudeY(bufferTrial, gtArray[i], 0); + lean_jt1_gt += getOrientation(bufferTrial, gtArray[i], 1); + ampZ_jt0_gt += getAmplitudeZ(bufferTrial, gtArray[i], 0); + } + speed_jt6_gt /= gtArray.length; + height_jt6_gt /= gtArray.length; + speed_jt10_gt /= gtArray.length; + height_jt10_gt /= gtArray.length; + speed_jt0_gt /= gtArray.length; + height_jt0_gt /= gtArray.length; + lean_jt1_gt /= gtArray.length; + ampZ_jt0_gt /= gtArray.length; + + for (var i in exArray) { + var speed_jt6_ex = getSpeed(bufferTrial, exArray[i], 6); + if (Math.abs(speed_jt6_gt) < threshold.Speed) { + barData.leftHandSpeed.push(0); + } + else { + barData.leftHandSpeed.push((speed_jt6_ex - speed_jt6_gt) / speed_jt6_gt * 100); + } + + var height_jt6_ex = getAmplitudeY(bufferTrial, exArray[i], 6); + if (Math.abs(height_jt6_gt) < threshold.HeightChange) { + barData.leftHandHeightChange.push(0); + } + else { + barData.leftHandHeightChange.push((height_jt6_ex - height_jt6_gt) / height_jt6_gt * 100); + } + + var speed_jt10_ex = getSpeed(bufferTrial, exArray[i], 10); + if (Math.abs(speed_jt10_gt) < threshold.Speed) { + barData.rightHandSpeed.push(0); + } + else { + barData.rightHandSpeed.push((speed_jt10_ex - speed_jt10_gt) / speed_jt10_gt * 100); + } + + var height_jt10_ex = getAmplitudeY(bufferTrial, exArray[i], 10); + if (Math.abs(height_jt10_gt) < threshold.HeightChange) { + barData.rightHandHeightChange.push(0); + } + else { + barData.rightHandHeightChange.push((height_jt10_ex - height_jt10_gt) / height_jt10_gt * 100); + } + + var speed_jt0_ex = getSpeed(bufferTrial, exArray[i], 0); + if (Math.abs(speed_jt0_gt) < threshold.Speed) { + barData.pelvicSpeed.push(0); + } + else { + barData.pelvicSpeed.push((speed_jt0_ex - speed_jt0_gt) / speed_jt0_gt * 100); + } + + var height_jt0_ex = getAmplitudeY(bufferTrial, exArray[i], 0); + if (Math.abs(height_jt0_gt) < threshold.HeightChange) { + barData.pelvicHeightChange.push(0); + } + else { + barData.pelvicHeightChange.push((height_jt0_ex - height_jt0_gt) / height_jt0_gt * 100); + } + + var lean_jt1_ex = getOrientation(bufferTrial, exArray[i], 1); + if (Math.abs(lean_jt1_ex) < threshold.HeightChange) { + barData.SpineMidOrientation.push(0); + } + else { + barData.SpineMidOrientation.push((lean_jt1_ex - lean_jt1_gt) / lean_jt1_gt * 100); + } + + var ampZ_jt0_ex = getAmplitudeZ(bufferTrial, exArray[i], 0); + if (Math.abs(ampZ_jt0_gt) < threshold.HeightChange) { + barData.SpineBaseMovement.push(0); + } + else { + barData.SpineBaseMovement.push((ampZ_jt0_ex - ampZ_jt0_gt) / ampZ_jt0_gt * 100); + } + + } + return barData; + } /* Reference Look-up for joint selection Kinect2.JointType = { diff --git a/exercise/public/index.html b/exercise/public/index.html index d3a22db..44df39e 100755 --- a/exercise/public/index.html +++ b/exercise/public/index.html @@ -13,6 +13,8 @@ + + - + \ No newline at end of file diff --git a/exercise/public/js/README.md b/exercise/public/js/README.md new file mode 100644 index 0000000..024e666 --- /dev/null +++ b/exercise/public/js/README.md @@ -0,0 +1,29 @@ +## Joint indices per Kinect2 API: + +Joint Type | Index +------------ | ------------- +spineBase | 0 +spineMid | 1 +neck | 2 +head | 3 +shoulderLeft | 4 +elbowLeft | 5 +wristLeft | 6 +handLeft | 7 +shoulderRight | 8 +elbowRight | 9 +wristRight | 10 +handRight | 11 +hipLeft | 12 + kneeLeft | 13 + ankleLeft | 14 + footLeft | 15 + hipRight | 16 + kneeRight | 17 + ankleRight | 18 + footRight | 19 + spineShoulder | 20 + handTipLeft | 21 + thumbLeft | 22 + handTipRight | 23 + thumbRight | 24 \ No newline at end of file diff --git a/exercise/public/js/kinect.js b/exercise/public/js/kinect.js index de58c56..252efe7 100755 --- a/exercise/public/js/kinect.js +++ b/exercise/public/js/kinect.js @@ -12,11 +12,12 @@ $(document).ready(function () { var width = canvasSKLT.width; var height = canvasSKLT.height; var IntervalID; - + var threshold_flag; + var reps = 0; // Use bodyFrame from server to update the canvas 1 on client socket.on('init', function (bodyFrame, systemState) { clientActive = true; - liveupdateCanvas1(bodyFrame, -1); + updateCanvas(bodyFrame, -1); document.getElementById("command").value = 'Start'; document.getElementById("command").style.backgroundColor = ''; document.getElementById("display").style.display = 'none'; @@ -24,7 +25,17 @@ $(document).ready(function () { socket.on('rec', function (bodyFrame, systemState, tracingID) { clientActive = true; - liveupdateCanvas1(bodyFrame, tracingID); + + // Initializing flag for counting repetitions + // For exercise, should get from reference + if (!threshold_flag){ + threshold_flag = 'down'; + } + temp_reps = updateCanvas(bodyFrame, tracingID, 'rec', threshold_flag); + if (temp_reps){ + threshold_flag = temp_reps[1]; + document.getElementById("reps").innerHTML = parseInt(document.getElementById("reps").innerHTML) + temp_reps[0]; + } document.getElementById("command").value = 'Stop'; document.getElementById("command").style.backgroundColor = 'red'; document.getElementById("display").style.display = 'none'; @@ -32,6 +43,7 @@ $(document).ready(function () { socket.on('disp', function (bufferBodyFrames, systemState, tracingID, activityLabeled) { clientActive = true; // unlock the button + reps = 0; IntervalID = animateCanvas1(bufferBodyFrames, tracingID, 'disp'); document.getElementById("command").value = 'Live'; document.getElementById("command").style.backgroundColor = ''; @@ -42,7 +54,7 @@ $(document).ready(function () { socket.on('live', function (bodyFrame) { clientActive = true; clearInterval(IntervalID); - liveupdateCanvas1(bodyFrame, -1); + updateCanvas(bodyFrame, -1); document.getElementById("command").value = 'Start'; document.getElementById("command").style.backgroundColor = ''; @@ -54,8 +66,17 @@ $(document).ready(function () { }); socket.on('showing-speed', function (speed) { - document.getElementById("speed").innerHTML = (Math.round(speed * 100) / 100).toString() + " m/s"; + var gt_speed = 0.3; // temp for testing + var ex_speed = Math.round(speed * 100) / 100; + var msg = 'The reference speed is ' + gt_speed.toString() + ' m/s. Your speed is ' + ex_speed.toString() + ' m/s.'; + if ((gt_speed + 0.1) < ex_speed){ + msg = 'Try slowing down. ' + msg; + } + else if ((gt_speed - 0.1) > ex_speed){ + msg = 'Try increasing your speed. ' + msg; + } + document.getElementById("speed").innerHTML = msg; }); @@ -65,17 +86,6 @@ $(document).ready(function () { drawJoints(body.joints[jointType].depthX * width, body.joints[jointType].depthY * height); }); - // Example of hand raising exercise. - var line_marker = document.getElementById("line-marker").value; - var gt_y_test; - if (line_marker == 11) { - gt_y_test = 250; - draw_height_line(body.joints[8].depthX * width, gt_y_test, body.joints[line_marker].depthY * height); - } else if (line_marker == 0) { - gt_y_test = 500; - draw_height_line(body.joints[13].depthX * width, gt_y_test, body.joints[line_marker].depthY * height, comparison = 'greater', direction = 'both'); - } - drawCenterCircle(width / 2, height / 5, 50, body.joints[2].depthX * width, body.joints[2].depthY * height); ctx1.beginPath(); @@ -112,11 +122,23 @@ $(document).ready(function () { ctx1.strokeStyle = "black"; } + function count_reps(body, threshold_flag){ + var reps = 0; + var joint = 0; + var current_pt = body.joints[joint].depthY*height; + if ((threshold_flag == 'down') && (current_pt < 500)){ + reps++; + return [reps,'up']; + } else if ((threshold_flag == 'up') && (current_pt > 600)){ + return [reps,'down']; + } else { + return [reps, threshold_flag] + } + } // Line to indicate user reaching some standard or requirement // Input is start of line, ground truth height, exercise height // Line is yellow if requirement unfulfilled, green if fulfilled - function draw_height_line(starting_x, gt_y, ex_y, comparison='less', direction='right') { ctx1.beginPath(); if (comparison == 'less') { @@ -148,24 +170,30 @@ $(document).ready(function () { ctx1.strokeStyle = "black"; } - function liveupdateCanvas1(bodyFrame, tracingID) { + function updatCanvas(bodyFrame, tracingID, mode='', threshold_flag='') { ctx1.clearRect(0, 0, width, height); + var reps = 0; if (tracingID == -1) { bodyFrame.bodies.some(function (body) { if (body.tracked) { drawBody(body); - return (body.tracked); + if (mode=='rec'){ + reps = count_reps(body, threshold_flag); + } } }); } else { drawBody(bodyFrame.bodies[tracingID]); + reps = count_reps(body, threshold_flag); } + return reps; } function animateCanvas1(bufferBodyFrames, tracingID, source='') { var i = 0; var TimerID = setInterval(function () { - liveupdateCanvas1(bufferBodyFrames[i], tracingID); + update + Canvas(bufferBodyFrames[i], tracingID); i++; if (i >= bufferBodyFrames.length) { i = 0; @@ -173,36 +201,4 @@ $(document).ready(function () { }, 20); return TimerID; } -}); - - -/* Reference -Look-up for joint selection -Kinect2.JointType = { - spineBase : 0, - spineMid : 1, - neck : 2, - head : 3, - shoulderLeft : 4, - elbowLeft : 5, - wristLeft : 6, - handLeft : 7, - shoulderRight : 8, - elbowRight : 9, - wristRight : 10, - handRight : 11, - hipLeft : 12, - kneeLeft : 13, - ankleLeft : 14, - footLeft : 15, - hipRight : 16, - kneeRight : 17, - ankleRight : 18, - footRight : 19, - spineShoulder : 20, - handTipLeft : 21, - thumbLeft : 22, - handTipRight : 23, - thumbRight : 24 -}; -*/ +}); \ No newline at end of file From 14846ece0c880a7d0e88da739f8df243f0b4d34c Mon Sep 17 00:00:00 2001 From: shreya726 Date: Sun, 13 May 2018 00:49:23 -0400 Subject: [PATCH 5/8] choose exercise and update fields based on it --- exercise/public/index.html | 9 ++++---- exercise/public/js/kinect.js | 41 ++++++++++++++++++++++-------------- 2 files changed, 30 insertions(+), 20 deletions(-) diff --git a/exercise/public/index.html b/exercise/public/index.html index c616a12..4581ede 100755 --- a/exercise/public/index.html +++ b/exercise/public/index.html @@ -36,10 +36,11 @@

ExerciseCheck

0
- + + +
diff --git a/exercise/public/js/kinect.js b/exercise/public/js/kinect.js index 252efe7..f63ba65 100755 --- a/exercise/public/js/kinect.js +++ b/exercise/public/js/kinect.js @@ -14,6 +14,7 @@ $(document).ready(function () { var IntervalID; var threshold_flag; var reps = 0; + // Use bodyFrame from server to update the canvas 1 on client socket.on('init', function (bodyFrame, systemState) { clientActive = true; @@ -27,9 +28,10 @@ $(document).ready(function () { clientActive = true; // Initializing flag for counting repetitions - // For exercise, should get from reference if (!threshold_flag){ - threshold_flag = 'down'; + + // Based on exercise (eg squat), know which direction we start counting reps in + threshold_flag = getExerciseInfo(document.getElementById("exercise").value)[1]; } temp_reps = updateCanvas(bodyFrame, tracingID, 'rec', threshold_flag); if (temp_reps){ @@ -122,9 +124,11 @@ $(document).ready(function () { ctx1.strokeStyle = "black"; } - function count_reps(body, threshold_flag){ + function countReps(body, threshold_flag){ var reps = 0; - var joint = 0; + + // Know what the important joint is based on exercise (eg squat) + var joint = getExerciseInfo(document.getElementById("exercise").value)[0]; var current_pt = body.joints[joint].depthY*height; if ((threshold_flag == 'down') && (current_pt < 500)){ reps++; @@ -170,7 +174,7 @@ $(document).ready(function () { ctx1.strokeStyle = "black"; } - function updatCanvas(bodyFrame, tracingID, mode='', threshold_flag='') { + function updateCanvas(bodyFrame, tracingID, mode='', threshold_flag='') { ctx1.clearRect(0, 0, width, height); var reps = 0; if (tracingID == -1) { @@ -178,27 +182,32 @@ $(document).ready(function () { if (body.tracked) { drawBody(body); if (mode=='rec'){ - reps = count_reps(body, threshold_flag); + reps = countReps(body, threshold_flag); } } }); } else { drawBody(bodyFrame.bodies[tracingID]); - reps = count_reps(body, threshold_flag); + reps = countReps(body, threshold_flag); } return reps; } - function animateCanvas1(bufferBodyFrames, tracingID, source='') { + function animateCanvas1(bufferBodyFrames, tracingID){ var i = 0; - var TimerID = setInterval(function () { - update - Canvas(bufferBodyFrames[i], tracingID); - i++; - if (i >= bufferBodyFrames.length) { - i = 0; - } - }, 20); + var TimerID = setInterval(function(){ + updateCanvas(bufferBodyFrames[i], tracingID); + i++; + if (i>=bufferBodyFrames.length){i=0;} + },20); return TimerID; + } + + function getExerciseInfo(exercise){ + exercise_info = { + 'hand_raise': [11, 'up'], + 'squat': [0, 'down'], + } + return exercise_info[exercise]; } }); \ No newline at end of file From 86968ffcbdde743aa48407b0735ebb20efe70611 Mon Sep 17 00:00:00 2001 From: shreya726 Date: Mon, 14 May 2018 12:24:24 -0400 Subject: [PATCH 6/8] added option to select exercise, fixed starting bug for reps --- exercise/public/index.html | 6 +++--- exercise/public/js/kinect.js | 19 ++++++++++++++----- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/exercise/public/index.html b/exercise/public/index.html index 4581ede..06d21b3 100755 --- a/exercise/public/index.html +++ b/exercise/public/index.html @@ -38,9 +38,9 @@

ExerciseCheck

0

diff --git a/exercise/public/js/kinect.js b/exercise/public/js/kinect.js index f63ba65..6d04f9d 100755 --- a/exercise/public/js/kinect.js +++ b/exercise/public/js/kinect.js @@ -128,8 +128,14 @@ $(document).ready(function () { var reps = 0; // Know what the important joint is based on exercise (eg squat) - var joint = getExerciseInfo(document.getElementById("exercise").value)[0]; - var current_pt = body.joints[joint].depthY*height; + var exInfo = getExerciseInfo(document.getElementById("exercise").value); + var joint = exInfo[0]; + var coordinate = exInfo[2]; + var current_pt = body.joints[joint][coordinate]*height; + + // 500 and 600 are temp values for testing + // Probably need to define thresholds in exerciseInfo for intial reference + // For exercise, should be based on reference if ((threshold_flag == 'down') && (current_pt < 500)){ reps++; return [reps,'up']; @@ -174,6 +180,7 @@ $(document).ready(function () { ctx1.strokeStyle = "black"; } + // Draw every new bodyframe on the canvas function updateCanvas(bodyFrame, tracingID, mode='', threshold_flag='') { ctx1.clearRect(0, 0, width, height); var reps = 0; @@ -193,7 +200,7 @@ $(document).ready(function () { return reps; } - function animateCanvas1(bufferBodyFrames, tracingID){ + function animateCanvas1(bufferBodyFrames, tracingID){ var i = 0; var TimerID = setInterval(function(){ updateCanvas(bufferBodyFrames[i], tracingID); @@ -203,10 +210,12 @@ $(document).ready(function () { return TimerID; } + + // Get info from JSON about a given exercise like salient joint, direction of reps, etc. function getExerciseInfo(exercise){ exercise_info = { - 'hand_raise': [11, 'up'], - 'squat': [0, 'down'], + 'hand_raise': [11, 'up', 'depthY'], + 'squat': [0, 'down', 'depthY'], } return exercise_info[exercise]; } From 40b50d968dbcf698203806383c565b9ef3c57671 Mon Sep 17 00:00:00 2001 From: shreya726 Date: Sun, 10 Jun 2018 15:34:44 -0400 Subject: [PATCH 7/8] normalized to neck, scaled to height of canvas --- exercise/index.js | 79 +++++++++++------------------------- exercise/public/index.html | 2 +- exercise/public/js/kinect.js | 50 ++++++++++++++++++----- 3 files changed, 64 insertions(+), 67 deletions(-) diff --git a/exercise/index.js b/exercise/index.js index ec3dffe..8e705b6 100755 --- a/exercise/index.js +++ b/exercise/index.js @@ -154,12 +154,33 @@ if (kinect.open()) { socket.on('disconnect', function () { console.log('a user disconnect'); --clients; - }) + }); }); // Helper functions +function get_ref_info(bufferTrial){ + // Used for testing for max, min vals for reps + var temp_pts = {'neck_y':[],'squat_y':[]} + var buffer_temp = bufferTrial[0]; + //console.log(buffer_temp); + for (var i =0; i < buffer_temp.length; i++){ + var bodies_temp = buffer_temp[i]['bodies']; + for (var j = 0; j < bodies_temp.length; j++){ + if (bodies_temp[j].hasOwnProperty('joints')){ + var temp_bj = bodies_temp[j]['joints']; + temp_pts['neck_y'].push(temp_bj[2]['depthY']) + temp_pts['squat_y'].push(temp_bj[0]['depthY']) + } + } + } + console.log('min squat', Math.min.apply(Math, temp_pts['squat_y'].filter(Boolean))) + console.log('max squat', Math.max.apply(Math,temp_pts['squat_y'].filter(Boolean))) + console.log('min neck', Math.min.apply(Math,temp_pts['neck_y'].filter(Boolean))) + console.log('max neck', Math.max.apply(Math,temp_pts['neck_y'].filter(Boolean))) +} + // Define the legal move between states function StateTrans(st) { return (st + 1) % 3; @@ -435,7 +456,7 @@ if (kinect.open()) { curveData.xticks.push(""); } } - // "xticks": ["1", "", "", "", "", "6", "", "", "", "", "11"], + // "xticks": ["1", "", "", "", "", "6", "", "", "", "", "11"], return curveData; } @@ -545,56 +566,4 @@ if (kinect.open()) { } return barData; } -/* Reference -Look-up for joint selection -Kinect2.JointType = { - spineBase : 0, - spineMid : 1, - neck : 2, - head : 3, - shoulderLeft : 4, - elbowLeft : 5, - wristLeft : 6, - handLeft : 7, - shoulderRight : 8, - elbowRight : 9, - wristRight : 10, - handRight : 11, - hipLeft : 12, - kneeLeft : 13, - ankleLeft : 14, - footLeft : 15, - hipRight : 16, - kneeRight : 17, - ankleRight : 18, - footRight : 19, - spineShoulder : 20, - handTipLeft : 21, - thumbLeft : 22, - handTipRight : 23, - thumbRight : 24 -}; - - -Structure of bodyFrame -bodyFrame = { -bodies:[ -0: - bodyIndex: 0 - joints: Array(25) [{depthX, depthY... orientationZ},{depthX, depthY... orientationZ} ] - leftHandState: 0 - rightHandState: 0 - tracked: true - trackingID: "7200399405055" -1: - bodyIndex: 1 - tracked: false -... -] -floorClipPlane: { - w: - x: - y: - z: -} -*/ +} \ No newline at end of file diff --git a/exercise/public/index.html b/exercise/public/index.html index 06d21b3..609416a 100755 --- a/exercise/public/index.html +++ b/exercise/public/index.html @@ -38,7 +38,7 @@

ExerciseCheck

0
diff --git a/exercise/public/js/kinect.js b/exercise/public/js/kinect.js index 6d04f9d..967b581 100755 --- a/exercise/public/js/kinect.js +++ b/exercise/public/js/kinect.js @@ -14,6 +14,8 @@ $(document).ready(function () { var IntervalID; var threshold_flag; var reps = 0; + var neck_y; + var neck_x; // Use bodyFrame from server to update the canvas 1 on client socket.on('init', function (bodyFrame, systemState) { @@ -28,6 +30,7 @@ $(document).ready(function () { clientActive = true; // Initializing flag for counting repetitions + if (!threshold_flag){ // Based on exercise (eg squat), know which direction we start counting reps in @@ -113,10 +116,15 @@ $(document).ready(function () { // Draw center circle - to help user position themselves function drawCenterCircle(x, y, r, nx, ny) { ctx1.beginPath(); - if (nx > x - r && nx < x + r && ny > y - r && ny < y + r) + if (nx > x - r && nx < x + r && ny > y - r && ny < y + r) { ctx1.strokeStyle = "green"; - else + if (!neck_y || !neck_x){ + neck_x = nx/width; + neck_y = ny/height; + } + } else { ctx1.strokeStyle = "red"; + } ctx1.arc(x, y, r, 0, Math.PI * 2); ctx1.stroke(); @@ -124,22 +132,38 @@ $(document).ready(function () { ctx1.strokeStyle = "black"; } + function countReps(body, threshold_flag){ var reps = 0; + var norm; - // Know what the important joint is based on exercise (eg squat) + // Get info based on exercise (eg squat) var exInfo = getExerciseInfo(document.getElementById("exercise").value); var joint = exInfo[0]; var coordinate = exInfo[2]; - var current_pt = body.joints[joint][coordinate]*height; - // 500 and 600 are temp values for testing - // Probably need to define thresholds in exerciseInfo for intial reference - // For exercise, should be based on reference - if ((threshold_flag == 'down') && (current_pt < 500)){ + // need to figure out how to set this non-arbitrarily + var error = 0.22; + + // This is set when user is correctly positioned in circle + if (coordinate == 'depthY') { + norm = neck_y; + } else if (coordinate == 'depthX') { + norm = neck_x; + } + + // Normalize to neck + var current_pt = (body.joints[joint][coordinate] - norm)*height; + + // Normalize to neck in reference + var ref_norm = exInfo[5]; + var top_thresh = height*(exInfo[3]-ref_norm + error); + var bottom_thresh = height*(exInfo[4]-ref_norm - error); + + if ((threshold_flag == 'down') && (current_pt < top_thresh)){ reps++; return [reps,'up']; - } else if ((threshold_flag == 'up') && (current_pt > 600)){ + } else if ((threshold_flag == 'up') && (current_pt > bottom_thresh)){ return [reps,'down']; } else { return [reps, threshold_flag] @@ -180,6 +204,7 @@ $(document).ready(function () { ctx1.strokeStyle = "black"; } + // Draw every new bodyframe on the canvas function updateCanvas(bodyFrame, tracingID, mode='', threshold_flag='') { ctx1.clearRect(0, 0, width, height); @@ -212,10 +237,13 @@ $(document).ready(function () { // Get info from JSON about a given exercise like salient joint, direction of reps, etc. + // this info should eventually be stored in a db function getExerciseInfo(exercise){ + //most important joint, starting direction of rep, min val in ref, max val in ref, min neck in ref, max neck in ref exercise_info = { - 'hand_raise': [11, 'up', 'depthY'], - 'squat': [0, 'down', 'depthY'], + 'hand_raise': [11, 'down', 'depthY'], + 'squat': [0, 'up', 'depthY', 0.54, 1.03, 0.21, 0.71], + } return exercise_info[exercise]; } From edab7133d4085cc81661e16b1f4581f3290e01e1 Mon Sep 17 00:00:00 2001 From: shreya726 Date: Fri, 15 Jun 2018 14:12:29 -0400 Subject: [PATCH 8/8] added normalization --- exercise/index.js | 689 ++++++++++++++++++----------------- exercise/public/js/kinect.js | 73 ++-- 2 files changed, 403 insertions(+), 359 deletions(-) diff --git a/exercise/index.js b/exercise/index.js index 8e705b6..fa5305b 100755 --- a/exercise/index.js +++ b/exercise/index.js @@ -82,6 +82,7 @@ if (kinect.open()) { } if (num == 1) { gtArray.push(testID); + get_ref_info(bufferTrial); } else { if (num == 2) { @@ -160,410 +161,426 @@ if (kinect.open()) { // Helper functions -function get_ref_info(bufferTrial){ +function get_ref_info(bufferTrial, joint=0){ // Used for testing for max, min vals for reps var temp_pts = {'neck_y':[],'squat_y':[]} var buffer_temp = bufferTrial[0]; - //console.log(buffer_temp); + for (var i =0; i < buffer_temp.length; i++){ var bodies_temp = buffer_temp[i]['bodies']; for (var j = 0; j < bodies_temp.length; j++){ if (bodies_temp[j].hasOwnProperty('joints')){ var temp_bj = bodies_temp[j]['joints']; temp_pts['neck_y'].push(temp_bj[2]['depthY']) - temp_pts['squat_y'].push(temp_bj[0]['depthY']) + temp_pts['squat_y'].push(temp_bj[joint]['depthY']) } } } + + // Save full signal to json + require('fs').writeFile( + './reference.json', + + JSON.stringify(temp_pts['squat_y']), + + function (err) { + if (err) { + console.error('Error in saving file'); + } + } + ); + + // Log max, min, average to console + const average = arr => arr.reduce( ( p, c ) => p + c, 0 ) / arr.length; + console.log('min squat', Math.min.apply(Math, temp_pts['squat_y'].filter(Boolean))) console.log('max squat', Math.max.apply(Math,temp_pts['squat_y'].filter(Boolean))) - console.log('min neck', Math.min.apply(Math,temp_pts['neck_y'].filter(Boolean))) - console.log('max neck', Math.max.apply(Math,temp_pts['neck_y'].filter(Boolean))) + console.log('mean squat', average(temp_pts['squat_y'].filter(Boolean))) } // Define the legal move between states - function StateTrans(st) { - return (st + 1) % 3; - } +function StateTrans(st) { + return (st + 1) % 3; +} - function locateBodyTrackedIndex(bufferBodyFrames) { - var ind = -1; - for (var i = 0; i <= 5; i++) { - if (bufferBodyFrames[0].bodies[i].tracked) { // tracked in the first frame - ind = i; - break; - } +function locateBodyTrackedIndex(bufferBodyFrames) { + var ind = -1; + for (var i = 0; i <= 5; i++) { + if (bufferBodyFrames[0].bodies[i].tracked) { // tracked in the first frame + ind = i; + break; } - return ind; } + return ind; +} + +function typeofTest(bufferTrial, id) { + var type // 0: Hand, 1: Squat + if (getAmplitudeY(bufferTrial, id, 0) > 0.15) //Base of spine moves > 0.15m + { + type = "Squat"; + } + else { + type = "Hand"; + } + return type; +} - function typeofTest(bufferTrial, id) { - var type // 0: Hand, 1: Squat - if (getAmplitudeY(bufferTrial, id, 0) > 0.15) //Base of spine moves > 0.15m - { - type = "Squat"; +function getRaw(bufferTrial, id, jt, datatype) { + var frames = bufferTrial[id]; + var ind = frames.bodyIndex, time = frames.durationsecs; + var rawdata = [] + for (var i = 0; i < frames.length; i++) { + if (datatype == 0) { + rawdata.push(frames[i].bodies[ind].joints[jt].cameraX); } - else { - type = "Hand"; + if (datatype == 1) { + rawdata.push(frames[i].bodies[ind].joints[jt].cameraY); } - return type; - } + if (datatype == 2) { + rawdata.push(frames[i].bodies[ind].joints[jt].cameraZ); + } + else { + var x = frames[i].bodies[ind].joints[jt].orientationX; + var y = frames[i].bodies[ind].joints[jt].orientationY; + var z = frames[i].bodies[ind].joints[jt].orientationZ; + var w = frames[i].bodies[ind].joints[jt].orientationW; - function getRaw(bufferTrial, id, jt, datatype) { - var frames = bufferTrial[id]; - var ind = frames.bodyIndex, time = frames.durationsecs; - var rawdata = [] - for (var i = 0; i < frames.length; i++) { - if (datatype == 0) { - rawdata.push(frames[i].bodies[ind].joints[jt].cameraX); + var T_x = 180 + 180 / 3.1416 * Math.atan2(2 * y * z + 2 * x * w, 1 - 2 * x * x - 2 * y * y); // leaning forward/backward + var T_y = 180 / 3.1416 * Math.asin(2 * y * w - 2 * x * z); // turning + var T_z = 180 + 180 / 3.1416 * Math.atan2(2 * x * y + 2 * z * w, 1 - 2 * y * y - 2 * z * z); // leaning left + while (T_x > 90) { + T_x += -180; } - if (datatype == 1) { - rawdata.push(frames[i].bodies[ind].joints[jt].cameraY); + if (T_y > 180) { + T_y += -180; } - if (datatype == 2) { - rawdata.push(frames[i].bodies[ind].joints[jt].cameraZ); + if (T_z > 180) { + T_z += -180; } - else { - var x = frames[i].bodies[ind].joints[jt].orientationX; - var y = frames[i].bodies[ind].joints[jt].orientationY; - var z = frames[i].bodies[ind].joints[jt].orientationZ; - var w = frames[i].bodies[ind].joints[jt].orientationW; - - var T_x = 180 + 180 / 3.1416 * Math.atan2(2 * y * z + 2 * x * w, 1 - 2 * x * x - 2 * y * y); // leaning forward/backward - var T_y = 180 / 3.1416 * Math.asin(2 * y * w - 2 * x * z); // turning - var T_z = 180 + 180 / 3.1416 * Math.atan2(2 * x * y + 2 * z * w, 1 - 2 * y * y - 2 * z * z); // leaning left - while (T_x > 90) { - T_x += -180; - } - if (T_y > 180) { - T_y += -180; - } - if (T_z > 180) { - T_z += -180; - } - if (datatype == 3) { - rawdata.push(T_x); - } - if (datatype == 4) { - rawdata.push(T_y); - } - if (datatype == 5) { - rawdata.push(T_z); - } - + if (datatype == 3) { + rawdata.push(T_x); } - } - return rawdata; - } - - function getSpeed(bufferTrial, id, jt) { - var frames = bufferTrial[id]; - var ind = frames.bodyIndex; - var time = frames.durationsecs; - var accumDist = 0; - for (var i = 0; i < frames.length - 1; i++) { - if (!frames[i + 1].bodies[ind]) { - continue; + if (datatype == 4) { + rawdata.push(T_y); } - var current_joint = frames[i + 1].bodies[ind].joints[jt]; - var prev_joint = frames[i].bodies[ind].joints[jt]; - var distance_x = current_joint.cameraX - prev_joint.cameraX; - var distance_y = current_joint.cameraY - prev_joint.cameraY; - var distance_z = current_joint.cameraZ - prev_joint.cameraZ; - var dist = Math.sqrt(Math.pow(distance_x, 2) + Math.pow(distance_y, 2) + Math.pow(distance_z, 2)); - if (dist) { - accumDist = accumDist + dist; + if (datatype == 5) { + rawdata.push(T_z); } + } - return accumDist / time; } + return rawdata; +} - function getAmplitudeX(bufferTrial, getSpeedid, jt) { - var ListX = getRaw(bufferTrial, id, jt, 0) - var DistX = (Math.max(...ListX) - Math.min(...ListX - )) - ; - return DistX; +function getSpeed(bufferTrial, id, jt) { + var frames = bufferTrial[id]; + var ind = frames.bodyIndex; + var time = frames.durationsecs; + var accumDist = 0; + for (var i = 0; i < frames.length - 1; i++) { + if (!frames[i + 1].bodies[ind]) { + continue; + } + var current_joint = frames[i + 1].bodies[ind].joints[jt]; + var prev_joint = frames[i].bodies[ind].joints[jt]; + var distance_x = current_joint.cameraX - prev_joint.cameraX; + var distance_y = current_joint.cameraY - prev_joint.cameraY; + var distance_z = current_joint.cameraZ - prev_joint.cameraZ; + var dist = Math.sqrt(Math.pow(distance_x, 2) + Math.pow(distance_y, 2) + Math.pow(distance_z, 2)); + if (dist) { + accumDist = accumDist + dist; + } } + return accumDist / time; +} - function getAmplitudeY(bufferTrial, id, jt) { - var ListY = getRaw(bufferTrial, id, jt, 1) - var DistY = (Math.max(...ListY) - Math.min(...ListY - )) - ; - return DistY; - } +function getAmplitudeX(bufferTrial, getSpeedid, jt) { + var ListX = getRaw(bufferTrial, id, jt, 0) + var DistX = (Math.max(...ListX) - Math.min(...ListX +)) + ; + return DistX; +} - function getAmplitudeZ(bufferTrial, id, jt) { - var ListZ = getRaw(bufferTrial, id, jt, 2) - var DistZ = (Math.max(...ListZ) - Math.min(...ListZ - )) - ; - return DistZ; - } +function getAmplitudeY(bufferTrial, id, jt) { + var ListY = getRaw(bufferTrial, id, jt, 1) + var DistY = (Math.max(...ListY) - Math.min(...ListY +)) + ; + return DistY; +} + +function getAmplitudeZ(bufferTrial, id, jt) { + var ListZ = getRaw(bufferTrial, id, jt, 2) + var DistZ = (Math.max(...ListZ) - Math.min(...ListZ +)) + ; + return DistZ; +} + +function getOrientation(bufferTrial, id, jt) { + var RotX = getRaw(bufferTrial, id, jt, 3); + var maxRot = Math.max(...RotX +), + minRot = Math.min(...RotX +) + var lean = Math.abs(maxRot - minRot); + return lean; +} + +function save2xlsx(bufferTrial, gtArray, exArray, filename) { - function getOrientation(bufferTrial, id, jt) { - var RotX = getRaw(bufferTrial, id, jt, 3); - var maxRot = Math.max(...RotX - ), - minRot = Math.min(...RotX - ) - var lean = Math.abs(maxRot - minRot); - return lean; + var wb = new Workbook(); //Create new wb object + for (var i in gtArray) { + var ws_name = "GT_" + (i).toString(); + var ws = sheet_from_bufferTrial(bufferTrial[gtArray[i]], ws_name); + wb.SheetNames.push(ws_name); + wb.Sheets[ws_name] = ws; } + for (var i in exArray) { + var ws_name = "EX_" + (i).toString(); + var ws = sheet_from_bufferTrial(bufferTrial[exArray[i]], ws_name); + wb.SheetNames.push(ws_name); + wb.Sheets[ws_name] = ws; + } + var wbout = XLSX.write(wb, {bookType: 'xlsx', bookSST: false, type: 'binary'}); //Define workbook type + XLSX.writeFile(wb, filename); //Write workbook +} - function save2xlsx(bufferTrial, gtArray, exArray, filename) { +function Workbook() { + if (!(this instanceof Workbook)) return new Workbook(); //Create new instance of workbook type + this.SheetNames = []; + this.Sheets = {}; +} - var wb = new Workbook(); //Create new wb object - for (var i in gtArray) { - var ws_name = "GT_" + (i).toString(); - var ws = sheet_from_bufferTrial(bufferTrial[gtArray[i]], ws_name); - wb.SheetNames.push(ws_name); - wb.Sheets[ws_name] = ws; +function sheet_from_bufferTrial(bufferBodyFrames, ws_name) { + var ws = {}; + var range = {s: {c: 0, r: 0}, e: {c: 275, r: 500}}; + skeleton = 0; //Track which skeleton # it is out of the maximum 6 + for (var i = 0; i < bufferBodyFrames[0].bodies.length; i++) { + if (bufferBodyFrames[0].bodies[i].tracked) { + skeleton = i; + break; } - for (var i in exArray) { - var ws_name = "EX_" + (i).toString(); - var ws = sheet_from_bufferTrial(bufferTrial[exArray[i]], ws_name); - wb.SheetNames.push(ws_name); - wb.Sheets[ws_name] = ws; + } + + for (var R = 0; R < bufferBodyFrames.length; R++) { + var column = 0; // Goes upto 275, i.e. 25 x 11 + for (var C = 0; C < bufferBodyFrames[R].bodies[skeleton].joints.length; C++) { + for (var attributename in bufferBodyFrames[R].bodies[skeleton].joints[C]) { + var cell = {v: bufferBodyFrames[R].bodies[skeleton].joints[C][attributename]}; + if (cell.v == null) continue; + var cell_ref = XLSX.utils.encode_cell({c: column, r: R}); + if (typeof cell.v === 'number') cell.t = 'n'; + else if (typeof cell.v === 'boolean') cell.t = 'b'; + else cell.t = 's'; + ws[cell_ref] = cell; + column++; + } } - var wbout = XLSX.write(wb, {bookType: 'xlsx', bookSST: false, type: 'binary'}); //Define workbook type - XLSX.writeFile(wb, filename); //Write workbook + } + ws['!ref'] = XLSX.utils.encode_range(range); + return ws; +} + +function chartAnalyze(bufferTrial, gtArray, exArray) { + var gtLabel = [], exLabel = []; + for (var i in gtArray) { + gtLabel.push("GT_" + (i).toString()); + } + for (var i in exArray) { + exLabel.push("EX_" + (i).toString()); } - function Workbook() { - if (!(this instanceof Workbook)) return new Workbook(); //Create new instance of workbook type - this.SheetNames = []; - this.Sheets = {}; + var chartData = [ + {"Name": "Duration (seconds)",}, + {"Name": "Type",}, + {"Name": "Left Wrist Speed (m/s)"}, + {"Name": "Left Wrist Height Change (m)"}, + {"Name": "Right Wrist Speed (m/s)"}, + {"Name": "Right Wrist Height Change (m)"}, + {"Name": "Pelvic Speed (m/s)"}, + {"Name": "Pelvic Height Change (m)"}, + {"Name": "Trunk Leaning (degrees)"}, + {"Name": "Hip A-P Movement (m)"}, + ]; + // Duration + for (var i in gtArray) { + chartData[0][gtLabel[i]] = bufferTrial[gtArray[i]].duration; + chartData[1][gtLabel[i]] = typeofTest(bufferTrial, gtArray[i]); + chartData[2][gtLabel[i]] = getSpeed(bufferTrial, gtArray[i], 6).toFixed(2); + chartData[3][gtLabel[i]] = getAmplitudeY(bufferTrial, gtArray[i], 6).toFixed(2); + chartData[4][gtLabel[i]] = getSpeed(bufferTrial, gtArray[i], 10).toFixed(2); + chartData[5][gtLabel[i]] = getAmplitudeY(bufferTrial, gtArray[i], 10).toFixed(2); + chartData[6][gtLabel[i]] = getSpeed(bufferTrial, gtArray[i], 0).toFixed(2); + chartData[7][gtLabel[i]] = getAmplitudeY(bufferTrial, gtArray[i], 0).toFixed(2); + chartData[8][gtLabel[i]] = getOrientation(bufferTrial, gtArray[i], 1).toFixed(2); + chartData[9][gtLabel[i]] = getAmplitudeZ(bufferTrial, gtArray[i], 0).toFixed(2); + } + for (var i in exArray) { + chartData[0][exLabel[i]] = bufferTrial[exArray[i]].duration; + chartData[1][exLabel[i]] = typeofTest(bufferTrial, exArray[i]); + chartData[2][exLabel[i]] = getSpeed(bufferTrial, exArray[i], 6).toFixed(2); + chartData[3][exLabel[i]] = getAmplitudeY(bufferTrial, exArray[i], 6).toFixed(2); + chartData[4][exLabel[i]] = getSpeed(bufferTrial, exArray[i], 10).toFixed(2); + chartData[5][exLabel[i]] = getAmplitudeY(bufferTrial, exArray[i], 10).toFixed(2); + chartData[6][exLabel[i]] = getSpeed(bufferTrial, exArray[i], 0).toFixed(2); + chartData[7][exLabel[i]] = getAmplitudeY(bufferTrial, exArray[i], 0).toFixed(2); + chartData[8][exLabel[i]] = getOrientation(bufferTrial, exArray[i], 1).toFixed(2); + chartData[9][exLabel[i]] = getAmplitudeZ(bufferTrial, exArray[i], 0).toFixed(2); } + return chartData; +} - function sheet_from_bufferTrial(bufferBodyFrames, ws_name) { - var ws = {}; - var range = {s: {c: 0, r: 0}, e: {c: 275, r: 500}}; - skeleton = 0; //Track which skeleton # it is out of the maximum 6 - for (var i = 0; i < bufferBodyFrames[0].bodies.length; i++) { - if (bufferBodyFrames[0].bodies[i].tracked) { - skeleton = i; - break; +function curveAnalyze(bufferTrial, gtArray, exArray, gtInd, exInd, jt, datatype) { + var curveData = {}; + var maxlength = 0; + curveData["numDataSets"] = gtInd.length + exInd.length; + curveData["labels"] = []; + curveData["dataset"] = []; + curveData["xticks"] = []; + if (gtInd.length > 0) { + for (var i = 0; i < gtInd.length; i++) { + curveData.labels.push("Referece_" + gtInd[i].toString()); + var id = gtArray[gtInd[i]]; + var rawdata = getRaw(bufferTrial, id, jt, datatype); + curveData.dataset.push(rawdata); + if (rawdata.length > maxlength) { + maxlength = rawdata.length } } + } - for (var R = 0; R < bufferBodyFrames.length; R++) { - var column = 0; // Goes upto 275, i.e. 25 x 11 - for (var C = 0; C < bufferBodyFrames[R].bodies[skeleton].joints.length; C++) { - for (var attributename in bufferBodyFrames[R].bodies[skeleton].joints[C]) { - var cell = {v: bufferBodyFrames[R].bodies[skeleton].joints[C][attributename]}; - if (cell.v == null) continue; - var cell_ref = XLSX.utils.encode_cell({c: column, r: R}); - if (typeof cell.v === 'number') cell.t = 'n'; - else if (typeof cell.v === 'boolean') cell.t = 'b'; - else cell.t = 's'; - ws[cell_ref] = cell; - column++; - } + if (exInd.length > 0) { + for (var i = 0; i < exInd.length; i++) { + curveData.labels.push("Exercise_" + exInd[i].toString()); + var id = exArray[exInd[i]]; + var rawdata = getRaw(bufferTrial, id, jt, datatype); + curveData.dataset.push(rawdata); + if (rawdata.length > maxlength) { + maxlength = rawdata.length } } - ws['!ref'] = XLSX.utils.encode_range(range); - return ws; } + var numMarks = 10; + var pads = Math.ceil(maxlength / numMarks); + + for (var i = 0; i < numMarks; i++) { + var timeMark = (i * pads * 0.008342).toFixed(2); + curveData.xticks.push(timeMark.toString()); + for (var j = 1; j < pads; j++) { + curveData.xticks.push(""); + } + } + // "xticks": ["1", "", "", "", "", "6", "", "", "", "", "11"], + + return curveData; +} - function chartAnalyze(bufferTrial, gtArray, exArray) { - var gtLabel = [], exLabel = []; - for (var i in gtArray) { - gtLabel.push("GT_" + (i).toString()); +function barAnalyze(bufferTrial, gtArray, exArray) { + var barData = {}; + barData.leftHandSpeed = []; + barData.leftHandHeightChange = []; + barData.rightHandSpeed = []; + barData.rightHandHeightChange = []; + barData.pelvicSpeed = []; + barData.pelvicHeightChange = []; + barData.SpineMidOrientation = []; + barData.SpineBaseMovement = []; + var threshold = { + Speed: 0.005, + HeightChange: 0.005, + Orientation: 1, + }; + var speed_jt6_gt = 0, height_jt6_gt = 0, speed_jt10_gt = 0, height_jt10_gt = 0, + speed_jt0_gt = 0, height_jt0_gt = 0; + var lean_jt1_gt = 0, ampZ_jt0_gt = 0; + for (var i in gtArray) { + speed_jt6_gt = getSpeed(bufferTrial, gtArray[i], 6); + height_jt6_gt += getAmplitudeY(bufferTrial, gtArray[i], 6); + speed_jt10_gt += getSpeed(bufferTrial, gtArray[i], 10); + height_jt10_gt += getAmplitudeY(bufferTrial, gtArray[i], 10); + speed_jt0_gt += getSpeed(bufferTrial, gtArray[i], 0); + height_jt0_gt += getAmplitudeY(bufferTrial, gtArray[i], 0); + lean_jt1_gt += getOrientation(bufferTrial, gtArray[i], 1); + ampZ_jt0_gt += getAmplitudeZ(bufferTrial, gtArray[i], 0); + } + speed_jt6_gt /= gtArray.length; + height_jt6_gt /= gtArray.length; + speed_jt10_gt /= gtArray.length; + height_jt10_gt /= gtArray.length; + speed_jt0_gt /= gtArray.length; + height_jt0_gt /= gtArray.length; + lean_jt1_gt /= gtArray.length; + ampZ_jt0_gt /= gtArray.length; + + for (var i in exArray) { + var speed_jt6_ex = getSpeed(bufferTrial, exArray[i], 6); + if (Math.abs(speed_jt6_gt) < threshold.Speed) { + barData.leftHandSpeed.push(0); } - for (var i in exArray) { - exLabel.push("EX_" + (i).toString()); + else { + barData.leftHandSpeed.push((speed_jt6_ex - speed_jt6_gt) / speed_jt6_gt * 100); } - var chartData = [ - {"Name": "Duration (seconds)",}, - {"Name": "Type",}, - {"Name": "Left Wrist Speed (m/s)"}, - {"Name": "Left Wrist Height Change (m)"}, - {"Name": "Right Wrist Speed (m/s)"}, - {"Name": "Right Wrist Height Change (m)"}, - {"Name": "Pelvic Speed (m/s)"}, - {"Name": "Pelvic Height Change (m)"}, - {"Name": "Trunk Leaning (degrees)"}, - {"Name": "Hip A-P Movement (m)"}, - ]; - // Duration - for (var i in gtArray) { - chartData[0][gtLabel[i]] = bufferTrial[gtArray[i]].duration; - chartData[1][gtLabel[i]] = typeofTest(bufferTrial, gtArray[i]); - chartData[2][gtLabel[i]] = getSpeed(bufferTrial, gtArray[i], 6).toFixed(2); - chartData[3][gtLabel[i]] = getAmplitudeY(bufferTrial, gtArray[i], 6).toFixed(2); - chartData[4][gtLabel[i]] = getSpeed(bufferTrial, gtArray[i], 10).toFixed(2); - chartData[5][gtLabel[i]] = getAmplitudeY(bufferTrial, gtArray[i], 10).toFixed(2); - chartData[6][gtLabel[i]] = getSpeed(bufferTrial, gtArray[i], 0).toFixed(2); - chartData[7][gtLabel[i]] = getAmplitudeY(bufferTrial, gtArray[i], 0).toFixed(2); - chartData[8][gtLabel[i]] = getOrientation(bufferTrial, gtArray[i], 1).toFixed(2); - chartData[9][gtLabel[i]] = getAmplitudeZ(bufferTrial, gtArray[i], 0).toFixed(2); + var height_jt6_ex = getAmplitudeY(bufferTrial, exArray[i], 6); + if (Math.abs(height_jt6_gt) < threshold.HeightChange) { + barData.leftHandHeightChange.push(0); } - for (var i in exArray) { - chartData[0][exLabel[i]] = bufferTrial[exArray[i]].duration; - chartData[1][exLabel[i]] = typeofTest(bufferTrial, exArray[i]); - chartData[2][exLabel[i]] = getSpeed(bufferTrial, exArray[i], 6).toFixed(2); - chartData[3][exLabel[i]] = getAmplitudeY(bufferTrial, exArray[i], 6).toFixed(2); - chartData[4][exLabel[i]] = getSpeed(bufferTrial, exArray[i], 10).toFixed(2); - chartData[5][exLabel[i]] = getAmplitudeY(bufferTrial, exArray[i], 10).toFixed(2); - chartData[6][exLabel[i]] = getSpeed(bufferTrial, exArray[i], 0).toFixed(2); - chartData[7][exLabel[i]] = getAmplitudeY(bufferTrial, exArray[i], 0).toFixed(2); - chartData[8][exLabel[i]] = getOrientation(bufferTrial, exArray[i], 1).toFixed(2); - chartData[9][exLabel[i]] = getAmplitudeZ(bufferTrial, exArray[i], 0).toFixed(2); + else { + barData.leftHandHeightChange.push((height_jt6_ex - height_jt6_gt) / height_jt6_gt * 100); } - return chartData; - } - function curveAnalyze(bufferTrial, gtArray, exArray, gtInd, exInd, jt, datatype) { - var curveData = {}; - var maxlength = 0; - curveData["numDataSets"] = gtInd.length + exInd.length; - curveData["labels"] = []; - curveData["dataset"] = []; - curveData["xticks"] = []; - if (gtInd.length > 0) { - for (var i = 0; i < gtInd.length; i++) { - curveData.labels.push("Referece_" + gtInd[i].toString()); - var id = gtArray[gtInd[i]]; - var rawdata = getRaw(bufferTrial, id, jt, datatype); - curveData.dataset.push(rawdata); - if (rawdata.length > maxlength) { - maxlength = rawdata.length - } - } + var speed_jt10_ex = getSpeed(bufferTrial, exArray[i], 10); + if (Math.abs(speed_jt10_gt) < threshold.Speed) { + barData.rightHandSpeed.push(0); + } + else { + barData.rightHandSpeed.push((speed_jt10_ex - speed_jt10_gt) / speed_jt10_gt * 100); } - if (exInd.length > 0) { - for (var i = 0; i < exInd.length; i++) { - curveData.labels.push("Exercise_" + exInd[i].toString()); - var id = exArray[exInd[i]]; - var rawdata = getRaw(bufferTrial, id, jt, datatype); - curveData.dataset.push(rawdata); - if (rawdata.length > maxlength) { - maxlength = rawdata.length - } - } + var height_jt10_ex = getAmplitudeY(bufferTrial, exArray[i], 10); + if (Math.abs(height_jt10_gt) < threshold.HeightChange) { + barData.rightHandHeightChange.push(0); } - var numMarks = 10; - var pads = Math.ceil(maxlength / numMarks); - - for (var i = 0; i < numMarks; i++) { - var timeMark = (i * pads * 0.008342).toFixed(2); - curveData.xticks.push(timeMark.toString()); - for (var j = 1; j < pads; j++) { - curveData.xticks.push(""); - } + else { + barData.rightHandHeightChange.push((height_jt10_ex - height_jt10_gt) / height_jt10_gt * 100); } - // "xticks": ["1", "", "", "", "", "6", "", "", "", "", "11"], - - return curveData; - } - function barAnalyze(bufferTrial, gtArray, exArray) { - var barData = {}; - barData.leftHandSpeed = []; - barData.leftHandHeightChange = []; - barData.rightHandSpeed = []; - barData.rightHandHeightChange = []; - barData.pelvicSpeed = []; - barData.pelvicHeightChange = []; - barData.SpineMidOrientation = []; - barData.SpineBaseMovement = []; - var threshold = { - Speed: 0.005, - HeightChange: 0.005, - Orientation: 1, - }; - var speed_jt6_gt = 0, height_jt6_gt = 0, speed_jt10_gt = 0, height_jt10_gt = 0, - speed_jt0_gt = 0, height_jt0_gt = 0; - var lean_jt1_gt = 0, ampZ_jt0_gt = 0; - for (var i in gtArray) { - speed_jt6_gt = getSpeed(bufferTrial, gtArray[i], 6); - height_jt6_gt += getAmplitudeY(bufferTrial, gtArray[i], 6); - speed_jt10_gt += getSpeed(bufferTrial, gtArray[i], 10); - height_jt10_gt += getAmplitudeY(bufferTrial, gtArray[i], 10); - speed_jt0_gt += getSpeed(bufferTrial, gtArray[i], 0); - height_jt0_gt += getAmplitudeY(bufferTrial, gtArray[i], 0); - lean_jt1_gt += getOrientation(bufferTrial, gtArray[i], 1); - ampZ_jt0_gt += getAmplitudeZ(bufferTrial, gtArray[i], 0); + var speed_jt0_ex = getSpeed(bufferTrial, exArray[i], 0); + if (Math.abs(speed_jt0_gt) < threshold.Speed) { + barData.pelvicSpeed.push(0); + } + else { + barData.pelvicSpeed.push((speed_jt0_ex - speed_jt0_gt) / speed_jt0_gt * 100); } - speed_jt6_gt /= gtArray.length; - height_jt6_gt /= gtArray.length; - speed_jt10_gt /= gtArray.length; - height_jt10_gt /= gtArray.length; - speed_jt0_gt /= gtArray.length; - height_jt0_gt /= gtArray.length; - lean_jt1_gt /= gtArray.length; - ampZ_jt0_gt /= gtArray.length; - - for (var i in exArray) { - var speed_jt6_ex = getSpeed(bufferTrial, exArray[i], 6); - if (Math.abs(speed_jt6_gt) < threshold.Speed) { - barData.leftHandSpeed.push(0); - } - else { - barData.leftHandSpeed.push((speed_jt6_ex - speed_jt6_gt) / speed_jt6_gt * 100); - } - - var height_jt6_ex = getAmplitudeY(bufferTrial, exArray[i], 6); - if (Math.abs(height_jt6_gt) < threshold.HeightChange) { - barData.leftHandHeightChange.push(0); - } - else { - barData.leftHandHeightChange.push((height_jt6_ex - height_jt6_gt) / height_jt6_gt * 100); - } - - var speed_jt10_ex = getSpeed(bufferTrial, exArray[i], 10); - if (Math.abs(speed_jt10_gt) < threshold.Speed) { - barData.rightHandSpeed.push(0); - } - else { - barData.rightHandSpeed.push((speed_jt10_ex - speed_jt10_gt) / speed_jt10_gt * 100); - } - - var height_jt10_ex = getAmplitudeY(bufferTrial, exArray[i], 10); - if (Math.abs(height_jt10_gt) < threshold.HeightChange) { - barData.rightHandHeightChange.push(0); - } - else { - barData.rightHandHeightChange.push((height_jt10_ex - height_jt10_gt) / height_jt10_gt * 100); - } - - var speed_jt0_ex = getSpeed(bufferTrial, exArray[i], 0); - if (Math.abs(speed_jt0_gt) < threshold.Speed) { - barData.pelvicSpeed.push(0); - } - else { - barData.pelvicSpeed.push((speed_jt0_ex - speed_jt0_gt) / speed_jt0_gt * 100); - } - - var height_jt0_ex = getAmplitudeY(bufferTrial, exArray[i], 0); - if (Math.abs(height_jt0_gt) < threshold.HeightChange) { - barData.pelvicHeightChange.push(0); - } - else { - barData.pelvicHeightChange.push((height_jt0_ex - height_jt0_gt) / height_jt0_gt * 100); - } - var lean_jt1_ex = getOrientation(bufferTrial, exArray[i], 1); - if (Math.abs(lean_jt1_ex) < threshold.HeightChange) { - barData.SpineMidOrientation.push(0); - } - else { - barData.SpineMidOrientation.push((lean_jt1_ex - lean_jt1_gt) / lean_jt1_gt * 100); - } + var height_jt0_ex = getAmplitudeY(bufferTrial, exArray[i], 0); + if (Math.abs(height_jt0_gt) < threshold.HeightChange) { + barData.pelvicHeightChange.push(0); + } + else { + barData.pelvicHeightChange.push((height_jt0_ex - height_jt0_gt) / height_jt0_gt * 100); + } - var ampZ_jt0_ex = getAmplitudeZ(bufferTrial, exArray[i], 0); - if (Math.abs(ampZ_jt0_gt) < threshold.HeightChange) { - barData.SpineBaseMovement.push(0); - } - else { - barData.SpineBaseMovement.push((ampZ_jt0_ex - ampZ_jt0_gt) / ampZ_jt0_gt * 100); - } + var lean_jt1_ex = getOrientation(bufferTrial, exArray[i], 1); + if (Math.abs(lean_jt1_ex) < threshold.HeightChange) { + barData.SpineMidOrientation.push(0); + } + else { + barData.SpineMidOrientation.push((lean_jt1_ex - lean_jt1_gt) / lean_jt1_gt * 100); + } + var ampZ_jt0_ex = getAmplitudeZ(bufferTrial, exArray[i], 0); + if (Math.abs(ampZ_jt0_gt) < threshold.HeightChange) { + barData.SpineBaseMovement.push(0); } - return barData; + else { + barData.SpineBaseMovement.push((ampZ_jt0_ex - ampZ_jt0_gt) / ampZ_jt0_gt * 100); + } + } + return barData; +} } \ No newline at end of file diff --git a/exercise/public/js/kinect.js b/exercise/public/js/kinect.js index 967b581..0691bef 100755 --- a/exercise/public/js/kinect.js +++ b/exercise/public/js/kinect.js @@ -34,7 +34,7 @@ $(document).ready(function () { if (!threshold_flag){ // Based on exercise (eg squat), know which direction we start counting reps in - threshold_flag = getExerciseInfo(document.getElementById("exercise").value)[1]; + threshold_flag = getExerciseInfo(document.getElementById("exercise").value)['direction']; } temp_reps = updateCanvas(bodyFrame, tracingID, 'rec', threshold_flag); if (temp_reps){ @@ -90,8 +90,9 @@ $(document).ready(function () { jointType.forEach(function (jointType) { drawJoints(body.joints[jointType].depthX * width, body.joints[jointType].depthY * height); }); + - drawCenterCircle(width / 2, height / 5, 50, body.joints[2].depthX * width, body.joints[2].depthY * height); + drawCenterCircle(width / 2, height / 5, 50, body.joints[2].depthX * width, body.joints[2].depthY * height, body.joints[2].cameraZ, body.joints[19].depthY, body.joints[0].depthY); ctx1.beginPath(); ctx1.moveTo(body.joints[7].depthX * width, body.joints[7].depthY * height); @@ -114,13 +115,16 @@ $(document).ready(function () { } // Draw center circle - to help user position themselves - function drawCenterCircle(x, y, r, nx, ny) { + function drawCenterCircle(x, y, r, nx, ny,nz, footright, spinebase) { ctx1.beginPath(); if (nx > x - r && nx < x + r && ny > y - r && ny < y + r) { ctx1.strokeStyle = "green"; if (!neck_y || !neck_x){ neck_x = nx/width; neck_y = ny/height; + console.log('neck_y', neck_y) + console.log('footright', footright) + console.log('spinebase', spinebase) } } else { ctx1.strokeStyle = "red"; @@ -132,18 +136,19 @@ $(document).ready(function () { ctx1.strokeStyle = "black"; } + // Function parameters: range_scale is how much to scale the distance between spine and foot, + // top_thresh and bottom_thresh are the thresholds the user should reach when the signal + // has been scaled to a range between 0 and 1, for a repetition to count - function countReps(body, threshold_flag){ + function countReps(body, threshold_flag, range_scale=0.7, top_thresh=0.25, bottom_thresh=0.75){ var reps = 0; var norm; - // Get info based on exercise (eg squat) + // Get info based on exercise (default is squat) + // This should eventually be a db call var exInfo = getExerciseInfo(document.getElementById("exercise").value); - var joint = exInfo[0]; - var coordinate = exInfo[2]; - - // need to figure out how to set this non-arbitrarily - var error = 0.22; + var joint = exInfo['joint']; + var coordinate = exInfo['axis']; // This is set when user is correctly positioned in circle if (coordinate == 'depthY') { @@ -152,13 +157,18 @@ $(document).ready(function () { norm = neck_x; } - // Normalize to neck - var current_pt = (body.joints[joint][coordinate] - norm)*height; + // Normalize reference points to neck + var ref_norm = exInfo['ref_neck']; + var ref_max = exInfo['ref_max'] - ref_norm; + var ref_min = exInfo['ref_min'] - ref_norm; - // Normalize to neck in reference - var ref_norm = exInfo[5]; - var top_thresh = height*(exInfo[3]-ref_norm + error); - var bottom_thresh = height*(exInfo[4]-ref_norm - error); + // Range is based on distance between foot and spine + var ref_foot = exInfo['ref_foot']; + var ref_spine = exInfo['ref_spine']; + var range = (ref_foot - ref_norm - ref_spine)*range_scale; + + // Normalize current point by range and current neck value + var current_pt = (body.joints[joint][coordinate] - norm - ref_max)/range; if ((threshold_flag == 'down') && (current_pt < top_thresh)){ reps++; @@ -219,7 +229,8 @@ $(document).ready(function () { } }); } else { - drawBody(bodyFrame.bodies[tracingID]); + var body = bodyFrame.bodies[tracingID]; + drawBody(body); reps = countReps(body, threshold_flag); } return reps; @@ -236,14 +247,30 @@ $(document).ready(function () { } - // Get info from JSON about a given exercise like salient joint, direction of reps, etc. - // this info should eventually be stored in a db + // Get info from JSON about a given exercise function getExerciseInfo(exercise){ - //most important joint, starting direction of rep, min val in ref, max val in ref, min neck in ref, max neck in ref + // This info should be patient-specific and eventually stored in the db exercise_info = { - 'hand_raise': [11, 'down', 'depthY'], - 'squat': [0, 'up', 'depthY', 0.54, 1.03, 0.21, 0.71], - + 'hand_raise': + {'joint': 11, + 'direction': 'down', + 'axis': 'depthY', + 'ref_max': 0.73, + 'ref_min': 1.19, + 'ref_mean': 0.76, + 'ref_neck': 0.27, + }, + 'squat': + {'joint': 0, + 'direction': 'up', + 'axis': 'depthY', + 'ref_max': 0.68, + 'ref_min': 1.13, + 'ref_mean': 0.76, + 'ref_neck': 0.27, + 'ref_foot': 1.43, + 'ref_spine': 0.70 + }, } return exercise_info[exercise]; }