added rock paper scissors detector
This commit is contained in:
@@ -0,0 +1,266 @@
|
||||
let video;
|
||||
let handPose;
|
||||
let hands = [];
|
||||
let hand;
|
||||
let handVals;
|
||||
let fingers;
|
||||
let handBounds;
|
||||
let folders = {};
|
||||
let painting;
|
||||
let connections = [
|
||||
[0, 1],
|
||||
[1, 2],
|
||||
[2, 3],
|
||||
[3, 4],
|
||||
[1, 5],
|
||||
[5, 6],
|
||||
[6, 7],
|
||||
[7, 8],
|
||||
[13, 9],
|
||||
[9, 5],
|
||||
[2, 5],
|
||||
[9, 10],
|
||||
[10, 11],
|
||||
[11, 12],
|
||||
[17, 13],
|
||||
[13, 14],
|
||||
[14, 15],
|
||||
[15, 16],
|
||||
[0, 17],
|
||||
[17, 18],
|
||||
[18, 19],
|
||||
[19, 20]
|
||||
];
|
||||
let clearStart = 0;
|
||||
let videoScale;
|
||||
|
||||
let conf = {
|
||||
hands: {
|
||||
palm_kps: [0, 1, 5, 9, 13, 17],
|
||||
palm_kps_str: null,
|
||||
Left: "#ff0000",
|
||||
Right: "#0000ff",
|
||||
show: true,
|
||||
paint: true,
|
||||
},
|
||||
canvas: {
|
||||
bg: "#00000000"
|
||||
},
|
||||
kps: {
|
||||
size: 8,
|
||||
color: "#000000",
|
||||
draw: false,
|
||||
},
|
||||
kp_conn: {
|
||||
connect: true,
|
||||
stroke: 1,
|
||||
},
|
||||
kp_text: {
|
||||
show: false,
|
||||
size: 8,
|
||||
offx: 10,
|
||||
offy: 5,
|
||||
color: "#000000ff"
|
||||
},
|
||||
camera: {
|
||||
show: true,
|
||||
},
|
||||
hand_bounds: {
|
||||
show: true,
|
||||
stroke: 2
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
let palm_kps = [0, 1, 5, 17];
|
||||
|
||||
function preload() {
|
||||
handPose = ml5.handPose({ flipped: true });
|
||||
}
|
||||
|
||||
function setup() {
|
||||
createCanvas(window.innerWidth, window.innerHeight);
|
||||
video = createCapture({
|
||||
video: {
|
||||
},
|
||||
audio: false,
|
||||
flipped: true,
|
||||
});
|
||||
videoScale = Math.min(window.innerWidth / 640, window.innerHeight / 480);
|
||||
video.size(640 * videoScale, 480 * videoScale);
|
||||
handPose.detectStart(video, (results) => { hands = results; });
|
||||
|
||||
video.hide();
|
||||
|
||||
}
|
||||
|
||||
function draw() {
|
||||
clear();
|
||||
strokeWeight(1);
|
||||
stroke(255);
|
||||
fill(conf.canvas.bg);
|
||||
rect(0, 0, width, height);
|
||||
rect(0, 0, video.width, video.height);
|
||||
|
||||
image(video, 0, 0);
|
||||
|
||||
handBounds = {};
|
||||
|
||||
if (hands.length > 0) {
|
||||
hand = hands[0];
|
||||
let index = {
|
||||
x: hand.index_finger_tip.x,
|
||||
y: hand.index_finger_tip.y
|
||||
}
|
||||
let middle = {
|
||||
x: hand.middle_finger_tip.x,
|
||||
y: hand.middle_finger_tip.y
|
||||
}
|
||||
let ring = {
|
||||
x: hand.ring_finger_tip.x,
|
||||
y: hand.ring_finger_tip.y
|
||||
}
|
||||
let pinky = {
|
||||
x: hand.pinky_finger_tip.x,
|
||||
y: hand.pinky_finger_tip.y
|
||||
}
|
||||
let thumb = {
|
||||
x: hand.thumb_tip.x,
|
||||
y: hand.thumb_tip.y
|
||||
}
|
||||
fingers = [thumb, index, middle, ring, pinky];
|
||||
|
||||
handVals = {
|
||||
fingers: fingers,
|
||||
handBounds: getBounds(hand.keypoints),
|
||||
handRad: null,
|
||||
palmBounds: getBounds(palm_kps.map(i => hand.keypoints[i])),
|
||||
palmRad: null,
|
||||
fingersBounds: getBounds(fingers),
|
||||
fingersRad: null,
|
||||
|
||||
|
||||
fingersInPalm: null,
|
||||
fingersOnBounds: 0,
|
||||
handedness: hand.handedness,
|
||||
pose: "none",
|
||||
}
|
||||
|
||||
handVals.palmRad = dist(handVals.palmBounds.min.x, handVals.palmBounds.min.y, handVals.palmBounds.max.x, handVals.palmBounds.max.y) / 2;
|
||||
handVals.handRad = dist(handVals.handBounds.min.x, handVals.handBounds.min.y, handVals.handBounds.max.x, handVals.handBounds.max.y) / 2;
|
||||
handVals.fingersRad = dist(handVals.fingersBounds.min.x, handVals.fingersBounds.min.y, handVals.fingersBounds.max.x, handVals.fingersBounds.max.y) / 2;
|
||||
|
||||
handVals.fingersInPalm = fingers.filter(f => dist(f.x, f.y, handVals.palmBounds.c.x, handVals.palmBounds.c.y) < handVals.palmRad * 1.2).length;
|
||||
handVals.fingersOnBounds = fingers.filter(f => dist(f.x, f.y, handVals.fingersBounds.c.x, handVals.fingersBounds.c.y) < handVals.fingersRad * 1.2).length;
|
||||
|
||||
loopKP(hand, handVals);
|
||||
// drawConnections(hand);
|
||||
// drawHandText(hand);
|
||||
drawBounds(handVals);
|
||||
detectGestures(handVals);
|
||||
|
||||
debug.innerHTML = `
|
||||
Hands detected: ${hands.length}<br>
|
||||
Palm radius: ${handVals.palmRad.toFixed(2)}<br>
|
||||
Fingers in palm: ${handVals.fingersInPalm}<br>
|
||||
Hand radius: ${handVals.handRad.toFixed(2)}<br>
|
||||
Fingers on edge: ${handVals.fingersOnBounds}<br>
|
||||
Pose: ${handVals.pose}<br>
|
||||
`;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
function drawConnections(hand) {
|
||||
for (let j = 0; j < connections.length; j++) {
|
||||
let pointAIndex = connections[j][0];
|
||||
let pointBIndex = connections[j][1];
|
||||
let pointA = hand.keypoints[pointAIndex];
|
||||
let pointB = hand.keypoints[pointBIndex];
|
||||
stroke(conf.hands[hand.handedness]);
|
||||
strokeWeight(conf.kp_conn.stroke);
|
||||
line(pointA.x, pointA.y, pointB.x, pointB.y);
|
||||
}
|
||||
}
|
||||
|
||||
function detectGestures(handVals) {
|
||||
if (handVals.fingersInPalm >= 4) {
|
||||
stroke(0, 255, 0);
|
||||
fill(0, 255, 0, 100);
|
||||
// circle(handVals.palmBounds.c.x, handVals.palmBounds.c.y, handVals.palmRad * 2);
|
||||
handVals.pose = "🪨";
|
||||
} else if (handVals.fingersOnBounds == 2 && handVals.fingersInPalm >= 2) {
|
||||
// && dist(handVals.fingers[0].x, handVals.fingers[0].y, handVals.palmBounds.c.x, handVals.palmBounds.c.y) < handVals.palmRad * 1.2
|
||||
stroke(255, 0, 0);
|
||||
fill(255, 0, 0, 100);
|
||||
|
||||
handVals.pose = "✂️";
|
||||
} else if (handVals.fingersInPalm == 0 && handVals.fingersOnBounds >= 3) {
|
||||
handVals.pose = "📄";
|
||||
}
|
||||
|
||||
textSize(64);
|
||||
fill(conf.hands[handVals.handedness]);
|
||||
text(handVals.pose, handVals.palmBounds.c.x - textWidth(handVals.pose) / 2, handVals.palmBounds.c.y);
|
||||
}
|
||||
|
||||
function drawBounds(handVals) {
|
||||
let x = handVals.handBounds.min.x;
|
||||
let y = handVals.handBounds.min.y;
|
||||
let w = handVals.handBounds.max.x - x;
|
||||
let h = handVals.handBounds.max.y - y;
|
||||
|
||||
noFill();
|
||||
stroke(conf.hands[handVals.handedness]);
|
||||
strokeWeight(conf.hand_bounds.stroke);
|
||||
// rect(x, y, w, h);
|
||||
|
||||
// circle(handVals.palmBounds.c.x, handVals.palmBounds.c.y, handVals.palmRad * 2);// Palm center
|
||||
// circle(handVals.fingersBounds.c.x, handVals.fingersBounds.c.y, handVals.fingersRad * 2);// Finger center
|
||||
// // rect(handVals.fingersBounds.min.x, handVals.fingersBounds.min.y, handVals.fingersBounds.max.x - handVals.fingersBounds.min.x, handVals.fingersBounds.max.y - handVals.fingersBounds.min.y);// Finger bounds
|
||||
// // rect(handVals.palmBounds.min.x, handVals.palmBounds.min.y, handVals.palmBounds.max.x - handVals.palmBounds.min.x, handVals.palmBounds.max.y - handVals.palmBounds.min.y);// Palm bounds
|
||||
}
|
||||
|
||||
function loopKP(hand, handVals) {
|
||||
for (let j = 0; j < hand.keypoints.length; j++) {
|
||||
const kp = hand.keypoints[j];
|
||||
fill(conf.kps.color);
|
||||
noStroke();
|
||||
if (conf.kps.draw) circle(kp.x, kp.y, conf.kps.size);
|
||||
|
||||
fill(conf.kp_text.color);
|
||||
textSize(conf.kp_text.size);
|
||||
// text(`[${j}]`, kp.x + conf.kp_text.offx, kp.y - conf.kp_text.offy);
|
||||
|
||||
|
||||
}
|
||||
handVals.fingersOnBounds = fingers.filter(f => f.x == handVals.handBounds.min.x || f.x == handVals.handBounds.max.x || f.y == handVals.handBounds.min.y || f.y == handVals.handBounds.max.y).length;
|
||||
|
||||
}
|
||||
|
||||
function drawHandText(hand) {
|
||||
fill(conf.hands[hand.handedness]);
|
||||
textSize(conf.kp_text.size * 1.5);
|
||||
|
||||
let avgX = conf.hands.palm_kps.reduce((sum, i) => sum + hand.keypoints[i].x, 0) / conf.hands.palm_kps.length;
|
||||
let avgY = conf.hands.palm_kps.reduce((sum, i) => sum + hand.keypoints[i].y, 0) / conf.hands.palm_kps.length;
|
||||
let offset = (conf.kp_text.size * 1.5) / 2;
|
||||
text(hand.handedness, avgX - textWidth(hand.handedness) / 2, avgY + offset);
|
||||
}
|
||||
function getBounds(arr) {
|
||||
let b = { min: { x: Infinity, y: Infinity }, max: { x: -Infinity, y: -Infinity }, c: { x: 0, y: 0 } };
|
||||
for (let i of arr) {
|
||||
if (i.x < b.min.x) b.min.x = i.x
|
||||
if (i.y < b.min.y) b.min.y = i.y
|
||||
if (i.x > b.max.x) b.max.x = i.x
|
||||
if (i.y > b.max.y) b.max.y = i.y
|
||||
}
|
||||
b.c.x = (b.min.x + b.max.x) / 2;
|
||||
b.c.y = (b.min.y + b.max.y) / 2;
|
||||
return b;
|
||||
}
|
||||
|
||||
const clamp = (min, num, max) => Math.min(Math.max(num, min), max);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user