Skip to content
Open
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/objectDetection-sigle-image/dog_cat.jpg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
24 changes: 24 additions & 0 deletions examples/objectDetection-sigle-image/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!--
👋 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 single 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 Example - Single Image</title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/p5.js"></script>
<script src="../../dist/ml5.js"></script>
</head>
<body>
<main>
</main>
<script src="sketch.js"></script>
</body>
</html>
44 changes: 44 additions & 0 deletions examples/objectDetection-sigle-image/sketch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
/*
* 👋 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 a live video through ml5.imageClassifier.
*/

let img;
let detector;
let detections = [];

function preload(){
detector = ml5.objectDetector("cocossd");
img = loadImage('dog_cat.jpg');
}

function setup() {
createCanvas(640, 480);
image(img, 0, 0);
detector.detectStart(img, gotDetections);
}

// Callback function is called each time the object detector finishes processing a frame.
function gotDetections(results) {
// Update detections array with the new results
detections = results;

for (let i = 0; i < detections.length; i += 1) {
let detection = detections[i];

// Draw bounding box
stroke(0, 255, 0);
strokeWeight(4);
noFill();
rect(detection.x, detection.y, detection.width, detection.height);

// Draw label
noStroke();
fill(255);
textSize(24);
text(detection.label, detection.x + 10, detection.y + 24);
}
}
24 changes: 24 additions & 0 deletions examples/objectDetection-video/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!--
👋 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 Example - Video</title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/p5.js"></script>
<script src="../../dist/ml5.js"></script>
</head>
<body>
<main>
</main>
<script src="sketch.js"></script>
</body>
</html>
89 changes: 89 additions & 0 deletions examples/objectDetection-video/sketch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
/*
* 👋 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 a video file through ml5.objectDetector.
*/

let video;
let detector;
let detections = [];
let canvasElement;

function preload(){
detector = ml5.objectDetector("cocossd");
}

function setup() {
// Create canvas with initial size - will be resized later
canvasElement = createCanvas(640, 480);
canvasElement.position(0, 0);

// Create video element (paused by default)
video = createVideo('test.mov');
video.position(0, 0);
video.volume(0);
video.showControls();

// Make canvas transparent and on top
canvasElement.style('z-index', '1');
canvasElement.style('pointer-events', 'none'); // Allow clicks to pass through to video
video.style('z-index', '-1');

// Set up video event listeners
video.elt.addEventListener('loadedmetadata', () => {
console.log('Video metadata loaded');

// Resize canvas to match video size
resizeCanvas(video.elt.videoWidth, video.elt.videoHeight);
});

video.elt.addEventListener('play', () => {
console.log('Video started playing');

Copy link
Member

Choose a reason for hiding this comment

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

Yes, I woudl avoid all this extra code if you can! You can treat the video just like the webcam, have it auto-start and loop. Here's an example from BlazePose you can use as a model:

https://editor.p5js.org/codingtrain/sketches/ftALPDieT

But yours can be simpler b/c you can hide the video element and draw it on the canvas.

Copy link
Author

Choose a reason for hiding this comment

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

oh okay! I will forget about showControls and try video.hide + video.loop(). Thank you 🙏

// Start detection
detector.detectStart(video, gotDetections);
});

video.elt.addEventListener('pause', () => {
console.log('Video paused');

// Stop detection when video is paused
detector.detectStop();
});

video.elt.addEventListener('ended', () => {
console.log('Video ended');

// Stop detection when video ends
detector.detectStop();
});
}

function draw(){
// Clear the canvas (this acts as the transparent overlay)
clear();

for (let i = 0; i < detections.length; i += 1) {
let detection = detections[i];

// Draw bounding box
stroke(0, 255, 0);
strokeWeight(4);
noFill();
rect(detection.x, detection.y, detection.width, detection.height);

// Draw label
noStroke();
fill(255);
textSize(24);
text(detection.label, detection.x + 10, detection.y + 24);
}
}

