human/src/posenet/util.js

119 lines
4.1 KiB
JavaScript

const tf = require('@tensorflow/tfjs');
const kpt = require('./keypoints');
function eitherPointDoesntMeetConfidence(a, b, minConfidence) {
return (a < minConfidence || b < minConfidence);
}
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;
}, []);
}
exports.getAdjacentKeyPoints = getAdjacentKeyPoints;
const { NEGATIVE_INFINITY, POSITIVE_INFINITY } = Number;
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,
});
}
exports.getBoundingBox = getBoundingBox;
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 }];
}
exports.getBoundingBoxPoints = getBoundingBoxPoints;
async function toTensorBuffers3D(tensors) {
return Promise.all(tensors.map((tensor) => tensor.buffer()));
}
exports.toTensorBuffers3D = toTensorBuffers3D;
function scalePose(pose, scaleY, scaleX, offsetY = 0, offsetX = 0) {
return {
score: pose.score,
keypoints: pose.keypoints.map(({ score, part, position }) => ({
score,
part,
position: {
x: position.x * scaleX + offsetX,
y: position.y * scaleY + offsetY,
},
})),
};
}
exports.scalePose = scalePose;
function scalePoses(poses, scaleY, scaleX, offsetY = 0, offsetX = 0) {
if (scaleX === 1 && scaleY === 1 && offsetY === 0 && offsetX === 0) {
return poses;
}
return poses.map((pose) => scalePose(pose, scaleY, scaleX, offsetY, offsetX));
}
exports.scalePoses = scalePoses;
function getInputTensorDimensions(input) {
return input instanceof tf.Tensor ? [input.shape[0], input.shape[1]] : [input.height, input.width];
}
exports.getInputTensorDimensions = getInputTensorDimensions;
function toInputTensor(input) {
return input instanceof tf.Tensor ? input : tf.browser.fromPixels(input);
}
exports.toInputTensor = toInputTensor;
function toResizedInputTensor(input, resizeHeight, resizeWidth) {
return tf.tidy(() => {
const imageTensor = toInputTensor(input);
return imageTensor.resizeBilinear([resizeHeight, resizeWidth]);
});
}
exports.toResizedInputTensor = toResizedInputTensor;
function padAndResizeTo(input, [targetH, targetW]) {
const [height, width] = getInputTensorDimensions(input);
const targetAspect = targetW / targetH;
const aspect = width / height;
let [padT, padB, padL, padR] = [0, 0, 0, 0];
if (aspect < targetAspect) {
// pads the width
padT = 0;
padB = 0;
padL = Math.round(0.5 * (targetAspect * height - width));
padR = Math.round(0.5 * (targetAspect * height - width));
} else {
// pads the height
padT = Math.round(0.5 * ((1.0 / targetAspect) * width - height));
padB = Math.round(0.5 * ((1.0 / targetAspect) * width - height));
padL = 0;
padR = 0;
}
const resized = tf.tidy(() => {
let imageTensor = toInputTensor(input);
imageTensor = tf.pad3d(imageTensor, [[padT, padB], [padL, padR], [0, 0]]);
return imageTensor.resizeBilinear([targetH, targetW]);
});
return { resized, padding: { top: padT, left: padL, right: padR, bottom: padB } };
}
exports.padAndResizeTo = padAndResizeTo;
function scaleAndFlipPoses(poses, [height, width], [inputResolutionHeight, inputResolutionWidth], padding) {
const scaleY = (height + padding.top + padding.bottom) / (inputResolutionHeight);
const scaleX = (width + padding.left + padding.right) / (inputResolutionWidth);
const scaledPoses = scalePoses(poses, scaleY, scaleX, -padding.top, -padding.left);
return scaledPoses;
}
exports.scaleAndFlipPoses = scaleAndFlipPoses;