Skip to content
Closed
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Binary file added examples/objectDetector-dimLight/dim.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/objectDetector-dimLight/dimmy.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
20 changes: 20 additions & 0 deletions examples/objectDetector-dimLight/index.html
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>
61 changes: 61 additions & 0 deletions examples/objectDetector-dimLight/sketch.js
Copy link
Member

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.

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();

Binary file not shown.
22 changes: 22 additions & 0 deletions examples/objectDetector-single-image copy/index.html
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>
Copy link
Member

Choose a reason for hiding this comment

The 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.

Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
73 changes: 73 additions & 0 deletions examples/objectDetector-single-image copy/sketch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* 👋 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."
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

According to @ziyuan-linn, you can call await tf.ready(); in your library code to avoid having this line of code in the sketch.

// see https://github.com/ml5js/ml5-next-gen/issues/117
ml5.setBackend("webgl");

// Load the objectDetector model
objectDetector = ml5.objectDetector();
}

function setup() {
createCanvas(800, 800);
// Draw the image
image(img, 0, 0);
Copy link
Member

Choose a reason for hiding this comment

The 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 draw

// 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];
Copy link
Member

Choose a reason for hiding this comment

The 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 => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

.map(...) is a language feature that one might only learn after lots of practice with JavaScript. I would consider trying to do the same with for (maybe for ... of)?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this also might confuse the simplicity of this example, I might just use a default color for all objects and not add properties to the results coming from the model.

object.color = {
r: random(255),
g: random(255),
b: random(255)
};
return object;
});

// Redraw canvas to update the bounding boxes
redraw();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This could probably be omitted for brevity, since the draw function is called periodically

}
Binary file not shown.
22 changes: 22 additions & 0 deletions examples/objectDetector-webcam/index.html
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>
Binary file added examples/objectDetector-webcam/objects.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
94 changes: 94 additions & 0 deletions examples/objectDetector-webcam/sketch.js
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.
*/

let objectDetector;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For structure, I would suggest copying how e.g. BodyPose-keypoints is doing it (using detectStart()). This leads to a much more concise example code, with fewer states that the user has to think about!
I quickly tried this approach with your code, and it appeared to work well!

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();
}
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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 @@
/*
* 👋 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;
}
3 changes: 2 additions & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note for @ziyuan-linn: coco-ssd indeed lists tfjs 4.20.0 as its peer dependency. Hope that bumping this won't cause any regressions..

"@tensorflow/tfjs-vis": "^1.5.1",
"axios": "^1.3.4",
"webpack-merge": "^5.9.0"
Expand Down
Loading