FRI | Machine Learning with ml5.js

FRI | Machine Learning with ml5.js


  • November 10, 2023
  • Room L208
  • 9:15–12:00

Project Proposals #

We start off by checking yout project proposals.

Machine Learning #

Machine learning is a way to make machines do certain tasks without being explicitly programmed to do so.

ml5.js #

ml5.js is a JavaScript library that can be combined with p5.js to use and explore certain artificial intelligence and machine learning libraries in your projects.

ml5.js uses the Tensorflow library by Google. ml5.js is a library that attempts to make the usage of tensorflow a little bit easier.

Important links

These are the models that are available in ml5.js, explore the examples to understand what is possible.

Image

Text

Sound


Example: PoseNet #

As we saw above, ml5.js allows you to use various models but we are going to explore just one of them in detail. This model is PoseNet.

Step #1: Prepare your sketch files #

The first step is to include the ml5.js library in your ìndex.html file. Add the following line inside the head part of the html file:

<script src="https://unpkg.com/ml5@latest/dist/ml5.min.js"></script>

The basic starting poinf for your p5.js sketch is here:

// Open up your console - if everything loaded properly you should see the version number
// corresponding to the latest version of ml5 printed to the console and in the p5.js canvas.
console.log("ml5 version:", ml5.version);

function setup() {
  createCanvas(640, 480);
}

function draw() {
  background(200);
}

Step 2: Enable Video Camera Input #

Next, make sure your webcam works.

// Open up your console - if everything loaded properly you should see the version number
// corresponding to the latest version of ml5 printed to the console and in the p5.js canvas.
console.log("ml5 version:", ml5.version);

let cam;

function setup() {
  createCanvas(640, 480);
  cam = createCapture(VIDEO, videoLoaded);
  cam.hide();
}

function draw() {
  background(200);
  image(cam, 0, 0);
}

function videoLoaded() {
  // resize the canvas to be the same size as you camera resolution
  resizeCanvas(cam.width, cam.height);
}
There seems to be something wrong with setting the video camera image ration in p5.js. to fix that you can use the following example code.
/*

MORE INFO

https://w3c.github.io/mediacapture-main/getusermedia.html#dom-constraindouble
https://www.folkstalk.com/tech/how-to-force-a-16-9-ratio-with-getusermedia-on-all-devices-solution/
https://calculateaspectratio.com/16-9-calculator

*/

let video; // or cam

const cameraWidth = 960;
const cameraHeight = 540;

function setup() {
  // canvas and other p5 functions HERE

  const constraints = {
    video: { width: cameraWidth, height: cameraHeight, facingMode: "user" },
  };
  // Dont remove or change anything from the function below. This is what you need to set any ratio
  navigator.mediaDevices
    .getUserMedia(constraints)
    .then((stream) => (video.srcObject = stream))
    .then(() => new Promise((resolve) => (video.onloadedmetadata = resolve)))
    .then(() => log(video.videoWidth + "x" + video.videoHeight))
    .catch((e) => {});

  // Shows video
  video = createCapture(constraints);
  // video.hide()
}

Step 3: Load the PoseNet model and save the poses to an array #

// Open up your console - if everything loaded properly you should see the version number
// corresponding to the latest version of ml5 printed to the console and in the p5.js canvas.
console.log("ml5 version:", ml5.version);

let cam;
let posenet;
// create an empty array to store the data from the posenet tracking
let poses = [];

function setup() {
  createCanvas(640, 480);
  cam = createCapture(VIDEO, videoLoaded);
  cam.hide();

  // Create a new poseNet method with a single detection
  // modelReady function is called when the model has been loaded
  poseNet = ml5.poseNet(cam, modelReady);

  // This sets up an event that fills the global variable "poses"
  // with an array every time new poses are detected
  poseNet.on("pose", poseResults);
}

function draw() {
  background(200);
  image(cam, 0, 0);
}

