Attempt at Mediapipe holistic tracking

This commit is contained in:
ksuprynowicz 2023-10-28 20:32:57 +02:00
parent 33ba6b8d89
commit 7bb4c1b913
2 changed files with 137 additions and 42 deletions
applications/emocam

View file

@ -39,6 +39,14 @@
var roll = 0;
var lastDataArrived = Date.now();
var isLeftHandTracked = false;
var leftHandRotation = null;
var leftHandPosition = null;
var isRightHandTracked = false;
var rightHandRotation = null;
var rightHandPosition = null;
button = tablet.addButton({
icon: ROOT + "images/face.png",
activeIcon: ROOT + "images/facei.png",
@ -76,14 +84,25 @@
}).to(Controller.Actions.TranslateX);
mapping.enable();
var propList = ["headRotation", "headType"];
var propList = ["headRotation", "headType",
"rightHandPosition", "rightHandRotation", "rightHandType",
"leftHandPosition", "leftHandRotation", "leftHandType"];
handlerId = MyAvatar.addAnimationStateHandler(function (props) {
if (Date.now() - lastDataArrived < 2000) {
let headTransform = Quat.fromPitchYawRollDegrees(pitch, -yaw, roll);
return {
headRotation: headTransform,
headType: 4
};
let returnProps = props;
if (isLeftHandTracked) {
returnProps.leftHandType = 0;
returnProps.leftHandRotation = leftHandRotation;
returnProps.leftHandPosition = leftHandPosition;
}
if (isRightHandTracked) {
returnProps.rightHandType = 0;
returnProps.rightHandRotation = rightHandRotation;
returnProps.rightHandPosition = rightHandPosition;
}
returnProps.headRotation = Quat.fromPitchYawRollDegrees(pitch, -yaw, roll);
returnProps.headType = 4;
return returnProps;
} else {
return props;
}
@ -130,8 +149,6 @@
"EyeOut_R": emotion["eyeLookOutRight"],
"EyeUp_L": emotion["eyeLookUpLeft"],
"EyeUp_R": emotion["eyeLookUpRight"],
"EyeSquint_L": emotion["eyeSquintLeft"],
"EyeSquint_R": emotion["eyeSquintRight"],
"TongueOut": emotion["jawForward"],
"JawLeft": emotion["jawLeft"] * 3,
"JawRight": emotion["jawRight"] * 3,
@ -196,12 +213,36 @@
}
}
let headLM = parsed.poselm3D[0]; // Nose landmark
let headPosition = {x: headLM.x, y: -headLM.y, z: -headLM.z};
let offset = { x: 0, y: 0.4, z: 0};
let scale = 2.0;
//print(JSON.stringify(parsed));
if (parsed.rightHandRig) {
isRightHandTracked = true;
rightHandPosition = {
//x: parsed.poselm3D[16].x,
//y: parsed.poselm3D[16].y,
//z: parsed.poselm3D[16].z}; // Left wrist
x: (parsed.poselm3D[16].x - headPosition.x) * scale + offset.x,
y: (-parsed.poselm3D[16].y - headPosition.y) * scale + offset.y,
z: (-parsed.poselm3D[16].z - headPosition.z) * scale + offset.z}; // Left wrist
//rightHandRotation = Quat.fromPitchYawRollRadians(parsed.rightHandRig.RightWrist.x,
// parsed.rightHandRig.RightWrist.y,
// parsed.rightHandRig.RightWrist.z);
print("RightHand: " + JSON.stringify(rightHandPosition) +" Head: " + JSON.stringify(headPosition));
} else {
isRightHandTracked = false;
}
yaw = parsed.yaw;
pitch = parsed.pitch;
roll = parsed.roll;
for (var blendshape in bend) {
MyAvatar.setBlendshape(blendshape, bend[blendshape]);
}
print("FPS: " + (1000 / (Date.now() - lastDataArrived)));
lastDataArrived = Date.now();
}
}

View file

