-
Notifications
You must be signed in to change notification settings - Fork 24
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Showing
8 changed files
with
10,409 additions
and
0 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/p5.min.js"></script> | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.0/addons/p5.sound.min.js"></script> | ||
<link rel="stylesheet" type="text/css" href="style.css" /> | ||
<meta charset="utf-8" /> | ||
<!-- <script src="https://unpkg.com/ml5@latest/dist/ml5.min.js"></script> --> | ||
|
||
<script src="../../dist/ml5.js"></script> | ||
</head> | ||
<body> | ||
<main></main> | ||
<script src="sketch.js"></script> | ||
</body> | ||
</html> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"modelTopology":{"class_name":"Sequential","config":{"name":"sequential_1","layers":[{"class_name":"Dense","config":{"units":16,"activation":"relu","use_bias":true,"kernel_initializer":{"class_name":"VarianceScaling","config":{"scale":1,"mode":"fan_avg","distribution":"normal","seed":null}},"bias_initializer":{"class_name":"Zeros","config":{}},"kernel_regularizer":null,"bias_regularizer":null,"activity_regularizer":null,"kernel_constraint":null,"bias_constraint":null,"name":"dense_Dense1","trainable":true,"batch_input_shape":[null,42],"dtype":"float32"}},{"class_name":"Dense","config":{"units":1,"activation":"sigmoid","use_bias":true,"kernel_initializer":{"class_name":"VarianceScaling","config":{"scale":1,"mode":"fan_avg","distribution":"normal","seed":null}},"bias_initializer":{"class_name":"Zeros","config":{}},"kernel_regularizer":null,"bias_regularizer":null,"activity_regularizer":null,"kernel_constraint":null,"bias_constraint":null,"name":"dense_Dense2","trainable":true}}]},"keras_version":"tfjs-layers 4.8.0","backend":"tensor_flow.js"},"weightsManifest":[{"paths":["./model.weights.bin"],"weights":[{"name":"dense_Dense1/kernel","shape":[42,16],"dtype":"float32"},{"name":"dense_Dense1/bias","shape":[16],"dtype":"float32"},{"name":"dense_Dense2/kernel","shape":[16,1],"dtype":"float32"},{"name":"dense_Dense2/bias","shape":[1],"dtype":"float32"}]}]} |
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
{"inputUnits":[42],"outputUnits":1,"inputs":{"0":{"dtype":"number","min":-57.76958238510858,"max":-13.999831790015833},"1":{"dtype":"number","min":131.43414293016707,"max":159.924955368042},"2":{"dtype":"number","min":-6.968890598842108,"max":31.736695425850996},"3":{"dtype":"number","min":119.89123140062605,"max":137.99373149871826},"4":{"dtype":"number","min":34.92387499128074,"max":68.55003266107468},"5":{"dtype":"number","min":86.28983633858815,"max":108.83269037519182},"6":{"dtype":"number","min":66.91991533551902,"max":93.43303589593796},"7":{"dtype":"number","min":47.85369804927279,"max":91.5161725452968},"8":{"dtype":"number","min":90.8791133335659,"max":117.17755817231682},"9":{"dtype":"number","min":18.55625356946672,"max":83.59517301831926},"10":{"dtype":"number","min":14.606426783970392,"max":32.62323288690476},"11":{"dtype":"number","min":19.65761116572787,"max":29.602417945861816},"12":{"dtype":"number","min":27.917972746349506,"max":46.10863322303409},"13":{"dtype":"number","min":-26.859703063964844,"max":-17.4877187183925},"14":{"dtype":"number","min":34.472816103980676,"max":54.346935635521305},"15":{"dtype":"number","min":-59.57366943359375,"max":-41.59209047045027},"16":{"dtype":"number","min":37.7084423246838,"max":62.167274838402165},"17":{"dtype":"number","min":-86.85015133449008,"max":-61.161516053336015},"18":{"dtype":"number","min":-8.089616412208187,"max":0.8015353339059033},"19":{"dtype":"number","min":13.56531824384416,"max":22.118067741394043},"20":{"dtype":"number","min":0.09358723958331439,"max":8.955929165794743},"21":{"dtype":"number","min":-36.900049618312266,"max":-31.20284625462125},"22":{"dtype":"number","min":1.6109820774623245,"max":18.862430935814274},"23":{"dtype":"number","min":-71.17194175720215,"max":-61.517507689339766},"24":{"dtype":"number","min":1.6053172520228713,"max":27.190496808006657},"25":{"dtype":"number","min":-99.1122954232352,"max":-84.49657985142301},"26":{"dtype":"number","min":-37.63207208542596,"max":-22.555205935523645},"27":{"dtype":"number","min":14.211675780160078,"max":27.486278670174727},"28":{"dtype":"number","min":-34.26525660923551,"max":-23.72821580796014},"29":{"dtype":"number","min":-34.03504167284285,"max":-22.428806849888417},"30":{"dtype":"number","min":-37.34232221330916,"max":-14.620387667701351},"31":{"dtype":"number","min":-64.2985418864659,"max":-48.99022919791088},"32":{"dtype":"number","min":-39.262144906180254,"max":-5.080850237891781},"33":{"dtype":"number","min":-92.4425309044974,"max":-70.4833616529192},"34":{"dtype":"number","min":-70.64437661852155,"max":-42.88441430954708},"35":{"dtype":"number","min":24.513933318001875,"max":43.58233656202043},"36":{"dtype":"number","min":-78.9972498303368,"max":-57.39633832659035},"37":{"dtype":"number","min":-14.574878556387773,"max":10.040790694100508},"38":{"dtype":"number","min":-88.76172815050397,"max":-62.79756818498879},"39":{"dtype":"number","min":-41.61689553942,"max":-12.152315548488048},"40":{"dtype":"number","min":-96.76713739122663,"max":-66.24826703752785},"41":{"dtype":"number","min":-66.82963166918074,"max":-31.430357524326894}},"outputs":{"0":{"dtype":"number","min":0.0765625,"max":0.90625}},"isNormalized":true} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,265 @@ | ||
// Hand Regressor | ||
// Based on https://editor.p5js.org/golan/sketches/dpzEzaapt | ||
|
||
let handPose; | ||
let video; | ||
let hands = []; | ||
let handTrackOptions = { maxHands: 1, flipHorizontal: true }; | ||
|
||
// Interface | ||
let dataButton; | ||
let dataLabel; | ||
let trainButton; | ||
|
||
const N_LANDMARKS = 21; | ||
let sampleCount = 0; | ||
let bTrainingCompleted = false; | ||
let theResults; | ||
let brain; | ||
let trainingData = []; | ||
|
||
//---------------------------------------------------- | ||
const neuralNetworkOptions = { | ||
task: "regression", | ||
debug: true, | ||
}; | ||
|
||
//------------------------------------------ | ||
function preload() { | ||
// Load the handpose model. | ||
handPose = ml5.handPose(handTrackOptions); | ||
} | ||
function gotHands(results) { | ||
// Callback function for when handpose outputs data. | ||
// Save the output to the hands variable | ||
hands = results; | ||
} | ||
|
||
//------------------------------------------ | ||
function setup() { | ||
let myCanvas = createCanvas(640, 480); | ||
myCanvas.position(0, 0); | ||
|
||
// Create the webcam video and hide it | ||
video = createCapture(VIDEO); | ||
video.size(width, height); | ||
video.hide(); | ||
|
||
// ML5 Handpose: detect hands from the webcam video | ||
handPose.detectStart(video, gotHands); | ||
|
||
// ML5 Neural Net: | ||
ml5.setBackend("webgl"); | ||
|
||
trainButton = createButton("Train model"); | ||
trainButton.mousePressed(trainModelFunction); | ||
trainButton.position(520, 35); | ||
trainButton.size(90, 40); | ||
|
||
// Create the model. | ||
let options = { | ||
inputs: N_LANDMARKS * 2, | ||
outputs: 1, | ||
task: "regression", | ||
debug: true, | ||
}; | ||
brain = ml5.neuralNetwork(options); | ||
|
||
// Save and download the model | ||
let saveBtn = createButton("Save Model"); | ||
saveBtn.position(520, 80); | ||
saveBtn.mousePressed(function () { | ||
brain.save(); | ||
}); | ||
|
||
//Load model explictly pointing to each file | ||
const modelDetails = { | ||
model: "model/model.json", | ||
metadata: "model/model_meta.json", | ||
weights: "model/model.weights.bin", | ||
}; | ||
brain.load(modelDetails, modelReady); | ||
} | ||
|
||
//------------------------------------------ | ||
function draw() { | ||
// Draw the webcam video | ||
background("white"); | ||
drawVideoBackground(); | ||
drawHandPoints(); | ||
|
||
if (bTrainingCompleted) { | ||
doRegression(); | ||
} | ||
drawResults(); | ||
} | ||
|
||
//------------------------------------------ | ||
function keyPressed() { | ||
if (key == " ") { | ||
addTrainingExample(); | ||
} | ||
} | ||
|
||
//------------------------------------------ | ||
// Add a training example | ||
function addTrainingExample() { | ||
let inputs = getInputData(); | ||
if (inputs && inputs.length > 0) { | ||
let target = map(mouseX, 0, width, 0, 1); | ||
brain.addData(inputs, [target]); | ||
sampleCount++; | ||
} | ||
} | ||
|
||
//------------------------------------------ | ||
// Train the model | ||
function trainModelFunction() { | ||
brain.normalizeData(); | ||
let options = { | ||
batchSize: 24, | ||
epochs: 30, | ||
}; | ||
brain.train(options, finishedTrainingCallback); | ||
bTrainingCompleted = true; | ||
} | ||
|
||
//------------------------------------------ | ||
// Begin prediction | ||
function finishedTrainingCallback() { | ||
print("Finished Training"); | ||
} | ||
//------------------------------------------ | ||
function modelReady() { | ||
console.log("model loaded!"); | ||
bTrainingCompleted = true; | ||
//doRegression(); | ||
} | ||
//------------------------------------------ | ||
function doRegression() { | ||
if (bTrainingCompleted) { | ||
let freshInput = getInputData(); | ||
if (freshInput) { | ||
brain.predict([freshInput], (results, err) => { | ||
if (err) { | ||
console.log(err); | ||
return; | ||
} | ||
theResults = results; | ||
}); | ||
} | ||
} | ||
} | ||
|
||
//------------------------------------------ | ||
function drawResults() { | ||
stroke("black"); | ||
fill("lightgray"); | ||
rect(0, 0, width, 110); | ||
fill("white"); | ||
rect(0, 0, width, 20); | ||
|
||
fill("black"); | ||
noStroke(); | ||
textAlign(LEFT); | ||
let ty = 20; | ||
text( | ||
"Step 1: Create a fist, set training value to 0 with mouse, press Space to add samples.", | ||
10, | ||
(ty += 15) | ||
); | ||
text( | ||
"Step 2: Open palm, set training value to 1 with mouse, press Space to add samples.", | ||
10, | ||
(ty += 15) | ||
); | ||
text("Sample count = " + sampleCount, 10, (ty += 15)); | ||
|
||
// theResults[i].confidence; | ||
|
||
if (bTrainingCompleted) { | ||
if (theResults && theResults.length > 0) { | ||
let prediction = theResults[0].value; // 0...1 | ||
let px = map(prediction, 0, 1, 0, width); | ||
fill("black"); | ||
rect(px, 0, 3, 20); | ||
if (prediction < 0.5) { | ||
textAlign(LEFT); | ||
text("prediction val: " + nf(prediction, 1, 3), px + 5, 15); | ||
} else { | ||
textAlign(RIGHT); | ||
text("prediction val: " + nf(prediction, 1, 3), px - 5, 15); | ||
} | ||
} | ||
} else { | ||
let trainingValue = map(mouseX, 0, width, 0, 1); | ||
let px = map(trainingValue, 0, 1, 0, width); | ||
fill("black"); | ||
rect(px, 0, 3, 20); | ||
if (trainingValue < 0.5) { | ||
textAlign(LEFT); | ||
text("training val: " + nf(trainingValue, 1, 3), px + 5, 15); | ||
} else { | ||
textAlign(RIGHT); | ||
text("training val: " + nf(trainingValue, 1, 3), px - 5, 15); | ||
} | ||
} | ||
} | ||
|
||
//------------------------------------------ | ||
function drawHandPoints() { | ||
// Draw all the tracked hand points | ||
for (let i = 0; i < hands.length; i++) { | ||
let hand = hands[i]; | ||
for (let j = 0; j < hand.keypoints.length; j++) { | ||
let keypoint = hand.keypoints[j]; | ||
stroke("black"); | ||
fill("lime"); | ||
strokeWeight(1); | ||
circle(keypoint.x, keypoint.y, 10); | ||
} | ||
} | ||
} | ||
|
||
//------------------------------------------ | ||
function getInputData() { | ||
// Copy the hand data into a normalized format for the brain. | ||
if (hands.length > 0) { | ||
const landmarkData = []; | ||
var firstHandIndex = 0; | ||
|
||
// Compute the centroid (averageX, averageY) of the hand | ||
var avgx = 0; | ||
var avgy = 0; | ||
for (var j = 0; j < N_LANDMARKS; j++) { | ||
let keypoint = hands[firstHandIndex].keypoints[j]; | ||
avgx += keypoint.x; | ||
avgy += keypoint.y; | ||
} | ||
avgx /= N_LANDMARKS; | ||
avgy /= N_LANDMARKS; | ||
|
||
// Create a copy of the hand data--but subtract the centroid. | ||
// This way, we're not training on WHERE the hand is located! | ||
for (var j = 0; j < N_LANDMARKS; j++) { | ||
let keypoint = hands[firstHandIndex].keypoints[j]; | ||
landmarkData.push(keypoint.x - avgx); | ||
landmarkData.push(keypoint.y - avgy); | ||
} | ||
return landmarkData; | ||
} | ||
return null; | ||
} | ||
|
||
//------------------------------------------ | ||
function drawVideoBackground() { | ||
push(); | ||
if (handTrackOptions.flipHorizontal) { | ||
translate(width, 0); | ||
scale(-1, 1); | ||
} | ||
let transparency = 255; // reduce this to make video transparent | ||
tint(255, 255, 255, transparency); | ||
image(video, 0, 0, width, height); | ||
pop(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
html, body { | ||
margin: 0; | ||
padding: 0; | ||
} | ||
canvas { | ||
display: block; | ||
} |