Skip to content
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

Add object detection implementation #195

Open
wants to merge 13 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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>
53 changes: 53 additions & 0 deletions examples/objectDetector-dimLight/sketch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
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();
22 changes: 22 additions & 0 deletions examples/objectDetector-single-image/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>
Binary file added examples/objectDetector-single-image/objects.jpg
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/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."
// 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);
// 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];

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();
}
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 object detection on a video 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>
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 a video 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();
}
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