Updated the complete “Speak with Your Hands” tutorial to use the modern ml5.js HandPose API.Speak with your hands 2.0#1509
Conversation
| <meta charset="UTF-8" /> | ||
| <title>Handpose with Webcam</title> | ||
|
|
||
| <script src="https://cdn.jsdelivr.net/npm/p5@2.0.5/lib/p5.js"></script> |
There was a problem hiding this comment.
Would it be possible to use p5@2 latest rather than a specific patch?
| createCanvas(400, 350); | ||
|
|
||
| // Load Image | ||
| img = await loadImage("https://raw.githubusercontent.com/ml5js/ml5-library/49b9bf2/examples/p5js/Handpose/Handpose_Image/data/hand.jpg"); |
There was a problem hiding this comment.
Should this be a relative url to one of the assets you added?
ksen0
left a comment
There was a problem hiding this comment.
A fe minor comments, but thanks so much for going through and updating everything! @doradocodes if you verify locally as well please feel free to merge.
| createCanvas(400, 350); | ||
|
|
||
| // Load the image and wait until it finishes loading | ||
| img = await loadImage("https://raw.githubusercontent.com/ml5js/ml5-library/49b9bf2/examples/p5js/Handpose/Handpose_Image/data/hand.jpg"); |
There was a problem hiding this comment.
Hi @colemanliyah thanks for this wonderful work. I made some small comments throughout. Some of my comments apply to the subsequent examples too but I only noted it for the first instance of a change.
Also, the ml5.js style is to use a variable called hands rather than predictions. That might be a little friendlier to the reader, but it's also ok for this tutorial to have its own code style if you prefer to keep it as predictions.
Let me know if you have any questions!
| async function setup() { | ||
| // Create a canvas that's at least the size of the image. | ||
| createCanvas(400, 350); |
There was a problem hiding this comment.
Small thing, but noting that the code isn't indented here.
| // we use await to wait until the model is ready before continuing. | ||
| handPose = await ml5.handPose(); | ||
|
|
||
| frameRate(1); // Set the frameRate to 1 since we don't need it to run quickly in this case. |
There was a problem hiding this comment.
Since this example incorporates noLoop() setting the frame rate to 1 seems extraneous to me.
| handPose.detect(img, results => { | ||
| predictions = results; | ||
| }); |
There was a problem hiding this comment.
For a single image this can actually be
| handPose.detect(img, results => { | |
| predictions = results; | |
| }); | |
| predictions = await handPose.detect(img); |
|
|
||
| fill(0, 255, 0); | ||
| noStroke(); | ||
| ellipse(keypoint.x, keypoint.y, 10, 10); |
There was a problem hiding this comment.
circle() is a little friendlier!
| ellipse(keypoint.x, keypoint.y, 10, 10); | |
| circle(keypoint.x, keypoint.y, 10); |
| try { | ||
| handPose = await ml5.handPose(); | ||
| console.log("HandPose loaded!"); | ||
| } catch (error) { | ||
| console.error(error); | ||
| } |
There was a problem hiding this comment.
I might skip the try catch here for simplicity.
| - `finger.points[3][0]` corresponds to the x-coordinate of the point | ||
| - `finger.points[3][1]` corresponds to the y-coordinate of the point |
There was a problem hiding this comment.
I think these should be .x and .y instead of [0] and [1]?
|
|
||
| Let's change this code to add hats on each fingertip. [Full Sketch](https://editor.p5js.org/colemanliyah/sketches/pjzyE3gCp) Here are the steps: | ||
|
|
||
| 1. Add a variable to store the hat image and load it using the `preload()` function. |
| - Replace the `drawKeypoints()` function with a new `drawObject()` function. | ||
| - In `drawObject()`, access the index fingertip by selecting the last point of the index finger: | ||
| ```js | ||
| let tip = prediction.keypoints.slice(4, 8)[3]; |
There was a problem hiding this comment.
I didn't comment on this for the previous examples b/c of the createFinger() method uses the arrays in an elegant way. However, here it would make a lot more sense to use the named points inside of the prediction object.
| let tip = prediction.keypoints.slice(4, 8)[3]; | |
| let tip = prediction.index_finger_tip; |
| handPose.detectStart(video, results => { | ||
| predictions = results; | ||
| }); |
There was a problem hiding this comment.
I would use a gotHands(results) callback here to match the ml5.js example style.
| let indexTip = prediction.keypoints.slice(4, 8)[3]; | ||
| let middleTip = prediction.keypoints.slice(8, 12)[3]; | ||
| let ringTip = prediction.keypoints.slice(12, 16)[3]; |
There was a problem hiding this comment.
same here, use the named points directly.
Resolves PR #1483 (#1483)
Replaced all older ml5 examples (ml5.handpose(), modelReady(), predict events, annotations) with the new API:
Updated every example sketch to work with the current ml5 version:
Embedded all example sketches directly into the tutorial using instead of linking out to external sketches.
Added updated comments and explanations to match the new code structure.
Updated explanations of prediction data to match the new HandPose output format (keypoints, keypoints3D, handedness, confidence).