Skip to content

Commit 80c35b2

Browse files
committed
add legacy object detection cocossd code and example from p5js
1 parent db0b171 commit 80c35b2

File tree

4 files changed

+248
-0
lines changed

4 files changed

+248
-0
lines changed
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
<!DOCTYPE html>
2+
<html lang="en">
3+
<head>
4+
<script src="https://cdn.jsdelivr.net/npm/[email protected]/lib/p5.js"></script>
5+
<!-- <script src="https://unpkg.com/[email protected]/dist/ml5.min.js"></script> -->
6+
<script src="../../dist/ml5.js"></script>
7+
<link rel="stylesheet" type="text/css" href="style.css">
8+
<meta charset="utf-8" />
9+
10+
</head>
11+
<body>
12+
<main>
13+
</main>
14+
<script src="sketch.js"></script>
15+
</body>
16+
</html>

examples/objectDetection/sketch.js

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
// Copyright (c) 2020 ml5
2+
//
3+
// This software is released under the MIT License.
4+
// https://opensource.org/licenses/MIT
5+
6+
/* ===
7+
ml5 Example
8+
Object Detection using COCOSSD
9+
This example uses a callback pattern to create the classifier
10+
=== */
11+
12+
let video;
13+
let detector;
14+
let detections = [];
15+
16+
function setup() {
17+
createCanvas(640, 480);
18+
video = createCapture(VIDEO, videoReady);
19+
video.size(640, 480);
20+
video.hide();
21+
}
22+
23+
function videoReady() {
24+
// Models available are 'cocossd', 'yolo'
25+
detector = ml5.objectDetector('cocossd', modelReady);
26+
}
27+
28+
function gotDetections(error, results) {
29+
if (error) {
30+
console.error(error);
31+
}
32+
detections = results;
33+
detector.detect(video, gotDetections);
34+
}
35+
36+
function modelReady() {
37+
detector.detect(video, gotDetections);
38+
}
39+
40+
function draw() {
41+
image(video, 0, 0);
42+
43+
for (let i = 0; i < detections.length; i += 1) {
44+
const object = detections[i];
45+
stroke(0, 255, 0);
46+
strokeWeight(4);
47+
noFill();
48+
rect(object.x, object.y, object.width, object.height);
49+
noStroke();
50+
fill(255);
51+
textSize(24);
52+
text(object.label, object.x + 10, object.y + 24);
53+
}
54+
}

src/ObjectDetector/cocossd.js

