|
1 | | -// Copyright (c) 2018 ml5 |
| 1 | +// Copyright (c) 2018-2024 ml5 |
2 | 2 | // |
3 | 3 | // This software is released under the MIT License. |
4 | 4 | // https://opensource.org/licenses/MIT |
5 | 5 |
|
6 | 6 | import { asyncLoadImage } from "../utils/testingUtils"; |
7 | | -import poseNet from "./index"; |
| 7 | +import bodyPose from "./index"; |
| 8 | +import crossFetch from "cross-fetch"; |
8 | 9 |
|
9 | 10 | const POSENET_IMG = |
10 | 11 | "https://github.com/ml5js/ml5-adjacent/raw/master/02_ImageClassification_Video/starter.png"; |
11 | 12 |
|
12 | | -const POSENET_DEFAULTS = { |
13 | | - architecture: "MobileNetV1", |
14 | | - outputStride: 16, |
15 | | - flipHorizontal: false, |
16 | | - minConfidence: 0.5, |
17 | | - maxPoseDetections: 5, |
18 | | - scoreThreshold: 0.5, |
19 | | - nmsRadius: 20, |
20 | | - detectionType: "multiple", |
21 | | - inputResolution: 256, |
22 | | - multiplier: 0.75, |
23 | | - quantBytes: 2, |
24 | | -}; |
25 | | - |
26 | | -describe("PoseNet", () => { |
27 | | - let net; |
| 13 | +describe("bodypose", () => { |
| 14 | + let myBodyPose; |
| 15 | + let image; |
28 | 16 |
|
29 | 17 | beforeAll(async () => { |
30 | | - jest.setTimeout(10000); |
31 | | - net = await poseNet(); |
| 18 | + |
| 19 | + // TODO: this should not be necessary! Should already be handled by setupTests.js. |
| 20 | + if (!global.fetch) { |
| 21 | + global.fetch = crossFetch; |
| 22 | + } |
| 23 | + |
| 24 | + myBodyPose = bodyPose(); |
| 25 | + await myBodyPose.ready; |
| 26 | + |
| 27 | + image = await asyncLoadImage(POSENET_IMG); |
32 | 28 | }); |
33 | 29 |
|
34 | | - it("instantiates poseNet", () => { |
35 | | - expect(net.architecture).toBe(POSENET_DEFAULTS.architecture); |
36 | | - expect(net.outputStride).toBe(POSENET_DEFAULTS.outputStride); |
37 | | - expect(net.inputResolution).toBe(POSENET_DEFAULTS.inputResolution); |
38 | | - expect(net.multiplier).toBe(POSENET_DEFAULTS.multiplier); |
39 | | - expect(net.quantBytes).toBe(POSENET_DEFAULTS.quantBytes); |
| 30 | + it("instantiates bodyPose", () => { |
| 31 | + expect(myBodyPose).toBeDefined() |
| 32 | + expect(myBodyPose.model).toBeDefined(); |
40 | 33 | }); |
41 | 34 |
|
42 | 35 | it("detects poses in image", async () => { |
43 | | - const image = await asyncLoadImage(POSENET_IMG); |
44 | 36 |
|
45 | | - // Result should be an array with a single object containing pose and skeleton. |
46 | | - const result = await net.singlePose(image); |
| 37 | + // Result should be an array with a single object containing the detection. |
| 38 | + const result = await myBodyPose.detect(image); |
47 | 39 | expect(result).toHaveLength(1); |
48 | | - expect(result[0]).toHaveProperty("pose"); |
49 | | - expect(result[0]).toHaveProperty("skeleton"); |
| 40 | + expect(result[0]).toHaveProperty("box"); |
| 41 | + expect(result[0]).toHaveProperty("score"); |
| 42 | + expect(result[0].keypoints.length).toBeGreaterThanOrEqual(5); |
50 | 43 |
|
51 | 44 | // Verify a known outcome. |
52 | | - const nose = result[0].pose.keypoints.find( |
53 | | - (keypoint) => keypoint.part === "nose" |
| 45 | + const nose = result[0].keypoints.find( |
| 46 | + (keypoint) => keypoint.name === "nose" |
54 | 47 | ); |
| 48 | + // Should be {"name": "nose", "score": 0.7217329144477844, "x": 454.1112813949585, "y": 256.606980448618} |
55 | 49 | expect(nose).toBeTruthy(); |
56 | | - expect(nose.position.x).toBeCloseTo(448.6, 0); |
57 | | - expect(nose.position.y).toBeCloseTo(255.9, 0); |
58 | | - expect(nose.score).toBeCloseTo(0.999); |
| 50 | + expect(nose.x).toBeCloseTo(454.1, 0); |
| 51 | + expect(nose.y).toBeCloseTo(256.6, 0); |
| 52 | + expect(nose.score).toBeCloseTo(0.721, 2); |
| 53 | + }); |
| 54 | + |
| 55 | + it("calls the user's callback",(done) => { |
| 56 | + expect.assertions(1); |
| 57 | + const callback = (result) => { |
| 58 | + expect(result).toHaveLength(1); // don't need to repeat the rest |
| 59 | + done(); |
| 60 | + } |
| 61 | + myBodyPose.detect(image, callback); |
59 | 62 | }); |
60 | 63 | }); |
0 commit comments