@ -16,6 +16,15 @@
<html lang="en">
<head>
<meta charset="UTF-8">
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils/camera_utils.js" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/control_utils/control_utils.js"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/@mediapipe/holistic@0.4.1633559476" crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/kalidokit@1.1/dist/kalidokit.umd.js"></script>
<link href="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css" rel="stylesheet">
<script src="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.3/dist/Chart.min.js"></script>
<title>MediaPipe Face Landmarker</title>
<style>
@use "@material";
@ -235,15 +244,6 @@
};
</script>
<meta charset="utf-8">
<meta http-equiv="Cache-control" content="no-cache, no-store, must-revalidate">
<meta http-equiv="Pragma" content="no-cache">
<meta name="viewport" content="width=device-width, initial-scale=1, user-scalable=no">
<link href="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.css" rel="stylesheet">
<script src="https://unpkg.com/material-components-web@latest/dist/material-components-web.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/chart.js@2.9.3/dist/Chart.min.js"></script>
</head>
<body bgcolor="white">
@ -271,9 +271,15 @@
</td>
</tr>
</table>
<div style="position: relative;">
<video id="webcam" autoplay playsinline></video>
<canvas class="output_canvas" id="output_canvas" style="position: absolute; left: 0px; top: 0px;"></canvas>
<div class="container">
<video class="input_video" id="holistics" width="426px" height="240px"></video>
<canvas class="output_canvas1" id="output_canvas1" width="426px" height="240px"
style="position: absolute; left: 0px; top: 42px;"></canvas>
</div>
<div style="position: absolute; left: 0px; top: 42px;">
<video id="webcam" width="426px" height="240px" autoplay playsinline></video>
<canvas class="output_canvas" id="output_canvas" width="426px" height="240px"
style="position: absolute; left: 0px; top: 0px;"></canvas>
</div>
</div>
@ -298,13 +304,71 @@
<p id="output"></p>
<div class="blend-shapes">
<ul class="blend-shapes-list" id="video-blend-shapes"></ul>
</div>
</section>
<!--/body>
</html-->
<script src="jquery.min.js"></script>
<script>
<script id="rendered-js" type="module">
var leftHandRig = [];
var rightHandRig = [];
var poseRig = [];
//var leftHandlm = {};
//var leftHandlm = {};
var poselm3D = [];
var poselm = [];
const videoElement = document.getElementById("holistics");
const canvasElement1 = document.getElementsByClassName('output_canvas1')[0];
const canvasCtx1 = canvasElement1.getContext('2d');
function onResults(results) {
if (results.faceLandmarks) {
let facelm = results.faceLandmarks;
poselm = results.poseLandmarks;
poselm3D = results.ea;
let rightHandlm = results.rightHandLandmarks;
let leftHandlm = results.leftHandLandmarks;
let faceRig = Kalidokit.Face.solve(facelm, {
runtime: "mediapipe",
video: HTMLVideoElement
});
poseRig = Kalidokit.Pose.solve(poselm3D, poselm, {
runtime: "mediapipe",
video: HTMLVideoElement
});
rightHandRig = Kalidokit.Hand.solve(rightHandlm, "Right");
leftHandRig = Kalidokit.Hand.solve(leftHandlm, "Left");
}
}
const holistic = new Holistic({
locateFile: (file) => {
return `https://cdn.jsdelivr.net/npm/@mediapipe/holistic/${file}`;
}
});
holistic.setOptions({
modelComplexity: 1,
smoothLandmarks: true,
enableSegmentation: true,
smoothSegmentation: true,
refineFaceLandmarks: true,
minDetectionConfidence: 0.5,
minTrackingConfidence: 0.5
});
holistic.onResults(onResults);
const camera = new Camera(videoElement, {
onFrame: async () => {
await holistic.send({image: videoElement});
},
width: 1280,
height: 720
});
camera.start();
var channel = "org.overte.application.emocam";
@ -642,8 +706,6 @@
}
</script>
<script id="rendered-js" type="module">
// Copyright 2023 The MediaPipe Authors.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
@ -664,7 +726,7 @@
let runningMode = "IMAGE";
let enableWebcamButton;
let webcamRunning = false;
const videoWidth = 400;
const videoWidth = 426;
var checkedValue = null;
var yawDegrees;
var pitchDegrees;
@ -868,21 +930,7 @@
//console.log("Yaw: ", yawDegrees, "Pitch: ", pitchDegrees, "Roll: ", rollDegrees);
}
//draw on canvas
for (const landmarks of results.faceLandmarks) {
drawingUtils.drawConnectors(landmarks, FaceLandmarker.FACE_LANDMARKS_TESSELATION, {
color: "#C0C0C070",
lineWidth: 1
});
drawingUtils.drawConnectors(landmarks, FaceLandmarker.FACE_LANDMARKS_RIGHT_EYE, {color: "#FF3030"});
drawingUtils.drawConnectors(landmarks, FaceLandmarker.FACE_LANDMARKS_RIGHT_EYEBROW, {color: "#FF3030"});
drawingUtils.drawConnectors(landmarks, FaceLandmarker.FACE_LANDMARKS_LEFT_EYE, {color: "#30FF30"});
drawingUtils.drawConnectors(landmarks, FaceLandmarker.FACE_LANDMARKS_LEFT_EYEBROW, {color: "#30FF30"});
drawingUtils.drawConnectors(landmarks, FaceLandmarker.FACE_LANDMARKS_FACE_OVAL, {color: "#E0E0E0"});
drawingUtils.drawConnectors(landmarks, FaceLandmarker.FACE_LANDMARKS_LIPS, {color: "#E0E0E0"});
drawingUtils.drawConnectors(landmarks, FaceLandmarker.FACE_LANDMARKS_RIGHT_IRIS, {color: "#FF3030"});
drawingUtils.drawConnectors(landmarks, FaceLandmarker.FACE_LANDMARKS_LEFT_IRIS, {color: "#30FF30"});
}
}
drawBlendShapes(videoBlendShapes, results.faceBlendshapes);
// Call this function again to keep predicting when the browser is ready.
@ -921,10 +969,16 @@
"data": mappedJson,
"yaw": yawDegrees,
"pitch": pitchDegrees,
"roll": rollDegrees
"roll": rollDegrees,
"leftHandRig": leftHandRig,
"rightHandRig": rightHandRig,
"poseRig": poseRig,
"poselm3D": poselm3D,
"poselm": poselm
}
}
EventBridge.emitWebEvent(JSON.stringify(send));
}