UNPKG

simple-peer-wrapper

Version:

A wrapper for simple-peer that includes a socket.io signaling server client. To be used in the browser with simple-peer-server.

247 lines (203 loc) 6.29 kB
// Simple Peer Wrapper Example — PoseNet // https://github.com/lisajamhoury/simple-peer-wrapper // This example allows for two users to interact on the same p5 canvas // using posenet via ml5 sent over webRTC peer connections. // It requires that a simple-peer-server is running to connect the two peers. // See https://github.com/lisajamhoury/simple-peer-server // Include this for to use p5 autofill in vscode // See https://stackoverflow.com/questions/30136319/what-is-reference-path-in-vscode /// <reference path="../shared/p5.d/p5.d.ts" /> /// <reference path="../shared/p5.d/p5.global-mode.d.ts" /> // Variable to hold SimplePeerWrapper let spw; // Posenet variables let video; let poseNet; // Variables to hold poses let myPose = {}; let partnerPose = {}; // Variables to hold noses let myNose; let partnerNose; // Use an offset if testing with just one person and webcam // This allows you to see both skeletons // Set to 0 if not needed const partnerOffset = 100; // Confidence threshold for posenet keypoints const scoreThreshold = 0.5; // Globals for growing animation const origSize = 10; let size = origSize; // Color palette const colors = { x: 'rgba(200, 63, 84, 0.5)', y: 'rgba(49, 128, 144, 0.5)', }; // Setup() is a p5 function // See this example if this is new to you // https://p5js.org/examples/structure-setup-and-draw.html function setup() { // Create p5 canvas createCanvas(640, 480); // Create webcam capture for posenet video = createCapture(VIDEO); video.size(width, height); // Create poseNet to run on webcam and call 'modelReady' when ready poseNet = ml5.poseNet(video, modelReady); // Everytime we get a pose from posenet, call "getPose" // and pass in the results poseNet.on('pose', (results) => getPose(results)); // Hide the webcam element, and just show the canvas video.hide(); // Include wrapper options here const options = { debug: false, serverUrl: 'http://localhost:8081', }; // Create a new simple-peer-wrapper spw = new SimplePeerWrapper(options); // Make the peer connection spw.connect(); // When data recieved over the connection call gotData spw.on('data', gotData); } function gotData(data) { partnerPose = data.data; } // Draw() is a p5 function // See this example if this is new to you // https://p5js.org/examples/structure-setup-and-draw.html function draw() { // Only proceed if the peer is started // And if there is a pose from posenet if ( !spw.isConnectionStarted() || typeof myPose.pose === 'undefined' ) { console.log('returning! waiting for my pose'); return; } // If we don't yet have a partner pose if (typeof partnerPose.pose === 'undefined') { // Return and try again for partner pose console.log('waiting for partner'); return; } // Get my nose from my pose myNose = getNose(myPose); // Get my partner's nose from their pose partnerNose = getNose(partnerPose); // Draw white background background(255); // Draw my keypoints and skeleton drawKeypoints(myPose, colors.x, partnerOffset); // draw keypoints drawSkeleton(myPose, colors.x, partnerOffset); // draw skeleton // Draw partner keypoints and skeleton drawKeypoints(partnerPose, colors.y, 0); drawSkeleton(partnerPose, colors.y, 0); // If our noses are touching if (touching(myNose, partnerNose, partnerOffset)) { console.log('touching'); // Increase the keypoint size size *= 1.01; } else { // Otherwise, draw keypoints at original size size = origSize; } // Use for debugging // drawFramerate(); // drawMyVideo(); } // When posenet model is ready, let us know! function modelReady() { console.log('Model Loaded'); } // Function to get and send pose from posenet function getPose(poses) { // We're using single detection so we'll only have one pose // which will be at [0] in the array myPose = poses[0]; // Send my pose over peer if the peer is started if (spw.isConnectionStarted()) { spw.send(myPose); } } // A function to draw ellipses over the detected keypoints // Include an offset if testing by yourself // And you want to offset one of the skeletons function drawKeypoints(pose, clr, offset) { // Loop through all keypoints for (let j = 0; j < pose.pose.keypoints.length; j++) { // A keypoint is an object describing a body part (like rightArm or leftShoulder) const keypoint = pose.pose.keypoints[j]; // Only draw an ellipse is the pose probability is bigger than 0.2 if (keypoint.score > scoreThreshold) { fill(clr); noStroke(); ellipse( keypoint.position.x + offset, // Offset useful if testing on your own keypoint.position.y, size, size, ); } } } // A function to draw the skeletons function drawSkeleton(pose, clr, offset) { // Loop through all the skeletons detected const skeleton = pose.skeleton; // For every skeleton, loop through all body connections for (let j = 0; j < skeleton.length; j++) { // Get the ends "joints" for each bone const partA = skeleton[j][0]; const partB = skeleton[j][1]; // If the score is high enough if ( partA.score > scoreThreshold && partB.score > scoreThreshold ) { // Draw a line to represent the bone stroke(clr); line( partA.position.x + offset, partA.position.y, partB.position.x + offset, partB.position.y, ); } } } // Function to get nose out of the pose function getNose(pose) { // Return the nose return pose.pose.nose; } // Function to see if two points are "touching" function touching(nose1, nose2, offset) { // Get the distance between the two noses const d = dist(nose1.x, nose1.y, nose2.x + offset, nose2.y); // If the distance is less than 50 pixels we are touching! if (d < 50) { return true; } // Otherwise we are not touching! return false; } function drawFramerate() { fill(0); stroke(0); text(getFrameRate(), 10, 10); } function drawMyVideo() { // Draw my video for debug push(); translate(0.25 * width, 0); scale(-0.25, 0.25); image(video, 0, 0, width, height); pop(); } // Press any key to stop the sketch function keyPressed() { noLoop(); }