casher-body

(wow I look tired)

I had been intrigued by the last project's option to design a drawing program in Glitch, so I thought it would be fun to explore that in this project. I also wanted to create something that involves the whole body in order to make the user look ridiculous. Combining the two, I made this silly drawing application (which, I realized, can also double as an exercise "machine," if the user plays with it intensely enough). In my process, since this is a live application, I had to figure out how to track the different motions of various body parts and calculate their distances from specific points on the screen. Originally I had planned for the wideness of the opening of your mouth to control the stroke weight of the lines, but I discovered that using this code template, which doesn't analyze the mouth, was easier for me to use, so I had to change my idea a little bit. I am mostly happy with the product here -- it is very similar to the vision I had in the beginning, which is awesome because it means that I have either (or both) made progress in my coding abilities or learned to not be overly ambitious in my projects! If I could change a few things, I would first try to make it collaborative, so that people could draw together; and once I realized that it could be a form of exercise, I thought it could be cool to make it a game where the user would have to race a clock to draw something of specific shape, color, and size, which would force them to hop, squat, and move pretty quickly.

Directions:

You draw around the board with your nose. To turn on the pen, lift your left hand until it crosses the top white bar. Pick up the pen by touching the left bar with your left hand, and back up to the top to turn it on again. To change the color of the pen, jump high enough that both feet cross above the bottom white line. To make the pen thicker, jump so your nose crosses the top line; to thin the pen, duck low enough that your nose crosses the bottom line. To erase all lines, cross the right bar with your right hand.

 

let video;
let poseNet;
let poses = [];
let colors = ["black", "white", "red", "orange", "yellow", "green", "blue", "purple", "pink", "brown", "grey"]
let colorindex = 0;
let inArea = false;
let drawing = false;
let inArea2 = false;
let inArea3 = false;
let allLines = [];
let lines = [];
let circle = [65, 50, 30, 30];
let prevKpX;
let prevKpY;
let strokewidth = 3;
 
// Storing the last keypoint position
let lastKeypoints = [];
 
function setup() {
  createCanvas(640, 480);
  frameRate(24);
  video = createCapture({
    audio: false,
    video: {
      width: {
        ideal: 640
      },
      height: {
        ideal: 480
      }
    }
  });
  video.size(width, height);
 
  // Create a new poseNet method with a single detection
  poseNet = ml5.poseNet(video);
  // This sets up an event that fills the global variable "poses"
  // with an array every time new poses are detected
  poseNet.on('pose', function(results) {
    poses = results;
  });
  // Hide the video element, and just show the canvas
  video.hide();
 
  //print(lastKeypoints); 
  // setup original keypoints
  createDefaultKeypoints();
  //print(lastKeypoints);
}
 
// Create default keypoints for easing. 
function createDefaultKeypoints() {
  let numKeypoints = 17;
  for (let i = 0; i < numKeypoints; i++) {
    newKeypoint = {
      x: width / 2,
      y: height / 2
    }
 
    lastKeypoints.push(newKeypoint);
  }
}
 
function updateKeypoints() {
  // If there are no poses, ignore it.
  if (poses.length <= 0) {
    return;
  }
 
  // Otherwise, let's update the points; 
 
  let pose = poses[0].pose;
  let keypoints = pose.keypoints;
 
  for (let kp = 0; kp < keypoints.length; kp++) {
 
    let oldKeypoint = lastKeypoints[kp];
    let newKeypoint = keypoints[kp].position;
 
    let interpX = lerp(oldKeypoint.x, newKeypoint.x, .3);
    let interpY = lerp(oldKeypoint.y, newKeypoint.y, .3);
 
    let interpolatedKeypoint = {
      x: interpX,
      y: interpY
    }
 
    lastKeypoints[kp] = interpolatedKeypoint;
  }
}
 
function draw() {
  push();
  translate(width, 0, 0);
  scale(-1, 1);
  image(video, 0, 0, width, height);
 
 
  updateKeypoints();
 
  drawKeypoints();
  pop();
 
  strokeWeight(5);
  stroke(255);
  fill(255);
  line(0, height * .9, width, height * .9);
  line(0, height *.1, width, height*.1);
  line(width*.1, 0, width*.1, height);
  line(width*.9, 0, width*.9, height);
  stroke(colors[colorindex]);
  ellipse(circle[0], circle[1], circle[2], circle[3]);
}
 
// A function to draw ellipses over the detected keypoints
function drawKeypoints() {
  for (let i = 0; i < lastKeypoints.length; i++) {
    if (i == 0) {
      keypoint = lastKeypoints[i];
      fill(colors[colorindex]);
      //console.log(allLines);
      for (let i = 0; i < allLines.length; i++) {
        for (let j = 0; j < allLines[i].length; j++) { //console.log("c"); stroke(colors[allLines[i][j][4]]); strokeWeight(allLines[i][j][5]); line(allLines[i][j][0], allLines[i][j][1], allLines[i][j][2], allLines[i][j][3]); } } if (drawing == true) { if (lastKeypoints[9].y > height * .1) {
          stroke(colors[colorindex]);
          //console.log(lines);
					lines[0] = [lastKeypoints[0].x, lastKeypoints[0].y, lastKeypoints[0].x, lastKeypoints[0].y, colorindex, strokewidth]
          x1 = prevKpX;
          y1 = prevKpY;
          x2 = lastKeypoints[0].x;
          y2 = lastKeypoints[0].y;
          lines.push([x1, y1, x2, y2, colorindex, strokewidth]);
          for (i = 1; i < lines.length; i++) {
            stroke(colors[lines[i][4]]);
            strokeWeight(lines[i][5]);
            line(lines[i][0], lines[i][1], lines[i][2], lines[i][3]);
          }
          prevKpX = x2;
          prevKpY = y2;
        }
 
      }
      if (lastKeypoints[9].y < height * .1) { if (drawing == false) { drawing = true; } } if (lastKeypoints[9].x > width * .9) {
        if (drawing == true) {
          allLines.push(lines);
          lines = [];
          drawing = false;
        }
      }
      if (lastKeypoints[10].x < width*.1) {
        allLines = [];
        lines = [];
        drawing = false;
      }
      if (lastKeypoints[0].y < height*.1) {
        if (inArea2 == false) {
          if (circle[2] < 80 && circle[3] < 80 && strokewidth < 52) { circle[2] += 5; circle[3] += 5; strokewidth += 3; inArea2 = true; } } } else { inArea2 = false; } if (lastKeypoints[0].y > height*.9) {
        if (inArea3 == false) {
          if (circle[2] > 10 && circle[3] > 10 && strokewidth > 3) {
            circle[2] -= 5;
            circle[3] -= 5;
            strokewidth -= 3;
            inArea3 = true;
          }
        }
      }
      else {
        inArea3 = false;
      }
      stroke(255);
      fill(255);
      strokeWeight(0);
      ellipse(lastKeypoints[0].x, lastKeypoints[0].y, 10, 10);
      ellipse(lastKeypoints[9].x, lastKeypoints[9].y, 20, 20);
      ellipse(lastKeypoints[10].x, lastKeypoints[10].y, 20, 20);
      ellipse(lastKeypoints[15].x, lastKeypoints[15].y, 20, 20);
      ellipse(lastKeypoints[16].x, lastKeypoints[16].y, 20, 20);
      if (lastKeypoints[15].y < height * .9 && lastKeypoints[16].y < height * .9) {
        if (inArea == false) {
          colorindex = (colorindex + 1) % colors.length;
          inArea = true;
        }
      } else {
        inArea = false;
      }
    }
  }
}