-
Notifications
You must be signed in to change notification settings - Fork 40
Add object detection implementation #195
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 7 commits
762a698
3123c21
f53a371
00e349d
53c6b1f
79cf58e
120b681
f1535b0
23dc069
cc08e77
0dbb20e
603514e
436e505
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,20 @@ | ||
|
||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<title>Object Detection in Dim Light</title> | ||
<style> | ||
canvas { | ||
border: 1px solid black; | ||
} | ||
</style> | ||
</head> | ||
<body> | ||
<canvas id="canvas" width="640" height="480"></canvas> | ||
<script src="https://cdn.jsdelivr.net/npm/@tensorflow/tfjs"></script> | ||
<script src="https://cdn.jsdelivr.net/npm/@tensorflow-models/coco-ssd"></script> | ||
<script src="sketch.js"></script> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,61 @@ | ||
let canvas; | ||
let ctx; | ||
let imageElement; | ||
let objectDetector; | ||
|
||
async function setup() { | ||
|
||
canvas = document.getElementById('canvas'); | ||
ctx = canvas.getContext('2d'); | ||
|
||
|
||
imageElement = new Image(); | ||
imageElement.src = 'dimmy.jpg'; | ||
imageElement.onload = async () => { | ||
|
||
canvas.width = imageElement.width; | ||
canvas.height = imageElement.height; | ||
ctx.drawImage(imageElement, 0, 0); | ||
|
||
|
||
objectDetector = await cocoSsd.load(); | ||
console.log('Object Detector Loaded'); | ||
|
||
|
||
detectObjects(); | ||
}; | ||
} | ||
|
||
async function detectObjects() { | ||
|
||
const results = await objectDetector.detect(canvas); | ||
console.log(results); | ||
|
||
|
||
drawResults(results); | ||
} | ||
|
||
function drawResults(objects) { | ||
|
||
ctx.clearRect(0, 0, canvas.width, canvas.height); | ||
|
||
|
||
ctx.drawImage(imageElement, 0, 0); | ||
|
||
|
||
objects.forEach(object => { | ||
ctx.beginPath(); | ||
ctx.rect(object.bbox[0], object.bbox[1], object.bbox[2], object.bbox[3]); | ||
ctx.lineWidth = 2; | ||
ctx.strokeStyle = 'red'; | ||
ctx.stroke(); | ||
|
||
ctx.font = '16px Arial'; | ||
ctx.fillStyle = 'red'; | ||
ctx.fillText(object.class, object.bbox[0], object.bbox[1] > 10 ? object.bbox[1] - 5 : 10); | ||
}); | ||
} | ||
|
||
|
||
setup(); | ||
|
douaaz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<!-- | ||
👋 Hello! This is an ml5.js example made and shared with ❤️. | ||
Learn more about the ml5.js project: https://ml5js.org/ | ||
ml5.js license and Code of Conduct: https://github.com/ml5js/ml5-next-gen/blob/main/LICENSE.md | ||
|
||
This example demonstrates detecting objects in an image through ml5.objectDetector. | ||
--> | ||
|
||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<title>ml5.js ObjectDetector Image Example</title> | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.4/p5.min.js"></script> | ||
<script src="../../dist/ml5.js"></script> | ||
</head> | ||
<body> | ||
<script src="sketch.js"></script> | ||
</body> | ||
</html> |
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Generally speaking, I think it's preferable to demonstrate examples without people in them. Who is this person? Do we have permission to use their face? Perhaps there is an image that can demonstrate a wider variety of classes inside the model. |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,73 @@ | ||
/* | ||
douaaz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
* 👋 Hello! This is an ml5.js example made and shared with ❤️. | ||
* Learn more about the ml5.js project: https://ml5js.org/ | ||
* ml5.js license and Code of Conduct: https://github.com/ml5js/ml5-next-gen/blob/main/LICENSE.md | ||
* | ||
* This example demonstrates object detection on an image through ml5.objectDetector. | ||
*/ | ||
|
||
let objectDetector; | ||
let img; | ||
let objects = []; | ||
|
||
function preload() { | ||
// Load the image to be detected | ||
img = loadImage("objects.jpg"); | ||
|
||
// trying to work around "WebGPU readSync is only available for CPU-resident tensors." | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. According to @ziyuan-linn, you can call |
||
// see https://github.com/ml5js/ml5-next-gen/issues/117 | ||
ml5.setBackend("webgl"); | ||
|
||
// Load the objectDetector model | ||
objectDetector = ml5.objectDetector(); | ||
douaaz marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} | ||
|
||
function setup() { | ||
createCanvas(800, 800); | ||
// Draw the image | ||
image(img, 0, 0); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Seems superfluous, as you're always drawing the image at the top of |
||
// Detect objects in the image | ||
objectDetector.detect(img, gotObjects); | ||
} | ||
|
||
function draw() { | ||
// Draw the image | ||
image(img, 0, 0); | ||
|
||
// Loop through all the detected objects and draw bounding boxes with labels | ||
for (let i = 0; i < objects.length; i++) { | ||
let object = objects[i]; | ||
let x = object.bbox[0]; | ||
let y = object.bbox[1]; | ||
let w = object.bbox[2]; | ||
let h = object.bbox[3]; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Do we want to consider renaming the underlying properties that come out of the model, something like the following might be more intuitive: let x = object.bbox.x
let y = object.bbox.y;
let w = object.bbox.w;
let h = object.bbox.h; This also offers the opportunity for "destructuring" though this is perhaps a concept less familiar to beginners: let { x, y, w, h } = object.bbox; |
||
|
||
stroke(object.color.r, object.color.g, object.color.b); | ||
noFill(); | ||
|
||
// Draw the bounding box | ||
rect(x, y, w, h); | ||
|
||
// Draw the label with the class name | ||
noStroke(); | ||
fill(object.color.r, object.color.g, object.color.b); | ||
textSize(16); | ||
text(object.class, x + 5, y + 15); | ||
} | ||
} | ||
|
||
// Callback function for when objectDetector outputs data | ||
function gotObjects(results) { | ||
// Save the output to the objects variable and assign a random color to each object | ||
objects = results.map(object => { | ||
|
||
object.color = { | ||
r: random(255), | ||
g: random(255), | ||
b: random(255) | ||
}; | ||
return object; | ||
}); | ||
|
||
// Redraw canvas to update the bounding boxes | ||
redraw(); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This could probably be omitted for brevity, since the |
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<!-- | ||
👋 Hello! This is an ml5.js example made and shared with ❤️. | ||
Learn more about the ml5.js project: https://ml5js.org/ | ||
ml5.js license and Code of Conduct: https://github.com/ml5js/ml5-next-gen/blob/main/LICENSE.md | ||
|
||
This example demonstrates hand tracking on an image through ml5.handPose. | ||
--> | ||
|
||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<title>ml5.js ObjectDetector Image Example</title> | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.4/p5.min.js"></script> | ||
<script src="../../dist/ml5.js"></script> | ||
</head> | ||
<body> | ||
<script src="sketch.js"></script> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
/* | ||
* 👋 Hello! This is an ml5.js example made and shared with ❤️. | ||
* Learn more about the ml5.js project: https://ml5js.org/ | ||
* ml5.js license and Code of Conduct: https://github.com/ml5js/ml5-next-gen/blob/main/LICENSE.md | ||
* | ||
* This example demonstrates object detection on an image through ml5.objectDetector. | ||
douaaz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
*/ | ||
|
||
let objectDetector; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. For structure, I would suggest copying how e.g. |
||
let video; | ||
let objects = []; | ||
let isModelLoaded = false; | ||
let isVideoReady = false; | ||
let detectionInterval = 30; // Number of frames between each detection | ||
let frameCount = 0; | ||
|
||
function preload() { | ||
// Set the backend to "webgl" | ||
ml5.setBackend("webgl"); | ||
|
||
// Load the objectDetector model | ||
objectDetector = ml5.objectDetector('cocossd', modelReady); | ||
} | ||
|
||
function setup() { | ||
createCanvas(800, 800); | ||
|
||
// Create a video capture element | ||
video = createCapture(VIDEO, videoReady); | ||
video.size(800, 800); | ||
video.hide(); // Hide the video element since we'll draw it on the canvas | ||
} | ||
|
||
function draw() { | ||
if (isVideoReady && isModelLoaded) { | ||
// Draw the video frame to the canvas | ||
image(video, 0, 0); | ||
|
||
frameCount++; | ||
|
||
// Run object detection at specified intervals | ||
if (frameCount % detectionInterval === 0) { | ||
objectDetector.detect(video, gotObjects); | ||
} | ||
|
||
// Loop through all the detected objects and draw bounding boxes with labels | ||
for (let i = 0; i < objects.length; i++) { | ||
let object = objects[i]; | ||
let x = object.bbox[0]; | ||
let y = object.bbox[1]; | ||
let w = object.bbox[2]; | ||
let h = object.bbox[3]; | ||
|
||
// Draw the bounding box | ||
stroke(object.color.r, object.color.g, object.color.b); | ||
noFill(); | ||
rect(x, y, w, h); | ||
|
||
// Draw the label with the class name | ||
noStroke(); | ||
fill(object.color.r, object.color.g, object.color.b); | ||
textSize(16); | ||
text(object.class, x + 5, y + 15); | ||
} | ||
} | ||
} | ||
|
||
// Callback when the model is ready | ||
function modelReady() { | ||
console.log("Model Loaded!"); | ||
isModelLoaded = true; | ||
} | ||
|
||
// Callback when the video is ready | ||
function videoReady() { | ||
console.log("Video Ready!"); | ||
isVideoReady = true; | ||
} | ||
|
||
// Callback function for when objectDetector outputs data | ||
function gotObjects(results) { | ||
// Save the output to the objects variable and assign a random color to each object | ||
objects = results.map(object => { | ||
object.color = { | ||
r: random(255), | ||
g: random(255), | ||
b: random(255) | ||
}; | ||
return object; | ||
}); | ||
|
||
// Redraw canvas to update the boxes | ||
redraw(); | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
<!-- | ||
👋 Hello! This is an ml5.js example made and shared with ❤️. | ||
Learn more about the ml5.js project: https://ml5js.org/ | ||
ml5.js license and Code of Conduct: https://github.com/ml5js/ml5-next-gen/blob/main/LICENSE.md | ||
|
||
This example demonstrates hand tracking on an image through ml5.handPose. | ||
--> | ||
|
||
<!DOCTYPE html> | ||
<html lang="en"> | ||
<head> | ||
<meta charset="UTF-8" /> | ||
<meta http-equiv="X-UA-Compatible" content="IE=edge" /> | ||
<meta name="viewport" content="width=device-width, initial-scale=1.0" /> | ||
<title>ml5.js handPose Image Example</title> | ||
<script src="https://cdnjs.cloudflare.com/ajax/libs/p5.js/1.9.4/p5.min.js"></script> | ||
<script src="../../dist/ml5.js"></script> | ||
</head> | ||
<body> | ||
<script src="sketch.js"></script> | ||
</body> | ||
</html> |
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,45 @@ | ||
/* | ||
douaaz marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
* 👋 Hello! This is an ml5.js example made and shared with ❤️. | ||
* Learn more about the ml5.js project: https://ml5js.org/ | ||
* ml5.js license and Code of Conduct: https://github.com/ml5js/ml5-next-gen/blob/main/LICENSE.md | ||
* | ||
* This example demonstrates hand tracking on an image through ml5.handPose. | ||
*/ | ||
|
||
let handPose; | ||
let video; | ||
let hands = []; | ||
|
||
function preload() { | ||
// Load the image to be detected | ||
img = loadImage("hand.jpg"); | ||
// Load the handPose model | ||
handPose = ml5.handPose(); | ||
} | ||
|
||
function setup() { | ||
createCanvas(640, 480); | ||
// Draw the image | ||
image(img, 0, 0); | ||
// Detect hands in an image | ||
handPose.detect(img, gotHands); | ||
} | ||
|
||
function draw() { | ||
// Draw all the hand keypoints | ||
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]; | ||
fill(0, 255, 0); | ||
noStroke(); | ||
circle(keypoint.x, keypoint.y, 10); | ||
} | ||
} | ||
} | ||
|
||
// Callback function for when handPose outputs data | ||
function gotHands(results) { | ||
// save the output to the hands variable | ||
hands = results; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -56,12 +56,13 @@ | |
"@mediapipe/pose": "^0.5.1675469404", | ||
"@mediapipe/selfie_segmentation": "~0.1.0", | ||
"@tensorflow-models/body-segmentation": "^1.0.1", | ||
"@tensorflow-models/coco-ssd": "^2.2.3", | ||
"@tensorflow-models/face-landmarks-detection": "1.0.5", | ||
"@tensorflow-models/hand-pose-detection": "^2.0.0", | ||
"@tensorflow-models/mobilenet": "^2.1.0", | ||
"@tensorflow-models/pose-detection": "^2.1.0", | ||
"@tensorflow-models/speech-commands": "^0.5.4", | ||
"@tensorflow/tfjs": "^4.2.0", | ||
"@tensorflow/tfjs": "^4.20.0", | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Note for @ziyuan-linn: |
||
"@tensorflow/tfjs-vis": "^1.5.1", | ||
"axios": "^1.3.4", | ||
"webpack-merge": "^5.9.0" | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is a lovely implementation, but I wonder if it's outside the scope of a basic set of Object Detection examples since it's not more about "image processing" than the model itself. Perhaps a separate tutorial could be written for the community page about pre-processing images since it could be applied across many models, not just object detection.
Regardless, if we were to keep this example I would suggest rewriting it with p5.js functions rather than the native JS code which will be unfamiliar to beginners.