Lines changed: 118 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,118 @@
1+
// Copyright (c) 2019 ml5
2+
//
3+
// This software is released under the MIT License.
4+
// https://opensource.org/licenses/MIT
5+
6+
/*
7+
COCO-SSD Object detection
8+
Wraps the coco-ssd model in tfjs to be used in ml5
9+
*/
10+
import * as tf from "@tensorflow/tfjs";
11+
import * as cocoSsd from "@tensorflow-models/coco-ssd";
12+
import callCallback from "../utils/callcallback";
13+
import handleArguments from "../utils/handleArguments";
14+
15+
const DEFAULTS = {
16+
base: "lite_mobilenet_v2",
17+
modelUrl: undefined,
18+
};
19+
20+
export class CocoSsdBase {
21+
/**
22+
* Create CocoSsd model. Works on video and images.
23+
* @param {function} constructorCallback - Optional. A callback function that is called once the model has loaded. If no callback is provided, it will return a promise
24+
* that will be resolved once the model has loaded.
25+
*/
26+
constructor(video, options, constructorCallback) {
27+
this.video = video || null;
28+
this.modelReady = false;
29+
this.isPredicting = false;
30+
this.config = {
31+
base: options.base || DEFAULTS.base,
32+
modelUrl: options.modelUrl || DEFAULTS.modelUrl,
33+
};
34+
this.callback = constructorCallback;
35+
36+
this.ready = callCallback(this.loadModel(), this.callback);
37+
}
38+
39+
/**
40+
* load model
41+
*/
42+
async loadModel() {
43+
this.model = await cocoSsd.load(this.config);
44+
45+
this.modelReady = true;
46+
return this;
47+
}
48+
49+
/**
50+
* @typedef {Object} ObjectDetectorPrediction
51+
* @property {number} x - top left x coordinate of the prediction box in pixels.
52+
* @property {number} y - top left y coordinate of the prediction box in pixels.
53+
* @property {number} width - width of the prediction box in pixels.
54+
* @property {number} height - height of the prediction box in pixels.
55+
* @property {string} label - the label given.
56+
* @property {number} confidence - the confidence score (0 to 1).
57+
* @property {ObjectDetectorPredictionNormalized} normalized - a normalized object of the predicition
58+
*/
59+
60+
/**
61+
* @typedef {Object} ObjectDetectorPredictionNormalized
62+
* @property {number} x - top left x coordinate of the prediction box (0 to 1).
63+
* @property {number} y - top left y coordinate of the prediction box (0 to 1).
64+
* @property {number} width - width of the prediction box (0 to 1).
65+
* @property {number} height - height of the prediction box (0 to 1).
66+
*/
67+
/**
68+
* Detect objects that are in video, returns bounding box, label, and confidence scores
69+
* @param {HTMLVideoElement|HTMLImageElement|HTMLCanvasElement|ImageData} subject - Subject of the detection.
70+
* @returns {ObjectDetectorPrediction}
71+
*/
72+
async detectInternal(imgToPredict) {
73+
this.isPredicting = true;
74+
const predictions = await this.model.detect(imgToPredict);
75+
const formattedPredictions = predictions.map(prediction => {
76+
return {
77+
label: prediction.class,
78+
confidence: prediction.score,
79+
x: prediction.bbox[0],
80+
y: prediction.bbox[1],
81+
width: prediction.bbox[2],
82+
height: prediction.bbox[3],
83+
normalized: {
84+
x: prediction.bbox[0] / imgToPredict.width,
85+
y: prediction.bbox[1] / imgToPredict.height,
86+
width: prediction.bbox[2] / imgToPredict.width,
87+
height: prediction.bbox[3] / imgToPredict.height,
88+
},
89+
};
90+
});
91+
this.isPredicting = false;
92+
return formattedPredictions;
93+
}
94+
95+
/**
96+
* Detect objects that are in video, returns bounding box, label, and confidence scores
97+
* @param {HTMLVideoElement|HTMLImageElement|HTMLCanvasElement|ImageData} subject - Subject of the detection.
98+
* @param {function} callback - Optional. A callback function that is called once the model has loaded. If no callback is provided, it will return a promise
99+
* that will be resolved once the prediction is done.
100+
* @returns {ObjectDetectorPrediction}
101+
*/
102+
async detect(inputOrCallback, cb) {
103+
await this.ready;
104+
await tf.nextFrame();
105+
106+
const args = handleArguments(this.video, inputOrCallback, cb);
107+
args.require("image", "Detection subject not supported");
108+
109+
return callCallback(this.detectInternal(args.image), args.callback);
110+
}
111+
}
112+
113+
export const CocoSsd = (...inputs) => {
114+
const { video, options = {}, callback } = handleArguments(...inputs);
115+
return new CocoSsdBase(video, options, callback);
116+
};
117+
118+
// export default CocoSsd;

src/ObjectDetector/index.js

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
// Copyright (c) 2019 ml5
2+
//
3+
// This software is released under the MIT License.
4+
// https://opensource.org/licenses/MIT
5+
6+
/*
7+
ObjectDetection
8+
*/
9+
10+
import handleArguments from "../utils/handleArguments";
11+
import {CocoSsd} from "./cocossd.js";
12+
13+
class ObjectDetector {
14+
/**
15+
* @typedef {Object} options
16+
* @property {number} filterBoxesThreshold - Optional. default 0.01
17+
* @property {number} IOUThreshold - Optional. default 0.4
18+
* @property {number} classProbThreshold - Optional. default 0.4
19+
*/
20+
/**
21+
* Create ObjectDetector model. Works on video and images.
22+
* @param {string} modelNameOrUrl - The name or the URL of the model to use. Current model name options
23+
* are: 'YOLO' and 'CocoSsd'.
24+
* @param {Object} options - Optional. A set of options.
25+
* @param {function} callback - Optional. A callback function that is called once the model has loaded.
26+
*/
27+
constructor(modelNameOrUrl, video, options, callback) {
28+
this.video = video;
29+
this.modelNameOrUrl = modelNameOrUrl;
30+
this.options = options || {};
31+
this.callback = callback;
32+
33+
switch (modelNameOrUrl) {
34+
case "cocossd":
35+
this.model = new CocoSsd(this.video, this.options, callback);
36+
return this;
37+
default:
38+
// use cocossd as default
39+
this.model = new CocoSsd(this.video, this.options, callback);
40+
return this;
41+
}
42+
}
43+
}
44+
45+
const objectDetector = (...inputs) => {
46+
const { video, options = {}, callback, string } = handleArguments(...inputs)
47+
.require('string', 'Please specify a model to use. E.g: "YOLO"');
48+
49+
let model = string;
50+
// TODO: I think we should delete this.
51+
if (model.indexOf("http") === -1) {
52+
model = model.toLowerCase();
53+
}
54+
55+
const instance = new ObjectDetector(model, video, options, callback);
56+
57+
return instance.model.callback ? instance.model : instance.model.ready;
58+
};
59+
60+
export default objectDetector;

0 commit comments

Comments
 (0)