Skip to content

Commit efe3e6d

Browse files
authored
Upgrade hand pose detection (tensorflow#1173)
1 parent 233b80c commit efe3e6d

File tree

5 files changed

+149
-133
lines changed

5 files changed

+149
-133
lines changed

hand-pose-detection/demos/live_video/package.json

+4-4
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@
1111
"dependencies": {
1212
"@mediapipe/hands": "~0.4.0",
1313
"@tensorflow-models/hand-pose-detection": "file:../../dist",
14-
"@tensorflow/tfjs-backend-wasm": "^3.9.0",
15-
"@tensorflow/tfjs-backend-webgl": "^3.9.0",
16-
"@tensorflow/tfjs-converter": "^3.9.0",
17-
"@tensorflow/tfjs-core": "^3.9.0",
14+
"@tensorflow/tfjs-backend-wasm": "^4.9.0",
15+
"@tensorflow/tfjs-backend-webgl": "^4.9.0",
16+
"@tensorflow/tfjs-converter": "^4.9.0",
17+
"@tensorflow/tfjs-core": "^4.9.0",
1818
"scatter-gl": "0.0.8"
1919
},
2020
"scripts": {

hand-pose-detection/demos/live_video/yarn.lock

+47-42
Original file line numberDiff line numberDiff line change
@@ -996,51 +996,51 @@
996996
"@tensorflow-models/hand-pose-detection@file:../../dist":
997997
version "0.0.0"
998998

999-
"@tensorflow/tfjs-backend-cpu@3.10.0":
1000-
version "3.10.0"
1001-
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-3.10.0.tgz#f192569c6326a954699779fb46eaae20108298ae"
1002-
integrity sha512-ng+LlxFlg/2nBIG8yJkuR5LnhZRP7vUcGNNZImRBo6rTbNhp7Oolx44G1U9ij6uFhw8DIYL+9D4FoIkHJHiS4A==
999+
"@tensorflow/tfjs-backend-cpu@4.9.0":
1000+
version "4.9.0"
1001+
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-backend-cpu/-/tfjs-backend-cpu-4.9.0.tgz#76ce8f4e83814293b662404f16d70f65926195a2"
1002+
integrity sha512-AHIfI3iD1fyQgQKeoQmtkI3exPWRfOo+W0Ws/bxOdapTXcAYWGg0179t52j8XPDwsl8WopfaTINNgYNG6FnP3Q==
10031003
dependencies:
1004-
"@types/seedrandom" "2.4.27"
1005-
seedrandom "2.4.3"
1004+
"@types/seedrandom" "^2.4.28"
1005+
seedrandom "^3.0.5"
10061006

1007-
"@tensorflow/tfjs-backend-wasm@^3.9.0":
1008-
version "3.10.0"
1009-
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-backend-wasm/-/tfjs-backend-wasm-3.10.0.tgz#0736fc793fa25eff3c17381fd6218bf52497be5b"
1010-
integrity sha512-iUrPcCOhBfa5i3tHvBrWMNNDIdc5UT9OuIdU9BFVt8XJQtQKf1Rn12UKoChseIJ5qIdEFpITEkeebP81frGvPg==
1007+
"@tensorflow/tfjs-backend-wasm@^4.9.0":
1008+
version "4.9.0"
1009+
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-backend-wasm/-/tfjs-backend-wasm-4.9.0.tgz#1e1fec3406b312efc814f8238c5c25052e01650e"
1010+
integrity sha512-HsRr9qyu/1pdpkmSoF+1QMtpuE61QOVpH55j6HGNcN+DGuF8TSh80imzZa9JC+A7DXyQdHBKCbUqytuisBQDaA==
10111011
dependencies:
1012-
"@tensorflow/tfjs-backend-cpu" "3.10.0"
1012+
"@tensorflow/tfjs-backend-cpu" "4.9.0"
10131013
"@types/emscripten" "~0.0.34"
10141014

1015-
"@tensorflow/tfjs-backend-webgl@^3.9.0":
1016-
version "3.10.0"
1017-
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-backend-webgl/-/tfjs-backend-webgl-3.10.0.tgz#67bcc11cf7a8d8e81f7d9b5cc832de68f72f5cf8"
1018-
integrity sha512-+QVjpX9778TPQ/+eSu2PaluoR6sVdpRXoFPuXnZ9MndWH6MhSWgn4BJRLO6Fn/ydw2sJhJL+iYPEXb3//EtHMw==
1015+
"@tensorflow/tfjs-backend-webgl@^4.9.0":
1016+
version "4.9.0"
1017+
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-backend-webgl/-/tfjs-backend-webgl-4.9.0.tgz#272812af5c61d02af3b541ed543c3484f5eb8618"
1018+
integrity sha512-lSEOjR9zi6vb1V9yhrby8jWt6SS+wWBXRa3sDE5GCbpcHMWHv41wZktB2WQyIXDqJQcw1lRZBDoYneibMqr2uQ==
10191019
dependencies:
1020-
"@tensorflow/tfjs-backend-cpu" "3.10.0"
1020+
"@tensorflow/tfjs-backend-cpu" "4.9.0"
10211021
"@types/offscreencanvas" "~2019.3.0"
1022-
"@types/seedrandom" "2.4.27"
1022+
"@types/seedrandom" "^2.4.28"
10231023
"@types/webgl-ext" "0.0.30"
1024-
"@types/webgl2" "0.0.6"
1025-
seedrandom "2.4.3"
1024+
seedrandom "^3.0.5"
10261025

1027-
"@tensorflow/tfjs-converter@^3.9.0":
1028-
version "3.10.0"
1029-
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-converter/-/tfjs-converter-3.10.0.tgz#d725230d5b0670503826368f545d1d4743551e84"
1030-
integrity sha512-x5I1Xv+IrM0QgcuP9nWB5lWVCSEai5U/uh52NG1F9SsM4R1Zi9xFwaN3HQjyCVoF8lpA+LpkTX8M3RYav2Rj2g==
1026+
"@tensorflow/tfjs-converter@^4.9.0":
1027+
version "4.9.0"
1028+
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-converter/-/tfjs-converter-4.9.0.tgz#7958f563043b3c54f757f47d2b5b08e963f466ad"
1029+
integrity sha512-mRlzdG3jVsxMkFfHFgDNY10HMoh+vtfPPIghtY+Fc4U/ZnBUFvSfZqwEFyXfOJAewn4fY4BX8+6RE4a0kRXqGA==
10311030

1032-
"@tensorflow/tfjs-core@^3.9.0":
1033-
version "3.10.0"
1034-
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-core/-/tfjs-core-3.10.0.tgz#8be4e980b76cd2f1bec833c3feff84e1c59a9b21"
1035-
integrity sha512-GYv69z/ov/cYOo2j1u6W561T88SxbOW5VDP/Z7se3QetVPqtkNGOJV2gjhtgvWdpJ6m7ZlaL00QZJohkePkbew==
1031+
"@tensorflow/tfjs-core@^4.9.0":
1032+
version "4.9.0"
1033+
resolved "https://registry.yarnpkg.com/@tensorflow/tfjs-core/-/tfjs-core-4.9.0.tgz#7df04d13df85dfb53762a5bb654bfcc24fb34de1"
1034+
integrity sha512-1nYs9OA934eSI33eTvyCVJUEji2wnMXyZ3VK7l2iS/TPDFISI3ETyh286mW56LCihoniv8HH2MtOAQwo4Qhrdg==
10361035
dependencies:
10371036
"@types/long" "^4.0.1"
1038-
"@types/offscreencanvas" "~2019.3.0"
1039-
"@types/seedrandom" "2.4.27"
1037+
"@types/offscreencanvas" "~2019.7.0"
1038+
"@types/seedrandom" "^2.4.28"
10401039
"@types/webgl-ext" "0.0.30"
1040+
"@webgpu/types" "0.1.30"
10411041
long "4.0.0"
10421042
node-fetch "~2.6.1"
1043-
seedrandom "2.4.3"
1043+
seedrandom "^3.0.5"
10441044

10451045
"@types/emscripten@~0.0.34":
10461046
version "0.0.34"
@@ -1057,25 +1057,30 @@
10571057
resolved "https://registry.yarnpkg.com/@types/offscreencanvas/-/offscreencanvas-2019.3.0.tgz#3336428ec7e9180cf4566dfea5da04eb586a6553"
10581058
integrity sha512-esIJx9bQg+QYF0ra8GnvfianIY8qWB0GBx54PK5Eps6m+xTj86KLavHv6qDhzKcu5UUOgNfJ2pWaIIV7TRUd9Q==
10591059

1060+
"@types/offscreencanvas@~2019.7.0":
1061+
version "2019.7.0"
1062+
resolved "https://registry.yarnpkg.com/@types/offscreencanvas/-/offscreencanvas-2019.7.0.tgz#e4a932069db47bb3eabeb0b305502d01586fa90d"
1063+
integrity sha512-PGcyveRIpL1XIqK8eBsmRBt76eFgtzuPiSTyKHZxnGemp2yzGzWpjYKAfK3wIMiU7eH+851yEpiuP8JZerTmWg==
1064+
10601065
"@types/q@^1.5.1":
10611066
version "1.5.5"
10621067
resolved "https://registry.yarnpkg.com/@types/q/-/q-1.5.5.tgz#75a2a8e7d8ab4b230414505d92335d1dcb53a6df"
10631068
integrity sha512-L28j2FcJfSZOnL1WBjDYp2vUHCeIFlyYI/53EwD/rKUBQ7MtUUfbQWiyKJGpcnv4/WgrhWsFKrcPstcAt/J0tQ==
10641069

1065-
"@types/seedrandom@2.4.27":
1066-
version "2.4.27"
1067-
resolved "https://registry.yarnpkg.com/@types/seedrandom/-/seedrandom-2.4.27.tgz#9db563937dd86915f69092bc43259d2f48578e41"
1068-
integrity sha1-nbVjk33YaRX2kJK8QyWdL0hXjkE=
1070+
"@types/seedrandom@^2.4.28":
1071+
version "2.4.30"
1072+
resolved "https://registry.yarnpkg.com/@types/seedrandom/-/seedrandom-2.4.30.tgz#d2efe425869b84163c2d56e779dddadb9372cbfa"
1073+
integrity sha512-AnxLHewubLVzoF/A4qdxBGHCKifw8cY32iro3DQX9TPcetE95zBeVt3jnsvtvAUf1vwzMfwzp4t/L2yqPlnjkQ==
10691074

10701075
"@types/webgl-ext@0.0.30":
10711076
version "0.0.30"
10721077
resolved "https://registry.yarnpkg.com/@types/webgl-ext/-/webgl-ext-0.0.30.tgz#0ce498c16a41a23d15289e0b844d945b25f0fb9d"
10731078
integrity sha512-LKVgNmBxN0BbljJrVUwkxwRYqzsAEPcZOe6S2T6ZaBDIrFp0qu4FNlpc5sM1tGbXUYFgdVQIoeLk1Y1UoblyEg==
10741079

1075-
"@types/webgl2@0.0.6":
1076-
version "0.0.6"
1077-
resolved "https://registry.yarnpkg.com/@types/webgl2/-/webgl2-0.0.6.tgz#1ea2db791362bd8521548d664dbd3c5311cdf4b6"
1078-
integrity sha512-50GQhDVTq/herLMiqSQkdtRu+d5q/cWHn4VvKJtrj4DJAjo1MNkWYa2MA41BaBO1q1HgsUjuQvEOk0QHvlnAaQ==
1080+
"@webgpu/types@0.1.30":
1081+
version "0.1.30"
1082+
resolved "https://registry.yarnpkg.com/@webgpu/types/-/types-0.1.30.tgz#b6406dc4a1c1e0d469028ceb30ddffbbd2fa706c"
1083+
integrity sha512-9AXJSmL3MzY8ZL//JjudA//q+2kBRGhLBFpkdGksWIuxrMy81nFrCzj2Am+mbh8WoU6rXmv7cY5E3rdlyru2Qg==
10791084

10801085
abab@^2.0.0:
10811086
version "2.0.5"
@@ -6079,10 +6084,10 @@ scatter-gl@0.0.8:
60796084
dependencies:
60806085
three "^0.113"
60816086

6082-
seedrandom@2.4.3:
6083-
version "2.4.3"
6084-
resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-2.4.3.tgz#2438504dad33917314bff18ac4d794f16d6aaecc"
6085-
integrity sha1-JDhQTa0zkXMUv/GKxNeU8W1qrsw=
6087+
seedrandom@^3.0.5:
6088+
version "3.0.5"
6089+
resolved "https://registry.yarnpkg.com/seedrandom/-/seedrandom-3.0.5.tgz#54edc85c95222525b0c7a6f6b3543d8e0b3aa0a7"
6090+
integrity sha512-8OwmbklUNzwezjGInmZ+2clQmExQPvomqjL7LFqOYqtmuxRgQYqOD3mHaU+MvZn5FLUeVxVfQjwLZW/n/JFuqg==
60866091

60876092
semver@7.0.0:
60886093
version "7.0.0"

hand-pose-detection/package.json

+10-9
Original file line numberDiff line numberDiff line change
@@ -14,20 +14,20 @@
1414
},
1515
"peerDependencies": {
1616
"@mediapipe/hands": "~0.4.0",
17-
"@tensorflow/tfjs-backend-webgl": "^3.9.0",
18-
"@tensorflow/tfjs-converter": "^3.9.0",
19-
"@tensorflow/tfjs-core": "^3.9.0"
17+
"@tensorflow/tfjs-backend-webgl": "^4.9.0",
18+
"@tensorflow/tfjs-converter": "^4.9.0",
19+
"@tensorflow/tfjs-core": "^4.9.0"
2020
},
2121
"devDependencies": {
2222
"@babel/polyfill": "^7.10.4",
2323
"@mediapipe/hands": "^0.4.0",
2424
"@rollup/plugin-commonjs": "^11.0.2",
2525
"@rollup/plugin-node-resolve": "^7.1.1",
2626
"@rollup/plugin-typescript": "^3.0.0",
27-
"@tensorflow/tfjs-backend-cpu": "^3.9.0",
28-
"@tensorflow/tfjs-backend-webgl": "^3.9.0",
29-
"@tensorflow/tfjs-converter": "^3.9.0",
30-
"@tensorflow/tfjs-core": "^3.9.0",
27+
"@tensorflow/tfjs-backend-cpu": "^4.9.0",
28+
"@tensorflow/tfjs-backend-webgl": "^4.9.0",
29+
"@tensorflow/tfjs-converter": "^4.9.0",
30+
"@tensorflow/tfjs-core": "^4.9.0",
3131
"@types/jasmine": "~2.8.8",
3232
"babel-core": "~6.26.0",
3333
"babel-plugin-transform-runtime": "~6.23.0",
@@ -45,7 +45,7 @@
4545
"rollup-plugin-visualizer": "~3.3.2",
4646
"ts-node": "~8.8.2",
4747
"tslint": "~5.18.0",
48-
"typescript": "~3.9.9",
48+
"typescript": "~4.4.0",
4949
"yalc": "~1.0.0-pre.21"
5050
},
5151
"scripts": {
@@ -61,6 +61,7 @@
6161
},
6262
"license": "Apache-2.0",
6363
"dependencies": {
64-
"rimraf": "^3.0.2"
64+
"rimraf": "^3.0.2",
65+
"tslib": "^2.6.1"
6566
}
6667
}

