mirror of https://github.com/vladmandic/human
update posenet model
parent
59cf501bcd
commit
8440d78d5f
10
CHANGELOG.md
10
CHANGELOG.md
|
@ -9,11 +9,15 @@ Repository: **<git+https://github.com/vladmandic/human.git>**
|
||||||
|
|
||||||
## Changelog
|
## Changelog
|
||||||
|
|
||||||
|
### **HEAD -> main** 2021/04/24 mandic00@live.com
|
||||||
|
|
||||||
|
|
||||||
|
### **origin/main** 2021/04/22 mandic00@live.com
|
||||||
|
|
||||||
|
|
||||||
### **1.6.1** 2021/04/22 mandic00@live.com
|
### **1.6.1** 2021/04/22 mandic00@live.com
|
||||||
|
|
||||||
|
- add npmrc
|
||||||
### **origin/main** 2021/04/20 mandic00@live.com
|
|
||||||
|
|
||||||
- added filter.flip feature
|
- added filter.flip feature
|
||||||
- added demo load image from http
|
- added demo load image from http
|
||||||
- mobile demo optimization and iris gestures
|
- mobile demo optimization and iris gestures
|
||||||
|
|
|
@ -208,7 +208,7 @@ Default models in Human library are:
|
||||||
- **Face Description**: HSE FaceRes
|
- **Face Description**: HSE FaceRes
|
||||||
- **Face Iris Analysis**: MediaPipe Iris
|
- **Face Iris Analysis**: MediaPipe Iris
|
||||||
- **Emotion Detection**: Oarriaga Emotion
|
- **Emotion Detection**: Oarriaga Emotion
|
||||||
- **Body Analysis**: PoseNet
|
- **Body Analysis**: PoseNet (AtomicBits version)
|
||||||
|
|
||||||
Note that alternative models are provided and can be enabled via configuration
|
Note that alternative models are provided and can be enabled via configuration
|
||||||
For example, `PoseNet` model can be switched for `BlazePose` model depending on the use case
|
For example, `PoseNet` model can be switched for `BlazePose` model depending on the use case
|
||||||
|
|
|
@ -29,7 +29,7 @@ const userConfig = {
|
||||||
},
|
},
|
||||||
hand: { enabled: false },
|
hand: { enabled: false },
|
||||||
gesture: { enabled: true },
|
gesture: { enabled: true },
|
||||||
body: { enabled: false },
|
body: { enabled: true, modelPath: 'posenet.json' },
|
||||||
// body: { enabled: true, modelPath: 'blazepose.json' },
|
// body: { enabled: true, modelPath: 'blazepose.json' },
|
||||||
// object: { enabled: true },
|
// object: { enabled: true },
|
||||||
};
|
};
|
||||||
|
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
Binary file not shown.
File diff suppressed because one or more lines are too long
|
@ -68,8 +68,8 @@
|
||||||
"canvas": "^2.7.0",
|
"canvas": "^2.7.0",
|
||||||
"chokidar": "^3.5.1",
|
"chokidar": "^3.5.1",
|
||||||
"dayjs": "^1.10.4",
|
"dayjs": "^1.10.4",
|
||||||
"esbuild": "^0.11.12",
|
"esbuild": "^0.11.14",
|
||||||
"eslint": "^7.24.0",
|
"eslint": "^7.25.0",
|
||||||
"eslint-config-airbnb-base": "^14.2.1",
|
"eslint-config-airbnb-base": "^14.2.1",
|
||||||
"eslint-plugin-import": "^2.22.1",
|
"eslint-plugin-import": "^2.22.1",
|
||||||
"eslint-plugin-json": "^2.1.2",
|
"eslint-plugin-json": "^2.1.2",
|
||||||
|
@ -80,7 +80,7 @@
|
||||||
"seedrandom": "^3.0.5",
|
"seedrandom": "^3.0.5",
|
||||||
"simple-git": "^2.38.0",
|
"simple-git": "^2.38.0",
|
||||||
"tslib": "^2.2.0",
|
"tslib": "^2.2.0",
|
||||||
"typedoc": "^0.20.35",
|
"typedoc": "^0.20.36",
|
||||||
"typescript": "^4.2.4"
|
"typescript": "^4.2.4"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -134,3 +134,20 @@
|
||||||
2021-04-22 19:46:37 [36mINFO: [39m Generate types: ["src/human.ts"]
|
2021-04-22 19:46:37 [36mINFO: [39m Generate types: ["src/human.ts"]
|
||||||
2021-04-22 19:46:41 [36mINFO: [39m Update Change log: ["/home/vlado/dev/human/CHANGELOG.md"]
|
2021-04-22 19:46:41 [36mINFO: [39m Update Change log: ["/home/vlado/dev/human/CHANGELOG.md"]
|
||||||
2021-04-22 19:46:41 [36mINFO: [39m Generate TypeDocs: ["src/human.ts"]
|
2021-04-22 19:46:41 [36mINFO: [39m Generate TypeDocs: ["src/human.ts"]
|
||||||
|
2021-04-24 11:48:49 [36mINFO: [39m @vladmandic/human version 1.6.1
|
||||||
|
2021-04-24 11:48:49 [36mINFO: [39m User: vlado Platform: linux Arch: x64 Node: v16.0.0
|
||||||
|
2021-04-24 11:48:49 [36mINFO: [39m Build: file startup all type: production config: {"minifyWhitespace":true,"minifyIdentifiers":true,"minifySyntax":true,"sourcemap":true,"bundle":true,"metafile":true,"target":"es2018"}
|
||||||
|
2021-04-24 11:48:49 [35mSTATE:[39m Build for: node type: tfjs: {"imports":1,"importBytes":39,"outputBytes":733,"outputFiles":"dist/tfjs.esm.js"}
|
||||||
|
2021-04-24 11:48:49 [35mSTATE:[39m Build for: node type: node: {"imports":43,"importBytes":547909,"outputBytes":306333,"outputFiles":"dist/human.node.js"}
|
||||||
|
2021-04-24 11:48:49 [35mSTATE:[39m Build for: nodeGPU type: tfjs: {"imports":1,"importBytes":43,"outputBytes":737,"outputFiles":"dist/tfjs.esm.js"}
|
||||||
|
2021-04-24 11:48:49 [35mSTATE:[39m Build for: nodeGPU type: node: {"imports":43,"importBytes":547913,"outputBytes":306341,"outputFiles":"dist/human.node-gpu.js"}
|
||||||
|
2021-04-24 11:48:49 [35mSTATE:[39m Build for: nodeWASM type: tfjs: {"imports":1,"importBytes":81,"outputBytes":783,"outputFiles":"dist/tfjs.esm.js"}
|
||||||
|
2021-04-24 11:48:49 [35mSTATE:[39m Build for: nodeWASM type: node: {"imports":43,"importBytes":547959,"outputBytes":306385,"outputFiles":"dist/human.node-wasm.js"}
|
||||||
|
2021-04-24 11:48:49 [35mSTATE:[39m Build for: browserNoBundle type: tfjs: {"imports":1,"importBytes":2488,"outputBytes":1394,"outputFiles":"dist/tfjs.esm.js"}
|
||||||
|
2021-04-24 11:48:49 [35mSTATE:[39m Build for: browserNoBundle type: esm: {"imports":43,"importBytes":548570,"outputBytes":306337,"outputFiles":"dist/human.esm-nobundle.js"}
|
||||||
|
2021-04-24 11:48:50 [35mSTATE:[39m Build for: browserBundle type: tfjs: {"modules":1267,"moduleBytes":4085087,"imports":7,"importBytes":2488,"outputBytes":1101728,"outputFiles":"dist/tfjs.esm.js"}
|
||||||
|
2021-04-24 11:48:51 [35mSTATE:[39m Build for: browserBundle type: iife: {"imports":43,"importBytes":1648904,"outputBytes":1404224,"outputFiles":"dist/human.js"}
|
||||||
|
2021-04-24 11:48:51 [35mSTATE:[39m Build for: browserBundle type: esm: {"imports":43,"importBytes":1648904,"outputBytes":1404182,"outputFiles":"dist/human.esm.js"}
|
||||||
|
2021-04-24 11:48:51 [36mINFO: [39m Generate types: ["src/human.ts"]
|
||||||
|
2021-04-24 11:48:56 [36mINFO: [39m Update Change log: ["/home/vlado/dev/human/CHANGELOG.md"]
|
||||||
|
2021-04-24 11:48:56 [36mINFO: [39m Generate TypeDocs: ["src/human.ts"]
|
||||||
|
|
|
@ -363,7 +363,7 @@ const config: Config = {
|
||||||
// can be either absolute path or relative to modelBasePath
|
// can be either absolute path or relative to modelBasePath
|
||||||
// can be 'posenet', 'blazepose' or 'efficientpose'
|
// can be 'posenet', 'blazepose' or 'efficientpose'
|
||||||
// 'blazepose' and 'efficientpose' are experimental
|
// 'blazepose' and 'efficientpose' are experimental
|
||||||
maxDetections: 10, // maximum number of people detected in the input
|
maxDetections: 1, // maximum number of people detected in the input
|
||||||
// should be set to the minimum number for performance
|
// should be set to the minimum number for performance
|
||||||
// only valid for posenet as blazepose only detects single pose
|
// only valid for posenet as blazepose only detects single pose
|
||||||
scoreThreshold: 0.3, // threshold for deciding when to remove boxes based on score
|
scoreThreshold: 0.3, // threshold for deciding when to remove boxes based on score
|
||||||
|
|
|
@ -55,7 +55,7 @@ export const options: DrawOptions = {
|
||||||
roundRect: <number>28,
|
roundRect: <number>28,
|
||||||
drawPoints: <Boolean>false,
|
drawPoints: <Boolean>false,
|
||||||
drawLabels: <Boolean>true,
|
drawLabels: <Boolean>true,
|
||||||
drawBoxes: <Boolean>true,
|
drawBoxes: <Boolean>false,
|
||||||
drawPolygons: <Boolean>true,
|
drawPolygons: <Boolean>true,
|
||||||
fillPolygons: <Boolean>false,
|
fillPolygons: <Boolean>false,
|
||||||
useDepth: <Boolean>true,
|
useDepth: <Boolean>true,
|
||||||
|
@ -253,7 +253,20 @@ export async function body(inCanvas: HTMLCanvasElement, result: Array<any>, draw
|
||||||
// result[i].keypoints = result[i].keypoints.filter((a) => a.score > 0.5);
|
// result[i].keypoints = result[i].keypoints.filter((a) => a.score > 0.5);
|
||||||
if (!lastDrawnPose[i] && localOptions.bufferedOutput) lastDrawnPose[i] = { ...result[i] };
|
if (!lastDrawnPose[i] && localOptions.bufferedOutput) lastDrawnPose[i] = { ...result[i] };
|
||||||
ctx.strokeStyle = localOptions.color;
|
ctx.strokeStyle = localOptions.color;
|
||||||
|
ctx.fillStyle = localOptions.color;
|
||||||
ctx.lineWidth = localOptions.lineWidth;
|
ctx.lineWidth = localOptions.lineWidth;
|
||||||
|
ctx.font = localOptions.font;
|
||||||
|
if (localOptions.drawBoxes) {
|
||||||
|
rect(ctx, result[i].box[0], result[i].box[1], result[i].box[2], result[i].box[3], localOptions);
|
||||||
|
if (localOptions.drawLabels) {
|
||||||
|
if (localOptions.shadowColor && localOptions.shadowColor !== '') {
|
||||||
|
ctx.fillStyle = localOptions.shadowColor;
|
||||||
|
ctx.fillText(`body ${100 * result[i].score}%`, result[i].box[0] + 3, 1 + result[i].box[1] + localOptions.lineHeight, result[i].box[2]);
|
||||||
|
}
|
||||||
|
ctx.fillStyle = localOptions.labelColor;
|
||||||
|
ctx.fillText(`body ${100 * result[i].score}%`, result[i].box[0] + 2, 0 + result[i].box[1] + localOptions.lineHeight, result[i].box[2]);
|
||||||
|
}
|
||||||
|
}
|
||||||
if (localOptions.drawPoints) {
|
if (localOptions.drawPoints) {
|
||||||
for (let pt = 0; pt < result[i].keypoints.length; pt++) {
|
for (let pt = 0; pt < result[i].keypoints.length; pt++) {
|
||||||
ctx.fillStyle = localOptions.useDepth && result[i].keypoints[pt].position.z ? `rgba(${127.5 + (2 * result[i].keypoints[pt].position.z)}, ${127.5 - (2 * result[i].keypoints[pt].position.z)}, 255, 0.5)` : localOptions.color;
|
ctx.fillStyle = localOptions.useDepth && result[i].keypoints[pt].position.z ? `rgba(${127.5 + (2 * result[i].keypoints[pt].position.z)}, ${127.5 - (2 * result[i].keypoints[pt].position.z)}, 255, 0.5)` : localOptions.color;
|
||||||
|
@ -271,7 +284,7 @@ export async function body(inCanvas: HTMLCanvasElement, result: Array<any>, draw
|
||||||
if (result[i].keypoints) {
|
if (result[i].keypoints) {
|
||||||
for (const pt of result[i].keypoints) {
|
for (const pt of result[i].keypoints) {
|
||||||
ctx.fillStyle = localOptions.useDepth && pt.position.z ? `rgba(${127.5 + (2 * pt.position.z)}, ${127.5 - (2 * pt.position.z)}, 255, 0.5)` : localOptions.color;
|
ctx.fillStyle = localOptions.useDepth && pt.position.z ? `rgba(${127.5 + (2 * pt.position.z)}, ${127.5 - (2 * pt.position.z)}, 255, 0.5)` : localOptions.color;
|
||||||
ctx.fillText(`${pt.part}`, pt.position.x + 4, pt.position.y + 4);
|
ctx.fillText(`${pt.part} ${Math.trunc(100 * pt.score)}%`, pt.position.x + 4, pt.position.y + 4);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,39 +0,0 @@
|
||||||
import * as heapSort from './heapSort';
|
|
||||||
|
|
||||||
function scoreIsMaximumInLocalWindow(keypointId, score, heatmapY, heatmapX, localMaximumRadius, scores) {
|
|
||||||
const [height, width] = scores.shape;
|
|
||||||
let localMaximum = true;
|
|
||||||
const yStart = Math.max(heatmapY - localMaximumRadius, 0);
|
|
||||||
const yEnd = Math.min(heatmapY + localMaximumRadius + 1, height);
|
|
||||||
for (let yCurrent = yStart; yCurrent < yEnd; ++yCurrent) {
|
|
||||||
const xStart = Math.max(heatmapX - localMaximumRadius, 0);
|
|
||||||
const xEnd = Math.min(heatmapX + localMaximumRadius + 1, width);
|
|
||||||
for (let xCurrent = xStart; xCurrent < xEnd; ++xCurrent) {
|
|
||||||
if (scores.get(yCurrent, xCurrent, keypointId) > score) {
|
|
||||||
localMaximum = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (!localMaximum) break;
|
|
||||||
}
|
|
||||||
return localMaximum;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function buildPartWithScoreQueue(scoreThreshold, localMaximumRadius, scores) {
|
|
||||||
const [height, width, numKeypoints] = scores.shape;
|
|
||||||
const queue = new heapSort.MaxHeap(height * width * numKeypoints, ({ score }) => score);
|
|
||||||
for (let heatmapY = 0; heatmapY < height; ++heatmapY) {
|
|
||||||
for (let heatmapX = 0; heatmapX < width; ++heatmapX) {
|
|
||||||
for (let keypointId = 0; keypointId < numKeypoints; ++keypointId) {
|
|
||||||
const 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, part: { heatmapY, heatmapX, id: keypointId } });
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return queue;
|
|
||||||
}
|
|
|
@ -1,14 +1,51 @@
|
||||||
import * as buildParts from './buildParts';
|
import * as decodeSingle from './decodeSingle';
|
||||||
import * as decodePose from './decodePose';
|
import * as utils from './utils';
|
||||||
import * as vectors from './vectors';
|
|
||||||
|
|
||||||
const kLocalMaximumRadius = 1;
|
const kLocalMaximumRadius = 1;
|
||||||
const defaultOutputStride = 16;
|
const defaultOutputStride = 16;
|
||||||
|
|
||||||
|
function scoreIsMaximumInLocalWindow(keypointId, score, heatmapY, heatmapX, localMaximumRadius, scores) {
|
||||||
|
const [height, width] = scores.shape;
|
||||||
|
let localMaximum = true;
|
||||||
|
const yStart = Math.max(heatmapY - localMaximumRadius, 0);
|
||||||
|
const yEnd = Math.min(heatmapY + localMaximumRadius + 1, height);
|
||||||
|
for (let yCurrent = yStart; yCurrent < yEnd; ++yCurrent) {
|
||||||
|
const xStart = Math.max(heatmapX - localMaximumRadius, 0);
|
||||||
|
const xEnd = Math.min(heatmapX + localMaximumRadius + 1, width);
|
||||||
|
for (let xCurrent = xStart; xCurrent < xEnd; ++xCurrent) {
|
||||||
|
if (scores.get(yCurrent, xCurrent, keypointId) > score) {
|
||||||
|
localMaximum = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (!localMaximum) break;
|
||||||
|
}
|
||||||
|
return localMaximum;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function buildPartWithScoreQueue(scoreThreshold, localMaximumRadius, scores) {
|
||||||
|
const [height, width, numKeypoints] = scores.shape;
|
||||||
|
const queue = new utils.MaxHeap(height * width * numKeypoints, ({ score }) => score);
|
||||||
|
for (let heatmapY = 0; heatmapY < height; ++heatmapY) {
|
||||||
|
for (let heatmapX = 0; heatmapX < width; ++heatmapX) {
|
||||||
|
for (let keypointId = 0; keypointId < numKeypoints; ++keypointId) {
|
||||||
|
const 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, part: { heatmapY, heatmapX, id: keypointId } });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return queue;
|
||||||
|
}
|
||||||
|
|
||||||
function withinNmsRadiusOfCorrespondingPoint(poses, squaredNmsRadius, { x, y }, keypointId) {
|
function withinNmsRadiusOfCorrespondingPoint(poses, squaredNmsRadius, { x, y }, keypointId) {
|
||||||
return poses.some(({ keypoints }) => {
|
return poses.some(({ keypoints }) => {
|
||||||
const correspondingKeypoint = keypoints[keypointId].position;
|
const correspondingKeypoint = keypoints[keypointId].position;
|
||||||
return vectors.squaredDistance(y, x, correspondingKeypoint.y, correspondingKeypoint.x) <= squaredNmsRadius;
|
return utils.squaredDistance(y, x, correspondingKeypoint.y, correspondingKeypoint.x) <= squaredNmsRadius;
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -21,20 +58,21 @@ function getInstanceScore(existingPoses, squaredNmsRadius, instanceKeypoints) {
|
||||||
}
|
}
|
||||||
|
|
||||||
export function decodeMultiplePoses(scoresBuffer, offsetsBuffer, displacementsFwdBuffer, displacementsBwdBuffer, nmsRadius, maxDetections, scoreThreshold) {
|
export function decodeMultiplePoses(scoresBuffer, offsetsBuffer, displacementsFwdBuffer, displacementsBwdBuffer, nmsRadius, maxDetections, scoreThreshold) {
|
||||||
const poses: Array<{ keypoints: any, score: number }> = [];
|
const poses: Array<{ keypoints: any, box: any, score: number }> = [];
|
||||||
const queue = buildParts.buildPartWithScoreQueue(scoreThreshold, kLocalMaximumRadius, scoresBuffer);
|
const queue = buildPartWithScoreQueue(scoreThreshold, kLocalMaximumRadius, scoresBuffer);
|
||||||
const squaredNmsRadius = nmsRadius ^ 2;
|
const squaredNmsRadius = nmsRadius ^ 2;
|
||||||
// Generate at most maxDetections object instances per image in decreasing root part score order.
|
// Generate at most maxDetections object instances per image in decreasing root part score order.
|
||||||
while (poses.length < maxDetections && !queue.empty()) {
|
while (poses.length < maxDetections && !queue.empty()) {
|
||||||
// The top element in the queue is the next root candidate.
|
// The top element in the queue is the next root candidate.
|
||||||
const root = queue.dequeue();
|
const 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.
|
// 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.
|
||||||
const rootImageCoords = vectors.getImageCoords(root.part, defaultOutputStride, offsetsBuffer);
|
const rootImageCoords = utils.getImageCoords(root.part, defaultOutputStride, offsetsBuffer);
|
||||||
if (withinNmsRadiusOfCorrespondingPoint(poses, squaredNmsRadius, rootImageCoords, root.part.id)) continue;
|
if (withinNmsRadiusOfCorrespondingPoint(poses, squaredNmsRadius, rootImageCoords, root.part.id)) continue;
|
||||||
// Else start a new detection instance at the position of the root.
|
// Else start a new detection instance at the position of the root.
|
||||||
const keypoints = decodePose.decodePose(root, scoresBuffer, offsetsBuffer, defaultOutputStride, displacementsFwdBuffer, displacementsBwdBuffer);
|
const keypoints = decodeSingle.decodePose(root, scoresBuffer, offsetsBuffer, defaultOutputStride, displacementsFwdBuffer, displacementsBwdBuffer);
|
||||||
const score = getInstanceScore(poses, squaredNmsRadius, keypoints);
|
const score = getInstanceScore(poses, squaredNmsRadius, keypoints);
|
||||||
if (score > scoreThreshold) poses.push({ keypoints, score: Math.round(100 * score) / 100 });
|
const box = utils.getBoundingBox(keypoints);
|
||||||
|
if (score > scoreThreshold) poses.push({ keypoints, box, score: Math.round(100 * score) / 100 });
|
||||||
}
|
}
|
||||||
return poses;
|
return poses;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,48 @@
|
||||||
|
import * as tf from '../../dist/tfjs.esm.js';
|
||||||
|
import * as keypoints from './keypoints';
|
||||||
|
|
||||||
|
export function getPointsConfidence(heatmapScores, heatMapCoords) {
|
||||||
|
const numKeypoints = keypoints.count; // also in heatMapCoords.shape[0];
|
||||||
|
const result:Array<number> = [];
|
||||||
|
for (let keypoint = 0; keypoint < numKeypoints; keypoint++) {
|
||||||
|
const y = heatMapCoords.get(keypoint, 0);
|
||||||
|
const x = heatMapCoords.get(keypoint, 1);
|
||||||
|
result.push(heatmapScores.get(y, x, keypoint));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getOffsetPoints(heatMapCoordsBuffer, outputStride, offsetsBuffer) {
|
||||||
|
const getOffsetPoint = (y, x, keypoint) => ([
|
||||||
|
offsetsBuffer.get(y, x, keypoint),
|
||||||
|
offsetsBuffer.get(y, x, keypoint + keypoints.count),
|
||||||
|
]);
|
||||||
|
|
||||||
|
const getOffsetVectors = () => {
|
||||||
|
const result: Array<number[]> = [];
|
||||||
|
for (let keypoint = 0; keypoint < keypoints.count; keypoint++) {
|
||||||
|
const heatmapY = heatMapCoordsBuffer.get(keypoint, 0);
|
||||||
|
const heatmapX = heatMapCoordsBuffer.get(keypoint, 1);
|
||||||
|
result.push(getOffsetPoint(heatmapY, heatmapX, keypoint));
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
};
|
||||||
|
|
||||||
|
return tf.tidy(() => heatMapCoordsBuffer.toTensor().mul(tf.scalar(outputStride, 'int32')).toFloat().add(getOffsetVectors()));
|
||||||
|
}
|
||||||
|
|
||||||
|
export function argmax2d(inputs) {
|
||||||
|
const mod = (a, b) => tf.tidy(() => {
|
||||||
|
const floored = a.div(tf.scalar(b, 'int32'));
|
||||||
|
return a.sub(floored.mul(tf.scalar(b, 'int32')));
|
||||||
|
});
|
||||||
|
const [height, width, depth] = inputs.shape;
|
||||||
|
|
||||||
|
return tf.tidy(() => {
|
||||||
|
const reshaped = inputs.reshape([height * width, depth]);
|
||||||
|
const coords = reshaped.argMax(0);
|
||||||
|
const yCoords = coords.div(tf.scalar(width, 'int32')).expandDims(1);
|
||||||
|
const xCoords = mod(coords, width).expandDims(1);
|
||||||
|
return tf.concat([yCoords, xCoords], 1);
|
||||||
|
});
|
||||||
|
}
|
|
@ -1,6 +1,6 @@
|
||||||
import * as keypoints from './keypoints';
|
import * as keypoints from './keypoints';
|
||||||
import * as vectors from './vectors';
|
import * as decoders from './decodeParts';
|
||||||
import * as decoders from './decoders';
|
import * as utils from './utils';
|
||||||
|
|
||||||
const parentChildrenTuples = keypoints.poseChain.map(([parentJoinName, childJoinName]) => ([keypoints.partIds[parentJoinName], keypoints.partIds[childJoinName]]));
|
const parentChildrenTuples = keypoints.poseChain.map(([parentJoinName, childJoinName]) => ([keypoints.partIds[parentJoinName], keypoints.partIds[childJoinName]]));
|
||||||
const parentToChildEdges = parentChildrenTuples.map(([, childJointId]) => childJointId);
|
const parentToChildEdges = parentChildrenTuples.map(([, childJointId]) => childJointId);
|
||||||
|
@ -18,8 +18,8 @@ function getDisplacement(edgeId, point, displacements) {
|
||||||
|
|
||||||
function getStridedIndexNearPoint(point, outputStride, height, width) {
|
function getStridedIndexNearPoint(point, outputStride, height, width) {
|
||||||
return {
|
return {
|
||||||
y: vectors.clamp(Math.round(point.y / outputStride), 0, height - 1),
|
y: utils.clamp(Math.round(point.y / outputStride), 0, height - 1),
|
||||||
x: vectors.clamp(Math.round(point.x / outputStride), 0, width - 1),
|
x: utils.clamp(Math.round(point.x / outputStride), 0, width - 1),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -28,12 +28,12 @@ function traverseToTargetKeypoint(edgeId, sourceKeypoint, targetKeypointId, scor
|
||||||
// Nearest neighbor interpolation for the source->target displacements.
|
// Nearest neighbor interpolation for the source->target displacements.
|
||||||
const sourceKeypointIndices = getStridedIndexNearPoint(sourceKeypoint.position, outputStride, height, width);
|
const sourceKeypointIndices = getStridedIndexNearPoint(sourceKeypoint.position, outputStride, height, width);
|
||||||
const displacement = getDisplacement(edgeId, sourceKeypointIndices, displacements);
|
const displacement = getDisplacement(edgeId, sourceKeypointIndices, displacements);
|
||||||
const displacedPoint = vectors.addVectors(sourceKeypoint.position, displacement);
|
const displacedPoint = utils.addVectors(sourceKeypoint.position, displacement);
|
||||||
let targetKeypoint = displacedPoint;
|
let targetKeypoint = displacedPoint;
|
||||||
for (let i = 0; i < offsetRefineStep; i++) {
|
for (let i = 0; i < offsetRefineStep; i++) {
|
||||||
const targetKeypointIndices = getStridedIndexNearPoint(targetKeypoint, outputStride, height, width);
|
const targetKeypointIndices = getStridedIndexNearPoint(targetKeypoint, outputStride, height, width);
|
||||||
const offsetPoint = vectors.getOffsetPoint(targetKeypointIndices.y, targetKeypointIndices.x, targetKeypointId, offsets);
|
const offsetPoint = utils.getOffsetPoint(targetKeypointIndices.y, targetKeypointIndices.x, targetKeypointId, offsets);
|
||||||
targetKeypoint = vectors.addVectors({
|
targetKeypoint = utils.addVectors({
|
||||||
x: targetKeypointIndices.x * outputStride,
|
x: targetKeypointIndices.x * outputStride,
|
||||||
y: targetKeypointIndices.y * outputStride,
|
y: targetKeypointIndices.y * outputStride,
|
||||||
}, { x: offsetPoint.x, y: offsetPoint.y });
|
}, { x: offsetPoint.x, y: offsetPoint.y });
|
||||||
|
@ -49,7 +49,7 @@ export function decodePose(root, scores, offsets, outputStride, displacementsFwd
|
||||||
const instanceKeypoints = new Array(numParts);
|
const instanceKeypoints = new Array(numParts);
|
||||||
// Start a new detection instance at the position of the root.
|
// Start a new detection instance at the position of the root.
|
||||||
const { part: rootPart, score: rootScore } = root;
|
const { part: rootPart, score: rootScore } = root;
|
||||||
const rootPoint = vectors.getImageCoords(rootPart, outputStride, offsets);
|
const rootPoint = utils.getImageCoords(rootPart, outputStride, offsets);
|
||||||
instanceKeypoints[rootPart.id] = {
|
instanceKeypoints[rootPart.id] = {
|
||||||
score: rootScore,
|
score: rootScore,
|
||||||
part: keypoints.partNames[rootPart.id],
|
part: keypoints.partNames[rootPart.id],
|
||||||
|
@ -75,28 +75,30 @@ export function decodePose(root, scores, offsets, outputStride, displacementsFwd
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function decodeSinglePose(heatmapScores, offsets, minScore) {
|
export async function decodeSinglePose(heatmapScores, offsets, minScore) {
|
||||||
let totalScore = 0.0;
|
|
||||||
const heatmapValues = decoders.argmax2d(heatmapScores);
|
const heatmapValues = decoders.argmax2d(heatmapScores);
|
||||||
const allTensorBuffers = await Promise.all([heatmapScores.buffer(), offsets.buffer(), heatmapValues.buffer()]);
|
const allTensorBuffers = await Promise.all([heatmapScores.buffer(), offsets.buffer(), heatmapValues.buffer()]);
|
||||||
const scoresBuffer = allTensorBuffers[0];
|
const scoresBuffer = allTensorBuffers[0];
|
||||||
const offsetsBuffer = allTensorBuffers[1];
|
const offsetsBuffer = allTensorBuffers[1];
|
||||||
const heatmapValuesBuffer = allTensorBuffers[2];
|
const heatmapValuesBuffer = allTensorBuffers[2];
|
||||||
const offsetPoints = decoders.getOffsetPoints(heatmapValuesBuffer, defaultOutputStride, offsetsBuffer);
|
const offsetPoints = decoders.getOffsetPoints(heatmapValuesBuffer, defaultOutputStride, offsetsBuffer);
|
||||||
const offsetPointsBuffer = await offsetPoints.buffer();
|
const offsetPointsData = offsetPoints.dataSync();
|
||||||
const keypointConfidence = Array.from(decoders.getPointsConfidence(scoresBuffer, heatmapValuesBuffer));
|
const keypointConfidence = decoders.getPointsConfidence(scoresBuffer, heatmapValuesBuffer);
|
||||||
const instanceKeypoints = keypointConfidence.map((score, i) => {
|
let avgScore = 0.0;
|
||||||
totalScore += score;
|
const filteredKeypoints = keypointConfidence
|
||||||
return {
|
.filter((score) => score > minScore)
|
||||||
position: {
|
.map((score, i) => {
|
||||||
y: offsetPointsBuffer.get(i, 0),
|
avgScore += score;
|
||||||
x: offsetPointsBuffer.get(i, 1),
|
return {
|
||||||
},
|
position: {
|
||||||
part: keypoints.partNames[i],
|
y: offsetPointsData[2 * i + 0], // offsetPointsBuffer.get(i, 0),
|
||||||
score,
|
x: offsetPointsData[2 * i + 1], // offsetPointsBuffer.get(i, 1),
|
||||||
};
|
},
|
||||||
});
|
part: keypoints.partNames[i],
|
||||||
const filteredKeypoints = instanceKeypoints.filter((kpt) => kpt.score > minScore);
|
score,
|
||||||
|
};
|
||||||
|
});
|
||||||
heatmapValues.dispose();
|
heatmapValues.dispose();
|
||||||
offsetPoints.dispose();
|
offsetPoints.dispose();
|
||||||
return { keypoints: filteredKeypoints, score: totalScore / instanceKeypoints.length };
|
const box = utils.getBoundingBox(filteredKeypoints);
|
||||||
|
return { keypoints: filteredKeypoints, box, score: Math.round(100 * avgScore / filteredKeypoints.length) / 100 };
|
||||||
}
|
}
|
|
@ -1,54 +0,0 @@
|
||||||
import * as tf from '../../dist/tfjs.esm.js';
|
|
||||||
import * as kpt from './keypoints';
|
|
||||||
|
|
||||||
export function getPointsConfidence(heatmapScores, heatMapCoords) {
|
|
||||||
const numKeypoints = heatMapCoords.shape[0];
|
|
||||||
const result = new Float32Array(numKeypoints);
|
|
||||||
for (let keypoint = 0; keypoint < numKeypoints; keypoint++) {
|
|
||||||
const y = heatMapCoords.get(keypoint, 0);
|
|
||||||
const x = heatMapCoords.get(keypoint, 1);
|
|
||||||
result[keypoint] = heatmapScores.get(y, x, keypoint);
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
function getOffsetPoint(y, x, keypoint, offsetsBuffer) {
|
|
||||||
return {
|
|
||||||
y: offsetsBuffer.get(y, x, keypoint),
|
|
||||||
x: offsetsBuffer.get(y, x, keypoint + kpt.NUM_KEYPOINTS),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getOffsetVectors(heatMapCoordsBuffer, offsetsBuffer) {
|
|
||||||
const result: Array<number> = [];
|
|
||||||
for (let keypoint = 0; keypoint < kpt.NUM_KEYPOINTS; keypoint++) {
|
|
||||||
const heatmapY = heatMapCoordsBuffer.get(keypoint, 0).valueOf();
|
|
||||||
const heatmapX = heatMapCoordsBuffer.get(keypoint, 1).valueOf();
|
|
||||||
const { x, y } = getOffsetPoint(heatmapY, heatmapX, keypoint, offsetsBuffer);
|
|
||||||
result.push(y);
|
|
||||||
result.push(x);
|
|
||||||
}
|
|
||||||
return tf.tensor2d(result, [kpt.NUM_KEYPOINTS, 2]);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getOffsetPoints(heatMapCoordsBuffer, outputStride, offsetsBuffer) {
|
|
||||||
return tf.tidy(() => heatMapCoordsBuffer.toTensor().mul(tf.scalar(outputStride, 'int32')).toFloat().add(getOffsetVectors(heatMapCoordsBuffer, offsetsBuffer)));
|
|
||||||
}
|
|
||||||
|
|
||||||
function mod(a, b) {
|
|
||||||
return tf.tidy(() => {
|
|
||||||
const floored = a.div(tf.scalar(b, 'int32'));
|
|
||||||
return a.sub(floored.mul(tf.scalar(b, 'int32')));
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function argmax2d(inputs) {
|
|
||||||
const [height, width, depth] = inputs.shape;
|
|
||||||
return tf.tidy(() => {
|
|
||||||
const reshaped = inputs.reshape([height * width, depth]);
|
|
||||||
const coords = reshaped.argMax(0);
|
|
||||||
const yCoords = coords.div(tf.scalar(width, 'int32')).expandDims(1);
|
|
||||||
const xCoords = mod(coords, width).expandDims(1);
|
|
||||||
return tf.concat([yCoords, xCoords], 1);
|
|
||||||
});
|
|
||||||
}
|
|
|
@ -1,75 +0,0 @@
|
||||||
// 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);
|
|
||||||
}
|
|
||||||
export class MaxHeap {
|
|
||||||
priorityQueue: any;
|
|
||||||
numberOfElements: number;
|
|
||||||
getElementValue: any;
|
|
||||||
|
|
||||||
constructor(maxSize, getElementValue) {
|
|
||||||
this.priorityQueue = new Array(maxSize);
|
|
||||||
this.numberOfElements = -1;
|
|
||||||
this.getElementValue = getElementValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
enqueue(x) {
|
|
||||||
this.priorityQueue[++this.numberOfElements] = x;
|
|
||||||
this.swim(this.numberOfElements);
|
|
||||||
}
|
|
||||||
|
|
||||||
dequeue() {
|
|
||||||
const max = this.priorityQueue[0];
|
|
||||||
this.exchange(0, this.numberOfElements--);
|
|
||||||
this.sink(0);
|
|
||||||
this.priorityQueue[this.numberOfElements + 1] = null;
|
|
||||||
return max;
|
|
||||||
}
|
|
||||||
|
|
||||||
empty() {
|
|
||||||
return this.numberOfElements === -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
size() {
|
|
||||||
return this.numberOfElements + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
all() {
|
|
||||||
return this.priorityQueue.slice(0, this.numberOfElements + 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
max() {
|
|
||||||
return this.priorityQueue[0];
|
|
||||||
}
|
|
||||||
|
|
||||||
swim(k) {
|
|
||||||
while (k > 0 && this.less(half(k), k)) {
|
|
||||||
this.exchange(k, half(k));
|
|
||||||
k = half(k);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sink(k) {
|
|
||||||
while (2 * k <= this.numberOfElements) {
|
|
||||||
let 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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
getValueAt(i) {
|
|
||||||
return this.getElementValue(this.priorityQueue[i]);
|
|
||||||
}
|
|
||||||
|
|
||||||
less(i, j) {
|
|
||||||
return this.getValueAt(i) < this.getValueAt(j);
|
|
||||||
}
|
|
||||||
|
|
||||||
exchange(i, j) {
|
|
||||||
const t = this.priorityQueue[i];
|
|
||||||
this.priorityQueue[i] = this.priorityQueue[j];
|
|
||||||
this.priorityQueue[j] = t;
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,7 @@ export const partNames = [
|
||||||
'leftHip', 'rightHip', 'leftKnee', 'rightKnee', 'leftAnkle', 'rightAnkle',
|
'leftHip', 'rightHip', 'leftKnee', 'rightKnee', 'leftAnkle', 'rightAnkle',
|
||||||
];
|
];
|
||||||
|
|
||||||
export const NUM_KEYPOINTS = partNames.length; // 17 keypoints
|
export const count = partNames.length; // 17 keypoints
|
||||||
|
|
||||||
export const partIds = partNames.reduce((result, jointName, i) => {
|
export const partIds = partNames.reduce((result, jointName, i) => {
|
||||||
result[jointName] = i;
|
result[jointName] = i;
|
||||||
|
@ -31,30 +31,3 @@ export const poseChain = [
|
||||||
['rightShoulder', 'rightHip'], ['rightHip', 'rightKnee'],
|
['rightShoulder', 'rightHip'], ['rightHip', 'rightKnee'],
|
||||||
['rightKnee', 'rightAnkle'],
|
['rightKnee', 'rightAnkle'],
|
||||||
];
|
];
|
||||||
|
|
||||||
export const 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',
|
|
||||||
];
|
|
||||||
|
|
|
@ -1,26 +0,0 @@
|
||||||
export class ModelWeights {
|
|
||||||
variables: any;
|
|
||||||
constructor(variables) {
|
|
||||||
this.variables = variables;
|
|
||||||
}
|
|
||||||
|
|
||||||
weights(layerName) {
|
|
||||||
return this.variables[`MobilenetV1/${layerName}/weights`];
|
|
||||||
}
|
|
||||||
|
|
||||||
depthwiseBias(layerName) {
|
|
||||||
return this.variables[`MobilenetV1/${layerName}/biases`];
|
|
||||||
}
|
|
||||||
|
|
||||||
convBias(layerName) {
|
|
||||||
return this.depthwiseBias(layerName);
|
|
||||||
}
|
|
||||||
|
|
||||||
depthwiseWeights(layerName) {
|
|
||||||
return this.variables[`MobilenetV1/${layerName}/depthwise_weights`];
|
|
||||||
}
|
|
||||||
|
|
||||||
dispose() {
|
|
||||||
for (let i = 0; i < this.variables.length; i++) this.variables[i].dispose();
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,29 +1,31 @@
|
||||||
import { log, join } from '../helpers';
|
import { log, join } from '../helpers';
|
||||||
import * as tf from '../../dist/tfjs.esm.js';
|
import * as tf from '../../dist/tfjs.esm.js';
|
||||||
import * as modelBase from './modelBase';
|
import * as posenetModel from './posenetModel';
|
||||||
import * as decodeMultiple from './decodeMultiple';
|
import * as decodeMultiple from './decodeMultiple';
|
||||||
import * as decodePose from './decodePose';
|
import * as decodeSingle from './decodeSingle';
|
||||||
import * as util from './util';
|
import * as util from './utils';
|
||||||
|
|
||||||
let model;
|
let model;
|
||||||
|
|
||||||
async function estimateMultiple(input, res, config, inputSize) {
|
async function estimateMultiple(input, res, config, inputSize) {
|
||||||
|
const toTensorBuffers3D = (tensors) => Promise.all(tensors.map((tensor) => tensor.buffer()));
|
||||||
|
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
const allTensorBuffers = await util.toTensorBuffers3D([res.heatmapScores, res.offsets, res.displacementFwd, res.displacementBwd]);
|
const allTensorBuffers = await toTensorBuffers3D([res.heatmapScores, res.offsets, res.displacementFwd, res.displacementBwd]);
|
||||||
const scoresBuffer = allTensorBuffers[0];
|
const scoresBuffer = allTensorBuffers[0];
|
||||||
const offsetsBuffer = allTensorBuffers[1];
|
const offsetsBuffer = allTensorBuffers[1];
|
||||||
const displacementsFwdBuffer = allTensorBuffers[2];
|
const displacementsFwdBuffer = allTensorBuffers[2];
|
||||||
const displacementsBwdBuffer = allTensorBuffers[3];
|
const displacementsBwdBuffer = allTensorBuffers[3];
|
||||||
const poses = await decodeMultiple.decodeMultiplePoses(scoresBuffer, offsetsBuffer, displacementsFwdBuffer, displacementsBwdBuffer, config.body.nmsRadius, config.body.maxDetections, config.body.scoreThreshold);
|
const poses = await decodeMultiple.decodeMultiplePoses(scoresBuffer, offsetsBuffer, displacementsFwdBuffer, displacementsBwdBuffer, config.body.nmsRadius, config.body.maxDetections, config.body.scoreThreshold);
|
||||||
const scaled = util.scaleAndFlipPoses(poses, [input.shape[1], input.shape[2]], [inputSize, inputSize]);
|
const scaled = util.scalePoses(poses, [input.shape[1], input.shape[2]], [inputSize, inputSize]);
|
||||||
resolve(scaled);
|
resolve(scaled);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function estimateSingle(input, res, config, inputSize) {
|
async function estimateSingle(input, res, config, inputSize) {
|
||||||
return new Promise(async (resolve) => {
|
return new Promise(async (resolve) => {
|
||||||
const pose = await decodePose.decodeSinglePose(res.heatmapScores, res.offsets, config.body.scoreThreshold);
|
const pose = await decodeSingle.decodeSinglePose(res.heatmapScores, res.offsets, config.body.scoreThreshold);
|
||||||
const scaled = util.scaleAndFlipPoses([pose], [input.shape[1], input.shape[2]], [inputSize, inputSize]);
|
const scaled = util.scalePoses([pose], [input.shape[1], input.shape[2]], [inputSize, inputSize]);
|
||||||
resolve(scaled);
|
resolve(scaled);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -31,15 +33,13 @@ async function estimateSingle(input, res, config, inputSize) {
|
||||||
export class PoseNet {
|
export class PoseNet {
|
||||||
baseModel: any;
|
baseModel: any;
|
||||||
inputSize: number
|
inputSize: number
|
||||||
constructor(mobilenet) {
|
constructor(baseModel) {
|
||||||
this.baseModel = mobilenet;
|
this.baseModel = baseModel;
|
||||||
this.inputSize = mobilenet.model.inputs[0].shape[1];
|
this.inputSize = baseModel.model.inputs[0].shape[1];
|
||||||
if (this.inputSize < 128) this.inputSize = 257;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
async estimatePoses(input, config) {
|
async estimatePoses(input, config) {
|
||||||
const resized = util.resizeTo(input, [this.inputSize, this.inputSize]);
|
const res = this.baseModel.predict(input, config);
|
||||||
const res = this.baseModel.predict(resized, config);
|
|
||||||
|
|
||||||
const poses = (config.body.maxDetections < 2)
|
const poses = (config.body.maxDetections < 2)
|
||||||
? await estimateSingle(input, res, config, this.inputSize)
|
? await estimateSingle(input, res, config, this.inputSize)
|
||||||
|
@ -49,7 +49,6 @@ export class PoseNet {
|
||||||
res.offsets.dispose();
|
res.offsets.dispose();
|
||||||
res.displacementFwd.dispose();
|
res.displacementFwd.dispose();
|
||||||
res.displacementBwd.dispose();
|
res.displacementBwd.dispose();
|
||||||
resized.dispose();
|
|
||||||
|
|
||||||
return poses;
|
return poses;
|
||||||
}
|
}
|
||||||
|
@ -65,7 +64,7 @@ export async function load(config) {
|
||||||
if (!model || !model.modelUrl) log('load model failed:', config.body.modelPath);
|
if (!model || !model.modelUrl) log('load model failed:', config.body.modelPath);
|
||||||
else if (config.debug) log('load model:', model.modelUrl);
|
else if (config.debug) log('load model:', model.modelUrl);
|
||||||
} else if (config.debug) log('cached model:', model.modelUrl);
|
} else if (config.debug) log('cached model:', model.modelUrl);
|
||||||
const mobilenet = new modelBase.BaseModel(model);
|
const mobilenet = new posenetModel.BaseModel(model);
|
||||||
const poseNet = new PoseNet(mobilenet);
|
const poseNet = new PoseNet(mobilenet);
|
||||||
return poseNet;
|
return poseNet;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,7 @@
|
||||||
import * as tf from '../../dist/tfjs.esm.js';
|
import * as tf from '../../dist/tfjs.esm.js';
|
||||||
|
|
||||||
|
const poseNetOutputs = ['MobilenetV1/offset_2/BiasAdd', 'MobilenetV1/heatmap_2/BiasAdd', 'MobilenetV1/displacement_fwd_2/BiasAdd', 'MobilenetV1/displacement_bwd_2/BiasAdd'];
|
||||||
|
|
||||||
function nameOutputResultsMobileNet(results) {
|
function nameOutputResultsMobileNet(results) {
|
||||||
const [offsets, heatmap, displacementFwd, displacementBwd] = results;
|
const [offsets, heatmap, displacementFwd, displacementBwd] = results;
|
||||||
return { offsets, heatmap, displacementFwd, displacementBwd };
|
return { offsets, heatmap, displacementFwd, displacementBwd };
|
||||||
|
@ -7,15 +9,18 @@ function nameOutputResultsMobileNet(results) {
|
||||||
|
|
||||||
export class BaseModel {
|
export class BaseModel {
|
||||||
model: any;
|
model: any;
|
||||||
|
inputSize: number;
|
||||||
constructor(model) {
|
constructor(model) {
|
||||||
this.model = model;
|
this.model = model;
|
||||||
|
this.inputSize = model.inputs[0].shape[1];
|
||||||
}
|
}
|
||||||
|
|
||||||
predict(input) {
|
predict(input) {
|
||||||
return tf.tidy(() => {
|
return tf.tidy(() => {
|
||||||
const asFloat = input.toFloat().div(127.5).sub(1.0);
|
const resized = input.resizeBilinear([this.inputSize, this.inputSize]);
|
||||||
const asBatch = asFloat.expandDims(0);
|
const normalized = resized.toFloat().div(127.5).sub(1.0);
|
||||||
const results = this.model.predict(asBatch);
|
// const asBatch = asFloat.expandDims(0);
|
||||||
|
const results = this.model.execute(normalized, poseNetOutputs);
|
||||||
const results3d = results.map((y) => y.squeeze([0]));
|
const results3d = results.map((y) => y.squeeze([0]));
|
||||||
const namedResults = nameOutputResultsMobileNet(results3d);
|
const namedResults = nameOutputResultsMobileNet(results3d);
|
||||||
return {
|
return {
|
|
@ -1,62 +0,0 @@
|
||||||
import * as kpt from './keypoints';
|
|
||||||
|
|
||||||
export function eitherPointDoesntMeetConfidence(a, b, minConfidence) {
|
|
||||||
return (a < minConfidence || b < minConfidence);
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getAdjacentKeyPoints(keypoints, minConfidence) {
|
|
||||||
return kpt.connectedPartIndices.reduce((result, [leftJoint, rightJoint]) => {
|
|
||||||
if (eitherPointDoesntMeetConfidence(keypoints[leftJoint].score, keypoints[rightJoint].score, minConfidence)) {
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
result.push([keypoints[leftJoint], keypoints[rightJoint]]);
|
|
||||||
return result;
|
|
||||||
}, []);
|
|
||||||
}
|
|
||||||
|
|
||||||
const { NEGATIVE_INFINITY, POSITIVE_INFINITY } = Number;
|
|
||||||
export function getBoundingBox(keypoints) {
|
|
||||||
return keypoints.reduce(({ maxX, maxY, minX, minY }, { position: { x, y } }) => ({
|
|
||||||
maxX: Math.max(maxX, x),
|
|
||||||
maxY: Math.max(maxY, y),
|
|
||||||
minX: Math.min(minX, x),
|
|
||||||
minY: Math.min(minY, y),
|
|
||||||
}), {
|
|
||||||
maxX: NEGATIVE_INFINITY,
|
|
||||||
maxY: NEGATIVE_INFINITY,
|
|
||||||
minX: POSITIVE_INFINITY,
|
|
||||||
minY: POSITIVE_INFINITY,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getBoundingBoxPoints(keypoints) {
|
|
||||||
const { minX, minY, maxX, maxY } = getBoundingBox(keypoints);
|
|
||||||
return [{ x: minX, y: minY }, { x: maxX, y: minY }, { x: maxX, y: maxY }, { x: minX, y: maxY }];
|
|
||||||
}
|
|
||||||
|
|
||||||
export async function toTensorBuffers3D(tensors) {
|
|
||||||
return Promise.all(tensors.map((tensor) => tensor.buffer()));
|
|
||||||
}
|
|
||||||
|
|
||||||
export function scalePose(pose, scaleY, scaleX) {
|
|
||||||
return {
|
|
||||||
score: pose.score,
|
|
||||||
keypoints: pose.keypoints.map(({ score, part, position }) => ({
|
|
||||||
score,
|
|
||||||
part,
|
|
||||||
position: { x: Math.trunc(position.x * scaleX), y: Math.trunc(position.y * scaleY) },
|
|
||||||
})),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function resizeTo(image, [targetH, targetW]) {
|
|
||||||
const input = image.squeeze(0);
|
|
||||||
const resized = input.resizeBilinear([targetH, targetW]);
|
|
||||||
input.dispose();
|
|
||||||
return resized;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function scaleAndFlipPoses(poses, [height, width], [inputResolutionHeight, inputResolutionWidth]) {
|
|
||||||
const scaledPoses = poses.map((pose) => scalePose(pose, height / inputResolutionHeight, width / inputResolutionWidth));
|
|
||||||
return scaledPoses;
|
|
||||||
}
|
|
|
@ -0,0 +1,154 @@
|
||||||
|
import * as kpt from './keypoints';
|
||||||
|
|
||||||
|
export function eitherPointDoesntMeetConfidence(a, b, minConfidence) {
|
||||||
|
return (a < minConfidence || b < minConfidence);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getAdjacentKeyPoints(keypoints, minConfidence) {
|
||||||
|
return kpt.connectedPartIndices.reduce((result, [leftJoint, rightJoint]) => {
|
||||||
|
if (eitherPointDoesntMeetConfidence(keypoints[leftJoint].score, keypoints[rightJoint].score, minConfidence)) {
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
result.push([keypoints[leftJoint], keypoints[rightJoint]]);
|
||||||
|
return result;
|
||||||
|
}, []);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getBoundingBox(keypoints) {
|
||||||
|
const coord = keypoints.reduce(({ maxX, maxY, minX, minY }, { position: { x, y } }) => ({
|
||||||
|
maxX: Math.max(maxX, x),
|
||||||
|
maxY: Math.max(maxY, y),
|
||||||
|
minX: Math.min(minX, x),
|
||||||
|
minY: Math.min(minY, y),
|
||||||
|
}), {
|
||||||
|
maxX: Number.NEGATIVE_INFINITY,
|
||||||
|
maxY: Number.NEGATIVE_INFINITY,
|
||||||
|
minX: Number.POSITIVE_INFINITY,
|
||||||
|
minY: Number.POSITIVE_INFINITY,
|
||||||
|
});
|
||||||
|
return [coord.minX, coord.minY, coord.maxX - coord.minX, coord.maxY - coord.minY];
|
||||||
|
}
|
||||||
|
|
||||||
|
export function scalePoses(poses, [height, width], [inputResolutionHeight, inputResolutionWidth]) {
|
||||||
|
const scalePose = (pose, scaleY, scaleX) => ({
|
||||||
|
score: pose.score,
|
||||||
|
box: [Math.trunc(pose.box[0] * scaleX), Math.trunc(pose.box[1] * scaleY), Math.trunc(pose.box[2] * scaleX), Math.trunc(pose.box[3] * scaleY)],
|
||||||
|
keypoints: pose.keypoints.map(({ score, part, position }) => ({
|
||||||
|
score,
|
||||||
|
part,
|
||||||
|
position: { x: Math.trunc(position.x * scaleX), y: Math.trunc(position.y * scaleY) },
|
||||||
|
})),
|
||||||
|
});
|
||||||
|
|
||||||
|
const scaledPoses = poses.map((pose) => scalePose(pose, height / inputResolutionHeight, width / inputResolutionWidth));
|
||||||
|
return scaledPoses;
|
||||||
|
}
|
||||||
|
|
||||||
|
// algorithm based on Coursera Lecture from Algorithms, Part 1: https://www.coursera.org/learn/algorithms-part1/lecture/ZjoSM/heapsort
|
||||||
|
export class MaxHeap {
|
||||||
|
priorityQueue: any;
|
||||||
|
numberOfElements: number;
|
||||||
|
getElementValue: any;
|
||||||
|
|
||||||
|
constructor(maxSize, getElementValue) {
|
||||||
|
this.priorityQueue = new Array(maxSize);
|
||||||
|
this.numberOfElements = -1;
|
||||||
|
this.getElementValue = getElementValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
enqueue(x) {
|
||||||
|
this.priorityQueue[++this.numberOfElements] = x;
|
||||||
|
this.swim(this.numberOfElements);
|
||||||
|
}
|
||||||
|
|
||||||
|
dequeue() {
|
||||||
|
const max = this.priorityQueue[0];
|
||||||
|
this.exchange(0, this.numberOfElements--);
|
||||||
|
this.sink(0);
|
||||||
|
this.priorityQueue[this.numberOfElements + 1] = null;
|
||||||
|
return max;
|
||||||
|
}
|
||||||
|
|
||||||
|
empty() { return this.numberOfElements === -1; }
|
||||||
|
|
||||||
|
size() { return this.numberOfElements + 1; }
|
||||||
|
|
||||||
|
all() { return this.priorityQueue.slice(0, this.numberOfElements + 1); }
|
||||||
|
|
||||||
|
max() { return this.priorityQueue[0]; }
|
||||||
|
|
||||||
|
swim(k) {
|
||||||
|
while (k > 0 && this.less(Math.floor(k / 2), k)) {
|
||||||
|
this.exchange(k, Math.floor(k / 2));
|
||||||
|
k = Math.floor(k / 2);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
sink(k) {
|
||||||
|
while (2 * k <= this.numberOfElements) {
|
||||||
|
let 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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
getValueAt(i) {
|
||||||
|
return this.getElementValue(this.priorityQueue[i]);
|
||||||
|
}
|
||||||
|
|
||||||
|
less(i, j) {
|
||||||
|
return this.getValueAt(i) < this.getValueAt(j);
|
||||||
|
}
|
||||||
|
|
||||||
|
exchange(i, j) {
|
||||||
|
const t = this.priorityQueue[i];
|
||||||
|
this.priorityQueue[i] = this.priorityQueue[j];
|
||||||
|
this.priorityQueue[j] = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getOffsetPoint(y, x, keypoint, offsets) {
|
||||||
|
return {
|
||||||
|
y: offsets.get(y, x, keypoint),
|
||||||
|
x: offsets.get(y, x, keypoint + kpt.count),
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function getImageCoords(part, outputStride, offsets) {
|
||||||
|
const { heatmapY, heatmapX, id: keypoint } = part;
|
||||||
|
const { y, x } = getOffsetPoint(heatmapY, heatmapX, keypoint, offsets);
|
||||||
|
return {
|
||||||
|
x: part.heatmapX * outputStride + x,
|
||||||
|
y: part.heatmapY * outputStride + y,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
export function fillArray(element, size) {
|
||||||
|
const result = new Array(size);
|
||||||
|
for (let i = 0; i < size; i++) {
|
||||||
|
result[i] = element;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clamp(a, min, max) {
|
||||||
|
if (a < min) return min;
|
||||||
|
if (a > max) return max;
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function squaredDistance(y1, x1, y2, x2) {
|
||||||
|
const dy = y2 - y1;
|
||||||
|
const dx = x2 - x1;
|
||||||
|
return dy * dy + dx * dx;
|
||||||
|
}
|
||||||
|
|
||||||
|
export function addVectors(a, b) {
|
||||||
|
return { x: a.x + b.x, y: a.y + b.y };
|
||||||
|
}
|
||||||
|
|
||||||
|
export function clampVector(a, min, max) {
|
||||||
|
return { y: clamp(a.y, min, max), x: clamp(a.x, min, max) };
|
||||||
|
}
|
|
@ -1,45 +0,0 @@
|
||||||
import * as kpt from './keypoints';
|
|
||||||
|
|
||||||
export function getOffsetPoint(y, x, keypoint, offsets) {
|
|
||||||
return {
|
|
||||||
y: offsets.get(y, x, keypoint),
|
|
||||||
x: offsets.get(y, x, keypoint + kpt.NUM_KEYPOINTS),
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function getImageCoords(part, outputStride, offsets) {
|
|
||||||
const { heatmapY, heatmapX, id: keypoint } = part;
|
|
||||||
const { y, x } = getOffsetPoint(heatmapY, heatmapX, keypoint, offsets);
|
|
||||||
return {
|
|
||||||
x: part.heatmapX * outputStride + x,
|
|
||||||
y: part.heatmapY * outputStride + y,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
export function fillArray(element, size) {
|
|
||||||
const result = new Array(size);
|
|
||||||
for (let i = 0; i < size; i++) {
|
|
||||||
result[i] = element;
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function clamp(a, min, max) {
|
|
||||||
if (a < min) return min;
|
|
||||||
if (a > max) return max;
|
|
||||||
return a;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function squaredDistance(y1, x1, y2, x2) {
|
|
||||||
const dy = y2 - y1;
|
|
||||||
const dx = x2 - x1;
|
|
||||||
return dy * dy + dx * dx;
|
|
||||||
}
|
|
||||||
|
|
||||||
export function addVectors(a, b) {
|
|
||||||
return { x: a.x + b.x, y: a.y + b.y };
|
|
||||||
}
|
|
||||||
|
|
||||||
export function clampVector(a, min, max) {
|
|
||||||
return { y: clamp(a.y, min, max), x: clamp(a.x, min, max) };
|
|
||||||
}
|
|
169
test/test.log
169
test/test.log
|
@ -744,3 +744,172 @@
|
||||||
2021-04-19 16:20:08 [31mERROR:[39m test-node-wasm.js failed: model server: request to http://localhost:10030/models/ failed, reason: connect ECONNREFUSED 127.0.0.1:10030
|
2021-04-19 16:20:08 [31mERROR:[39m test-node-wasm.js failed: model server: request to http://localhost:10030/models/ failed, reason: connect ECONNREFUSED 127.0.0.1:10030
|
||||||
2021-04-19 16:20:08 [31mERROR:[39m test-node-wasm.js aborting test
|
2021-04-19 16:20:08 [31mERROR:[39m test-node-wasm.js aborting test
|
||||||
2021-04-19 16:20:08 [36mINFO: [39m status: {"passed":50,"failed":1}
|
2021-04-19 16:20:08 [36mINFO: [39m status: {"passed":50,"failed":1}
|
||||||
|
2021-04-24 11:45:56 [36mINFO: [39m @vladmandic/human version 1.6.1
|
||||||
|
2021-04-24 11:45:56 [36mINFO: [39m User: vlado Platform: linux Arch: x64 Node: v16.0.0
|
||||||
|
2021-04-24 11:45:56 [36mINFO: [39m tests: ["test-node.js","test-node-gpu.js","test-node-wasm.js"]
|
||||||
|
2021-04-24 11:45:56 [36mINFO: [39m test-node.js start
|
||||||
|
2021-04-24 11:45:57 [35mSTATE:[39m test-node.js passed: create human
|
||||||
|
2021-04-24 11:45:57 [36mINFO: [39m test-node.js human version: 1.6.1
|
||||||
|
2021-04-24 11:45:57 [36mINFO: [39m test-node.js platform: linux x64 agent: NodeJS v16.0.0
|
||||||
|
2021-04-24 11:45:57 [36mINFO: [39m test-node.js tfjs version: 3.5.0
|
||||||
|
2021-04-24 11:45:58 [35mSTATE:[39m test-node.js passed: set backend: tensorflow
|
||||||
|
2021-04-24 11:45:58 [35mSTATE:[39m test-node.js passed: load models
|
||||||
|
2021-04-24 11:45:58 [35mSTATE:[39m test-node.js result: defined models: 12 loaded models: 6
|
||||||
|
2021-04-24 11:45:58 [35mSTATE:[39m test-node.js passed: warmup: none default
|
||||||
|
2021-04-24 11:45:59 [35mSTATE:[39m test-node.js passed: warmup: face default
|
||||||
|
2021-04-24 11:45:59 [32mDATA: [39m test-node.js result: face: 1 body: 1 hand: 0 gesture: 5 object: 1 {"confidence":1,"age":23.6,"gender":"female"} {"score":0.52,"class":"person"} {"score":0.88,"keypoints":6}
|
||||||
|
2021-04-24 11:45:59 [32mDATA: [39m test-node.js result: performance: load: 393 total: 1436
|
||||||
|
2021-04-24 11:46:00 [35mSTATE:[39m test-node.js passed: warmup: body default
|
||||||
|
2021-04-24 11:46:00 [32mDATA: [39m test-node.js result: face: 1 body: 1 hand: 0 gesture: 3 object: 3 {"confidence":1,"age":28.5,"gender":"female"} {"score":0.86,"class":"person"} {"score":0.92,"keypoints":17}
|
||||||
|
2021-04-24 11:46:00 [32mDATA: [39m test-node.js result: performance: load: 393 total: 1407
|
||||||
|
2021-04-24 11:46:00 [36mINFO: [39m test-node.js test body variants
|
||||||
|
2021-04-24 11:46:02 [35mSTATE:[39m test-node.js passed: load image: assets/human-sample-body.jpg [1,1200,1200,3]
|
||||||
|
2021-04-24 11:46:03 [35mSTATE:[39m test-node.js passed: detect: assets/human-sample-body.jpg posenet
|
||||||
|
2021-04-24 11:46:03 [32mDATA: [39m test-node.js result: face: 1 body: 1 hand: 0 gesture: 3 object: 3 {"confidence":1,"age":28.5,"gender":"female"} {"score":0.86,"class":"person"} {"score":0.92,"keypoints":17}
|
||||||
|
2021-04-24 11:46:03 [32mDATA: [39m test-node.js result: performance: load: 393 total: 1295
|
||||||
|
2021-04-24 11:46:04 [35mSTATE:[39m test-node.js passed: load image: assets/human-sample-body.jpg [1,1200,1200,3]
|
||||||
|
2021-04-24 11:46:05 [35mSTATE:[39m test-node.js passed: detect: assets/human-sample-body.jpg blazepose
|
||||||
|
2021-04-24 11:46:05 [32mDATA: [39m test-node.js result: face: 1 body: 1 hand: 0 gesture: 3 object: 3 {"confidence":1,"age":28.5,"gender":"female"} {"score":0.86,"class":"person"} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:46:05 [32mDATA: [39m test-node.js result: performance: load: 393 total: 1405
|
||||||
|
2021-04-24 11:46:06 [35mSTATE:[39m test-node.js passed: detect: random default
|
||||||
|
2021-04-24 11:46:06 [32mDATA: [39m test-node.js result: face: 0 body: 1 hand: 0 gesture: 1 object: 0 {} {} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:46:06 [32mDATA: [39m test-node.js result: performance: load: 393 total: 734
|
||||||
|
2021-04-24 11:46:06 [36mINFO: [39m test-node.js test: first instance
|
||||||
|
2021-04-24 11:46:07 [35mSTATE:[39m test-node.js passed: load image: assets/sample-me.jpg [1,700,700,3]
|
||||||
|
2021-04-24 11:46:08 [35mSTATE:[39m test-node.js passed: detect: assets/sample-me.jpg default
|
||||||
|
2021-04-24 11:46:08 [32mDATA: [39m test-node.js result: face: 1 body: 1 hand: 0 gesture: 6 object: 2 {"confidence":1,"age":39.2,"gender":"male"} {"score":0.7,"class":"person"} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:46:08 [32mDATA: [39m test-node.js result: performance: load: 393 total: 1126
|
||||||
|
2021-04-24 11:46:08 [36mINFO: [39m test-node.js test: second instance
|
||||||
|
2021-04-24 11:46:08 [35mSTATE:[39m test-node.js passed: load image: assets/sample-me.jpg [1,700,700,3]
|
||||||
|
2021-04-24 11:46:09 [35mSTATE:[39m test-node.js passed: detect: assets/sample-me.jpg default
|
||||||
|
2021-04-24 11:46:09 [32mDATA: [39m test-node.js result: face: 1 body: 1 hand: 0 gesture: 6 object: 2 {"confidence":1,"age":39.2,"gender":"male"} {"score":0.7,"class":"person"} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:46:09 [32mDATA: [39m test-node.js result: performance: load: 3 total: 1008
|
||||||
|
2021-04-24 11:46:09 [36mINFO: [39m test-node.js test: concurrent
|
||||||
|
2021-04-24 11:46:09 [35mSTATE:[39m test-node.js passed: load image: assets/human-sample-face.jpg [1,256,256,3]
|
||||||
|
2021-04-24 11:46:09 [35mSTATE:[39m test-node.js passed: load image: assets/human-sample-face.jpg [1,256,256,3]
|
||||||
|
2021-04-24 11:46:10 [35mSTATE:[39m test-node.js passed: load image: assets/human-sample-body.jpg [1,1200,1200,3]
|
||||||
|
2021-04-24 11:46:11 [35mSTATE:[39m test-node.js passed: load image: assets/human-sample-body.jpg [1,1200,1200,3]
|
||||||
|
2021-04-24 11:46:16 [35mSTATE:[39m test-node.js passed: detect: assets/human-sample-face.jpg default
|
||||||
|
2021-04-24 11:46:16 [32mDATA: [39m test-node.js result: face: 1 body: 1 hand: 0 gesture: 6 object: 1 {"confidence":1,"age":23.6,"gender":"female"} {"score":0.53,"class":"person"} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:46:16 [32mDATA: [39m test-node.js result: performance: load: 393 total: 4598
|
||||||
|
2021-04-24 11:46:16 [35mSTATE:[39m test-node.js passed: detect: assets/human-sample-face.jpg default
|
||||||
|
2021-04-24 11:46:16 [32mDATA: [39m test-node.js result: face: 1 body: 1 hand: 0 gesture: 6 object: 1 {"confidence":1,"age":23.6,"gender":"female"} {"score":0.53,"class":"person"} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:46:16 [32mDATA: [39m test-node.js result: performance: load: 3 total: 4598
|
||||||
|
2021-04-24 11:46:16 [35mSTATE:[39m test-node.js passed: detect: assets/human-sample-body.jpg default
|
||||||
|
2021-04-24 11:46:16 [32mDATA: [39m test-node.js result: face: 1 body: 1 hand: 0 gesture: 3 object: 3 {"confidence":1,"age":28.5,"gender":"female"} {"score":0.86,"class":"person"} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:46:16 [32mDATA: [39m test-node.js result: performance: load: 393 total: 4598
|
||||||
|
2021-04-24 11:46:16 [35mSTATE:[39m test-node.js passed: detect: assets/human-sample-body.jpg default
|
||||||
|
2021-04-24 11:46:16 [32mDATA: [39m test-node.js result: face: 1 body: 1 hand: 0 gesture: 3 object: 3 {"confidence":1,"age":28.5,"gender":"female"} {"score":0.86,"class":"person"} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:46:16 [32mDATA: [39m test-node.js result: performance: load: 3 total: 4598
|
||||||
|
2021-04-24 11:46:16 [36mINFO: [39m test-node.js test complete: 18747 ms
|
||||||
|
2021-04-24 11:46:16 [36mINFO: [39m test-node-gpu.js start
|
||||||
|
2021-04-24 11:46:17 [33mWARN: [39m test-node-gpu.js stderr: 2021-04-24 11:46:17.503614: W tensorflow/stream_executor/platform/default/dso_loader.cc:60] Could not load dynamic library 'libcudart.so.11.0'; dlerror: libcudart.so.11.0: cannot open shared object file: No such file or directory
|
||||||
|
2021-04-24 11:46:17 [33mWARN: [39m test-node-gpu.js stderr: 2021-04-24 11:46:17.721982: W tensorflow/stream_executor/platform/default/dso_loader.cc:60] Could not load dynamic library 'libcuda.so.1'; dlerror: libcuda.so.1: cannot open shared object file: No such file or directory
|
||||||
|
2021-04-24 11:46:17 [33mWARN: [39m test-node-gpu.js stderr: 2021-04-24 11:46:17.722060: I tensorflow/stream_executor/cuda/cuda_diagnostics.cc:156] kernel driver does not appear to be running on this host (wyse): /proc/driver/nvidia/version does not exist
|
||||||
|
2021-04-24 11:46:17 [35mSTATE:[39m test-node-gpu.js passed: create human
|
||||||
|
2021-04-24 11:46:17 [36mINFO: [39m test-node-gpu.js human version: 1.6.1
|
||||||
|
2021-04-24 11:46:17 [36mINFO: [39m test-node-gpu.js platform: linux x64 agent: NodeJS v16.0.0
|
||||||
|
2021-04-24 11:46:17 [36mINFO: [39m test-node-gpu.js tfjs version: 3.5.0
|
||||||
|
2021-04-24 11:46:18 [35mSTATE:[39m test-node-gpu.js passed: set backend: tensorflow
|
||||||
|
2021-04-24 11:46:18 [35mSTATE:[39m test-node-gpu.js passed: load models
|
||||||
|
2021-04-24 11:46:18 [35mSTATE:[39m test-node-gpu.js result: defined models: 12 loaded models: 6
|
||||||
|
2021-04-24 11:46:18 [35mSTATE:[39m test-node-gpu.js passed: warmup: none default
|
||||||
|
2021-04-24 11:46:19 [35mSTATE:[39m test-node-gpu.js passed: warmup: face default
|
||||||
|
2021-04-24 11:46:19 [32mDATA: [39m test-node-gpu.js result: face: 1 body: 1 hand: 0 gesture: 5 object: 1 {"confidence":1,"age":23.6,"gender":"female"} {"score":0.52,"class":"person"} {"score":0.88,"keypoints":6}
|
||||||
|
2021-04-24 11:46:19 [32mDATA: [39m test-node-gpu.js result: performance: load: 351 total: 1557
|
||||||
|
2021-04-24 11:46:21 [35mSTATE:[39m test-node-gpu.js passed: warmup: body default
|
||||||
|
2021-04-24 11:46:21 [32mDATA: [39m test-node-gpu.js result: face: 1 body: 1 hand: 0 gesture: 3 object: 3 {"confidence":1,"age":28.5,"gender":"female"} {"score":0.86,"class":"person"} {"score":0.92,"keypoints":17}
|
||||||
|
2021-04-24 11:46:21 [32mDATA: [39m test-node-gpu.js result: performance: load: 351 total: 1325
|
||||||
|
2021-04-24 11:46:21 [36mINFO: [39m test-node-gpu.js test body variants
|
||||||
|
2021-04-24 11:46:22 [35mSTATE:[39m test-node-gpu.js passed: load image: assets/human-sample-body.jpg [1,1200,1200,3]
|
||||||
|
2021-04-24 11:46:23 [35mSTATE:[39m test-node-gpu.js passed: detect: assets/human-sample-body.jpg posenet
|
||||||
|
2021-04-24 11:46:23 [32mDATA: [39m test-node-gpu.js result: face: 1 body: 1 hand: 0 gesture: 3 object: 3 {"confidence":1,"age":28.5,"gender":"female"} {"score":0.86,"class":"person"} {"score":0.92,"keypoints":17}
|
||||||
|
2021-04-24 11:46:23 [32mDATA: [39m test-node-gpu.js result: performance: load: 351 total: 1412
|
||||||
|
2021-04-24 11:46:24 [35mSTATE:[39m test-node-gpu.js passed: load image: assets/human-sample-body.jpg [1,1200,1200,3]
|
||||||
|
2021-04-24 11:46:26 [35mSTATE:[39m test-node-gpu.js passed: detect: assets/human-sample-body.jpg blazepose
|
||||||
|
2021-04-24 11:46:26 [32mDATA: [39m test-node-gpu.js result: face: 1 body: 1 hand: 0 gesture: 3 object: 3 {"confidence":1,"age":28.5,"gender":"female"} {"score":0.86,"class":"person"} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:46:26 [32mDATA: [39m test-node-gpu.js result: performance: load: 351 total: 1361
|
||||||
|
2021-04-24 11:46:26 [35mSTATE:[39m test-node-gpu.js passed: detect: random default
|
||||||
|
2021-04-24 11:46:26 [32mDATA: [39m test-node-gpu.js result: face: 0 body: 1 hand: 0 gesture: 1 object: 0 {} {} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:46:26 [32mDATA: [39m test-node-gpu.js result: performance: load: 351 total: 721
|
||||||
|
2021-04-24 11:46:26 [36mINFO: [39m test-node-gpu.js test: first instance
|
||||||
|
2021-04-24 11:46:27 [35mSTATE:[39m test-node-gpu.js passed: load image: assets/sample-me.jpg [1,700,700,3]
|
||||||
|
2021-04-24 11:46:28 [35mSTATE:[39m test-node-gpu.js passed: detect: assets/sample-me.jpg default
|
||||||
|
2021-04-24 11:46:28 [32mDATA: [39m test-node-gpu.js result: face: 1 body: 1 hand: 0 gesture: 6 object: 2 {"confidence":1,"age":39.2,"gender":"male"} {"score":0.7,"class":"person"} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:46:28 [32mDATA: [39m test-node-gpu.js result: performance: load: 351 total: 1122
|
||||||
|
2021-04-24 11:46:28 [36mINFO: [39m test-node-gpu.js test: second instance
|
||||||
|
2021-04-24 11:46:28 [35mSTATE:[39m test-node-gpu.js passed: load image: assets/sample-me.jpg [1,700,700,3]
|
||||||
|
2021-04-24 11:46:29 [35mSTATE:[39m test-node-gpu.js passed: detect: assets/sample-me.jpg default
|
||||||
|
2021-04-24 11:46:29 [32mDATA: [39m test-node-gpu.js result: face: 1 body: 1 hand: 0 gesture: 6 object: 2 {"confidence":1,"age":39.2,"gender":"male"} {"score":0.7,"class":"person"} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:46:29 [32mDATA: [39m test-node-gpu.js result: performance: load: 3 total: 1139
|
||||||
|
2021-04-24 11:46:29 [36mINFO: [39m test-node-gpu.js test: concurrent
|
||||||
|
2021-04-24 11:46:29 [35mSTATE:[39m test-node-gpu.js passed: load image: assets/human-sample-face.jpg [1,256,256,3]
|
||||||
|
2021-04-24 11:46:29 [35mSTATE:[39m test-node-gpu.js passed: load image: assets/human-sample-face.jpg [1,256,256,3]
|
||||||
|
2021-04-24 11:46:31 [35mSTATE:[39m test-node-gpu.js passed: load image: assets/human-sample-body.jpg [1,1200,1200,3]
|
||||||
|
2021-04-24 11:46:32 [35mSTATE:[39m test-node-gpu.js passed: load image: assets/human-sample-body.jpg [1,1200,1200,3]
|
||||||
|
2021-04-24 11:46:36 [35mSTATE:[39m test-node-gpu.js passed: detect: assets/human-sample-face.jpg default
|
||||||
|
2021-04-24 11:46:36 [32mDATA: [39m test-node-gpu.js result: face: 1 body: 1 hand: 0 gesture: 6 object: 1 {"confidence":1,"age":23.6,"gender":"female"} {"score":0.53,"class":"person"} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:46:36 [32mDATA: [39m test-node-gpu.js result: performance: load: 351 total: 4281
|
||||||
|
2021-04-24 11:46:36 [35mSTATE:[39m test-node-gpu.js passed: detect: assets/human-sample-face.jpg default
|
||||||
|
2021-04-24 11:46:36 [32mDATA: [39m test-node-gpu.js result: face: 1 body: 1 hand: 0 gesture: 6 object: 1 {"confidence":1,"age":23.6,"gender":"female"} {"score":0.53,"class":"person"} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:46:36 [32mDATA: [39m test-node-gpu.js result: performance: load: 3 total: 4281
|
||||||
|
2021-04-24 11:46:36 [35mSTATE:[39m test-node-gpu.js passed: detect: assets/human-sample-body.jpg default
|
||||||
|
2021-04-24 11:46:36 [32mDATA: [39m test-node-gpu.js result: face: 1 body: 1 hand: 0 gesture: 3 object: 3 {"confidence":1,"age":28.5,"gender":"female"} {"score":0.86,"class":"person"} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:46:36 [32mDATA: [39m test-node-gpu.js result: performance: load: 351 total: 4281
|
||||||
|
2021-04-24 11:46:36 [35mSTATE:[39m test-node-gpu.js passed: detect: assets/human-sample-body.jpg default
|
||||||
|
2021-04-24 11:46:36 [32mDATA: [39m test-node-gpu.js result: face: 1 body: 1 hand: 0 gesture: 3 object: 3 {"confidence":1,"age":28.5,"gender":"female"} {"score":0.86,"class":"person"} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:46:36 [32mDATA: [39m test-node-gpu.js result: performance: load: 3 total: 4281
|
||||||
|
2021-04-24 11:46:36 [36mINFO: [39m test-node-gpu.js test complete: 18563 ms
|
||||||
|
2021-04-24 11:46:36 [36mINFO: [39m test-node-wasm.js start
|
||||||
|
2021-04-24 11:46:36 [35mSTATE:[39m test-node-wasm.js passed: model server: http://localhost:10030/models/
|
||||||
|
2021-04-24 11:46:36 [35mSTATE:[39m test-node-wasm.js passed: create human
|
||||||
|
2021-04-24 11:46:36 [36mINFO: [39m test-node-wasm.js human version: 1.6.1
|
||||||
|
2021-04-24 11:46:36 [36mINFO: [39m test-node-wasm.js platform: linux x64 agent: NodeJS v16.0.0
|
||||||
|
2021-04-24 11:46:36 [36mINFO: [39m test-node-wasm.js tfjs version: 3.5.0
|
||||||
|
2021-04-24 11:46:37 [35mSTATE:[39m test-node-wasm.js passed: set backend: wasm
|
||||||
|
2021-04-24 11:46:37 [35mSTATE:[39m test-node-wasm.js passed: load models
|
||||||
|
2021-04-24 11:46:37 [35mSTATE:[39m test-node-wasm.js result: defined models: 12 loaded models: 5
|
||||||
|
2021-04-24 11:46:37 [35mSTATE:[39m test-node-wasm.js passed: warmup: none default
|
||||||
|
2021-04-24 11:46:37 [31mERROR:[39m test-node-wasm.js failed: warmup: face default
|
||||||
|
2021-04-24 11:46:37 [31mERROR:[39m test-node-wasm.js failed: warmup: body default
|
||||||
|
2021-04-24 11:46:37 [36mINFO: [39m test-node-wasm.js test body variants
|
||||||
|
2021-04-24 11:46:39 [35mSTATE:[39m test-node-wasm.js passed: load image: assets/human-sample-body.jpg [1,1200,1200,3]
|
||||||
|
2021-04-24 11:46:42 [35mSTATE:[39m test-node-wasm.js passed: detect: assets/human-sample-body.jpg posenet
|
||||||
|
2021-04-24 11:46:42 [32mDATA: [39m test-node-wasm.js result: face: 1 body: 1 hand: 0 gesture: 3 object: 0 {"confidence":1,"age":28.5,"gender":"female"} {} {"score":0.95,"keypoints":17}
|
||||||
|
2021-04-24 11:46:42 [32mDATA: [39m test-node-wasm.js result: performance: load: 687 total: 3290
|
||||||
|
2021-04-24 11:46:44 [35mSTATE:[39m test-node-wasm.js passed: load image: assets/human-sample-body.jpg [1,1200,1200,3]
|
||||||
|
2021-04-24 11:46:47 [35mSTATE:[39m test-node-wasm.js passed: detect: assets/human-sample-body.jpg blazepose
|
||||||
|
2021-04-24 11:46:47 [32mDATA: [39m test-node-wasm.js result: face: 1 body: 1 hand: 0 gesture: 3 object: 0 {"confidence":1,"age":28.5,"gender":"female"} {} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:46:47 [32mDATA: [39m test-node-wasm.js result: performance: load: 687 total: 2494
|
||||||
|
2021-04-24 11:46:48 [35mSTATE:[39m test-node-wasm.js passed: detect: random default
|
||||||
|
2021-04-24 11:46:48 [32mDATA: [39m test-node-wasm.js result: face: 0 body: 1 hand: 0 gesture: 1 object: 0 {} {} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:46:48 [32mDATA: [39m test-node-wasm.js result: performance: load: 687 total: 1409
|
||||||
|
2021-04-24 11:46:48 [36mINFO: [39m test-node-wasm.js test: first instance
|
||||||
|
2021-04-24 11:46:49 [35mSTATE:[39m test-node-wasm.js passed: load image: assets/sample-me.jpg [1,700,700,3]
|
||||||
|
2021-04-24 11:46:51 [35mSTATE:[39m test-node-wasm.js passed: detect: assets/sample-me.jpg default
|
||||||
|
2021-04-24 11:46:51 [32mDATA: [39m test-node-wasm.js result: face: 1 body: 1 hand: 0 gesture: 6 object: 0 {"confidence":1,"age":39.2,"gender":"male"} {} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:46:51 [32mDATA: [39m test-node-wasm.js result: performance: load: 687 total: 2061
|
||||||
|
2021-04-24 11:46:51 [36mINFO: [39m test-node-wasm.js test: second instance
|
||||||
|
2021-04-24 11:46:52 [35mSTATE:[39m test-node-wasm.js passed: load image: assets/sample-me.jpg [1,700,700,3]
|
||||||
|
2021-04-24 11:46:54 [35mSTATE:[39m test-node-wasm.js passed: detect: assets/sample-me.jpg default
|
||||||
|
2021-04-24 11:46:54 [32mDATA: [39m test-node-wasm.js result: face: 1 body: 1 hand: 0 gesture: 6 object: 0 {"confidence":1,"age":39.2,"gender":"male"} {} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:46:54 [32mDATA: [39m test-node-wasm.js result: performance: load: 5 total: 1998
|
||||||
|
2021-04-24 11:46:54 [36mINFO: [39m test-node-wasm.js test: concurrent
|
||||||
|
2021-04-24 11:46:54 [35mSTATE:[39m test-node-wasm.js passed: load image: assets/human-sample-face.jpg [1,256,256,3]
|
||||||
|
2021-04-24 11:46:54 [35mSTATE:[39m test-node-wasm.js passed: load image: assets/human-sample-face.jpg [1,256,256,3]
|
||||||
|
2021-04-24 11:46:56 [35mSTATE:[39m test-node-wasm.js passed: load image: assets/human-sample-body.jpg [1,1200,1200,3]
|
||||||
|
2021-04-24 11:46:58 [35mSTATE:[39m test-node-wasm.js passed: load image: assets/human-sample-body.jpg [1,1200,1200,3]
|
||||||
|
2021-04-24 11:47:05 [35mSTATE:[39m test-node-wasm.js passed: detect: assets/human-sample-face.jpg default
|
||||||
|
2021-04-24 11:47:05 [32mDATA: [39m test-node-wasm.js result: face: 1 body: 1 hand: 0 gesture: 6 object: 0 {"confidence":1,"age":23.6,"gender":"female"} {} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:47:05 [32mDATA: [39m test-node-wasm.js result: performance: load: 687 total: 7833
|
||||||
|
2021-04-24 11:47:05 [35mSTATE:[39m test-node-wasm.js passed: detect: assets/human-sample-face.jpg default
|
||||||
|
2021-04-24 11:47:05 [32mDATA: [39m test-node-wasm.js result: face: 1 body: 1 hand: 0 gesture: 6 object: 0 {"confidence":1,"age":23.6,"gender":"female"} {} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:47:05 [32mDATA: [39m test-node-wasm.js result: performance: load: 5 total: 7833
|
||||||
|
2021-04-24 11:47:05 [35mSTATE:[39m test-node-wasm.js passed: detect: assets/human-sample-body.jpg default
|
||||||
|
2021-04-24 11:47:05 [32mDATA: [39m test-node-wasm.js result: face: 1 body: 1 hand: 0 gesture: 3 object: 0 {"confidence":1,"age":28.5,"gender":"female"} {} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:47:05 [32mDATA: [39m test-node-wasm.js result: performance: load: 687 total: 7833
|
||||||
|
2021-04-24 11:47:05 [35mSTATE:[39m test-node-wasm.js passed: detect: assets/human-sample-body.jpg default
|
||||||
|
2021-04-24 11:47:05 [32mDATA: [39m test-node-wasm.js result: face: 1 body: 1 hand: 0 gesture: 3 object: 0 {"confidence":1,"age":28.5,"gender":"female"} {} {"score":1,"keypoints":39}
|
||||||
|
2021-04-24 11:47:05 [32mDATA: [39m test-node-wasm.js result: performance: load: 5 total: 7833
|
||||||
|
2021-04-24 11:47:05 [36mINFO: [39m test-node-wasm.js test complete: 29200 ms
|
||||||
|
2021-04-24 11:47:06 [36mINFO: [39m status: {"passed":68,"failed":2}
|
||||||
|
|
|
@ -1,2 +0,0 @@
|
||||||
import * as heapSort from './heapSort';
|
|
||||||
export declare function buildPartWithScoreQueue(scoreThreshold: any, localMaximumRadius: any, scores: any): heapSort.MaxHeap;
|
|
|
@ -1,4 +1,7 @@
|
||||||
|
import * as utils from './utils';
|
||||||
|
export declare function buildPartWithScoreQueue(scoreThreshold: any, localMaximumRadius: any, scores: any): utils.MaxHeap;
|
||||||
export declare function decodeMultiplePoses(scoresBuffer: any, offsetsBuffer: any, displacementsFwdBuffer: any, displacementsBwdBuffer: any, nmsRadius: any, maxDetections: any, scoreThreshold: any): {
|
export declare function decodeMultiplePoses(scoresBuffer: any, offsetsBuffer: any, displacementsFwdBuffer: any, displacementsBwdBuffer: any, nmsRadius: any, maxDetections: any, scoreThreshold: any): {
|
||||||
keypoints: any;
|
keypoints: any;
|
||||||
|
box: any;
|
||||||
score: number;
|
score: number;
|
||||||
}[];
|
}[];
|
||||||
|
|
|
@ -1,4 +1,3 @@
|
||||||
export declare function getPointsConfidence(heatmapScores: any, heatMapCoords: any): Float32Array;
|
export declare function getPointsConfidence(heatmapScores: any, heatMapCoords: any): number[];
|
||||||
export declare function getOffsetVectors(heatMapCoordsBuffer: any, offsetsBuffer: any): any;
|
|
||||||
export declare function getOffsetPoints(heatMapCoordsBuffer: any, outputStride: any, offsetsBuffer: any): any;
|
export declare function getOffsetPoints(heatMapCoordsBuffer: any, outputStride: any, offsetsBuffer: any): any;
|
||||||
export declare function argmax2d(inputs: any): any;
|
export declare function argmax2d(inputs: any): any;
|
|
@ -8,5 +8,6 @@ export declare function decodeSinglePose(heatmapScores: any, offsets: any, minSc
|
||||||
part: string;
|
part: string;
|
||||||
score: number;
|
score: number;
|
||||||
}[];
|
}[];
|
||||||
|
box: any[];
|
||||||
score: number;
|
score: number;
|
||||||
}>;
|
}>;
|
|
@ -1,17 +0,0 @@
|
||||||
export declare class MaxHeap {
|
|
||||||
priorityQueue: any;
|
|
||||||
numberOfElements: number;
|
|
||||||
getElementValue: any;
|
|
||||||
constructor(maxSize: any, getElementValue: any);
|
|
||||||
enqueue(x: any): void;
|
|
||||||
dequeue(): any;
|
|
||||||
empty(): boolean;
|
|
||||||
size(): number;
|
|
||||||
all(): any;
|
|
||||||
max(): any;
|
|
||||||
swim(k: any): void;
|
|
||||||
sink(k: any): void;
|
|
||||||
getValueAt(i: any): any;
|
|
||||||
less(i: any, j: any): boolean;
|
|
||||||
exchange(i: any, j: any): void;
|
|
||||||
}
|
|
|
@ -1,6 +1,5 @@
|
||||||
export declare const partNames: string[];
|
export declare const partNames: string[];
|
||||||
export declare const NUM_KEYPOINTS: number;
|
export declare const count: number;
|
||||||
export declare const partIds: {};
|
export declare const partIds: {};
|
||||||
export declare const connectedPartIndices: any[][];
|
export declare const connectedPartIndices: any[][];
|
||||||
export declare const poseChain: string[][];
|
export declare const poseChain: string[][];
|
||||||
export declare const partChannels: string[];
|
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
export declare class PoseNet {
|
export declare class PoseNet {
|
||||||
baseModel: any;
|
baseModel: any;
|
||||||
inputSize: number;
|
inputSize: number;
|
||||||
constructor(mobilenet: any);
|
constructor(baseModel: any);
|
||||||
estimatePoses(input: any, config: any): Promise<unknown>;
|
estimatePoses(input: any, config: any): Promise<unknown>;
|
||||||
dispose(): void;
|
dispose(): void;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
export declare class BaseModel {
|
export declare class BaseModel {
|
||||||
model: any;
|
model: any;
|
||||||
|
inputSize: number;
|
||||||
constructor(model: any);
|
constructor(model: any);
|
||||||
predict(input: any): any;
|
predict(input: any): any;
|
||||||
dispose(): void;
|
dispose(): void;
|
|
@ -1,14 +0,0 @@
|
||||||
export declare function eitherPointDoesntMeetConfidence(a: any, b: any, minConfidence: any): boolean;
|
|
||||||
export declare function getAdjacentKeyPoints(keypoints: any, minConfidence: any): any[];
|
|
||||||
export declare function getBoundingBox(keypoints: any): any;
|
|
||||||
export declare function getBoundingBoxPoints(keypoints: any): {
|
|
||||||
x: any;
|
|
||||||
y: any;
|
|
||||||
}[];
|
|
||||||
export declare function toTensorBuffers3D(tensors: any): Promise<[unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown, unknown]>;
|
|
||||||
export declare function scalePose(pose: any, scaleY: any, scaleX: any): {
|
|
||||||
score: any;
|
|
||||||
keypoints: any;
|
|
||||||
};
|
|
||||||
export declare function resizeTo(image: any, [targetH, targetW]: [any, any]): any;
|
|
||||||
export declare function scaleAndFlipPoses(poses: any, [height, width]: [any, any], [inputResolutionHeight, inputResolutionWidth]: [any, any]): any;
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
export declare function eitherPointDoesntMeetConfidence(a: any, b: any, minConfidence: any): boolean;
|
||||||
|
export declare function getAdjacentKeyPoints(keypoints: any, minConfidence: any): any[];
|
||||||
|
export declare function getBoundingBox(keypoints: any): any[];
|
||||||
|
export declare function scalePoses(poses: any, [height, width]: [any, any], [inputResolutionHeight, inputResolutionWidth]: [any, any]): any;
|
||||||
|
export declare class MaxHeap {
|
||||||
|
priorityQueue: any;
|
||||||
|
numberOfElements: number;
|
||||||
|
getElementValue: any;
|
||||||
|
constructor(maxSize: any, getElementValue: any);
|
||||||
|
enqueue(x: any): void;
|
||||||
|
dequeue(): any;
|
||||||
|
empty(): boolean;
|
||||||
|
size(): number;
|
||||||
|
all(): any;
|
||||||
|
max(): any;
|
||||||
|
swim(k: any): void;
|
||||||
|
sink(k: any): void;
|
||||||
|
getValueAt(i: any): any;
|
||||||
|
less(i: any, j: any): boolean;
|
||||||
|
exchange(i: any, j: any): void;
|
||||||
|
}
|
||||||
|
export declare function getOffsetPoint(y: any, x: any, keypoint: any, offsets: any): {
|
||||||
|
y: any;
|
||||||
|
x: any;
|
||||||
|
};
|
||||||
|
export declare function getImageCoords(part: any, outputStride: any, offsets: any): {
|
||||||
|
x: any;
|
||||||
|
y: any;
|
||||||
|
};
|
||||||
|
export declare function fillArray(element: any, size: any): any[];
|
||||||
|
export declare function clamp(a: any, min: any, max: any): any;
|
||||||
|
export declare function squaredDistance(y1: any, x1: any, y2: any, x2: any): number;
|
||||||
|
export declare function addVectors(a: any, b: any): {
|
||||||
|
x: any;
|
||||||
|
y: any;
|
||||||
|
};
|
||||||
|
export declare function clampVector(a: any, min: any, max: any): {
|
||||||
|
y: any;
|
||||||
|
x: any;
|
||||||
|
};
|
|
@ -1,19 +0,0 @@
|
||||||
export declare function getOffsetPoint(y: any, x: any, keypoint: any, offsets: any): {
|
|
||||||
y: any;
|
|
||||||
x: any;
|
|
||||||
};
|
|
||||||
export declare function getImageCoords(part: any, outputStride: any, offsets: any): {
|
|
||||||
x: any;
|
|
||||||
y: any;
|
|
||||||
};
|
|
||||||
export declare function fillArray(element: any, size: any): any[];
|
|
||||||
export declare function clamp(a: any, min: any, max: any): any;
|
|
||||||
export declare function squaredDistance(y1: any, x1: any, y2: any, x2: any): number;
|
|
||||||
export declare function addVectors(a: any, b: any): {
|
|
||||||
x: any;
|
|
||||||
y: any;
|
|
||||||
};
|
|
||||||
export declare function clampVector(a: any, min: any, max: any): {
|
|
||||||
y: any;
|
|
||||||
x: any;
|
|
||||||
};
|
|
2
wiki
2
wiki
|
@ -1 +1 @@
|
||||||
Subproject commit 4cb4534d2812d092946fbe51f8078df15b2c07d7
|
Subproject commit ee4cf3aa27940b10e275ef9e8119e220c4b2d70d
|
Loading…
Reference in New Issue