xxxxxxxxxx
201
// this code is adapted from Pippin Barr's example
// Mirror video?
var mirror = true;
var angle = 0;
var videoElement = document.getElementById(`webcam`);
function onResults(results) {
if (results.multiHandLandmarks && mirror) {
results.multiHandLandmarks.forEach((h) => {
h.forEach((pt) => {
pt.x = pt.x * -1 + 1;
});
});
}
if (results.multiHandedness && mirror) {
results.multiHandedness.forEach((h) => {
h.label = h.label === "Left" ? "Right" : "Left";
});
}
handResults = results;
}
// Camera parameters
var cameraObj = new Camera(videoElement, {
onFrame: async () => {
await hands.send({
image: videoElement,
});
},
facingMode: "environment",
width: 1280,
height: 720,
});
// Hand tracking parameters
var handOptions = {
maxNumHands: 2, // change max number of detected hands here
modelComplexity: 1,
minDetectionConfidence: 0.5, // hand detection confidence threshold
minTrackingConfidence: 0.5,
};
var hands = new Hands({
locateFile: (file) => {
return `https://cdn.jsdelivr.net/npm/@mediapipe/hands/${file}`;
},
});
hands.setOptions(handOptions);
hands.onResults(onResults);
cameraObj.start();
var handResults = undefined;
var webcam = undefined;
function displayHands(results) {
if (!results) return;
if (results.multiHandLandmarks) {
for (var l = 0; l < results.multiHandLandmarks.length; l++) {
var colorCode = color(`hsb(${(200 + 70 * l) % 360}, 100%, 100%)`);
h = results.multiHandLandmarks[l];
var minX = Math.min(h.map((p) => p.x)) * width;
var maxX = Math.max(h.map((p) => p.x)) * width;
var minY = Math.min(h.map((p) => p.y)) * height;
var maxY = Math.max(h.map((p) => p.y)) * height;
noFill();
stroke(colorCode);
strokeWeight(1);
rect(minX, minY, maxX - minX, maxY - minY);
for (var j = 0; j < 5; j++) {
for (var i = 1; i < 4; i++) {
var index = j * 4 + i;
var pointA = remapHandPoint(h[index]);
var pointB = remapHandPoint(h[index + 1]);
line(pointA.x, pointA.y, pointB.x, pointB.y);
}
}
line(
remapHandPoint(h[0]).x,
remapHandPoint(h[0]).y,
remapHandPoint(h[1]).x,
remapHandPoint(h[1]).y
);
beginShape();
vertex(remapHandPoint(h[0]).x, remapHandPoint(h[0]).y);
vertex(remapHandPoint(h[5]).x, remapHandPoint(h[5]).y);
vertex(remapHandPoint(h[9]).x, remapHandPoint(h[9]).y);
vertex(remapHandPoint(h[13]).x, remapHandPoint(h[13]).y);
vertex(remapHandPoint(h[17]).x, remapHandPoint(h[17]).y);
endShape(CLOSE);
noStroke();
fill(colorCode);
for (var i = 0; i < h.length; i++) {
var point = remapHandPoint(h[i]);
circle(point.x, point.y, 5);
}
text(results.multiHandedness[l].label, minX, minY);
}
}
}
// maps points to the width and height of the canvas as a p5.Vector object
function remapHandPoint(pt) {
if (pt.x && pt.y) {
return createVector(pt.x * width, pt.y * height);
}
return undefined;
}
function remapAllHandLandmarks(hr) {
if (hr) {
if (hr.multiHandLandmarks.length > 0) {
return hr.multiHandLandmarks.map((l) =>
l.map((h) => ({
pt: remapHandPoint(h),
x: h.x * width,
y: h.y * height,
z: h.z,
}))
);
}
return [];
}
return undefined;
}
/////////////////////////
//
// p5.js portion
//
/////////////////////////
var pg1, pg2;
var img;
var mask;
function preload() {
img = loadImage("strange2.png");
mask = loadImage("mask.png");
}
function setup() {
createCanvas(640, 360);
pg1 = createGraphics(width, height);
pg2 = createGraphics(width, height);
webcam = select("#webcam");
}
function draw() {
background(0);
var remappedHandLandmarks = remapAllHandLandmarks(handResults);
push();
if (mirror) {
translate(width, 0);
scale(-1, 1);
}
imageMode(CORNER);
image(webcam, 0, 0, width, height);
pop();
if (remappedHandLandmarks) {
if (remappedHandLandmarks.length > 0) {
var fingerA = remappedHandLandmarks[0][8];
pg1.clear();
pg1.imageMode(CENTER);
pg1.image(mask, fingerA.x, fingerA.y, 300, 300);
pg2.image(img, 0, 0, pg2.width, pg2.height);
pg1.loadPixels();
pg2.loadPixels();
for (var i = 0; i < pg1.pixels.length; i = i + 4) {
pg2.pixels[i + 3] = pg1.pixels[i + 3];
}
pg2.updatePixels();
image(pg2, 0, 0, width, height);
}
}
displayHands(handResults);
}