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
|
||||
|
||||
### **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
|
||||
|
||||
|
||||
### **origin/main** 2021/04/20 mandic00@live.com
|
||||
|
||||
- add npmrc
|
||||
- added filter.flip feature
|
||||
- added demo load image from http
|
||||
- mobile demo optimization and iris gestures
|
||||
|
|
|
@ -208,7 +208,7 @@ Default models in Human library are:
|
|||
- **Face Description**: HSE FaceRes
|
||||
- **Face Iris Analysis**: MediaPipe Iris
|
||||
- **Emotion Detection**: Oarriaga Emotion
|
||||
- **Body Analysis**: PoseNet
|
||||
- **Body Analysis**: PoseNet (AtomicBits version)
|
||||
|
||||
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
|
||||
|
|
|
@ -29,7 +29,7 @@ const userConfig = {
|
|||
},
|
||||
hand: { enabled: false },
|
||||
gesture: { enabled: true },
|
||||
body: { enabled: false },
|
||||
body: { enabled: true, modelPath: 'posenet.json' },
|
||||
// body: { enabled: true, modelPath: 'blazepose.json' },
|
||||
// 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",
|
||||
"chokidar": "^3.5.1",
|
||||
"dayjs": "^1.10.4",
|
||||
"esbuild": "^0.11.12",
|
||||
"eslint": "^7.24.0",
|
||||
"esbuild": "^0.11.14",
|
||||
"eslint": "^7.25.0",
|
||||
"eslint-config-airbnb-base": "^14.2.1",
|
||||
"eslint-plugin-import": "^2.22.1",
|
||||
"eslint-plugin-json": "^2.1.2",
|
||||
|
@ -80,7 +80,7 @@
|
|||
"seedrandom": "^3.0.5",
|
||||
"simple-git": "^2.38.0",
|
||||
"tslib": "^2.2.0",
|
||||
"typedoc": "^0.20.35",
|
||||
"typedoc": "^0.20.36",
|
||||
"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: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-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 'posenet', 'blazepose' or 'efficientpose'
|
||||
// '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
|
||||
// only valid for posenet as blazepose only detects single pose
|
||||
scoreThreshold: 0.3, // threshold for deciding when to remove boxes based on score
|
||||
|
|
|
@ -55,7 +55,7 @@ export const options: DrawOptions = {
|
|||
roundRect: <number>28,
|
||||
drawPoints: <Boolean>false,
|
||||
drawLabels: <Boolean>true,
|
||||
drawBoxes: <Boolean>true,
|
||||
drawBoxes: <Boolean>false,
|
||||
drawPolygons: <Boolean>true,
|
||||
fillPolygons: <Boolean>false,
|
||||
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);
|
||||
if (!lastDrawnPose[i] && localOptions.bufferedOutput) lastDrawnPose[i] = { ...result[i] };
|
||||
ctx.strokeStyle = localOptions.color;
|
||||
ctx.fillStyle = localOptions.color;
|
||||
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) {
|
||||
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;
|
||||
|
@ -271,7 +284,7 @@ export async function body(inCanvas: HTMLCanvasElement, result: Array<any>, draw
|
|||
if (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.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 decodePose from './decodePose';
|
||||
import * as vectors from './vectors';
|
||||
import * as decodeSingle from './decodeSingle';
|
||||
import * as utils from './utils';
|
||||
|
||||
const kLocalMaximumRadius = 1;
|
||||
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) {
|
||||
return poses.some(({ keypoints }) => {
|
||||
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) {
|
||||
const poses: Array<{ keypoints: any, score: number }> = [];
|
||||
const queue = buildParts.buildPartWithScoreQueue(scoreThreshold, kLocalMaximumRadius, scoresBuffer);
|
||||
const poses: Array<{ keypoints: any, box: any, score: number }> = [];
|
||||
const queue = buildPartWithScoreQueue(scoreThreshold, kLocalMaximumRadius, scoresBuffer);
|
||||
const squaredNmsRadius = nmsRadius ^ 2;
|
||||
// Generate at most maxDetections object instances per image in decreasing root part score order.
|
||||
while (poses.length < maxDetections && !queue.empty()) {
|
||||
// The top element in the queue is the next root candidate.
|
||||
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.
|
||||
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;
|
||||
// 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);
|
||||
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;
|
||||
}
|
||||
|
|
|
@ -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 vectors from './vectors';
|
||||
import * as decoders from './decoders';
|
||||
import * as decoders from './decodeParts';
|
||||
import * as utils from './utils';
|
||||
|
||||
const parentChildrenTuples = keypoints.poseChain.map(([parentJoinName, childJoinName]) => ([keypoints.partIds[parentJoinName], keypoints.partIds[childJoinName]]));
|
||||
const parentToChildEdges = parentChildrenTuples.map(([, childJointId]) => childJointId);
|
||||
|
@ -18,8 +18,8 @@ function getDisplacement(edgeId, point, displacements) {
|
|||
|
||||
function getStridedIndexNearPoint(point, outputStride, height, width) {
|
||||
return {
|
||||
y: vectors.clamp(Math.round(point.y / outputStride), 0, height - 1),
|
||||
x: vectors.clamp(Math.round(point.x / outputStride), 0, width - 1),
|
||||
y: utils.clamp(Math.round(point.y / outputStride), 0, height - 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.
|
||||
const sourceKeypointIndices = getStridedIndexNearPoint(sourceKeypoint.position, outputStride, height, width);
|
||||
const displacement = getDisplacement(edgeId, sourceKeypointIndices, displacements);
|
||||
const displacedPoint = vectors.addVectors(sourceKeypoint.position, displacement);
|
||||
const displacedPoint = utils.addVectors(sourceKeypoint.position, displacement);
|
||||
let targetKeypoint = displacedPoint;
|
||||
for (let i = 0; i < offsetRefineStep; i++) {
|
||||
const targetKeypointIndices = getStridedIndexNearPoint(targetKeypoint, outputStride, height, width);
|
||||
const offsetPoint = vectors.getOffsetPoint(targetKeypointIndices.y, targetKeypointIndices.x, targetKeypointId, offsets);
|
||||
targetKeypoint = vectors.addVectors({
|
||||
const offsetPoint = utils.getOffsetPoint(targetKeypointIndices.y, targetKeypointIndices.x, targetKeypointId, offsets);
|
||||
targetKeypoint = utils.addVectors({
|
||||
x: targetKeypointIndices.x * outputStride,
|
||||
y: targetKeypointIndices.y * outputStride,
|
||||
}, { x: offsetPoint.x, y: offsetPoint.y });
|
||||
|
@ -49,7 +49,7 @@ export function decodePose(root, scores, offsets, outputStride, displacementsFwd
|
|||
const instanceKeypoints = new Array(numParts);
|
||||
// Start a new detection instance at the position of the root.
|
||||
const { part: rootPart, score: rootScore } = root;
|
||||
const rootPoint = vectors.getImageCoords(rootPart, outputStride, offsets);
|
||||
const rootPoint = utils.getImageCoords(rootPart, outputStride, offsets);
|
||||
instanceKeypoints[rootPart.id] = {
|
||||
score: rootScore,
|
||||
part: keypoints.partNames[rootPart.id],
|
||||
|
@ -75,28 +75,30 @@ export function decodePose(root, scores, offsets, outputStride, displacementsFwd
|
|||
}
|
||||
|
||||
export async function decodeSinglePose(heatmapScores, offsets, minScore) {
|
||||
let totalScore = 0.0;
|
||||
const heatmapValues = decoders.argmax2d(heatmapScores);
|
||||
const allTensorBuffers = await Promise.all([heatmapScores.buffer(), offsets.buffer(), heatmapValues.buffer()]);
|
||||
const scoresBuffer = allTensorBuffers[0];
|
||||
const offsetsBuffer = allTensorBuffers[1];
|
||||
const heatmapValuesBuffer = allTensorBuffers[2];
|
||||
const offsetPoints = decoders.getOffsetPoints(heatmapValuesBuffer, defaultOutputStride, offsetsBuffer);
|
||||
const offsetPointsBuffer = await offsetPoints.buffer();
|
||||
const keypointConfidence = Array.from(decoders.getPointsConfidence(scoresBuffer, heatmapValuesBuffer));
|
||||
const instanceKeypoints = keypointConfidence.map((score, i) => {
|
||||
totalScore += score;
|
||||
return {
|
||||
position: {
|
||||
y: offsetPointsBuffer.get(i, 0),
|
||||
x: offsetPointsBuffer.get(i, 1),
|
||||
},
|
||||
part: keypoints.partNames[i],
|
||||
score,
|
||||
};
|
||||
});
|
||||
const filteredKeypoints = instanceKeypoints.filter((kpt) => kpt.score > minScore);
|
||||
const offsetPointsData = offsetPoints.dataSync();
|
||||
const keypointConfidence = decoders.getPointsConfidence(scoresBuffer, heatmapValuesBuffer);
|
||||
let avgScore = 0.0;
|
||||
const filteredKeypoints = keypointConfidence
|
||||
.filter((score) => score > minScore)
|
||||
.map((score, i) => {
|
||||
avgScore += score;
|
||||
return {
|
||||
position: {
|
||||
y: offsetPointsData[2 * i + 0], // offsetPointsBuffer.get(i, 0),
|
||||
x: offsetPointsData[2 * i + 1], // offsetPointsBuffer.get(i, 1),
|
||||
},
|
||||
part: keypoints.partNames[i],
|
||||
score,
|
||||
};
|
||||
});
|
||||
heatmapValues.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',
|
||||
];
|
||||
|
||||
export const NUM_KEYPOINTS = partNames.length; // 17 keypoints
|
||||
export const count = partNames.length; // 17 keypoints
|
||||
|
||||
export const partIds = partNames.reduce((result, jointName, i) => {
|
||||
result[jointName] = i;
|
||||
|
@ -31,30 +31,3 @@ export const poseChain = [
|
|||
['rightShoulder', 'rightHip'], ['rightHip', 'rightKnee'],
|
||||
['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 * as tf from '../../dist/tfjs.esm.js';
|
||||
import * as modelBase from './modelBase';
|
||||
import * as posenetModel from './posenetModel';
|
||||
import * as decodeMultiple from './decodeMultiple';
|
||||
import * as decodePose from './decodePose';
|
||||
import * as util from './util';
|
||||
import * as decodeSingle from './decodeSingle';
|
||||
import * as util from './utils';
|
||||
|
||||
let model;
|
||||
|
||||
async function estimateMultiple(input, res, config, inputSize) {
|
||||
const toTensorBuffers3D = (tensors) => Promise.all(tensors.map((tensor) => tensor.buffer()));
|
||||
|
||||
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 offsetsBuffer = allTensorBuffers[1];
|
||||
const displacementsFwdBuffer = allTensorBuffers[2];
|
||||
const displacementsBwdBuffer = allTensorBuffers[3];
|
||||
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);
|
||||
});
|
||||
}
|
||||
|
||||
async function estimateSingle(input, res, config, inputSize) {
|
||||
return new Promise(async (resolve) => {
|
||||
const pose = await decodePose.decodeSinglePose(res.heatmapScores, res.offsets, config.body.scoreThreshold);
|
||||
const scaled = util.scaleAndFlipPoses([pose], [input.shape[1], input.shape[2]], [inputSize, inputSize]);
|
||||
const pose = await decodeSingle.decodeSinglePose(res.heatmapScores, res.offsets, config.body.scoreThreshold);
|
||||
const scaled = util.scalePoses([pose], [input.shape[1], input.shape[2]], [inputSize, inputSize]);
|
||||
resolve(scaled);
|
||||
});
|
||||
}
|
||||
|
@ -31,15 +33,13 @@ async function estimateSingle(input, res, config, inputSize) {
|
|||
export class PoseNet {
|
||||
baseModel: any;
|
||||
inputSize: number
|
||||
constructor(mobilenet) {
|
||||
this.baseModel = mobilenet;
|
||||
this.inputSize = mobilenet.model.inputs[0].shape[1];
|
||||
if (this.inputSize < 128) this.inputSize = 257;
|
||||
constructor(baseModel) {
|
||||
this.baseModel = baseModel;
|
||||
this.inputSize = baseModel.model.inputs[0].shape[1];
|
||||
}
|
||||
|
||||
async estimatePoses(input, config) {
|
||||
const resized = util.resizeTo(input, [this.inputSize, this.inputSize]);
|
||||
const res = this.baseModel.predict(resized, config);
|
||||
const res = this.baseModel.predict(input, config);
|
||||
|
||||
const poses = (config.body.maxDetections < 2)
|
||||
? await estimateSingle(input, res, config, this.inputSize)
|
||||
|
@ -49,7 +49,6 @@ export class PoseNet {
|
|||
res.offsets.dispose();
|
||||
res.displacementFwd.dispose();
|
||||
res.displacementBwd.dispose();
|
||||
resized.dispose();
|
||||
|
||||
return poses;
|
||||
}
|
||||
|
@ -65,7 +64,7 @@ export async function load(config) {
|
|||
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('cached model:', model.modelUrl);
|
||||
const mobilenet = new modelBase.BaseModel(model);
|
||||
const mobilenet = new posenetModel.BaseModel(model);
|
||||
const poseNet = new PoseNet(mobilenet);
|
||||
return poseNet;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,7 @@
|
|||
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) {
|
||||
const [offsets, heatmap, displacementFwd, displacementBwd] = results;
|
||||
return { offsets, heatmap, displacementFwd, displacementBwd };
|
||||
|
@ -7,15 +9,18 @@ function nameOutputResultsMobileNet(results) {
|
|||
|
||||
export class BaseModel {
|
||||
model: any;
|
||||
inputSize: number;
|
||||
constructor(model) {
|
||||
this.model = model;
|
||||
this.inputSize = model.inputs[0].shape[1];
|
||||
}
|
||||
|
||||
predict(input) {
|
||||
return tf.tidy(() => {
|
||||
const asFloat = input.toFloat().div(127.5).sub(1.0);
|
||||
const asBatch = asFloat.expandDims(0);
|
||||
const results = this.model.predict(asBatch);
|
||||
const resized = input.resizeBilinear([this.inputSize, this.inputSize]);
|
||||
const normalized = resized.toFloat().div(127.5).sub(1.0);
|
||||
// const asBatch = asFloat.expandDims(0);
|
||||
const results = this.model.execute(normalized, poseNetOutputs);
|
||||
const results3d = results.map((y) => y.squeeze([0]));
|
||||
const namedResults = nameOutputResultsMobileNet(results3d);
|
||||
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 aborting test
|
||||
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): {
|
||||
keypoints: any;
|
||||
box: any;
|
||||
score: number;
|
||||
}[];
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
export declare function getPointsConfidence(heatmapScores: any, heatMapCoords: any): Float32Array;
|
||||
export declare function getOffsetVectors(heatMapCoordsBuffer: any, offsetsBuffer: any): any;
|
||||
export declare function getPointsConfidence(heatmapScores: any, heatMapCoords: any): number[];
|
||||
export declare function getOffsetPoints(heatMapCoordsBuffer: any, outputStride: any, offsetsBuffer: any): any;
|
||||
export declare function argmax2d(inputs: any): any;
|
|
@ -8,5 +8,6 @@ export declare function decodeSinglePose(heatmapScores: any, offsets: any, minSc
|
|||
part: string;
|
||||
score: number;
|
||||
}[];
|
||||
box: any[];
|
||||
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 NUM_KEYPOINTS: number;
|
||||
export declare const count: number;
|
||||
export declare const partIds: {};
|
||||
export declare const connectedPartIndices: any[][];
|
||||
export declare const poseChain: string[][];
|
||||
export declare const partChannels: string[];
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
export declare class PoseNet {
|
||||
baseModel: any;
|
||||
inputSize: number;
|
||||
constructor(mobilenet: any);
|
||||
constructor(baseModel: any);
|
||||
estimatePoses(input: any, config: any): Promise<unknown>;
|
||||
dispose(): void;
|
||||
}
|
||||
|
|
|
@ -1,5 +1,6 @@
|
|||
export declare class BaseModel {
|
||||
model: any;
|
||||
inputSize: number;
|
||||
constructor(model: any);
|
||||
predict(input: any): any;
|
||||
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