// Callback function is called each time the object detector finishes processing a frame.
function gotDetections(results) {
// Update detections array with the new results
detections = results;
}
Binary file added examples/objectDetection-video/test.mov
Binary file not shown.
24 changes: 24 additions & 0 deletions examples/objectDetection-webcam/index.html
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
<!--
👋 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 live 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 Example - Webcam</title>
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/p5.js"></script>
<script src="../../dist/ml5.js"></script>
</head>
<body>
<main>
</main>
<script src="sketch.js"></script>
</body>
</html>
53 changes: 53 additions & 0 deletions examples/objectDetection-webcam/sketch.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
/*
* 👋 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 a live video through ml5.imageClassifier.
*/

let video;
let detector;
let detections = [];

function preload(){
detector = ml5.objectDetector("cocossd");
}

function setup() {
createCanvas(640, 480);

// Using webcam feed as video input, hiding html element to avoid duplicate with canvas
video = createCapture(VIDEO);
video.size(width, height);
Comment on lines +18 to +22
Copy link
Member

Choose a reason for hiding this comment

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

Ah, I just tested and confirm that the #264 applies here too! If I change the webcam to 320,240 then the bounding boxes are all off. @yiyujin I don't think this has to be fixed in this PR, it can be done separately after the fact or along with #264. @nasif-co maybe you can help track this in the issue thread or a new issue so that we can merge at least the SelfieSegmentation fix?

video.hide();

detector.detectStart(video, gotDetections);
}

// Callback function is called each time the object detector finishes processing a frame.
function gotDetections(results) {
// Update detections array with the new results
detections = results;
}

function draw() {
// Draw the current video frame onto the canvas.
image(video, 0, 0);

for (let i = 0; i < detections.length; i += 1) {
let detection = detections[i];

// Draw bounding box
stroke(0, 255, 0);
strokeWeight(4);
noFill();
rect(detection.x, detection.y, detection.width, detection.height);

// Draw label
noStroke();
fill(255);
textSize(24);
text(detection.label, detection.x + 10, detection.y + 24);
}
}
1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,7 @@
"@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",
Expand Down
72 changes: 72 additions & 0 deletions src/ObjectDetector/cocossd.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
// Copyright (c) 2019 ml5
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT

/*
COCO-SSD Object detection model
Wraps the coco-ssd model in tfjs to be used in ml5
*/
import * as tf from "@tensorflow/tfjs";
import * as cocoSsd from "@tensorflow-models/coco-ssd";
import { mediaReady } from "../utils/imageUtilities";

const DEFAULTS = {
base: "lite_mobilenet_v2",
modelUrl: undefined,
};

export class CocoSsd {
constructor(options = {}) {
this.model = null;
this.config = {
base: options.base || DEFAULTS.base,
modelUrl: options.modelUrl || DEFAULTS.modelUrl,
};
}

async load() {
await tf.setBackend("webgl"); // this line resolves warning : performance is poor on webgpu backend
await tf.ready();

this.model = await cocoSsd.load(this.config);
return this;
}

/**
* Detect objects that are in the image/video/canvas
* @param {HTMLVideoElement|HTMLImageElement|HTMLCanvasElement|ImageData} imgToPredict - Subject of the detection.
* @returns {Array} Array of detection detections
*/
async detect(imgToPredict) {
mediaReady(imgToPredict, true);

await tf.nextFrame();

const detections = await this.model.detect(imgToPredict);
const formattedDetections = detections.map(prediction => {
return {
label: prediction.class,
confidence: prediction.score,
x: prediction.bbox[0],
y: prediction.bbox[1],
width: prediction.bbox[2],
height: prediction.bbox[3],
normalized: {
x: prediction.bbox[0] / imgToPredict.width,
y: prediction.bbox[1] / imgToPredict.height,
width: prediction.bbox[2] / imgToPredict.width,
height: prediction.bbox[3] / imgToPredict.height,
},
};
});

return formattedDetections;
}
}

export async function load(modelConfig = {}) {
const cocoSsdInstance = new CocoSsd(modelConfig);
await cocoSsdInstance.load();
return cocoSsdInstance;
}
Loading