-
Notifications
You must be signed in to change notification settings - Fork 0
/
neckTracking.js
190 lines (153 loc) · 4.96 KB
/
neckTracking.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
let faceMesh;
let video;
let faces = [];
let options = { maxFaces: 1, refineLandmarks: false, flipHorizontal: true };
let ballX, ballY;
let ballSize = 10;
let ballSpeed = 0.0000000000000001;
let steerX = 0, steerY = 0;
let path = [];
let drawingEnabled = false;
// Indices for specific eyes and nose landmarks
const leftEyeIndex = 130; // Left eye
const rightEyeIndex = 359; // Right eye
const noseIndex = 1; // Nose tip
function preload() {
// Load the faceMesh model
faceMesh = ml5.faceMesh(options);
}
function setup() {
let myCanvas = createCanvas(windowWidth, windowHeight);
myCanvas.parent("canvasContainer"); // Use the ID of the div where you want the canvas to be
frameRate(20); // Set the frame rate to 15 frames per second
// Create the webcam video and hide it
video = createCapture(VIDEO);
video.size(width, height);
video.hide();
// Start detecting faces from the webcam video
faceMesh.detectStart(video, gotFaces);
// Initialize the ball position at the center of the canvas
ballX = width / 2;
ballY = height / 2;
document.getElementById('saveArtButton').addEventListener('click', function() {
let ctx = canvas.getContext('2d');
let text1 = "all.draw";
// Set the font properties
let fontFamily = 'Lexend, Inter, Sans-serif';
let fontSize = '48px';
let fontWeight = '800';
// Set the font style
ctx.font = `${fontWeight} ${fontSize} ${fontFamily}`;
// text1.style
// text1.style.fontFamily = "Lexend";
// // Lexend, Inter, sans-serif
let text2 = " by " + document.getElementById('artistname').value;
ctx.fillText(text1, 10, 50); // 30 is a little lower than y=10 to account for font size
let canvasHeight = canvas.clientHeight;
ctx.fillText(text2, 10, canvasHeight - 20); // Adjust y for font size
// saveArt();
saveCanvas(text2, 'png');
clearCanvas();
});
}
function draw() {
if (!drawingEnabled) return;
// Draw the webcam video
// image(video, 0, 0, width, height);
// background(255);
// Draw the reference points
for (let i = 0; i < faces.length; i++) {
let face = faces[i];
if (face.keypoints.length > 0) {
const keypointsToDraw = [
face.keypoints[leftEyeIndex],
face.keypoints[rightEyeIndex],
face.keypoints[noseIndex],
];
// Calculate and display yaw, pitch, and roll
let angles = calculateHeadAngles(face.keypoints);
fill(0);
textSize(16);
// Update the ball position based on angles
steerBall(angles);
// Draw the path of the keypoint
noFill();
// stroke(0, 0, 255);
stroke(0)
strokeWeight(2);
beginShape();
for (let pt of path) {
vertex(pt.x, pt.y);
}
endShape();
}
}
}
// Callback function for when faceMesh outputs data
function gotFaces(results) {
// Save the output to the faces variable
faces = results;
}
function moveBall() {
// Move the ball with some constant speed
ballX += ballSpeed;
ballY += ballSpeed;
// Constrain the ball within the canvas
ballX = constrain(ballX, 50, width-50);
ballY = constrain(ballY, 50, height-50);
}
function steerBall(angles) {
// Update the ball position based on yaw and pitch
ballX += angles.yaw * 0.25; // Reduced speed for yaw
ballX += angles.roll * 0.5; // Reduced speed for yaw
// Check if pitch exceeds the threshold to allow vertical movement
if (angles.pitch < 90) {
ballY += angles.pitch * 0.05; // Increased impact for pitch
}
if (angles.pitch > 100) {
ballY -= angles.pitch * 0.05; // Increased impact for pitch
}
// Constrain the ball within the canvas
ballX = constrain(ballX, 50, width-50);
ballY = constrain(ballY, 50, height-50);
moveBall();
path.push(createVector(ballX, ballY));
}
function drawVectorPath(x, y, size) {
// Draw a custom vector path instead of an ellipse
noFill();
stroke(255, 0, 0);
strokeWeight(3);
beginShape();
vertex(x, y);
endShape(CLOSE);
}
function calculateHeadAngles(keypoints) {
const leftEye = keypoints[leftEyeIndex];
const rightEye = keypoints[rightEyeIndex];
const nose = keypoints[noseIndex];
// Calculate the roll (tilt)
let roll = Math.atan2(rightEye.y - leftEye.y, rightEye.x - leftEye.x) * (180 / Math.PI);
// Calculate the pitch (up-down rotation)
let pitch = Math.atan2(nose.y - (leftEye.y + rightEye.y) / 2, nose.z - (leftEye.z + rightEye.z) / 2) * (180 / Math.PI) - 65;
// console.log(pitch);
// Calculate the yaw (left-right rotation)
// let yaw = 0
let mideye = (leftEye.x + rightEye.x) / 2;
let yaw = Math.atan2(nose.x - mideye, -nose.z) * (180 / Math.PI);
return { yaw, pitch, roll };
}
// Cleanup function to be called when sketch is stopped
function remove() {
faceMesh.detectStop(); // Stop the faceMesh detection
video.remove(); // Remove video capture
clear(); // Clear the canvas
}
function clearCanvas() {
path = [];
clear();
let drawingEnabled = false;
}
function touchStarted() {
drawingEnabled = true;
}