hand-pose-detection/src/tfjs/tfjs_test.ts

+37-37
Original file line numberDiff line numberDiff line change
@@ -17,35 +17,35 @@
1717

1818
import * as tf from '@tensorflow/tfjs-core';
1919
// tslint:disable-next-line: no-imports-from-dist
20-
import {ALL_ENVS, BROWSER_ENVS, describeWithFlags} from '@tensorflow/tfjs-core/dist/jasmine_util';
20+
import { ALL_ENVS, BROWSER_ENVS, describeWithFlags } from '@tensorflow/tfjs-core/dist/jasmine_util';
2121
// tslint:disable-next-line: no-imports-from-dist
22-
import {expectArraysClose} from '@tensorflow/tfjs-core/dist/test_util';
23-
import {MEDIAPIPE_CONNECTED_KEYPOINTS_PAIRS} from '../constants';
22+
import { expectArraysClose } from '@tensorflow/tfjs-core/dist/test_util';
23+
import { MEDIAPIPE_CONNECTED_KEYPOINTS_PAIRS } from '../constants';
2424

2525
import * as handPoseDetection from '../index';
26-
import {getXYPerFrame, KARMA_SERVER, loadImage, loadVideo} from '../shared/test_util';
26+
import { getXYPerFrame, KARMA_SERVER, loadImage, loadVideo } from '../shared/test_util';
2727

