';
+ }
+ if (sitsecond==sittotalsecond) {
+ msgbox.innerHTML=msgbox.innerHTML+'
静坐完成!
';
+ window.clearInterval(timer1);
+ sitsecond=0;
+ }
+ // End monitoring code for frames per second
+ stats.end();
+
+ requestAnimationFrame(poseDetectionFrame);
+ }
+
+ poseDetectionFrame();
+}
+
+/**
+ * Kicks off the demo by loading the posenet model, finding and loading
+ * available camera devices, and setting off the detectPoseInRealTime function.
+ */
+export async function bindPage() {
+ toggleLoadingUI(true);
+ const net = await posenet.load({
+ architecture: guiState.input.architecture,
+ outputStride: guiState.input.outputStride,
+ inputResolution: guiState.input.inputResolution,
+ multiplier: guiState.input.multiplier,
+ quantBytes: guiState.input.quantBytes,
+ });
+ toggleLoadingUI(false);
+
+ let video;
+
+ try {
+ video = await loadVideo();
+ } catch (e) {
+ let info = document.getElementById('info');
+ info.textContent = 'this browser does not support video capture,' +
+ 'or this device does not have a camera';
+ info.style.display = 'block';
+ throw e;
+ }
+
+ setupGui([], net);
+ setupFPS();
+ detectPoseInRealTime(video, net);
+}
+
+navigator.getUserMedia = navigator.getUserMedia ||
+ navigator.webkitGetUserMedia || navigator.mozGetUserMedia;
+// kick off the demo
+
+document.getElementById('begin').onclick=function() {
+ bindPage();
+};
+document.getElementById('end').onclick=function() {
+ bindPage();
+};
+
diff --git a/image.html b/image.html
new file mode 100644
index 0000000..6f58262
--- /dev/null
+++ b/image.html
@@ -0,0 +1,83 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/images/qp04.jpg b/images/qp04.jpg
new file mode 100644
index 0000000..60a2cf7
Binary files /dev/null and b/images/qp04.jpg differ
diff --git a/index.html b/index.html
new file mode 100644
index 0000000..1cf52c4
--- /dev/null
+++ b/index.html
@@ -0,0 +1,108 @@
+
+
+
+
+ PoseNet - Camera Feed Demo
+
+
+
+
+
+
+
+
+
+
+ Loading PoseNet model...
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 有人进入!!!
+
+
+
+
+
+
+
+
diff --git a/modules/posenet/base_model.d.ts b/modules/posenet/base_model.d.ts
new file mode 100644
index 0000000..dd8e514
--- /dev/null
+++ b/modules/posenet/base_model.d.ts
@@ -0,0 +1,63 @@
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+import * as tfconv from '@tensorflow/tfjs-converter';
+import * as tf from '@tensorflow/tfjs-core';
+import { PoseNetOutputStride } from './types';
+/**
+ * PoseNet supports using various convolution neural network models
+ * (e.g. ResNet and MobileNetV1) as its underlying base model.
+ * The following BaseModel interface defines a unified interface for
+ * creating such PoseNet base models. Currently both MobileNet (in
+ * ./mobilenet.ts) and ResNet (in ./resnet.ts) implements the BaseModel
+ * interface. New base models that conform to the BaseModel interface can be
+ * added to PoseNet.
+ */
+export declare abstract class BaseModel {
+ protected readonly model: tfconv.GraphModel;
+ readonly outputStride: PoseNetOutputStride;
+ constructor(model: tfconv.GraphModel, outputStride: PoseNetOutputStride);
+ abstract preprocessInput(input: tf.Tensor3D): tf.Tensor3D;
+ /**
+ * Predicts intermediate Tensor representations.
+ *
+ * @param input The input RGB image of the base model.
+ * A Tensor of shape: [`inputResolution`, `inputResolution`, 3].
+ *
+ * @return A dictionary of base model's intermediate predictions.
+ * The returned dictionary should contains the following elements:
+ * heatmapScores: A Tensor3D that represents the heatmapScores.
+ * offsets: A Tensor3D that represents the offsets.
+ * displacementFwd: A Tensor3D that represents the forward displacement.
+ * displacementBwd: A Tensor3D that represents the backward displacement.
+ */
+ predict(input: tf.Tensor3D): {
+ heatmapScores: tf.Tensor3D;
+ offsets: tf.Tensor3D;
+ displacementFwd: tf.Tensor3D;
+ displacementBwd: tf.Tensor3D;
+ };
+ abstract nameOutputResults(results: tf.Tensor3D[]): {
+ heatmap: tf.Tensor3D;
+ offsets: tf.Tensor3D;
+ displacementFwd: tf.Tensor3D;
+ displacementBwd: tf.Tensor3D;
+ };
+ /**
+ * Releases the CPU and GPU memory allocated by the model.
+ */
+ dispose(): void;
+}
diff --git a/modules/posenet/base_model.js b/modules/posenet/base_model.js
new file mode 100644
index 0000000..1148352
--- /dev/null
+++ b/modules/posenet/base_model.js
@@ -0,0 +1,75 @@
+"use strict";
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+Object.defineProperty(exports, "__esModule", { value: true });
+var tf = require("@tensorflow/tfjs-core");
+/**
+ * PoseNet supports using various convolution neural network models
+ * (e.g. ResNet and MobileNetV1) as its underlying base model.
+ * The following BaseModel interface defines a unified interface for
+ * creating such PoseNet base models. Currently both MobileNet (in
+ * ./mobilenet.ts) and ResNet (in ./resnet.ts) implements the BaseModel
+ * interface. New base models that conform to the BaseModel interface can be
+ * added to PoseNet.
+ */
+var BaseModel = /** @class */ (function () {
+ function BaseModel(model, outputStride) {
+ this.model = model;
+ this.outputStride = outputStride;
+ var inputShape = this.model.inputs[0].shape;
+ tf.util.assert((inputShape[1] === -1) && (inputShape[2] === -1), function () { return "Input shape [" + inputShape[1] + ", " + inputShape[2] + "] " +
+ "must both be equal to or -1"; });
+ }
+ /**
+ * Predicts intermediate Tensor representations.
+ *
+ * @param input The input RGB image of the base model.
+ * A Tensor of shape: [`inputResolution`, `inputResolution`, 3].
+ *
+ * @return A dictionary of base model's intermediate predictions.
+ * The returned dictionary should contains the following elements:
+ * heatmapScores: A Tensor3D that represents the heatmapScores.
+ * offsets: A Tensor3D that represents the offsets.
+ * displacementFwd: A Tensor3D that represents the forward displacement.
+ * displacementBwd: A Tensor3D that represents the backward displacement.
+ */
+ BaseModel.prototype.predict = function (input) {
+ var _this = this;
+ return tf.tidy(function () {
+ var asFloat = _this.preprocessInput(tf.cast(input, 'float32'));
+ var asBatch = tf.expandDims(asFloat, 0);
+ var results = _this.model.predict(asBatch);
+ var results3d = results.map(function (y) { return tf.squeeze(y, [0]); });
+ var namedResults = _this.nameOutputResults(results3d);
+ return {
+ heatmapScores: tf.sigmoid(namedResults.heatmap),
+ offsets: namedResults.offsets,
+ displacementFwd: namedResults.displacementFwd,
+ displacementBwd: namedResults.displacementBwd
+ };
+ });
+ };
+ /**
+ * Releases the CPU and GPU memory allocated by the model.
+ */
+ BaseModel.prototype.dispose = function () {
+ this.model.dispose();
+ };
+ return BaseModel;
+}());
+exports.BaseModel = BaseModel;
+//# sourceMappingURL=base_model.js.map
\ No newline at end of file
diff --git a/modules/posenet/base_model.js.map b/modules/posenet/base_model.js.map
new file mode 100644
index 0000000..9870e40
--- /dev/null
+++ b/modules/posenet/base_model.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"base_model.js","sourceRoot":"","sources":["../src/base_model.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;AAGH,0CAA4C;AAG5C;;;;;;;;GAQG;AACH;IACE,mBACuB,KAAwB,EAC3B,YAAiC;QAD9B,UAAK,GAAL,KAAK,CAAmB;QAC3B,iBAAY,GAAZ,YAAY,CAAqB;QACnD,IAAM,UAAU,GACZ,IAAI,CAAC,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,KAAyC,CAAC;QACnE,EAAE,CAAC,IAAI,CAAC,MAAM,CACV,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAChD,cAAM,OAAA,kBAAgB,UAAU,CAAC,CAAC,CAAC,UAAK,UAAU,CAAC,CAAC,CAAC,OAAI;YACrD,6BAA6B,EAD3B,CAC2B,CAAC,CAAC;IACzC,CAAC;IAID;;;;;;;;;;;;OAYG;IACH,2BAAO,GAAP,UAAQ,KAAkB;QAA1B,iBAqBC;QAfC,OAAO,EAAE,CAAC,IAAI,CAAC;YACb,IAAM,OAAO,GAAG,KAAI,CAAC,eAAe,CAAC,EAAE,CAAC,IAAI,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC,CAAC;YAChE,IAAM,OAAO,GAAG,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;YAC1C,IAAM,OAAO,GAAG,KAAI,CAAC,KAAK,CAAC,OAAO,CAAC,OAAO,CAAkB,CAAC;YAC7D,IAAM,SAAS,GAAkB,OAAO,CAAC,GAAG,CAAC,UAAA,CAAC,IAAI,OAAA,EAAE,CAAC,OAAO,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,EAAlB,CAAkB,CAAC,CAAC;YAEtE,IAAM,YAAY,GAAG,KAAI,CAAC,iBAAiB,CAAC,SAAS,CAAC,CAAC;YAEvD,OAAO;gBACL,aAAa,EAAE,EAAE,CAAC,OAAO,CAAC,YAAY,CAAC,OAAO,CAAC;gBAC/C,OAAO,EAAE,YAAY,CAAC,OAAO;gBAC7B,eAAe,EAAE,YAAY,CAAC,eAAe;gBAC7C,eAAe,EAAE,YAAY,CAAC,eAAe;aAC9C,CAAC;QACJ,CAAC,CAAC,CAAC;IACL,CAAC;IAWD;;OAEG;IACH,2BAAO,GAAP;QACE,IAAI,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC;IACvB,CAAC;IACH,gBAAC;AAAD,CAAC,AAjED,IAiEC;AAjEqB,8BAAS"}
\ No newline at end of file
diff --git a/modules/posenet/checkpoints.d.ts b/modules/posenet/checkpoints.d.ts
new file mode 100644
index 0000000..2e948b6
--- /dev/null
+++ b/modules/posenet/checkpoints.d.ts
@@ -0,0 +1,18 @@
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+export declare function resNet50Checkpoint(stride: number, quantBytes: number): string;
+export declare function mobileNetCheckpoint(stride: number, multiplier: number, quantBytes: number): string;
diff --git a/modules/posenet/checkpoints.js b/modules/posenet/checkpoints.js
new file mode 100644
index 0000000..627d54e
--- /dev/null
+++ b/modules/posenet/checkpoints.js
@@ -0,0 +1,49 @@
+"use strict";
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+Object.defineProperty(exports, "__esModule", { value: true });
+var MOBILENET_BASE_URL = 'https://storage.googleapis.com/tfjs-models/savedmodel/posenet/mobilenet/';
+var RESNET50_BASE_URL = 'https://storage.googleapis.com/tfjs-models/savedmodel/posenet/resnet50/';
+// The PoseNet 2.0 ResNet50 models use the latest TensorFlow.js 1.0 model
+// format.
+function resNet50Checkpoint(stride, quantBytes) {
+ var graphJson = "model-stride" + stride + ".json";
+ // quantBytes=4 corresponding to the non-quantized full-precision checkpoints.
+ if (quantBytes === 4) {
+ return RESNET50_BASE_URL + "float/" + graphJson;
+ }
+ else {
+ return RESNET50_BASE_URL + ("quant" + quantBytes + "/") + graphJson;
+ }
+}
+exports.resNet50Checkpoint = resNet50Checkpoint;
+// The PoseNet 2.0 MobileNetV1 models use the latest TensorFlow.js 1.0 model
+// format.
+function mobileNetCheckpoint(stride, multiplier, quantBytes) {
+ var toStr = { 1.0: '100', 0.75: '075', 0.50: '050' };
+ var graphJson = "model-stride" + stride + ".json";
+ // quantBytes=4 corresponding to the non-quantized full-precision checkpoints.
+ if (quantBytes === 4) {
+ return MOBILENET_BASE_URL + ("float/" + toStr[multiplier] + "/") + graphJson;
+ }
+ else {
+ return MOBILENET_BASE_URL + ("quant" + quantBytes + "/" + toStr[multiplier] + "/") +
+ graphJson;
+ }
+}
+exports.mobileNetCheckpoint = mobileNetCheckpoint;
+//# sourceMappingURL=checkpoints.js.map
\ No newline at end of file
diff --git a/modules/posenet/checkpoints.js.map b/modules/posenet/checkpoints.js.map
new file mode 100644
index 0000000..b36e477
--- /dev/null
+++ b/modules/posenet/checkpoints.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"checkpoints.js","sourceRoot":"","sources":["../src/checkpoints.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;AAEH,IAAM,kBAAkB,GACpB,0EAA0E,CAAC;AAC/E,IAAM,iBAAiB,GACnB,yEAAyE,CAAC;AAE9E,yEAAyE;AACzE,UAAU;AACV,SAAgB,kBAAkB,CAAC,MAAc,EAAE,UAAkB;IACnE,IAAM,SAAS,GAAG,iBAAe,MAAM,UAAO,CAAC;IAC/C,8EAA8E;IAC9E,IAAI,UAAU,KAAK,CAAC,EAAE;QACpB,OAAO,iBAAiB,GAAG,QAAQ,GAAG,SAAS,CAAC;KACjD;SAAM;QACL,OAAO,iBAAiB,IAAG,UAAQ,UAAU,MAAG,CAAA,GAAG,SAAS,CAAC;KAC9D;AACH,CAAC;AARD,gDAQC;AAED,4EAA4E;AAC5E,UAAU;AACV,SAAgB,mBAAmB,CAC/B,MAAc,EAAE,UAAkB,EAAE,UAAkB;IACxD,IAAM,KAAK,GAA4B,EAAC,GAAG,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAC,CAAC;IAC9E,IAAM,SAAS,GAAG,iBAAe,MAAM,UAAO,CAAC;IAC/C,8EAA8E;IAC9E,IAAI,UAAU,KAAK,CAAC,EAAE;QACpB,OAAO,kBAAkB,IAAG,WAAS,KAAK,CAAC,UAAU,CAAC,MAAG,CAAA,GAAG,SAAS,CAAC;KACvE;SAAM;QACL,OAAO,kBAAkB,IAAG,UAAQ,UAAU,SAAI,KAAK,CAAC,UAAU,CAAC,MAAG,CAAA;YAClE,SAAS,CAAC;KACf;AACH,CAAC;AAXD,kDAWC"}
\ No newline at end of file
diff --git a/modules/posenet/index.d.ts b/modules/posenet/index.d.ts
new file mode 100644
index 0000000..7107c96
--- /dev/null
+++ b/modules/posenet/index.d.ts
@@ -0,0 +1,25 @@
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+import { MobileNet } from './mobilenet';
+import { decodeMultiplePoses } from './multi_pose/decode_multiple_poses';
+import { decodeSinglePose } from './single_pose/decode_single_pose';
+export { partChannels, partIds, partNames, poseChain } from './keypoints';
+export { load, ModelConfig, MultiPersonInferenceConfig, PoseNet, SinglePersonInterfaceConfig } from './posenet_model';
+export { InputResolution, Keypoint, MobileNetMultiplier, Pose, PoseNetOutputStride } from './types';
+export { getAdjacentKeyPoints, getBoundingBox, getBoundingBoxPoints, scaleAndFlipPoses, scalePose } from './util';
+export { version } from './version';
+export { decodeMultiplePoses, decodeSinglePose, MobileNet };
diff --git a/modules/posenet/index.js b/modules/posenet/index.js
new file mode 100644
index 0000000..e9e60e5
--- /dev/null
+++ b/modules/posenet/index.js
@@ -0,0 +1,41 @@
+"use strict";
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * https://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+Object.defineProperty(exports, "__esModule", { value: true });
+var mobilenet_1 = require("./mobilenet");
+exports.MobileNet = mobilenet_1.MobileNet;
+var decode_multiple_poses_1 = require("./multi_pose/decode_multiple_poses");
+exports.decodeMultiplePoses = decode_multiple_poses_1.decodeMultiplePoses;
+var decode_single_pose_1 = require("./single_pose/decode_single_pose");
+exports.decodeSinglePose = decode_single_pose_1.decodeSinglePose;
+var keypoints_1 = require("./keypoints");
+exports.partChannels = keypoints_1.partChannels;
+exports.partIds = keypoints_1.partIds;
+exports.partNames = keypoints_1.partNames;
+exports.poseChain = keypoints_1.poseChain;
+var posenet_model_1 = require("./posenet_model");
+exports.load = posenet_model_1.load;
+exports.PoseNet = posenet_model_1.PoseNet;
+var util_1 = require("./util");
+exports.getAdjacentKeyPoints = util_1.getAdjacentKeyPoints;
+exports.getBoundingBox = util_1.getBoundingBox;
+exports.getBoundingBoxPoints = util_1.getBoundingBoxPoints;
+exports.scaleAndFlipPoses = util_1.scaleAndFlipPoses;
+exports.scalePose = util_1.scalePose;
+var version_1 = require("./version");
+exports.version = version_1.version;
+//# sourceMappingURL=index.js.map
\ No newline at end of file
diff --git a/modules/posenet/index.js.map b/modules/posenet/index.js.map
new file mode 100644
index 0000000..42a51cc
--- /dev/null
+++ b/modules/posenet/index.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;AAEH,yCAAsC;AASS,oBATvC,qBAAS,CASuC;AARxD,4EAAuE;AAQ/D,8BARA,2CAAmB,CAQA;AAP3B,uEAAkE;AAOrC,2BAPrB,qCAAgB,CAOqB;AAL7C,yCAAwE;AAAhE,mCAAA,YAAY,CAAA;AAAE,8BAAA,OAAO,CAAA;AAAE,gCAAA,SAAS,CAAA;AAAE,gCAAA,SAAS,CAAA;AACnD,iDAAoH;AAA5G,+BAAA,IAAI,CAAA;AAA2C,kCAAA,OAAO,CAAA;AAE9D,+BAAgH;AAAxG,sCAAA,oBAAoB,CAAA;AAAE,gCAAA,cAAc,CAAA;AAAE,sCAAA,oBAAoB,CAAA;AAAE,mCAAA,iBAAiB,CAAA;AAAE,2BAAA,SAAS,CAAA;AAChG,qCAAkC;AAA1B,4BAAA,OAAO,CAAA"}
\ No newline at end of file
diff --git a/modules/posenet/keypoints.d.ts b/modules/posenet/keypoints.d.ts
new file mode 100644
index 0000000..a446ca5
--- /dev/null
+++ b/modules/posenet/keypoints.d.ts
@@ -0,0 +1,28 @@
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+export declare type Tuple = [T, T];
+export declare type StringTuple = Tuple;
+export declare type NumberTuple = Tuple;
+export declare const partNames: string[];
+export declare const NUM_KEYPOINTS: number;
+export interface NumberDict {
+ [jointName: string]: number;
+}
+export declare const partIds: NumberDict;
+export declare const poseChain: StringTuple[];
+export declare const connectedPartIndices: number[][];
+export declare const partChannels: string[];
diff --git a/modules/posenet/keypoints.js b/modules/posenet/keypoints.js
new file mode 100644
index 0000000..e80f316
--- /dev/null
+++ b/modules/posenet/keypoints.js
@@ -0,0 +1,83 @@
+"use strict";
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+Object.defineProperty(exports, "__esModule", { value: true });
+exports.partNames = [
+ 'nose', 'leftEye', 'rightEye', 'leftEar', 'rightEar', 'leftShoulder',
+ 'rightShoulder', 'leftElbow', 'rightElbow', 'leftWrist', 'rightWrist',
+ 'leftHip', 'rightHip', 'leftKnee', 'rightKnee', 'leftAnkle', 'rightAnkle'
+];
+exports.NUM_KEYPOINTS = exports.partNames.length;
+exports.partIds = exports.partNames.reduce(function (result, jointName, i) {
+ result[jointName] = i;
+ return result;
+}, {});
+var connectedPartNames = [
+ ['leftHip', 'leftShoulder'], ['leftElbow', 'leftShoulder'],
+ ['leftElbow', 'leftWrist'], ['leftHip', 'leftKnee'],
+ ['leftKnee', 'leftAnkle'], ['rightHip', 'rightShoulder'],
+ ['rightElbow', 'rightShoulder'], ['rightElbow', 'rightWrist'],
+ ['rightHip', 'rightKnee'], ['rightKnee', 'rightAnkle'],
+ ['leftShoulder', 'rightShoulder'], ['leftHip', 'rightHip']
+];
+/*
+ * Define the skeleton. This defines the parent->child relationships of our
+ * tree. Arbitrarily this defines the nose as the root of the tree, however
+ * since we will infer the displacement for both parent->child and
+ * child->parent, we can define the tree root as any node.
+ */
+exports.poseChain = [
+ ['nose', 'leftEye'], ['leftEye', 'leftEar'], ['nose', 'rightEye'],
+ ['rightEye', 'rightEar'], ['nose', 'leftShoulder'],
+ ['leftShoulder', 'leftElbow'], ['leftElbow', 'leftWrist'],
+ ['leftShoulder', 'leftHip'], ['leftHip', 'leftKnee'],
+ ['leftKnee', 'leftAnkle'], ['nose', 'rightShoulder'],
+ ['rightShoulder', 'rightElbow'], ['rightElbow', 'rightWrist'],
+ ['rightShoulder', 'rightHip'], ['rightHip', 'rightKnee'],
+ ['rightKnee', 'rightAnkle']
+];
+exports.connectedPartIndices = connectedPartNames.map(function (_a) {
+ var jointNameA = _a[0], jointNameB = _a[1];
+ return ([exports.partIds[jointNameA], exports.partIds[jointNameB]]);
+});
+exports.partChannels = [
+ 'left_face',
+ 'right_face',
+ 'right_upper_leg_front',
+ 'right_lower_leg_back',
+ 'right_upper_leg_back',
+ 'left_lower_leg_front',
+ 'left_upper_leg_front',
+ 'left_upper_leg_back',
+ 'left_lower_leg_back',
+ 'right_feet',
+ 'right_lower_leg_front',
+ 'left_feet',
+ 'torso_front',
+ 'torso_back',
+ 'right_upper_arm_front',
+ 'right_upper_arm_back',
+ 'right_lower_arm_back',
+ 'left_lower_arm_front',
+ 'left_upper_arm_front',
+ 'left_upper_arm_back',
+ 'left_lower_arm_back',
+ 'right_hand',
+ 'right_lower_arm_front',
+ 'left_hand'
+];
+//# sourceMappingURL=keypoints.js.map
\ No newline at end of file
diff --git a/modules/posenet/keypoints.js.map b/modules/posenet/keypoints.js.map
new file mode 100644
index 0000000..888d9d5
--- /dev/null
+++ b/modules/posenet/keypoints.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"keypoints.js","sourceRoot":"","sources":["../src/keypoints.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;AAMU,QAAA,SAAS,GAAG;IACvB,MAAM,EAAE,SAAS,EAAE,UAAU,EAAE,SAAS,EAAE,UAAU,EAAE,cAAc;IACpE,eAAe,EAAE,WAAW,EAAE,YAAY,EAAE,WAAW,EAAE,YAAY;IACrE,SAAS,EAAE,UAAU,EAAE,UAAU,EAAE,WAAW,EAAE,WAAW,EAAE,YAAY;CAC1E,CAAC;AAEW,QAAA,aAAa,GAAG,iBAAS,CAAC,MAAM,CAAC;AAMjC,QAAA,OAAO,GAChB,iBAAS,CAAC,MAAM,CAAC,UAAC,MAAkB,EAAE,SAAS,EAAE,CAAC;IAChD,MAAM,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC;IACtB,OAAO,MAAM,CAAC;AAChB,CAAC,EAAE,EAAE,CAAe,CAAC;AAEzB,IAAM,kBAAkB,GAAkB;IACxC,CAAC,SAAS,EAAE,cAAc,CAAC,EAAE,CAAC,WAAW,EAAE,cAAc,CAAC;IAC1D,CAAC,WAAW,EAAE,WAAW,CAAC,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC;IACnD,CAAC,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC,UAAU,EAAE,eAAe,CAAC;IACxD,CAAC,YAAY,EAAE,eAAe,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC;IAC7D,CAAC,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC,WAAW,EAAE,YAAY,CAAC;IACtD,CAAC,cAAc,EAAE,eAAe,CAAC,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC;CAC3D,CAAC;AAEF;;;;;GAKG;AACU,QAAA,SAAS,GAAkB;IACtC,CAAC,MAAM,EAAE,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,UAAU,CAAC;IACjE,CAAC,UAAU,EAAE,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,cAAc,CAAC;IAClD,CAAC,cAAc,EAAE,WAAW,CAAC,EAAE,CAAC,WAAW,EAAE,WAAW,CAAC;IACzD,CAAC,cAAc,EAAE,SAAS,CAAC,EAAE,CAAC,SAAS,EAAE,UAAU,CAAC;IACpD,CAAC,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC,MAAM,EAAE,eAAe,CAAC;IACpD,CAAC,eAAe,EAAE,YAAY,CAAC,EAAE,CAAC,YAAY,EAAE,YAAY,CAAC;IAC7D,CAAC,eAAe,EAAE,UAAU,CAAC,EAAE,CAAC,UAAU,EAAE,WAAW,CAAC;IACxD,CAAC,WAAW,EAAE,YAAY,CAAC;CAC5B,CAAC;AAEW,QAAA,oBAAoB,GAAG,kBAAkB,CAAC,GAAG,CACtD,UAAC,EAAwB;QAAvB,kBAAU,EAAE,kBAAU;IAAM,OAAA,CAAC,CAAC,eAAO,CAAC,UAAU,CAAC,EAAE,eAAO,CAAC,UAAU,CAAC,CAAC,CAAC;AAA5C,CAA4C,CAAC,CAAC;AAEnE,QAAA,YAAY,GAAa;IACpC,WAAW;IACX,YAAY;IACZ,uBAAuB;IACvB,sBAAsB;IACtB,sBAAsB;IACtB,sBAAsB;IACtB,sBAAsB;IACtB,qBAAqB;IACrB,qBAAqB;IACrB,YAAY;IACZ,uBAAuB;IACvB,WAAW;IACX,aAAa;IACb,YAAY;IACZ,uBAAuB;IACvB,sBAAsB;IACtB,sBAAsB;IACtB,sBAAsB;IACtB,sBAAsB;IACtB,qBAAqB;IACrB,qBAAqB;IACrB,YAAY;IACZ,uBAAuB;IACvB,WAAW;CACZ,CAAC"}
\ No newline at end of file
diff --git a/modules/posenet/mobilenet.d.ts b/modules/posenet/mobilenet.d.ts
new file mode 100644
index 0000000..9eaaff1
--- /dev/null
+++ b/modules/posenet/mobilenet.d.ts
@@ -0,0 +1,27 @@
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+import * as tf from '@tensorflow/tfjs-core';
+import { BaseModel } from './base_model';
+export declare class MobileNet extends BaseModel {
+ preprocessInput(input: tf.Tensor3D): tf.Tensor3D;
+ nameOutputResults(results: tf.Tensor3D[]): {
+ offsets: tf.Tensor;
+ heatmap: tf.Tensor;
+ displacementFwd: tf.Tensor;
+ displacementBwd: tf.Tensor;
+ };
+}
diff --git a/modules/posenet/mobilenet.js b/modules/posenet/mobilenet.js
new file mode 100644
index 0000000..d091f49
--- /dev/null
+++ b/modules/posenet/mobilenet.js
@@ -0,0 +1,50 @@
+"use strict";
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+var __extends = (this && this.__extends) || (function () {
+ var extendStatics = function (d, b) {
+ extendStatics = Object.setPrototypeOf ||
+ ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) ||
+ function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; };
+ return extendStatics(d, b);
+ };
+ return function (d, b) {
+ extendStatics(d, b);
+ function __() { this.constructor = d; }
+ d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __());
+ };
+})();
+Object.defineProperty(exports, "__esModule", { value: true });
+var tf = require("@tensorflow/tfjs-core");
+var base_model_1 = require("./base_model");
+var MobileNet = /** @class */ (function (_super) {
+ __extends(MobileNet, _super);
+ function MobileNet() {
+ return _super !== null && _super.apply(this, arguments) || this;
+ }
+ MobileNet.prototype.preprocessInput = function (input) {
+ // Normalize the pixels [0, 255] to be between [-1, 1].
+ return tf.tidy(function () { return tf.sub(tf.div(input, 127.5), 1.0); });
+ };
+ MobileNet.prototype.nameOutputResults = function (results) {
+ var offsets = results[0], heatmap = results[1], displacementFwd = results[2], displacementBwd = results[3];
+ return { offsets: offsets, heatmap: heatmap, displacementFwd: displacementFwd, displacementBwd: displacementBwd };
+ };
+ return MobileNet;
+}(base_model_1.BaseModel));
+exports.MobileNet = MobileNet;
+//# sourceMappingURL=mobilenet.js.map
\ No newline at end of file
diff --git a/modules/posenet/mobilenet.js.map b/modules/posenet/mobilenet.js.map
new file mode 100644
index 0000000..6bec315
--- /dev/null
+++ b/modules/posenet/mobilenet.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"mobilenet.js","sourceRoot":"","sources":["../src/mobilenet.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;;;;;;;;;;;;;;AAEH,0CAA4C;AAC5C,2CAAuC;AAEvC;IAA+B,6BAAS;IAAxC;;IAUA,CAAC;IATC,mCAAe,GAAf,UAAgB,KAAkB;QAChC,uDAAuD;QACvD,OAAO,EAAE,CAAC,IAAI,CAAC,cAAM,OAAA,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,KAAK,EAAE,KAAK,CAAC,EAAE,GAAG,CAAC,EAAjC,CAAiC,CAAC,CAAC;IAC1D,CAAC;IAED,qCAAiB,GAAjB,UAAkB,OAAsB;QAC/B,IAAA,oBAAO,EAAE,oBAAO,EAAE,4BAAe,EAAE,4BAAe,CAAY;QACrE,OAAO,EAAC,OAAO,SAAA,EAAE,OAAO,SAAA,EAAE,eAAe,iBAAA,EAAE,eAAe,iBAAA,EAAC,CAAC;IAC9D,CAAC;IACH,gBAAC;AAAD,CAAC,AAVD,CAA+B,sBAAS,GAUvC;AAVY,8BAAS"}
\ No newline at end of file
diff --git a/modules/posenet/model_weights.d.ts b/modules/posenet/model_weights.d.ts
new file mode 100644
index 0000000..700fa27
--- /dev/null
+++ b/modules/posenet/model_weights.d.ts
@@ -0,0 +1,28 @@
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+import * as tf from '@tensorflow/tfjs-core';
+export declare class ModelWeights {
+ private variables;
+ constructor(variables: {
+ [varName: string]: tf.Tensor;
+ });
+ weights(layerName: string): tf.Tensor;
+ depthwiseBias(layerName: string): tf.Tensor;
+ convBias(layerName: string): tf.Tensor;
+ depthwiseWeights(layerName: string): tf.Tensor;
+ dispose(): void;
+}
diff --git a/modules/posenet/model_weights.js b/modules/posenet/model_weights.js
new file mode 100644
index 0000000..b5528c1
--- /dev/null
+++ b/modules/posenet/model_weights.js
@@ -0,0 +1,43 @@
+"use strict";
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+Object.defineProperty(exports, "__esModule", { value: true });
+var ModelWeights = /** @class */ (function () {
+ function ModelWeights(variables) {
+ this.variables = variables;
+ }
+ ModelWeights.prototype.weights = function (layerName) {
+ return this.variables["MobilenetV1/" + layerName + "/weights"];
+ };
+ ModelWeights.prototype.depthwiseBias = function (layerName) {
+ return this.variables["MobilenetV1/" + layerName + "/biases"];
+ };
+ ModelWeights.prototype.convBias = function (layerName) {
+ return this.depthwiseBias(layerName);
+ };
+ ModelWeights.prototype.depthwiseWeights = function (layerName) {
+ return this.variables["MobilenetV1/" + layerName + "/depthwise_weights"];
+ };
+ ModelWeights.prototype.dispose = function () {
+ for (var varName in this.variables) {
+ this.variables[varName].dispose();
+ }
+ };
+ return ModelWeights;
+}());
+exports.ModelWeights = ModelWeights;
+//# sourceMappingURL=model_weights.js.map
\ No newline at end of file
diff --git a/modules/posenet/model_weights.js.map b/modules/posenet/model_weights.js.map
new file mode 100644
index 0000000..b13448f
--- /dev/null
+++ b/modules/posenet/model_weights.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"model_weights.js","sourceRoot":"","sources":["../src/model_weights.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;AAIH;IAGE,sBAAY,SAAyC;QACnD,IAAI,CAAC,SAAS,GAAG,SAAS,CAAC;IAC7B,CAAC;IAED,8BAAO,GAAP,UAAQ,SAAiB;QACvB,OAAO,IAAI,CAAC,SAAS,CAAC,iBAAe,SAAS,aAAU,CAAgB,CAAC;IAC3E,CAAC;IAED,oCAAa,GAAb,UAAc,SAAiB;QAC7B,OAAO,IAAI,CAAC,SAAS,CAAC,iBAAe,SAAS,YAAS,CAAgB,CAAC;IAC1E,CAAC;IAED,+BAAQ,GAAR,UAAS,SAAiB;QACxB,OAAO,IAAI,CAAC,aAAa,CAAC,SAAS,CAAC,CAAC;IACvC,CAAC;IAED,uCAAgB,GAAhB,UAAiB,SAAiB;QAChC,OAAO,IAAI,CAAC,SAAS,CAAC,iBAAe,SAAS,uBAAoB,CACnD,CAAC;IAClB,CAAC;IAED,8BAAO,GAAP;QACE,KAAK,IAAM,OAAO,IAAI,IAAI,CAAC,SAAS,EAAE;YACpC,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC,OAAO,EAAE,CAAC;SACnC;IACH,CAAC;IACH,mBAAC;AAAD,CAAC,AA7BD,IA6BC;AA7BY,oCAAY"}
\ No newline at end of file
diff --git a/modules/posenet/multi_pose/build_part_with_score_queue.d.ts b/modules/posenet/multi_pose/build_part_with_score_queue.d.ts
new file mode 100644
index 0000000..e82d8bf
--- /dev/null
+++ b/modules/posenet/multi_pose/build_part_with_score_queue.d.ts
@@ -0,0 +1,24 @@
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+import { PartWithScore, TensorBuffer3D } from '../types';
+import { MaxHeap } from './max_heap';
+/**
+ * Builds a priority queue with part candidate positions for a specific image in
+ * the batch. For this we find all local maxima in the score maps with score
+ * values above a threshold. We create a single priority queue across all parts.
+ */
+export declare function buildPartWithScoreQueue(scoreThreshold: number, localMaximumRadius: number, scores: TensorBuffer3D): MaxHeap;
diff --git a/modules/posenet/multi_pose/build_part_with_score_queue.js b/modules/posenet/multi_pose/build_part_with_score_queue.js
new file mode 100644
index 0000000..5014f50
--- /dev/null
+++ b/modules/posenet/multi_pose/build_part_with_score_queue.js
@@ -0,0 +1,70 @@
+"use strict";
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+Object.defineProperty(exports, "__esModule", { value: true });
+var max_heap_1 = require("./max_heap");
+function scoreIsMaximumInLocalWindow(keypointId, score, heatmapY, heatmapX, localMaximumRadius, scores) {
+ var _a = scores.shape, height = _a[0], width = _a[1];
+ var localMaximum = true;
+ var yStart = Math.max(heatmapY - localMaximumRadius, 0);
+ var yEnd = Math.min(heatmapY + localMaximumRadius + 1, height);
+ for (var yCurrent = yStart; yCurrent < yEnd; ++yCurrent) {
+ var xStart = Math.max(heatmapX - localMaximumRadius, 0);
+ var xEnd = Math.min(heatmapX + localMaximumRadius + 1, width);
+ for (var xCurrent = xStart; xCurrent < xEnd; ++xCurrent) {
+ if (scores.get(yCurrent, xCurrent, keypointId) > score) {
+ localMaximum = false;
+ break;
+ }
+ }
+ if (!localMaximum) {
+ break;
+ }
+ }
+ return localMaximum;
+}
+/**
+ * Builds a priority queue with part candidate positions for a specific image in
+ * the batch. For this we find all local maxima in the score maps with score
+ * values above a threshold. We create a single priority queue across all parts.
+ */
+function buildPartWithScoreQueue(scoreThreshold, localMaximumRadius, scores) {
+ var _a = scores.shape, height = _a[0], width = _a[1], numKeypoints = _a[2];
+ var queue = new max_heap_1.MaxHeap(height * width * numKeypoints, function (_a) {
+ var score = _a.score;
+ return score;
+ });
+ for (var heatmapY = 0; heatmapY < height; ++heatmapY) {
+ for (var heatmapX = 0; heatmapX < width; ++heatmapX) {
+ for (var keypointId = 0; keypointId < numKeypoints; ++keypointId) {
+ var score = scores.get(heatmapY, heatmapX, keypointId);
+ // Only consider parts with score greater or equal to threshold as
+ // root candidates.
+ if (score < scoreThreshold) {
+ continue;
+ }
+ // Only consider keypoints whose score is maximum in a local window.
+ if (scoreIsMaximumInLocalWindow(keypointId, score, heatmapY, heatmapX, localMaximumRadius, scores)) {
+ queue.enqueue({ score: score, part: { heatmapY: heatmapY, heatmapX: heatmapX, id: keypointId } });
+ }
+ }
+ }
+ }
+ return queue;
+}
+exports.buildPartWithScoreQueue = buildPartWithScoreQueue;
+//# sourceMappingURL=build_part_with_score_queue.js.map
\ No newline at end of file
diff --git a/modules/posenet/multi_pose/build_part_with_score_queue.js.map b/modules/posenet/multi_pose/build_part_with_score_queue.js.map
new file mode 100644
index 0000000..85f8084
--- /dev/null
+++ b/modules/posenet/multi_pose/build_part_with_score_queue.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"build_part_with_score_queue.js","sourceRoot":"","sources":["../../src/multi_pose/build_part_with_score_queue.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;AAIH,uCAAmC;AAEnC,SAAS,2BAA2B,CAChC,UAAkB,EAAE,KAAa,EAAE,QAAgB,EAAE,QAAgB,EACrE,kBAA0B,EAAE,MAAsB;IAC9C,IAAA,iBAA8B,EAA7B,cAAM,EAAE,aAAqB,CAAC;IAErC,IAAI,YAAY,GAAG,IAAI,CAAC;IACxB,IAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,kBAAkB,EAAE,CAAC,CAAC,CAAC;IAC1D,IAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,kBAAkB,GAAG,CAAC,EAAE,MAAM,CAAC,CAAC;IACjE,KAAK,IAAI,QAAQ,GAAG,MAAM,EAAE,QAAQ,GAAG,IAAI,EAAE,EAAE,QAAQ,EAAE;QACvD,IAAM,MAAM,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,kBAAkB,EAAE,CAAC,CAAC,CAAC;QAC1D,IAAM,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,QAAQ,GAAG,kBAAkB,GAAG,CAAC,EAAE,KAAK,CAAC,CAAC;QAChE,KAAK,IAAI,QAAQ,GAAG,MAAM,EAAE,QAAQ,GAAG,IAAI,EAAE,EAAE,QAAQ,EAAE;YACvD,IAAI,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,CAAC,GAAG,KAAK,EAAE;gBACtD,YAAY,GAAG,KAAK,CAAC;gBACrB,MAAM;aACP;SACF;QACD,IAAI,CAAC,YAAY,EAAE;YACjB,MAAM;SACP;KACF;IAED,OAAO,YAAY,CAAC;AACtB,CAAC;AAED;;;;GAIG;AACH,SAAgB,uBAAuB,CACnC,cAAsB,EAAE,kBAA0B,EAClD,MAAsB;IAClB,IAAA,iBAA4C,EAA3C,cAAM,EAAE,aAAK,EAAE,oBAA4B,CAAC;IAEnD,IAAM,KAAK,GAAG,IAAI,kBAAO,CACrB,MAAM,GAAG,KAAK,GAAG,YAAY,EAAE,UAAC,EAAO;YAAN,gBAAK;QAAM,OAAA,KAAK;IAAL,CAAK,CAAC,CAAC;IAEvD,KAAK,IAAI,QAAQ,GAAG,CAAC,EAAE,QAAQ,GAAG,MAAM,EAAE,EAAE,QAAQ,EAAE;QACpD,KAAK,IAAI,QAAQ,GAAG,CAAC,EAAE,QAAQ,GAAG,KAAK,EAAE,EAAE,QAAQ,EAAE;YACnD,KAAK,IAAI,UAAU,GAAG,CAAC,EAAE,UAAU,GAAG,YAAY,EAAE,EAAE,UAAU,EAAE;gBAChE,IAAM,KAAK,GAAG,MAAM,CAAC,GAAG,CAAC,QAAQ,EAAE,QAAQ,EAAE,UAAU,CAAC,CAAC;gBAEzD,kEAAkE;gBAClE,mBAAmB;gBACnB,IAAI,KAAK,GAAG,cAAc,EAAE;oBAC1B,SAAS;iBACV;gBAED,oEAAoE;gBACpE,IAAI,2BAA2B,CACvB,UAAU,EAAE,KAAK,EAAE,QAAQ,EAAE,QAAQ,EAAE,kBAAkB,EACzD,MAAM,CAAC,EAAE;oBACf,KAAK,CAAC,OAAO,CAAC,EAAC,KAAK,OAAA,EAAE,IAAI,EAAE,EAAC,QAAQ,UAAA,EAAE,QAAQ,UAAA,EAAE,EAAE,EAAE,UAAU,EAAC,EAAC,CAAC,CAAC;iBACpE;aACF;SACF;KACF;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AA9BD,0DA8BC"}
\ No newline at end of file
diff --git a/modules/posenet/multi_pose/decode_multiple_poses.d.ts b/modules/posenet/multi_pose/decode_multiple_poses.d.ts
new file mode 100644
index 0000000..6f54241
--- /dev/null
+++ b/modules/posenet/multi_pose/decode_multiple_poses.d.ts
@@ -0,0 +1,73 @@
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+import { Pose, TensorBuffer3D } from '../types';
+/**
+ * Detects multiple poses and finds their parts from part scores and
+ * displacement vectors. It returns up to `maxDetections` object instance
+ * detections in decreasing root score order. It works as follows: We first
+ * create a priority queue with local part score maxima above
+ * `scoreThreshold`, considering all parts at the same time. Then we
+ * iteratively pull the top element of the queue (in decreasing score order)
+ * and treat it as a root candidate for a new object instance. To avoid
+ * duplicate detections, we reject the root candidate if it is within a disk
+ * of `nmsRadius` pixels from the corresponding part of a previously detected
+ * instance, which is a form of part-based non-maximum suppression (NMS). If
+ * the root candidate passes the NMS check, we start a new object instance
+ * detection, treating the corresponding part as root and finding the
+ * positions of the remaining parts by following the displacement vectors
+ * along the tree-structured part graph. We assign to the newly detected
+ * instance a score equal to the sum of scores of its parts which have not
+ * been claimed by a previous instance (i.e., those at least `nmsRadius`
+ * pixels away from the corresponding part of all previously detected
+ * instances), divided by the total number of parts `numParts`.
+ *
+ * @param heatmapScores 3-D tensor with shape `[height, width, numParts]`.
+ * The value of heatmapScores[y, x, k]` is the score of placing the `k`-th
+ * object part at position `(y, x)`.
+ *
+ * @param offsets 3-D tensor with shape `[height, width, numParts * 2]`.
+ * The value of [offsets[y, x, k], offsets[y, x, k + numParts]]` is the
+ * short range offset vector of the `k`-th object part at heatmap
+ * position `(y, x)`.
+ *
+ * @param displacementsFwd 3-D tensor of shape
+ * `[height, width, 2 * num_edges]`, where `num_edges = num_parts - 1` is the
+ * number of edges (parent-child pairs) in the tree. It contains the forward
+ * displacements between consecutive part from the root towards the leaves.
+ *
+ * @param displacementsBwd 3-D tensor of shape
+ * `[height, width, 2 * num_edges]`, where `num_edges = num_parts - 1` is the
+ * number of edges (parent-child pairs) in the tree. It contains the backward
+ * displacements between consecutive part from the root towards the leaves.
+ *
+ * @param outputStride The output stride that was used when feed-forwarding
+ * through the PoseNet model. Must be 32, 16, or 8.
+ *
+ * @param maxPoseDetections Maximum number of returned instance detections per
+ * image.
+ *
+ * @param scoreThreshold Only return instance detections that have root part
+ * score greater or equal to this value. Defaults to 0.5.
+ *
+ * @param nmsRadius Non-maximum suppression part distance. It needs to be
+ * strictly positive. Two parts suppress each other if they are less than
+ * `nmsRadius` pixels away. Defaults to 20.
+ *
+ * @return An array of poses and their scores, each containing keypoints and
+ * the corresponding keypoint scores.
+ */
+export declare function decodeMultiplePoses(scoresBuffer: TensorBuffer3D, offsetsBuffer: TensorBuffer3D, displacementsFwdBuffer: TensorBuffer3D, displacementsBwdBuffer: TensorBuffer3D, outputStride: number, maxPoseDetections: number, scoreThreshold?: number, nmsRadius?: number): Pose[];
diff --git a/modules/posenet/multi_pose/decode_multiple_poses.js b/modules/posenet/multi_pose/decode_multiple_poses.js
new file mode 100644
index 0000000..626f5b3
--- /dev/null
+++ b/modules/posenet/multi_pose/decode_multiple_poses.js
@@ -0,0 +1,130 @@
+"use strict";
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+Object.defineProperty(exports, "__esModule", { value: true });
+var build_part_with_score_queue_1 = require("./build_part_with_score_queue");
+var decode_pose_1 = require("./decode_pose");
+var util_1 = require("./util");
+function withinNmsRadiusOfCorrespondingPoint(poses, squaredNmsRadius, _a, keypointId) {
+ var x = _a.x, y = _a.y;
+ return poses.some(function (_a) {
+ var keypoints = _a.keypoints;
+ var correspondingKeypoint = keypoints[keypointId].position;
+ return util_1.squaredDistance(y, x, correspondingKeypoint.y, correspondingKeypoint.x) <=
+ squaredNmsRadius;
+ });
+}
+/* Score the newly proposed object instance without taking into account
+ * the scores of the parts that overlap with any previously detected
+ * instance.
+ */
+function getInstanceScore(existingPoses, squaredNmsRadius, instanceKeypoints) {
+ var notOverlappedKeypointScores = instanceKeypoints.reduce(function (result, _a, keypointId) {
+ var position = _a.position, score = _a.score;
+ if (!withinNmsRadiusOfCorrespondingPoint(existingPoses, squaredNmsRadius, position, keypointId)) {
+ result += score;
+ }
+ return result;
+ }, 0.0);
+ return notOverlappedKeypointScores /= instanceKeypoints.length;
+}
+// A point (y, x) is considered as root part candidate if its score is a
+// maximum in a window |y - y'| <= kLocalMaximumRadius, |x - x'| <=
+// kLocalMaximumRadius.
+var kLocalMaximumRadius = 1;
+/**
+ * Detects multiple poses and finds their parts from part scores and
+ * displacement vectors. It returns up to `maxDetections` object instance
+ * detections in decreasing root score order. It works as follows: We first
+ * create a priority queue with local part score maxima above
+ * `scoreThreshold`, considering all parts at the same time. Then we
+ * iteratively pull the top element of the queue (in decreasing score order)
+ * and treat it as a root candidate for a new object instance. To avoid
+ * duplicate detections, we reject the root candidate if it is within a disk
+ * of `nmsRadius` pixels from the corresponding part of a previously detected
+ * instance, which is a form of part-based non-maximum suppression (NMS). If
+ * the root candidate passes the NMS check, we start a new object instance
+ * detection, treating the corresponding part as root and finding the
+ * positions of the remaining parts by following the displacement vectors
+ * along the tree-structured part graph. We assign to the newly detected
+ * instance a score equal to the sum of scores of its parts which have not
+ * been claimed by a previous instance (i.e., those at least `nmsRadius`
+ * pixels away from the corresponding part of all previously detected
+ * instances), divided by the total number of parts `numParts`.
+ *
+ * @param heatmapScores 3-D tensor with shape `[height, width, numParts]`.
+ * The value of heatmapScores[y, x, k]` is the score of placing the `k`-th
+ * object part at position `(y, x)`.
+ *
+ * @param offsets 3-D tensor with shape `[height, width, numParts * 2]`.
+ * The value of [offsets[y, x, k], offsets[y, x, k + numParts]]` is the
+ * short range offset vector of the `k`-th object part at heatmap
+ * position `(y, x)`.
+ *
+ * @param displacementsFwd 3-D tensor of shape
+ * `[height, width, 2 * num_edges]`, where `num_edges = num_parts - 1` is the
+ * number of edges (parent-child pairs) in the tree. It contains the forward
+ * displacements between consecutive part from the root towards the leaves.
+ *
+ * @param displacementsBwd 3-D tensor of shape
+ * `[height, width, 2 * num_edges]`, where `num_edges = num_parts - 1` is the
+ * number of edges (parent-child pairs) in the tree. It contains the backward
+ * displacements between consecutive part from the root towards the leaves.
+ *
+ * @param outputStride The output stride that was used when feed-forwarding
+ * through the PoseNet model. Must be 32, 16, or 8.
+ *
+ * @param maxPoseDetections Maximum number of returned instance detections per
+ * image.
+ *
+ * @param scoreThreshold Only return instance detections that have root part
+ * score greater or equal to this value. Defaults to 0.5.
+ *
+ * @param nmsRadius Non-maximum suppression part distance. It needs to be
+ * strictly positive. Two parts suppress each other if they are less than
+ * `nmsRadius` pixels away. Defaults to 20.
+ *
+ * @return An array of poses and their scores, each containing keypoints and
+ * the corresponding keypoint scores.
+ */
+function decodeMultiplePoses(scoresBuffer, offsetsBuffer, displacementsFwdBuffer, displacementsBwdBuffer, outputStride, maxPoseDetections, scoreThreshold, nmsRadius) {
+ if (scoreThreshold === void 0) { scoreThreshold = 0.5; }
+ if (nmsRadius === void 0) { nmsRadius = 20; }
+ var poses = [];
+ var queue = build_part_with_score_queue_1.buildPartWithScoreQueue(scoreThreshold, kLocalMaximumRadius, scoresBuffer);
+ var squaredNmsRadius = nmsRadius * nmsRadius;
+ // Generate at most maxDetections object instances per image in
+ // decreasing root part score order.
+ while (poses.length < maxPoseDetections && !queue.empty()) {
+ // The top element in the queue is the next root candidate.
+ var root = queue.dequeue();
+ // Part-based non-maximum suppression: We reject a root candidate if it
+ // is within a disk of `nmsRadius` pixels from the corresponding part of
+ // a previously detected instance.
+ var rootImageCoords = util_1.getImageCoords(root.part, outputStride, offsetsBuffer);
+ if (withinNmsRadiusOfCorrespondingPoint(poses, squaredNmsRadius, rootImageCoords, root.part.id)) {
+ continue;
+ }
+ // Start a new detection instance at the position of the root.
+ var keypoints = decode_pose_1.decodePose(root, scoresBuffer, offsetsBuffer, outputStride, displacementsFwdBuffer, displacementsBwdBuffer);
+ var score = getInstanceScore(poses, squaredNmsRadius, keypoints);
+ poses.push({ keypoints: keypoints, score: score });
+ }
+ return poses;
+}
+exports.decodeMultiplePoses = decodeMultiplePoses;
+//# sourceMappingURL=decode_multiple_poses.js.map
\ No newline at end of file
diff --git a/modules/posenet/multi_pose/decode_multiple_poses.js.map b/modules/posenet/multi_pose/decode_multiple_poses.js.map
new file mode 100644
index 0000000..ac86ad2
--- /dev/null
+++ b/modules/posenet/multi_pose/decode_multiple_poses.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"decode_multiple_poses.js","sourceRoot":"","sources":["../../src/multi_pose/decode_multiple_poses.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;AAIH,6EAAsE;AACtE,6CAAyC;AACzC,+BAAuD;AAEvD,SAAS,mCAAmC,CACxC,KAAa,EAAE,gBAAwB,EAAE,EAA8B,EACvE,UAAkB;QADwB,QAAC,EAAE,QAAC;IAEhD,OAAO,KAAK,CAAC,IAAI,CAAC,UAAC,EAAW;YAAV,wBAAS;QAC3B,IAAM,qBAAqB,GAAG,SAAS,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC;QAC7D,OAAO,sBAAe,CACX,CAAC,EAAE,CAAC,EAAE,qBAAqB,CAAC,CAAC,EAAE,qBAAqB,CAAC,CAAC,CAAC;YAC9D,gBAAgB,CAAC;IACvB,CAAC,CAAC,CAAC;AACL,CAAC;AAED;;;GAGG;AACH,SAAS,gBAAgB,CACrB,aAAqB,EAAE,gBAAwB,EAC/C,iBAA6B;IAC/B,IAAI,2BAA2B,GAAG,iBAAiB,CAAC,MAAM,CACtD,UAAC,MAAM,EAAE,EAAiB,EAAE,UAAU;YAA5B,sBAAQ,EAAE,gBAAK;QACvB,IAAI,CAAC,mCAAmC,CAChC,aAAa,EAAE,gBAAgB,EAAE,QAAQ,EAAE,UAAU,CAAC,EAAE;YAC9D,MAAM,IAAI,KAAK,CAAC;SACjB;QACD,OAAO,MAAM,CAAC;IAChB,CAAC,EAAE,GAAG,CAAC,CAAC;IAEZ,OAAO,2BAA2B,IAAI,iBAAiB,CAAC,MAAM,CAAC;AACjE,CAAC;AAED,wEAAwE;AACxE,mEAAmE;AACnE,uBAAuB;AACvB,IAAM,mBAAmB,GAAG,CAAC,CAAC;AAE9B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAsDG;AACH,SAAgB,mBAAmB,CAC/B,YAA4B,EAAE,aAA6B,EAC3D,sBAAsC,EACtC,sBAAsC,EAAE,YAAoB,EAC5D,iBAAyB,EAAE,cAAoB,EAAE,SAAc;IAApC,+BAAA,EAAA,oBAAoB;IAAE,0BAAA,EAAA,cAAc;IACjE,IAAM,KAAK,GAAW,EAAE,CAAC;IAEzB,IAAM,KAAK,GAAG,qDAAuB,CACjC,cAAc,EAAE,mBAAmB,EAAE,YAAY,CAAC,CAAC;IAEvD,IAAM,gBAAgB,GAAG,SAAS,GAAG,SAAS,CAAC;IAE/C,+DAA+D;IAC/D,oCAAoC;IACpC,OAAO,KAAK,CAAC,MAAM,GAAG,iBAAiB,IAAI,CAAC,KAAK,CAAC,KAAK,EAAE,EAAE;QACzD,2DAA2D;QAC3D,IAAM,IAAI,GAAG,KAAK,CAAC,OAAO,EAAE,CAAC;QAE7B,uEAAuE;QACvE,wEAAwE;QACxE,kCAAkC;QAClC,IAAM,eAAe,GACjB,qBAAc,CAAC,IAAI,CAAC,IAAI,EAAE,YAAY,EAAE,aAAa,CAAC,CAAC;QAC3D,IAAI,mCAAmC,CAC/B,KAAK,EAAE,gBAAgB,EAAE,eAAe,EAAE,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE;YAC/D,SAAS;SACV;QAED,8DAA8D;QAC9D,IAAM,SAAS,GAAG,wBAAU,CACxB,IAAI,EAAE,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,sBAAsB,EACvE,sBAAsB,CAAC,CAAC;QAE5B,IAAM,KAAK,GAAG,gBAAgB,CAAC,KAAK,EAAE,gBAAgB,EAAE,SAAS,CAAC,CAAC;QAEnE,KAAK,CAAC,IAAI,CAAC,EAAC,SAAS,WAAA,EAAE,KAAK,OAAA,EAAC,CAAC,CAAC;KAChC;IAED,OAAO,KAAK,CAAC;AACf,CAAC;AAvCD,kDAuCC"}
\ No newline at end of file
diff --git a/modules/posenet/multi_pose/decode_pose.d.ts b/modules/posenet/multi_pose/decode_pose.d.ts
new file mode 100644
index 0000000..15c4cef
--- /dev/null
+++ b/modules/posenet/multi_pose/decode_pose.d.ts
@@ -0,0 +1,24 @@
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+import { Keypoint, PartWithScore, TensorBuffer3D } from '../types';
+/**
+ * Follows the displacement fields to decode the full pose of the object
+ * instance given the position of a part that acts as root.
+ *
+ * @return An array of decoded keypoints and their scores for a single pose
+ */
+export declare function decodePose(root: PartWithScore, scores: TensorBuffer3D, offsets: TensorBuffer3D, outputStride: number, displacementsFwd: TensorBuffer3D, displacementsBwd: TensorBuffer3D): Keypoint[];
diff --git a/modules/posenet/multi_pose/decode_pose.js b/modules/posenet/multi_pose/decode_pose.js
new file mode 100644
index 0000000..8d96c4c
--- /dev/null
+++ b/modules/posenet/multi_pose/decode_pose.js
@@ -0,0 +1,115 @@
+"use strict";
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+Object.defineProperty(exports, "__esModule", { value: true });
+var keypoints_1 = require("../keypoints");
+var util_1 = require("./util");
+var util_2 = require("./util");
+var parentChildrenTuples = keypoints_1.poseChain.map(function (_a) {
+ var parentJoinName = _a[0], childJoinName = _a[1];
+ return ([keypoints_1.partIds[parentJoinName], keypoints_1.partIds[childJoinName]]);
+});
+var parentToChildEdges = parentChildrenTuples.map(function (_a) {
+ var childJointId = _a[1];
+ return childJointId;
+});
+var childToParentEdges = parentChildrenTuples.map(function (_a) {
+ var parentJointId = _a[0];
+ return parentJointId;
+});
+function getDisplacement(edgeId, point, displacements) {
+ var numEdges = displacements.shape[2] / 2;
+ return {
+ y: displacements.get(point.y, point.x, edgeId),
+ x: displacements.get(point.y, point.x, numEdges + edgeId)
+ };
+}
+function getStridedIndexNearPoint(point, outputStride, height, width) {
+ return {
+ y: util_1.clamp(Math.round(point.y / outputStride), 0, height - 1),
+ x: util_1.clamp(Math.round(point.x / outputStride), 0, width - 1)
+ };
+}
+/**
+ * We get a new keypoint along the `edgeId` for the pose instance, assuming
+ * that the position of the `idSource` part is already known. For this, we
+ * follow the displacement vector from the source to target part (stored in
+ * the `i`-t channel of the displacement tensor). The displaced keypoint
+ * vector is refined using the offset vector by `offsetRefineStep` times.
+ */
+function traverseToTargetKeypoint(edgeId, sourceKeypoint, targetKeypointId, scoresBuffer, offsets, outputStride, displacements, offsetRefineStep) {
+ if (offsetRefineStep === void 0) { offsetRefineStep = 2; }
+ var _a = scoresBuffer.shape, height = _a[0], width = _a[1];
+ // Nearest neighbor interpolation for the source->target displacements.
+ var sourceKeypointIndices = getStridedIndexNearPoint(sourceKeypoint.position, outputStride, height, width);
+ var displacement = getDisplacement(edgeId, sourceKeypointIndices, displacements);
+ var displacedPoint = util_2.addVectors(sourceKeypoint.position, displacement);
+ var targetKeypoint = displacedPoint;
+ for (var i = 0; i < offsetRefineStep; i++) {
+ var targetKeypointIndices = getStridedIndexNearPoint(targetKeypoint, outputStride, height, width);
+ var offsetPoint = util_1.getOffsetPoint(targetKeypointIndices.y, targetKeypointIndices.x, targetKeypointId, offsets);
+ targetKeypoint = util_2.addVectors({
+ x: targetKeypointIndices.x * outputStride,
+ y: targetKeypointIndices.y * outputStride
+ }, { x: offsetPoint.x, y: offsetPoint.y });
+ }
+ var targetKeyPointIndices = getStridedIndexNearPoint(targetKeypoint, outputStride, height, width);
+ var score = scoresBuffer.get(targetKeyPointIndices.y, targetKeyPointIndices.x, targetKeypointId);
+ return { position: targetKeypoint, part: keypoints_1.partNames[targetKeypointId], score: score };
+}
+/**
+ * Follows the displacement fields to decode the full pose of the object
+ * instance given the position of a part that acts as root.
+ *
+ * @return An array of decoded keypoints and their scores for a single pose
+ */
+function decodePose(root, scores, offsets, outputStride, displacementsFwd, displacementsBwd) {
+ var numParts = scores.shape[2];
+ var numEdges = parentToChildEdges.length;
+ var instanceKeypoints = new Array(numParts);
+ // Start a new detection instance at the position of the root.
+ var rootPart = root.part, rootScore = root.score;
+ var rootPoint = util_2.getImageCoords(rootPart, outputStride, offsets);
+ instanceKeypoints[rootPart.id] = {
+ score: rootScore,
+ part: keypoints_1.partNames[rootPart.id],
+ position: rootPoint
+ };
+ // Decode the part positions upwards in the tree, following the backward
+ // displacements.
+ for (var edge = numEdges - 1; edge >= 0; --edge) {
+ var sourceKeypointId = parentToChildEdges[edge];
+ var targetKeypointId = childToParentEdges[edge];
+ if (instanceKeypoints[sourceKeypointId] &&
+ !instanceKeypoints[targetKeypointId]) {
+ instanceKeypoints[targetKeypointId] = traverseToTargetKeypoint(edge, instanceKeypoints[sourceKeypointId], targetKeypointId, scores, offsets, outputStride, displacementsBwd);
+ }
+ }
+ // Decode the part positions downwards in the tree, following the forward
+ // displacements.
+ for (var edge = 0; edge < numEdges; ++edge) {
+ var sourceKeypointId = childToParentEdges[edge];
+ var targetKeypointId = parentToChildEdges[edge];
+ if (instanceKeypoints[sourceKeypointId] &&
+ !instanceKeypoints[targetKeypointId]) {
+ instanceKeypoints[targetKeypointId] = traverseToTargetKeypoint(edge, instanceKeypoints[sourceKeypointId], targetKeypointId, scores, offsets, outputStride, displacementsFwd);
+ }
+ }
+ return instanceKeypoints;
+}
+exports.decodePose = decodePose;
+//# sourceMappingURL=decode_pose.js.map
\ No newline at end of file
diff --git a/modules/posenet/multi_pose/decode_pose.js.map b/modules/posenet/multi_pose/decode_pose.js.map
new file mode 100644
index 0000000..2738899
--- /dev/null
+++ b/modules/posenet/multi_pose/decode_pose.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"decode_pose.js","sourceRoot":"","sources":["../../src/multi_pose/decode_pose.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/modules/posenet/multi_pose/max_heap.d.ts b/modules/posenet/multi_pose/max_heap.d.ts
new file mode 100644
index 0000000..78858d7
--- /dev/null
+++ b/modules/posenet/multi_pose/max_heap.d.ts
@@ -0,0 +1,33 @@
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+export declare class MaxHeap {
+ private priorityQueue;
+ private numberOfElements;
+ private getElementValue;
+ constructor(maxSize: number, getElementValue: (element: T) => number);
+ enqueue(x: T): void;
+ dequeue(): T;
+ empty(): boolean;
+ size(): number;
+ all(): T[];
+ max(): T;
+ private swim;
+ private sink;
+ private getValueAt;
+ private less;
+ private exchange;
+}
diff --git a/modules/posenet/multi_pose/max_heap.js b/modules/posenet/multi_pose/max_heap.js
new file mode 100644
index 0000000..2471352
--- /dev/null
+++ b/modules/posenet/multi_pose/max_heap.js
@@ -0,0 +1,86 @@
+"use strict";
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+Object.defineProperty(exports, "__esModule", { value: true });
+// algorithm based on Coursera Lecture from Algorithms, Part 1:
+// https://www.coursera.org/learn/algorithms-part1/lecture/ZjoSM/heapsort
+function half(k) {
+ return Math.floor(k / 2);
+}
+var MaxHeap = /** @class */ (function () {
+ function MaxHeap(maxSize, getElementValue) {
+ this.priorityQueue = new Array(maxSize);
+ this.numberOfElements = -1;
+ this.getElementValue = getElementValue;
+ }
+ MaxHeap.prototype.enqueue = function (x) {
+ this.priorityQueue[++this.numberOfElements] = x;
+ this.swim(this.numberOfElements);
+ };
+ MaxHeap.prototype.dequeue = function () {
+ var max = this.priorityQueue[0];
+ this.exchange(0, this.numberOfElements--);
+ this.sink(0);
+ this.priorityQueue[this.numberOfElements + 1] = null;
+ return max;
+ };
+ MaxHeap.prototype.empty = function () {
+ return this.numberOfElements === -1;
+ };
+ MaxHeap.prototype.size = function () {
+ return this.numberOfElements + 1;
+ };
+ MaxHeap.prototype.all = function () {
+ return this.priorityQueue.slice(0, this.numberOfElements + 1);
+ };
+ MaxHeap.prototype.max = function () {
+ return this.priorityQueue[0];
+ };
+ MaxHeap.prototype.swim = function (k) {
+ while (k > 0 && this.less(half(k), k)) {
+ this.exchange(k, half(k));
+ k = half(k);
+ }
+ };
+ MaxHeap.prototype.sink = function (k) {
+ while (2 * k <= this.numberOfElements) {
+ var j = 2 * k;
+ if (j < this.numberOfElements && this.less(j, j + 1)) {
+ j++;
+ }
+ if (!this.less(k, j)) {
+ break;
+ }
+ this.exchange(k, j);
+ k = j;
+ }
+ };
+ MaxHeap.prototype.getValueAt = function (i) {
+ return this.getElementValue(this.priorityQueue[i]);
+ };
+ MaxHeap.prototype.less = function (i, j) {
+ return this.getValueAt(i) < this.getValueAt(j);
+ };
+ MaxHeap.prototype.exchange = function (i, j) {
+ var t = this.priorityQueue[i];
+ this.priorityQueue[i] = this.priorityQueue[j];
+ this.priorityQueue[j] = t;
+ };
+ return MaxHeap;
+}());
+exports.MaxHeap = MaxHeap;
+//# sourceMappingURL=max_heap.js.map
\ No newline at end of file
diff --git a/modules/posenet/multi_pose/max_heap.js.map b/modules/posenet/multi_pose/max_heap.js.map
new file mode 100644
index 0000000..3864615
--- /dev/null
+++ b/modules/posenet/multi_pose/max_heap.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"max_heap.js","sourceRoot":"","sources":["../../src/multi_pose/max_heap.ts"],"names":[],"mappings":"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"}
\ No newline at end of file
diff --git a/modules/posenet/multi_pose/util.d.ts b/modules/posenet/multi_pose/util.d.ts
new file mode 100644
index 0000000..5b6c661
--- /dev/null
+++ b/modules/posenet/multi_pose/util.d.ts
@@ -0,0 +1,24 @@
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+import { Part, TensorBuffer3D, Vector2D } from '../types';
+export declare function getOffsetPoint(y: number, x: number, keypoint: number, offsets: TensorBuffer3D): Vector2D;
+export declare function getImageCoords(part: Part, outputStride: number, offsets: TensorBuffer3D): Vector2D;
+export declare function fillArray(element: T, size: number): T[];
+export declare function clamp(a: number, min: number, max: number): number;
+export declare function squaredDistance(y1: number, x1: number, y2: number, x2: number): number;
+export declare function addVectors(a: Vector2D, b: Vector2D): Vector2D;
+export declare function clampVector(a: Vector2D, min: number, max: number): Vector2D;
diff --git a/modules/posenet/multi_pose/util.js b/modules/posenet/multi_pose/util.js
new file mode 100644
index 0000000..adbd3aa
--- /dev/null
+++ b/modules/posenet/multi_pose/util.js
@@ -0,0 +1,68 @@
+"use strict";
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+Object.defineProperty(exports, "__esModule", { value: true });
+var keypoints_1 = require("../keypoints");
+function getOffsetPoint(y, x, keypoint, offsets) {
+ return {
+ y: offsets.get(y, x, keypoint),
+ x: offsets.get(y, x, keypoint + keypoints_1.NUM_KEYPOINTS)
+ };
+}
+exports.getOffsetPoint = getOffsetPoint;
+function getImageCoords(part, outputStride, offsets) {
+ var heatmapY = part.heatmapY, heatmapX = part.heatmapX, keypoint = part.id;
+ var _a = getOffsetPoint(heatmapY, heatmapX, keypoint, offsets), y = _a.y, x = _a.x;
+ return {
+ x: part.heatmapX * outputStride + x,
+ y: part.heatmapY * outputStride + y
+ };
+}
+exports.getImageCoords = getImageCoords;
+function fillArray(element, size) {
+ var result = new Array(size);
+ for (var i = 0; i < size; i++) {
+ result[i] = element;
+ }
+ return result;
+}
+exports.fillArray = fillArray;
+function clamp(a, min, max) {
+ if (a < min) {
+ return min;
+ }
+ if (a > max) {
+ return max;
+ }
+ return a;
+}
+exports.clamp = clamp;
+function squaredDistance(y1, x1, y2, x2) {
+ var dy = y2 - y1;
+ var dx = x2 - x1;
+ return dy * dy + dx * dx;
+}
+exports.squaredDistance = squaredDistance;
+function addVectors(a, b) {
+ return { x: a.x + b.x, y: a.y + b.y };
+}
+exports.addVectors = addVectors;
+function clampVector(a, min, max) {
+ return { y: clamp(a.y, min, max), x: clamp(a.x, min, max) };
+}
+exports.clampVector = clampVector;
+//# sourceMappingURL=util.js.map
\ No newline at end of file
diff --git a/modules/posenet/multi_pose/util.js.map b/modules/posenet/multi_pose/util.js.map
new file mode 100644
index 0000000..f35088e
--- /dev/null
+++ b/modules/posenet/multi_pose/util.js.map
@@ -0,0 +1 @@
+{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/multi_pose/util.ts"],"names":[],"mappings":";AAAA;;;;;;;;;;;;;;;GAeG;;AAEH,0CAA2C;AAG3C,SAAgB,cAAc,CAC1B,CAAS,EAAE,CAAS,EAAE,QAAgB,EAAE,OAAuB;IACjE,OAAO;QACL,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,CAAC;QAC9B,CAAC,EAAE,OAAO,CAAC,GAAG,CAAC,CAAC,EAAE,CAAC,EAAE,QAAQ,GAAG,yBAAa,CAAC;KAC/C,CAAC;AACJ,CAAC;AAND,wCAMC;AAED,SAAgB,cAAc,CAC1B,IAAU,EAAE,YAAoB,EAAE,OAAuB;IACpD,IAAA,wBAAQ,EAAE,wBAAQ,EAAE,kBAAY,CAAS;IAC1C,IAAA,0DAA8D,EAA7D,QAAC,EAAE,QAA0D,CAAC;IACrE,OAAO;QACL,CAAC,EAAE,IAAI,CAAC,QAAQ,GAAG,YAAY,GAAG,CAAC;QACnC,CAAC,EAAE,IAAI,CAAC,QAAQ,GAAG,YAAY,GAAG,CAAC;KACpC,CAAC;AACJ,CAAC;AARD,wCAQC;AAED,SAAgB,SAAS,CAAI,OAAU,EAAE,IAAY;IACnD,IAAM,MAAM,GAAQ,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC;IAEpC,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,IAAI,EAAE,CAAC,EAAE,EAAE;QAC7B,MAAM,CAAC,CAAC,CAAC,GAAG,OAAO,CAAC;KACrB;IAED,OAAO,MAAM,CAAC;AAChB,CAAC;AARD,8BAQC;AAED,SAAgB,KAAK,CAAC,CAAS,EAAE,GAAW,EAAE,GAAW;IACvD,IAAI,CAAC,GAAG,GAAG,EAAE;QACX,OAAO,GAAG,CAAC;KACZ;IACD,IAAI,CAAC,GAAG,GAAG,EAAE;QACX,OAAO,GAAG,CAAC;KACZ;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AARD,sBAQC;AAED,SAAgB,eAAe,CAC3B,EAAU,EAAE,EAAU,EAAE,EAAU,EAAE,EAAU;IAChD,IAAM,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IACnB,IAAM,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;IACnB,OAAO,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,CAAC;AAC3B,CAAC;AALD,0CAKC;AAED,SAAgB,UAAU,CAAC,CAAW,EAAE,CAAW;IACjD,OAAO,EAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAC,CAAC;AACtC,CAAC;AAFD,gCAEC;AAED,SAAgB,WAAW,CAAC,CAAW,EAAE,GAAW,EAAE,GAAW;IAC/D,OAAO,EAAC,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,EAAE,CAAC,EAAE,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,GAAG,CAAC,EAAC,CAAC;AAC5D,CAAC;AAFD,kCAEC"}
\ No newline at end of file
diff --git a/modules/posenet/posenet_model.d.ts b/modules/posenet/posenet_model.d.ts
new file mode 100644
index 0000000..6a7b2d4
--- /dev/null
+++ b/modules/posenet/posenet_model.d.ts
@@ -0,0 +1,167 @@
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+import { BaseModel } from './base_model';
+import { InputResolution, MobileNetMultiplier, Pose, PoseNetArchitecture, PosenetInput, PoseNetOutputStride, PoseNetQuantBytes } from './types';
+/**
+ * PoseNet model loading is configurable using the following config dictionary.
+ *
+ * `architecture`: PoseNetArchitecture. It determines wich PoseNet architecture
+ * to load. The supported architectures are: MobileNetV1 and ResNet.
+ *
+ * `outputStride`: Specifies the output stride of the PoseNet model.
+ * The smaller the value, the larger the output resolution, and more accurate
+ * the model at the cost of speed. Set this to a larger value to increase speed
+ * at the cost of accuracy. Stride 32 is supported for ResNet and
+ * stride 8,16,32 are supported for various MobileNetV1 models.
+ *
+ * * `inputResolution`: A number or an Object of type {width: number, height:
+ * number}. Specifies the size the input image is scaled to before feeding it
+ * through the PoseNet model. The larger the value, more accurate the model at
+ * the cost of speed. Set this to a smaller value to increase speed at the cost
+ * of accuracy. If a number is provided, the input will be resized and padded to
+ * be a square with the same width and height. If width and height are
+ * provided, the input will be resized and padded to the specified width and
+ * height.
+ *
+ * `multiplier`: An optional number with values: 1.01, 1.0, 0.75, or
+ * 0.50. The value is used only by MobileNet architecture. It is the float
+ * multiplier for the depth (number of channels) for all convolution ops.
+ * The larger the value, the larger the size of the layers, and more accurate
+ * the model at the cost of speed. Set this to a smaller value to increase speed
+ * at the cost of accuracy.
+ *
+ * `modelUrl`: An optional string that specifies custom url of the model. This
+ * is useful for area/countries that don't have access to the model hosted on
+ * GCP.
+ *
+ * `quantBytes`: An opional number with values: 1, 2, or 4. This parameter
+ * affects weight quantization in the models. The available options are
+ * 1 byte, 2 bytes, and 4 bytes. The higher the value, the larger the model size
+ * and thus the longer the loading time, the lower the value, the shorter the
+ * loading time but lower the accuracy.
+ */
+export interface ModelConfig {
+ architecture: PoseNetArchitecture;
+ outputStride: PoseNetOutputStride;
+ inputResolution: InputResolution;
+ multiplier?: MobileNetMultiplier;
+ modelUrl?: string;
+ quantBytes?: PoseNetQuantBytes;
+}
+/**
+ * PoseNet inference is configurable using the following config dictionary.
+ *
+ * `flipHorizontal`: If the poses should be flipped/mirrored horizontally.
+ * This should be set to true for videos where the video is by default flipped
+ * horizontally (i.e. a webcam), and you want the poses to be returned in the
+ * proper orientation.
+ *
+ */
+export interface InferenceConfig {
+ flipHorizontal: boolean;
+}
+/**
+ * Single Person Inference Config
+ */
+export interface SinglePersonInterfaceConfig extends InferenceConfig {
+}
+/**
+ * Multiple Person Inference Config
+ *
+ * `maxDetections`: Maximum number of returned instance detections per image.
+ *
+ * `scoreThreshold`: Only return instance detections that have root part
+ * score greater or equal to this value. Defaults to 0.5
+ *
+ * `nmsRadius`: Non-maximum suppression part distance in pixels. It needs
+ * to be strictly positive. Two parts suppress each other if they are less
+ * than `nmsRadius` pixels away. Defaults to 20.
+ */
+export interface MultiPersonInferenceConfig extends InferenceConfig {
+ maxDetections?: number;
+ scoreThreshold?: number;
+ nmsRadius?: number;
+}
+export interface LegacyMultiPersonInferenceConfig extends MultiPersonInferenceConfig {
+ decodingMethod: 'multi-person';
+}
+export interface LegacySinglePersonInferenceConfig extends SinglePersonInterfaceConfig {
+ decodingMethod: 'single-person';
+}
+export declare const SINGLE_PERSON_INFERENCE_CONFIG: SinglePersonInterfaceConfig;
+export declare const MULTI_PERSON_INFERENCE_CONFIG: MultiPersonInferenceConfig;
+export declare class PoseNet {
+ readonly baseModel: BaseModel;
+ readonly inputResolution: [number, number];
+ constructor(net: BaseModel, inputResolution: [number, number]);
+ /**
+ * Infer through PoseNet, and estimates multiple poses using the outputs.
+ * This does standard ImageNet pre-processing before inferring through the
+ * model. The image should pixels should have values [0-255]. It detects
+ * multiple poses and finds their parts from part scores and displacement
+ * vectors using a fast greedy decoding algorithm. It returns up to
+ * `config.maxDetections` object instance detections in decreasing root
+ * score order.
+ *
+ * @param input
+ * ImageData|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement) The input
+ * image to feed through the network.
+ *
+ * @param config MultiPoseEstimationConfig object that contains parameters
+ * for the PoseNet inference using multiple pose estimation.
+ *
+ * @return An array of poses and their scores, each containing keypoints and
+ * the corresponding keypoint scores. The positions of the keypoints are
+ * in the same scale as the original image
+ */
+ estimateMultiplePoses(input: PosenetInput, config?: MultiPersonInferenceConfig): Promise;
+ /**
+ * Infer through PoseNet, and estimates a single pose using the outputs.
+ * This does standard ImageNet pre-processing before inferring through the
+ * model. The image should pixels should have values [0-255]. It detects
+ * multiple poses and finds their parts from part scores and displacement
+ * vectors using a fast greedy decoding algorithm. It returns a single pose
+ *
+ * @param input
+ * ImageData|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement) The input
+ * image to feed through the network.
+ *
+ * @param config SinglePersonEstimationConfig object that contains
+ * parameters for the PoseNet inference using single pose estimation.
+ *
+ * @return An pose and its scores, containing keypoints and
+ * the corresponding keypoint scores. The positions of the keypoints are
+ * in the same scale as the original image
+ */
+ estimateSinglePose(input: PosenetInput, config?: SinglePersonInterfaceConfig): Promise;
+ /** Deprecated: Use either estimateSinglePose or estimateMultiplePoses */
+ estimatePoses(input: PosenetInput, config: LegacySinglePersonInferenceConfig | LegacyMultiPersonInferenceConfig): Promise;
+ dispose(): void;
+}
+/**
+ * Loads the PoseNet model instance from a checkpoint, with the ResNet
+ * or MobileNet architecture. The model to be loaded is configurable using the
+ * config dictionary ModelConfig. Please find more details in the
+ * documentation of the ModelConfig.
+ *
+ * @param config ModelConfig dictionary that contains parameters for
+ * the PoseNet loading process. Please find more details of each parameters
+ * in the documentation of the ModelConfig interface. The predefined
+ * `MOBILENET_V1_CONFIG` and `RESNET_CONFIG` can also be used as references
+ * for defining your customized config.
+ */
+export declare function load(config?: ModelConfig): Promise;
diff --git a/modules/posenet/posenet_model.js b/modules/posenet/posenet_model.js
new file mode 100644
index 0000000..fdf8563
--- /dev/null
+++ b/modules/posenet/posenet_model.js
@@ -0,0 +1,379 @@
+"use strict";
+/**
+ * @license
+ * Copyright 2019 Google LLC. All Rights Reserved.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ * =============================================================================
+ */
+var __assign = (this && this.__assign) || function () {
+ __assign = Object.assign || function(t) {
+ for (var s, i = 1, n = arguments.length; i < n; i++) {
+ s = arguments[i];
+ for (var p in s) if (Object.prototype.hasOwnProperty.call(s, p))
+ t[p] = s[p];
+ }
+ return t;
+ };
+ return __assign.apply(this, arguments);
+};
+var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
+ return new (P || (P = Promise))(function (resolve, reject) {
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
+ function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); }
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
+ });
+};
+var __generator = (this && this.__generator) || function (thisArg, body) {
+ var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g;
+ return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g;
+ function verb(n) { return function (v) { return step([n, v]); }; }
+ function step(op) {
+ if (f) throw new TypeError("Generator is already executing.");
+ while (_) try {
+ if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t;
+ if (y = 0, t) op = [op[0] & 2, t.value];
+ switch (op[0]) {
+ case 0: case 1: t = op; break;
+ case 4: _.label++; return { value: op[1], done: false };
+ case 5: _.label++; y = op[1]; op = [0]; continue;
+ case 7: op = _.ops.pop(); _.trys.pop(); continue;
+ default:
+ if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; }
+ if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; }
+ if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; }
+ if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; }
+ if (t[2]) _.ops.pop();
+ _.trys.pop(); continue;
+ }
+ op = body.call(thisArg, _);
+ } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; }
+ if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true };
+ }
+};
+Object.defineProperty(exports, "__esModule", { value: true });
+var tfconv = require("@tensorflow/tfjs-converter");
+var tf = require("@tensorflow/tfjs-core");
+var checkpoints_1 = require("./checkpoints");
+var mobilenet_1 = require("./mobilenet");
+var decode_multiple_poses_1 = require("./multi_pose/decode_multiple_poses");
+var resnet_1 = require("./resnet");
+var decode_single_pose_1 = require("./single_pose/decode_single_pose");
+var util_1 = require("./util");
+// The default configuration for loading MobileNetV1 based PoseNet.
+//
+// (And for references, the default configuration for loading ResNet
+// based PoseNet is also included).
+//
+// ```
+// const RESNET_CONFIG = {
+// architecture: 'ResNet50',
+// outputStride: 32,
+// quantBytes: 2,
+// } as ModelConfig;
+// ```
+var MOBILENET_V1_CONFIG = {
+ architecture: 'MobileNetV1',
+ outputStride: 16,
+ multiplier: 0.75,
+ inputResolution: 257,
+};
+var VALID_ARCHITECTURE = ['MobileNetV1', 'ResNet50'];
+var VALID_STRIDE = {
+ 'MobileNetV1': [8, 16, 32],
+ 'ResNet50': [32, 16]
+};
+var VALID_MULTIPLIER = {
+ 'MobileNetV1': [0.50, 0.75, 1.0],
+ 'ResNet50': [1.0]
+};
+var VALID_QUANT_BYTES = [1, 2, 4];
+function validateModelConfig(config) {
+ config = config || MOBILENET_V1_CONFIG;
+ if (config.architecture == null) {
+ config.architecture = 'MobileNetV1';
+ }
+ if (VALID_ARCHITECTURE.indexOf(config.architecture) < 0) {
+ throw new Error("Invalid architecture " + config.architecture + ". " +
+ ("Should be one of " + VALID_ARCHITECTURE));
+ }
+ if (config.inputResolution == null) {
+ config.inputResolution = 257;
+ }
+ util_1.validateInputResolution(config.inputResolution);
+ if (config.outputStride == null) {
+ config.outputStride = 16;
+ }
+ if (VALID_STRIDE[config.architecture].indexOf(config.outputStride) < 0) {
+ throw new Error("Invalid outputStride " + config.outputStride + ". " +
+ ("Should be one of " + VALID_STRIDE[config.architecture] + " ") +
+ ("for architecture " + config.architecture + "."));
+ }
+ if (config.multiplier == null) {
+ config.multiplier = 1.0;
+ }
+ if (VALID_MULTIPLIER[config.architecture].indexOf(config.multiplier) < 0) {
+ throw new Error("Invalid multiplier " + config.multiplier + ". " +
+ ("Should be one of " + VALID_MULTIPLIER[config.architecture] + " ") +
+ ("for architecture " + config.architecture + "."));
+ }
+ if (config.quantBytes == null) {
+ config.quantBytes = 4;
+ }
+ if (VALID_QUANT_BYTES.indexOf(config.quantBytes) < 0) {
+ throw new Error("Invalid quantBytes " + config.quantBytes + ". " +
+ ("Should be one of " + VALID_QUANT_BYTES + " ") +
+ ("for architecture " + config.architecture + "."));
+ }
+ if (config.architecture === 'MobileNetV1' && config.outputStride === 32 &&
+ config.multiplier !== 1) {
+ throw new Error("When using an output stride of 32, " +
+ "you must select 1 as the multiplier.");
+ }
+ return config;
+}
+exports.SINGLE_PERSON_INFERENCE_CONFIG = {
+ flipHorizontal: false
+};
+exports.MULTI_PERSON_INFERENCE_CONFIG = {
+ flipHorizontal: false,
+ maxDetections: 5,
+ scoreThreshold: 0.5,
+ nmsRadius: 20
+};
+function validateSinglePersonInferenceConfig(config) { }
+function validateMultiPersonInputConfig(config) {
+ var maxDetections = config.maxDetections, scoreThreshold = config.scoreThreshold, nmsRadius = config.nmsRadius;
+ if (maxDetections <= 0) {
+ throw new Error("Invalid maxDetections " + maxDetections + ". " +
+ "Should be > 0");
+ }
+ if (scoreThreshold < 0.0 || scoreThreshold > 1.0) {
+ throw new Error("Invalid scoreThreshold " + scoreThreshold + ". " +
+ "Should be in range [0.0, 1.0]");
+ }
+ if (nmsRadius <= 0) {
+ throw new Error("Invalid nmsRadius " + nmsRadius + ".");
+ }
+}
+var PoseNet = /** @class */ (function () {
+ function PoseNet(net, inputResolution) {
+ util_1.assertValidOutputStride(net.outputStride);
+ util_1.assertValidResolution(inputResolution, net.outputStride);
+ this.baseModel = net;
+ this.inputResolution = inputResolution;
+ }
+ /**
+ * Infer through PoseNet, and estimates multiple poses using the outputs.
+ * This does standard ImageNet pre-processing before inferring through the
+ * model. The image should pixels should have values [0-255]. It detects
+ * multiple poses and finds their parts from part scores and displacement
+ * vectors using a fast greedy decoding algorithm. It returns up to
+ * `config.maxDetections` object instance detections in decreasing root
+ * score order.
+ *
+ * @param input
+ * ImageData|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement) The input
+ * image to feed through the network.
+ *
+ * @param config MultiPoseEstimationConfig object that contains parameters
+ * for the PoseNet inference using multiple pose estimation.
+ *
+ * @return An array of poses and their scores, each containing keypoints and
+ * the corresponding keypoint scores. The positions of the keypoints are
+ * in the same scale as the original image
+ */
+ PoseNet.prototype.estimateMultiplePoses = function (input, config) {
+ if (config === void 0) { config = exports.MULTI_PERSON_INFERENCE_CONFIG; }
+ return __awaiter(this, void 0, void 0, function () {
+ var configWithDefaults, outputStride, inputResolution, _a, height, width, _b, resized, padding, _c, heatmapScores, offsets, displacementFwd, displacementBwd, allTensorBuffers, scoresBuffer, offsetsBuffer, displacementsFwdBuffer, displacementsBwdBuffer, poses, resultPoses;
+ return __generator(this, function (_d) {
+ switch (_d.label) {
+ case 0:
+ configWithDefaults = __assign({}, exports.MULTI_PERSON_INFERENCE_CONFIG, config);
+ validateMultiPersonInputConfig(config);
+ outputStride = this.baseModel.outputStride;
+ inputResolution = this.inputResolution;
+ _a = util_1.getInputTensorDimensions(input), height = _a[0], width = _a[1];
+ _b = util_1.padAndResizeTo(input, inputResolution), resized = _b.resized, padding = _b.padding;
+ _c = this.baseModel.predict(resized), heatmapScores = _c.heatmapScores, offsets = _c.offsets, displacementFwd = _c.displacementFwd, displacementBwd = _c.displacementBwd;
+ return [4 /*yield*/, util_1.toTensorBuffers3D([heatmapScores, offsets, displacementFwd, displacementBwd])];
+ case 1:
+ allTensorBuffers = _d.sent();
+ scoresBuffer = allTensorBuffers[0];
+ offsetsBuffer = allTensorBuffers[1];
+ displacementsFwdBuffer = allTensorBuffers[2];
+ displacementsBwdBuffer = allTensorBuffers[3];
+ return [4 /*yield*/, decode_multiple_poses_1.decodeMultiplePoses(scoresBuffer, offsetsBuffer, displacementsFwdBuffer, displacementsBwdBuffer, outputStride, configWithDefaults.maxDetections, configWithDefaults.scoreThreshold, configWithDefaults.nmsRadius)];
+ case 2:
+ poses = _d.sent();
+ resultPoses = util_1.scaleAndFlipPoses(poses, [height, width], inputResolution, padding, configWithDefaults.flipHorizontal);
+ heatmapScores.dispose();
+ offsets.dispose();
+ displacementFwd.dispose();
+ displacementBwd.dispose();
+ resized.dispose();
+ return [2 /*return*/, resultPoses];
+ }
+ });
+ });
+ };
+ /**
+ * Infer through PoseNet, and estimates a single pose using the outputs.
+ * This does standard ImageNet pre-processing before inferring through the
+ * model. The image should pixels should have values [0-255]. It detects
+ * multiple poses and finds their parts from part scores and displacement
+ * vectors using a fast greedy decoding algorithm. It returns a single pose
+ *
+ * @param input
+ * ImageData|HTMLImageElement|HTMLCanvasElement|HTMLVideoElement) The input
+ * image to feed through the network.
+ *
+ * @param config SinglePersonEstimationConfig object that contains
+ * parameters for the PoseNet inference using single pose estimation.
+ *
+ * @return An pose and its scores, containing keypoints and
+ * the corresponding keypoint scores. The positions of the keypoints are
+ * in the same scale as the original image
+ */
+ PoseNet.prototype.estimateSinglePose = function (input, config) {
+ if (config === void 0) { config = exports.SINGLE_PERSON_INFERENCE_CONFIG; }
+ return __awaiter(this, void 0, void 0, function () {
+ var configWithDefaults, outputStride, inputResolution, _a, height, width, _b, resized, padding, _c, heatmapScores, offsets, displacementFwd, displacementBwd, pose, poses, resultPoses;
+ return __generator(this, function (_d) {
+ switch (_d.label) {
+ case 0:
+ configWithDefaults = __assign({}, exports.SINGLE_PERSON_INFERENCE_CONFIG, config);
+ validateSinglePersonInferenceConfig(configWithDefaults);
+ outputStride = this.baseModel.outputStride;
+ inputResolution = this.inputResolution;
+ _a = util_1.getInputTensorDimensions(input), height = _a[0], width = _a[1];
+ _b = util_1.padAndResizeTo(input, inputResolution), resized = _b.resized, padding = _b.padding;
+ _c = this.baseModel.predict(resized), heatmapScores = _c.heatmapScores, offsets = _c.offsets, displacementFwd = _c.displacementFwd, displacementBwd = _c.displacementBwd;
+ return [4 /*yield*/, decode_single_pose_1.decodeSinglePose(heatmapScores, offsets, outputStride)];
+ case 1:
+ pose = _d.sent();
+ poses = [pose];
+ resultPoses = util_1.scaleAndFlipPoses(poses, [height, width], inputResolution, padding, configWithDefaults.flipHorizontal);
+ heatmapScores.dispose();
+ offsets.dispose();
+ displacementFwd.dispose();
+ displacementBwd.dispose();
+ resized.dispose();
+ return [2 /*return*/, resultPoses[0]];
+ }
+ });
+ });
+ };
+ /** Deprecated: Use either estimateSinglePose or estimateMultiplePoses */
+ PoseNet.prototype.estimatePoses = function (input, config) {
+ return __awaiter(this, void 0, void 0, function () {
+ var pose;
+ return __generator(this, function (_a) {
+ switch (_a.label) {
+ case 0:
+ if (!(config.decodingMethod === 'single-person')) return [3 /*break*/, 2];
+ return [4 /*yield*/, this.estimateSinglePose(input, config)];
+ case 1:
+ pose = _a.sent();
+ return [2 /*return*/, [pose]];
+ case 2: return [2 /*return*/, this.estimateMultiplePoses(input, config)];
+ }
+ });
+ });
+ };
+ PoseNet.prototype.dispose = function () {
+ this.baseModel.dispose();
+ };
+ return PoseNet;
+}());
+exports.PoseNet = PoseNet;
+function loadMobileNet(config) {
+ return __awaiter(this, void 0, void 0, function () {
+ var outputStride, quantBytes, multiplier, url, graphModel, mobilenet, validInputResolution;
+ return __generator(this, function (_a) {
+ switch (_a.label) {
+ case 0:
+ outputStride = config.outputStride;
+ quantBytes = config.quantBytes;
+ multiplier = config.multiplier;
+ if (tf == null) {
+ throw new Error("Cannot find TensorFlow.js. If you are using a