function videoLoaded() {
  // resize the canvas to be the same size as you camera resolution
  resizeCanvas(cam.width, cam.height);
}

function modelReady() {
  console.log("model loaded!");
}

function poseResults(results) {
  poses = results;
}

function mousePressed() {
  console.log(poses);
}

Step 4: Draw all the keypoints for one person (pose) #

// Open up your console - if everything loaded properly you should see the version number
// corresponding to the latest version of ml5 printed to the console and in the p5.js canvas.
console.log("ml5 version:", ml5.version);

let cam;
let posenet;
// create an empty array to store the data from the posenet tracking
let poses = [];

function setup() {
  createCanvas(640, 480);
  cam = createCapture(VIDEO, videoLoaded);
  cam.hide();

  // Create a new poseNet method with a single detection
  // modelReady function is called when the model has been loaded
  poseNet = ml5.poseNet(cam, modelReady);

  // This sets up an event that fills the global variable "poses"
  // with an array every time new poses are detected
  poseNet.on("pose", poseResults);
}

function draw() {
  background(200);
  image(cam, 0, 0);

  // check that there is at least one person
  if (poses.length > 0) {
    // get the first pose (person) in the array
    let person = poses[0].pose;
    fill(255);
    noStroke();
    // loop through all of the keypoints in the pose
    for (let i = 0; i < person.keypoints.length; i++) {
      let x = person.keypoints[i].position.x;
      let y = person.keypoints[i].position.y;
      circle(x, y, 10);
    }
  }
}

function videoLoaded() {
  // resize the canvas to be the same size as you camera resolution
  resizeCanvas(cam.width, cam.height);
}

function modelReady() {
  console.log("model loaded!");
}

function poseResults(results) {
  poses = results;
}

function mousePressed() {
  // print the poses in the console when the mouse is pressed
  console.log(poses);
}

Step 5: Get individual points #

// Open up your console - if everything loaded properly you should see the version number
// corresponding to the latest version of ml5 printed to the console and in the p5.js canvas.
console.log("ml5 version:", ml5.version);

let cam;
let posenet;
// create an empty array to store the data from the posenet tracking
let poses = [];
let noseEmoji = "👃🏻";
let eyeEmoji = "👁️";

function setup() {
  createCanvas(640, 480);
  cam = createCapture(VIDEO, videoLoaded);
  cam.hide();

  // Create a new poseNet method with a single detection
  // modelReady function is called when the model has been loaded
  poseNet = ml5.poseNet(cam, modelReady);

  // This sets up an event that fills the global variable "poses"
  // with an array every time new poses are detected
  poseNet.on("pose", poseResults);
}

function draw() {
  background(200);
  image(cam, 0, 0);

  // check that there is at least one person
  if (poses.length > 0) {
    // get the first pose (person) in the array
    let person = poses[0].pose;
    fill(255);
    noStroke();
    // loop through all of the keypoints in the pose
    for (let i = 0; i < person.keypoints.length; i++) {
      let x = person.keypoints[i].position.x;
      let y = person.keypoints[i].position.y;
      circle(x, y, 10);
    }

    // set the text size and alignment for drawing the emojis
    textAlign(CENTER, CENTER);
    textSize(50);

    // get the nose point and draw the nose emoji in that location
    let nosePoint = person.nose;
    text(noseEmoji, nosePoint.x, nosePoint.y);

    // get the eye points
    let leftEyePoint = person.leftEye;
    let rightEyePoint = person.rightEye;
    text(eyeEmoji, leftEyePoint.x, leftEyePoint.y);
    text(eyeEmoji, rightEyePoint.x, rightEyePoint.y);
  }
}

function videoLoaded() {
  // resize the canvas to be the same size as you camera resolution
  resizeCanvas(cam.width, cam.height);
}

function modelReady() {
  console.log("model loaded!");
}

function poseResults(results) {
  poses = results;
}

function mousePressed() {
  // print the poses in the console when the mouse is pressed
  console.log(poses);
}