2828
// Measured in pixels.
2929
const EPSILON_IMAGE = 12;
3030
// Measured in pixels.
31-
const EPSILON_VIDEO = 18;
31+
const EPSILON_VIDEO = 22;
3232
// Measured in meters.
33-
const EPSILON_VIDEO_WORLD = 0.01;
33+
const EPSILON_VIDEO_WORLD = 0.012;
3434

3535
// ref:
3636
// https://github.com/google/mediapipe/blob/master/mediapipe/python/solutions/hands_test.py
3737
const EXPECTED_HAND_KEYPOINTS_PREDICTION = [
3838
[
39-
[580, 34], [504, 50], [459, 94], [429, 146], [397, 182], [507, 167],
39+
[580, 34], [504, 50], [459, 94], [429, 146], [397, 182], [507, 167],
4040
[479, 245], [469, 292], [464, 330], [545, 180], [534, 265], [533, 319],
4141
[536, 360], [581, 172], [587, 252], [593, 304], [599, 346], [615, 168],
4242
[628, 223], [638, 258], [648, 288]
4343
],
4444
[
4545
[138, 343], [211, 330], [257, 286], [289, 237], [322, 203], [219, 216],
46-
[238, 138], [249, 90], [253, 51], [177, 204], [184, 115], [187, 60],
47-
[185, 19], [138, 208], [131, 127], [124, 77], [117, 36], [106, 222],
48-
[92, 159], [79, 124], [68, 93]
46+
[238, 138], [249, 90], [253, 51], [177, 204], [184, 115], [187, 60],
47+
[185, 19], [138, 208], [131, 127], [124, 77], [117, 36], [106, 222],
48+
[92, 159], [79, 124], [68, 93]
4949
]
5050
];
5151

@@ -66,7 +66,7 @@ describeWithFlags('MediaPipeHands', ALL_ENVS, () => {
6666

6767
// Note: this makes a network request for model assets.
6868
const detector = await handPoseDetection.createDetector(
69-
handPoseDetection.SupportedModels.MediaPipeHands, {runtime: 'tfjs'});
69+
handPoseDetection.SupportedModels.MediaPipeHands, { runtime: 'tfjs' });
7070
const input: tf.Tensor3D = tf.zeros([128, 128, 3]);
7171

7272
const beforeTensors = tf.memory().numTensors;
@@ -84,12 +84,12 @@ describeWithFlags('MediaPipeHands', ALL_ENVS, () => {
8484
it('throws error when runtime is not set.', async (done) => {
8585
try {
8686
await handPoseDetection.createDetector(
87-
handPoseDetection.SupportedModels.MediaPipeHands);
87+
handPoseDetection.SupportedModels.MediaPipeHands);
8888
done.fail('Loading without runtime succeeded unexpectedly.');
8989
} catch (e) {
9090
expect(e.message).toEqual(
91-
`Expect modelConfig.runtime to be either ` +
92-
`'tfjs' or 'mediapipe', but got undefined`);
91+
`Expect modelConfig.runtime to be either ` +
92+
`'tfjs' or 'mediapipe', but got undefined`);
9393
done();
9494
}
9595
});
@@ -102,7 +102,7 @@ describeWithFlags('MediaPipeHands static image ', BROWSER_ENVS, () => {
102102

103103
beforeAll(async () => {
104104
timeout = jasmine.DEFAULT_TIMEOUT_INTERVAL;
105-
jasmine.DEFAULT_TIMEOUT_INTERVAL = 120000; // 2mins
105+
jasmine.DEFAULT_TIMEOUT_INTERVAL = 240000; // 2mins
106106
image = await loadImage('hands.jpg', 720, 382);
107107
});
108108

@@ -115,19 +115,19 @@ describeWithFlags('MediaPipeHands static image ', BROWSER_ENVS, () => {
115115

116116
// Note: this makes a network request for model assets.
117117
detector = await handPoseDetection.createDetector(
118-
handPoseDetection.SupportedModels.MediaPipeHands,
119-
{runtime: 'tfjs', modelType: 'lite'});
118+
handPoseDetection.SupportedModels.MediaPipeHands,
119+
{ runtime: 'tfjs', modelType: 'lite' });
120120

121121
const beforeTensors = tf.memory().numTensors;
122122

123123
const result = await detector.estimateHands(image, {
124124
staticImageMode: true
125125
} as handPoseDetection.MediaPipeHandsTfjsEstimationConfig);
126126
const keypoints = result.map(
127-
hand => hand.keypoints.map(keypoint => [keypoint.x, keypoint.y]));
127+
hand => hand.keypoints.map(keypoint => [keypoint.x, keypoint.y]));
128128

129129
expectArraysClose(
130-
keypoints, EXPECTED_HAND_KEYPOINTS_PREDICTION, EPSILON_IMAGE);
130+
keypoints, EXPECTED_HAND_KEYPOINTS_PREDICTION, EPSILON_IMAGE);
131131

132132
expect(tf.memory().numTensors).toEqual(beforeTensors);
133133

@@ -141,19 +141,19 @@ describeWithFlags('MediaPipeHands static image ', BROWSER_ENVS, () => {
141141

142142
// Note: this makes a network request for model assets.
143143
detector = await handPoseDetection.createDetector(
144-
handPoseDetection.SupportedModels.MediaPipeHands,
145-
{runtime: 'tfjs', modelType: 'full'});
144+
handPoseDetection.SupportedModels.MediaPipeHands,
145+
{ runtime: 'tfjs', modelType: 'full' });
146146

147147
const beforeTensors = tf.memory().numTensors;
148148

149149
const result = await detector.estimateHands(image, {
150150
staticImageMode: true
151151
} as handPoseDetection.MediaPipeHandsTfjsEstimationConfig);
152152
const keypoints = result.map(
153-
hand => hand.keypoints.map(keypoint => [keypoint.x, keypoint.y]));
153+
hand => hand.keypoints.map(keypoint => [keypoint.x, keypoint.y]));
154154

155155
expectArraysClose(
156-
keypoints, EXPECTED_HAND_KEYPOINTS_PREDICTION, EPSILON_IMAGE);
156+
keypoints, EXPECTED_HAND_KEYPOINTS_PREDICTION, EPSILON_IMAGE);
157157

158158
expect(tf.memory().numTensors).toEqual(beforeTensors);
159159

@@ -174,11 +174,11 @@ describeWithFlags('MediaPipe Hands video ', BROWSER_ENVS, () => {
174174
jasmine.DEFAULT_TIMEOUT_INTERVAL = 120000; // 2mins
175175

176176
expected = await fetch(`${KARMA_SERVER}/asl_hand.full.json`)
177-
.then(response => response.json())
178-
.then(result => getXYPerFrame(result));
177+
.then(response => response.json())
178+
.then(result => getXYPerFrame(result));
179179

180180
expected3D = await fetch(`${KARMA_SERVER}/asl_hand_3d.full.json`)
181-
.then(response => response.json());
181+
.then(response => response.json());
182182
});
183183

184184
afterAll(() => {
@@ -189,25 +189,25 @@ describeWithFlags('MediaPipe Hands video ', BROWSER_ENVS, () => {
189189
// Note: this makes a network request for model assets.
190190
const model = handPoseDetection.SupportedModels.MediaPipeHands;
191191
detector = await handPoseDetection.createDetector(
192-
model, {runtime: 'tfjs', maxHands: 1});
192+
model, { runtime: 'tfjs', maxHands: 1 });
193193

194194
const result: number[][][] = [];
195195
const result3D: number[][][] = [];
196196

197-
const callback = async(video: HTMLVideoElement, timestamp: number):
198-
Promise<handPoseDetection.Keypoint[]> => {
199-
const hands = await detector.estimateHands(video, null /* config */);
197+
const callback = async (video: HTMLVideoElement, timestamp: number):
198+
Promise<handPoseDetection.Keypoint[]> => {
199+
const hands = await detector.estimateHands(video, null /* config */);
200200

201-
// maxNumHands is set to 1.
202-
result.push(hands[0].keypoints.map(kp => [kp.x, kp.y]));
203-
result3D.push(hands[0].keypoints3D.map(kp => [kp.x, kp.y, kp.z]));
201+
// maxNumHands is set to 1.
202+
result.push(hands[0].keypoints.map(kp => [kp.x, kp.y]));
203+
result3D.push(hands[0].keypoints3D.map(kp => [kp.x, kp.y, kp.z]));
204204

205-
return hands[0].keypoints;
206-
};
205+
return hands[0].keypoints;
206+
};
207207

208208
await loadVideo(
209-
'asl_hand.25fps.mp4', 25 /* fps */, callback, expected,
210-
MEDIAPIPE_CONNECTED_KEYPOINTS_PAIRS, 0 /* simulatedInterval unused */);
209+
'asl_hand.25fps.mp4', 25 /* fps */, callback, expected,
210+
MEDIAPIPE_CONNECTED_KEYPOINTS_PAIRS, 0 /* simulatedInterval unused */);
211211

212212
expectArraysClose(result, expected, EPSILON_VIDEO);
213213
expectArraysClose(result3D, expected3D, EPSILON_VIDEO_WORLD);

0 commit comments

Comments
 (0)