mirror of https://github.com/vladmandic/human
added node build and demo
parent
412f5d6b3b
commit
dfa78e1103
60
README.md
60
README.md
|
@ -5,6 +5,8 @@
|
||||||
**Package**: <https://www.npmjs.com/package/@vladmandic/human>
|
**Package**: <https://www.npmjs.com/package/@vladmandic/human>
|
||||||
**Live Demo**: <https://vladmandic.github.io/human/demo/demo-esm.html>
|
**Live Demo**: <https://vladmandic.github.io/human/demo/demo-esm.html>
|
||||||
|
|
||||||
|
Compatible with Browser, WebWorker and NodeJS** execution!
|
||||||
|
|
||||||
*Suggestions are welcome!*
|
*Suggestions are welcome!*
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
@ -88,13 +90,15 @@ You also need to install and includ `tfjs` in your project
|
||||||
|
|
||||||
Install with:
|
Install with:
|
||||||
```shell
|
```shell
|
||||||
npm install @tensorflow/tfjs @vladmandic/human
|
npm install @tensorflow/tfjs-node @vladmandic/human
|
||||||
```
|
```
|
||||||
And then use with:
|
And then use with:
|
||||||
```js
|
```js
|
||||||
import * as tf from '@tensorflow/tfjs';
|
const tf = require('@tensorflow/tfjs-node');
|
||||||
import human from '@vladmandic/Human';
|
const human = require('@vladmandic/human');
|
||||||
```
|
```
|
||||||
|
*See limitations for NodeJS usage under `demo`*
|
||||||
|
|
||||||
|
|
||||||
### Weights
|
### Weights
|
||||||
|
|
||||||
|
@ -108,10 +112,20 @@ If your application resides in a different folder, modify `modelPath` property i
|
||||||
|
|
||||||
Demos are included in `/demo`:
|
Demos are included in `/demo`:
|
||||||
|
|
||||||
- `demo-esm`: Demo using ESM module
|
Browser:
|
||||||
- `demo-iife`: Demo using IIFE module
|
- `demo-esm`: Demo using Browser with ESM module
|
||||||
|
- `demo-iife`: Demo using Browser with IIFE module
|
||||||
|
- `demo-webworker`: Demo using Browser with ESM module and Web Workers
|
||||||
|
*All three following demos are identical, they just illustrate different ways to load and work with `Human` library:*
|
||||||
|
|
||||||
Both demos are identical, they just illustrate different ways to load `Human` library
|
NodeJS:
|
||||||
|
- `demo-node`: Demo using NodeJS with CJS module
|
||||||
|
This is a very simple demo as althought `Human` library is compatible with NodeJS execution
|
||||||
|
and is able to load images and models from local filesystem,
|
||||||
|
`tfjs-node` backend does not implement function required for execution of some models
|
||||||
|
|
||||||
|
Currently only body pose detection works while face and hand models are not supported
|
||||||
|
See `tfjs-node` issue <https://github.com/tensorflow/tfjs/issues/4066> for details
|
||||||
|
|
||||||
<hr>
|
<hr>
|
||||||
|
|
||||||
|
@ -219,34 +233,34 @@ Result of `humand.detect()` is a single object that includes data for all enable
|
||||||
|
|
||||||
```js
|
```js
|
||||||
result = {
|
result = {
|
||||||
face: // <array of detected objects>
|
face: // <array of detected objects>
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
confidence: // <number>
|
confidence, // <number>
|
||||||
box: // <array [x, y, width, height]>
|
box, // <array [x, y, width, height]>
|
||||||
mesh: // <array of 3D points [x, y, z]> (468 base points & 10 iris points)
|
mesh, // <array of 3D points [x, y, z]> (468 base points & 10 iris points)
|
||||||
annotations: // <list of object { landmark: array of points }> (32 base annotated landmarks & 2 iris annotations)
|
annotations, // <list of object { landmark: array of points }> (32 base annotated landmarks & 2 iris annotations)
|
||||||
iris: // <number> (relative distance of iris to camera, multiple by focal lenght to get actual distance)
|
iris, // <number> (relative distance of iris to camera, multiple by focal lenght to get actual distance)
|
||||||
age: // <number> (estimated age)
|
age, // <number> (estimated age)
|
||||||
gender: // <string> (male or female)
|
gender, // <string> (male or female)
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
body: // <array of detected objects>
|
body: // <array of detected objects>
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
score: // <number>,
|
score, // <number>,
|
||||||
keypoints: // <array of 2D landmarks [ score, landmark, position [x, y] ]> (17 annotated landmarks)
|
keypoints, // <array of 2D landmarks [ score, landmark, position [x, y] ]> (17 annotated landmarks)
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
hand: // <array of detected objects>
|
hand: // <array of detected objects>
|
||||||
[
|
[
|
||||||
{
|
{
|
||||||
confidence: // <number>,
|
confidence, // <number>,
|
||||||
box: // <array [x, y, width, height]>,
|
box, // <array [x, y, width, height]>,
|
||||||
landmarks: // <array of 3D points [x, y,z]> (21 points)
|
landmarks, // <array of 3D points [x, y,z]> (21 points)
|
||||||
annotations: // <array of 3D landmarks [ landmark: <array of points> ]> (5 annotated landmakrs)
|
annotations, // <array of 3D landmarks [ landmark: <array of points> ]> (5 annotated landmakrs)
|
||||||
}
|
}
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
|
@ -286,4 +300,6 @@ Library can also be used on mobile devices
|
||||||
## Todo
|
## Todo
|
||||||
|
|
||||||
- Improve detection of smaller faces
|
- Improve detection of smaller faces
|
||||||
|
- Tweak default parameters
|
||||||
- Verify age/gender models
|
- Verify age/gender models
|
||||||
|
- Make it work with multiple hands
|
||||||
|
|
|
@ -215,9 +215,11 @@ function setupGUI() {
|
||||||
settings = QuickSettings.create(10, 10, 'Settings', document.getElementById('main'));
|
settings = QuickSettings.create(10, 10, 'Settings', document.getElementById('main'));
|
||||||
settings.addRange('FPS', 0, 100, 0, 1);
|
settings.addRange('FPS', 0, 100, 0, 1);
|
||||||
settings.addBoolean('Pause', false, (val) => {
|
settings.addBoolean('Pause', false, (val) => {
|
||||||
if (val) document.getElementById('video').pause();
|
const video = document.getElementById('video');
|
||||||
else document.getElementById('video').play();
|
const canvas = document.getElementById('canvas');
|
||||||
runHumanDetect();
|
if (val) video.pause();
|
||||||
|
else video.play();
|
||||||
|
runHumanDetect(video, canvas);
|
||||||
});
|
});
|
||||||
settings.addHTML('line1', '<hr>'); settings.hideTitle('line1');
|
settings.addHTML('line1', '<hr>'); settings.hideTitle('line1');
|
||||||
settings.addBoolean('Draw Boxes', false);
|
settings.addBoolean('Draw Boxes', false);
|
||||||
|
@ -283,10 +285,10 @@ async function setupCamera() {
|
||||||
video.srcObject = stream;
|
video.srcObject = stream;
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
video.onloadedmetadata = () => {
|
video.onloadedmetadata = () => {
|
||||||
resolve(video);
|
|
||||||
video.width = video.videoWidth;
|
video.width = video.videoWidth;
|
||||||
video.height = video.videoHeight;
|
video.height = video.videoHeight;
|
||||||
video.play();
|
video.play();
|
||||||
|
resolve(video);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,11 @@
|
||||||
/* global human, QuickSettings */
|
/* global human, QuickSettings */
|
||||||
|
|
||||||
|
const ui = {
|
||||||
|
baseColor: 'rgba(255, 200, 255, 0.3)',
|
||||||
|
baseFont: 'small-caps 1.2rem "Segoe UI"',
|
||||||
|
baseLineWidth: 16,
|
||||||
|
};
|
||||||
|
|
||||||
const config = {
|
const config = {
|
||||||
face: {
|
face: {
|
||||||
enabled: true,
|
enabled: true,
|
||||||
|
@ -14,17 +20,20 @@ const config = {
|
||||||
};
|
};
|
||||||
let settings;
|
let settings;
|
||||||
|
|
||||||
async function drawFace(result) {
|
async function drawFace(result, canvas) {
|
||||||
const canvas = document.getElementById('canvas');
|
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
ctx.fillStyle = 'lightcoral';
|
ctx.fillStyle = ui.baseColor;
|
||||||
ctx.strokeStyle = 'lightcoral';
|
ctx.strokeStyle = ui.baseColor;
|
||||||
ctx.font = 'small-caps 1rem "Segoe UI"';
|
ctx.font = ui.baseFont;
|
||||||
for (const face of result) {
|
for (const face of result) {
|
||||||
|
ctx.lineWidth = ui.baseLineWidth;
|
||||||
ctx.beginPath();
|
ctx.beginPath();
|
||||||
ctx.rect(face.box[0], face.box[1], face.box[2], face.box[3]);
|
if (settings.getValue('Draw Boxes')) {
|
||||||
ctx.fillText(`face ${face.gender || ''} ${face.age || ''} ${face.iris ? 'iris: ' + face.iris : ''}`, face.box[0] + 2, face.box[1] + 16, face.box[2]);
|
ctx.rect(face.box[0], face.box[1], face.box[2], face.box[3]);
|
||||||
|
}
|
||||||
|
ctx.fillText(`face ${face.gender || ''} ${face.age || ''} ${face.iris ? 'iris: ' + face.iris : ''}`, face.box[0] + 2, face.box[1] + 22, face.box[2]);
|
||||||
ctx.stroke();
|
ctx.stroke();
|
||||||
|
ctx.lineWidth = 1;
|
||||||
if (face.mesh) {
|
if (face.mesh) {
|
||||||
if (settings.getValue('Draw Points')) {
|
if (settings.getValue('Draw Points')) {
|
||||||
for (const point of face.mesh) {
|
for (const point of face.mesh) {
|
||||||
|
@ -47,10 +56,10 @@ async function drawFace(result) {
|
||||||
path.lineTo(point[0], point[1]);
|
path.lineTo(point[0], point[1]);
|
||||||
}
|
}
|
||||||
path.closePath();
|
path.closePath();
|
||||||
ctx.fillStyle = `rgba(${127.5 + (2 * points[0][2])}, ${127.5 - (2 * points[0][2])}, 255, 0.5)`;
|
ctx.strokeStyle = `rgba(${127.5 + (2 * points[0][2])}, ${127.5 - (2 * points[0][2])}, 255, 0.3)`;
|
||||||
ctx.strokeStyle = `rgba(${127.5 + (2 * points[0][2])}, ${127.5 - (2 * points[0][2])}, 255, 0.5)`;
|
|
||||||
ctx.stroke(path);
|
ctx.stroke(path);
|
||||||
if (settings.getValue('Fill Polygons')) {
|
if (settings.getValue('Fill Polygons')) {
|
||||||
|
ctx.fillStyle = `rgba(${127.5 + (2 * points[0][2])}, ${127.5 - (2 * points[0][2])}, 255, 0.3)`;
|
||||||
ctx.fill(path);
|
ctx.fill(path);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,12 +68,12 @@ async function drawFace(result) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function drawBody(result) {
|
async function drawBody(result, canvas) {
|
||||||
const canvas = document.getElementById('canvas');
|
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
ctx.fillStyle = 'lightcoral';
|
ctx.fillStyle = ui.baseColor;
|
||||||
ctx.strokeStyle = 'lightcoral';
|
ctx.strokeStyle = ui.baseColor;
|
||||||
ctx.font = 'small-caps 1rem "Segoe UI"';
|
ctx.font = ui.baseFont;
|
||||||
|
ctx.lineWidth = ui.baseLineWidth;
|
||||||
for (const pose of result) {
|
for (const pose of result) {
|
||||||
if (settings.getValue('Draw Points')) {
|
if (settings.getValue('Draw Points')) {
|
||||||
for (const point of pose.keypoints) {
|
for (const point of pose.keypoints) {
|
||||||
|
@ -120,12 +129,19 @@ async function drawBody(result) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function drawHand(result) {
|
async function drawHand(result, canvas) {
|
||||||
const canvas = document.getElementById('canvas');
|
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
ctx.font = 'small-caps 1rem "Segoe UI"';
|
ctx.font = ui.baseFont;
|
||||||
|
ctx.lineWidth = ui.baseLineWidth;
|
||||||
window.result = result;
|
window.result = result;
|
||||||
for (const hand of result) {
|
for (const hand of result) {
|
||||||
|
if (settings.getValue('Draw Boxes')) {
|
||||||
|
ctx.lineWidth = ui.baseLineWidth;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.rect(hand.box[0], hand.box[1], hand.box[2], hand.box[3]);
|
||||||
|
ctx.fillText('hand', hand.box[0] + 2, hand.box[1] + 22, hand.box[2]);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
if (settings.getValue('Draw Points')) {
|
if (settings.getValue('Draw Points')) {
|
||||||
for (const point of hand.landmarks) {
|
for (const point of hand.landmarks) {
|
||||||
ctx.fillStyle = `rgba(${127.5 + (2 * point[2])}, ${127.5 - (2 * point[2])}, 255, 0.5)`;
|
ctx.fillStyle = `rgba(${127.5 + (2 * point[2])}, ${127.5 - (2 * point[2])}, 255, 0.5)`;
|
||||||
|
@ -136,13 +152,14 @@ async function drawHand(result) {
|
||||||
}
|
}
|
||||||
if (settings.getValue('Draw Polygons')) {
|
if (settings.getValue('Draw Polygons')) {
|
||||||
const addPart = (part) => {
|
const addPart = (part) => {
|
||||||
ctx.beginPath();
|
for (let i = 1; i < part.length; i++) {
|
||||||
for (const i in part) {
|
ctx.lineWidth = ui.baseLineWidth;
|
||||||
|
ctx.beginPath();
|
||||||
ctx.strokeStyle = `rgba(${127.5 + (2 * part[i][2])}, ${127.5 - (2 * part[i][2])}, 255, 0.5)`;
|
ctx.strokeStyle = `rgba(${127.5 + (2 * part[i][2])}, ${127.5 - (2 * part[i][2])}, 255, 0.5)`;
|
||||||
if (i === 0) ctx.moveTo(part[i][0], part[i][1]);
|
ctx.moveTo(part[i - 1][0], part[i - 1][1]);
|
||||||
else ctx.lineTo(part[i][0], part[i][1]);
|
ctx.lineTo(part[i][0], part[i][1]);
|
||||||
|
ctx.stroke();
|
||||||
}
|
}
|
||||||
ctx.stroke();
|
|
||||||
};
|
};
|
||||||
addPart(hand.annotations.indexFinger);
|
addPart(hand.annotations.indexFinger);
|
||||||
addPart(hand.annotations.middleFinger);
|
addPart(hand.annotations.middleFinger);
|
||||||
|
@ -154,48 +171,62 @@ async function drawHand(result) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
async function runHumanDetect() {
|
async function runHumanDetect(input, canvas) {
|
||||||
const video = document.getElementById('video');
|
|
||||||
const canvas = document.getElementById('canvas');
|
|
||||||
const log = document.getElementById('log');
|
const log = document.getElementById('log');
|
||||||
const live = video.srcObject ? ((video.srcObject.getVideoTracks()[0].readyState === 'live') && (video.readyState > 2) && (!video.paused)) : true;
|
const live = input.srcObject ? ((input.srcObject.getVideoTracks()[0].readyState === 'live') && (input.readyState > 2) && (!input.paused)) : false;
|
||||||
if (live) {
|
// perform detect if live video or not video at all
|
||||||
|
if (live || !(input instanceof HTMLVideoElement)) {
|
||||||
// perform detection
|
// perform detection
|
||||||
const t0 = performance.now();
|
const t0 = performance.now();
|
||||||
const result = await human.detect(video, config);
|
let result;
|
||||||
|
try {
|
||||||
|
result = await human.detect(input, config);
|
||||||
|
} catch (err) {
|
||||||
|
log.innerText = err.message;
|
||||||
|
}
|
||||||
|
if (!result) return;
|
||||||
const t1 = performance.now();
|
const t1 = performance.now();
|
||||||
// update fps
|
// update fps
|
||||||
settings.setValue('FPS', Math.round(1000 / (t1 - t0)));
|
settings.setValue('FPS', Math.round(1000 / (t1 - t0)));
|
||||||
// draw image from video
|
// draw image from video
|
||||||
const ctx = canvas.getContext('2d');
|
const ctx = canvas.getContext('2d');
|
||||||
ctx.drawImage(video, 0, 0, video.width, video.height, 0, 0, canvas.width, canvas.height);
|
ctx.drawImage(input, 0, 0, input.width, input.height, 0, 0, canvas.width, canvas.height);
|
||||||
// draw all results
|
// draw all results
|
||||||
drawFace(result.face);
|
drawFace(result.face, canvas);
|
||||||
drawBody(result.body);
|
drawBody(result.body, canvas);
|
||||||
drawHand(result.hand);
|
drawHand(result.hand, canvas);
|
||||||
// update log
|
// update log
|
||||||
const engine = await human.tf.engine();
|
const engine = await human.tf.engine();
|
||||||
log.innerText = `
|
log.innerText = `
|
||||||
TFJS Version: ${human.tf.version_core} Memory: ${engine.state.numBytes.toLocaleString()} bytes ${engine.state.numDataBuffers.toLocaleString()} buffers ${engine.state.numTensors.toLocaleString()} tensors
|
TFJS Version: ${human.tf.version_core} Memory: ${engine.state.numBytes.toLocaleString()} bytes ${engine.state.numDataBuffers.toLocaleString()} buffers ${engine.state.numTensors.toLocaleString()} tensors
|
||||||
GPU Memory: used ${engine.backendInstance.numBytesInGPU.toLocaleString()} bytes free ${Math.floor(1024 * 1024 * engine.backendInstance.numMBBeforeWarning).toLocaleString()} bytes
|
GPU Memory: used ${engine.backendInstance.numBytesInGPU.toLocaleString()} bytes free ${Math.floor(1024 * 1024 * engine.backendInstance.numMBBeforeWarning).toLocaleString()} bytes
|
||||||
Result: Face: ${(JSON.stringify(result.face)).length.toLocaleString()} bytes Body: ${(JSON.stringify(result.body)).length.toLocaleString()} bytes Hand: ${(JSON.stringify(result.hand)).length.toLocaleString()} bytes
|
Result Object Size: Face: ${(JSON.stringify(result.face)).length.toLocaleString()} bytes Body: ${(JSON.stringify(result.body)).length.toLocaleString()} bytes Hand: ${(JSON.stringify(result.hand)).length.toLocaleString()} bytes
|
||||||
`;
|
`;
|
||||||
// rinse & repeate
|
// rinse & repeate
|
||||||
requestAnimationFrame(runHumanDetect);
|
// if (input.readyState) setTimeout(() => runHumanDetect(), 1000); // slow loop for debugging purposes
|
||||||
|
if (input.readyState) requestAnimationFrame(() => runHumanDetect(input, canvas)); // immediate loop
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setupGUI() {
|
function setupGUI() {
|
||||||
|
// add all variables to ui control panel
|
||||||
|
settings = QuickSettings.create(10, 10, 'Settings', document.getElementById('main'));
|
||||||
settings.addRange('FPS', 0, 100, 0, 1);
|
settings.addRange('FPS', 0, 100, 0, 1);
|
||||||
settings.addBoolean('Pause', true, (val) => {
|
settings.addBoolean('Pause', false, (val) => {
|
||||||
if (val) document.getElementById('video').pause();
|
const video = document.getElementById('video');
|
||||||
else document.getElementById('video').play();
|
const canvas = document.getElementById('canvas');
|
||||||
runHumanDetect();
|
if (val) video.pause();
|
||||||
|
else video.play();
|
||||||
|
runHumanDetect(video, canvas);
|
||||||
});
|
});
|
||||||
settings.addHTML('line1', '<hr>'); settings.hideTitle('line1');
|
settings.addHTML('line1', '<hr>'); settings.hideTitle('line1');
|
||||||
|
settings.addBoolean('Draw Boxes', false);
|
||||||
settings.addBoolean('Draw Points', true);
|
settings.addBoolean('Draw Points', true);
|
||||||
settings.addBoolean('Draw Polygons', true);
|
settings.addBoolean('Draw Polygons', true);
|
||||||
settings.addBoolean('Fill Polygons', true);
|
settings.addBoolean('Fill Polygons', true);
|
||||||
|
settings.bindText('baseColor', ui.baseColor, config);
|
||||||
|
settings.bindText('baseFont', ui.baseFont, config);
|
||||||
|
settings.bindRange('baseLineWidth', 1, 100, ui.baseLineWidth, 1, config);
|
||||||
settings.addHTML('line2', '<hr>'); settings.hideTitle('line2');
|
settings.addHTML('line2', '<hr>'); settings.hideTitle('line2');
|
||||||
settings.addBoolean('Face Detect', config.face.enabled, (val) => config.face.enabled = val);
|
settings.addBoolean('Face Detect', config.face.enabled, (val) => config.face.enabled = val);
|
||||||
settings.addBoolean('Face Mesh', config.face.mesh.enabled, (val) => config.face.mesh.enabled = val);
|
settings.addBoolean('Face Mesh', config.face.mesh.enabled, (val) => config.face.mesh.enabled = val);
|
||||||
|
@ -229,38 +260,62 @@ function setupGUI() {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
async function setupCanvas() {
|
async function setupCanvas(input) {
|
||||||
const video = document.getElementById('video');
|
// setup canvas object to same size as input as camera resolution may change
|
||||||
const canvas = document.getElementById('canvas');
|
const canvas = document.getElementById('canvas');
|
||||||
canvas.width = video.width;
|
canvas.width = input.width;
|
||||||
canvas.height = video.height;
|
canvas.height = input.height;
|
||||||
settings = QuickSettings.create(10, 10, 'Settings', document.getElementById('main'));
|
return canvas;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
async function setupCamera() {
|
async function setupCamera() {
|
||||||
|
// setup webcam. note that navigator.mediaDevices requires that page is accessed via https
|
||||||
const video = document.getElementById('video');
|
const video = document.getElementById('video');
|
||||||
|
if (!navigator.mediaDevices) {
|
||||||
|
document.getElementById('log').innerText = 'Video not supported';
|
||||||
|
return null;
|
||||||
|
}
|
||||||
const stream = await navigator.mediaDevices.getUserMedia({
|
const stream = await navigator.mediaDevices.getUserMedia({
|
||||||
audio: true,
|
audio: false,
|
||||||
video: { facingMode: 'user', width: window.innerWidth, height: window.innerHeight },
|
video: { facingMode: 'user', width: window.innerWidth, height: window.innerHeight },
|
||||||
});
|
});
|
||||||
video.srcObject = stream;
|
video.srcObject = stream;
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
video.onloadedmetadata = () => {
|
video.onloadedmetadata = () => {
|
||||||
resolve(video);
|
|
||||||
video.width = video.videoWidth;
|
video.width = video.videoWidth;
|
||||||
video.height = video.videoHeight;
|
video.height = video.videoHeight;
|
||||||
video.play();
|
video.play();
|
||||||
|
resolve(video);
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
async function setupImage() {
|
||||||
|
const image = document.getElementById('image');
|
||||||
|
image.width = window.innerWidth;
|
||||||
|
image.height = window.innerHeight;
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
image.onload = () => resolve(image);
|
||||||
|
image.src = 'sample.jpg';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
|
// initialize tensorflow
|
||||||
await human.tf.setBackend('webgl');
|
await human.tf.setBackend('webgl');
|
||||||
await human.tf.ready();
|
await human.tf.ready();
|
||||||
await setupCamera();
|
// setup ui control panel
|
||||||
await setupCanvas();
|
|
||||||
await setupGUI();
|
await setupGUI();
|
||||||
runHumanDetect();
|
// setup webcam
|
||||||
|
const video = await setupCamera();
|
||||||
|
// or setup image
|
||||||
|
// const image = await setupImage();
|
||||||
|
// setup output canvas from input object, select video or image
|
||||||
|
const canvas = await setupCanvas(video);
|
||||||
|
// run actual detection. if input is video, it will run in a loop else it will run only once
|
||||||
|
runHumanDetect(video, canvas);
|
||||||
}
|
}
|
||||||
|
|
||||||
window.onload = main;
|
window.onload = main;
|
||||||
|
|
|
@ -0,0 +1,68 @@
|
||||||
|
const fs = require('fs');
|
||||||
|
const process = require('process');
|
||||||
|
const console = require('console');
|
||||||
|
const tf = require('@tensorflow/tfjs-node');
|
||||||
|
const human = require('..'); // this would be '@vladmandic/human'
|
||||||
|
|
||||||
|
const logger = new console.Console({
|
||||||
|
stdout: process.stdout,
|
||||||
|
stderr: process.stderr,
|
||||||
|
ignoreErrors: true,
|
||||||
|
groupIndentation: 2,
|
||||||
|
inspectOptions: {
|
||||||
|
showHidden: true,
|
||||||
|
depth: 5,
|
||||||
|
colors: true,
|
||||||
|
showProxy: true,
|
||||||
|
maxArrayLength: 1024,
|
||||||
|
maxStringLength: 10240,
|
||||||
|
breakLength: 200,
|
||||||
|
compact: 64,
|
||||||
|
sorted: false,
|
||||||
|
getters: true,
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
face: {
|
||||||
|
enabled: false,
|
||||||
|
detector: { modelPath: 'file://models/blazeface/model.json', inputSize: 128, maxFaces: 10, skipFrames: 5, minConfidence: 0.8, iouThreshold: 0.3, scoreThreshold: 0.75 },
|
||||||
|
mesh: { enabled: true, modelPath: 'file://models/facemesh/model.json', inputSize: 192 },
|
||||||
|
iris: { enabled: true, modelPath: 'file://models/iris/model.json', inputSize: 192 },
|
||||||
|
age: { enabled: true, modelPath: 'file://models/ssrnet-age/imdb/model.json', inputSize: 64, skipFrames: 5 },
|
||||||
|
gender: { enabled: true, modelPath: 'file://models/ssrnet-gender/imdb/model.json' },
|
||||||
|
},
|
||||||
|
body: { enabled: true, modelPath: 'file://models/posenet/model.json', inputResolution: 257, outputStride: 16, maxDetections: 5, scoreThreshold: 0.75, nmsRadius: 20 },
|
||||||
|
hand: {
|
||||||
|
enabled: false,
|
||||||
|
inputSize: 256,
|
||||||
|
skipFrames: 5,
|
||||||
|
minConfidence: 0.8,
|
||||||
|
iouThreshold: 0.3,
|
||||||
|
scoreThreshold: 0.75,
|
||||||
|
detector: { anchors: 'file://models/handdetect/anchors.json', modelPath: 'file://models/handdetect/model.json' },
|
||||||
|
skeleton: { modelPath: 'file://models/handskeleton/model.json' },
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
async function detect(input, output) {
|
||||||
|
await tf.setBackend('tensorflow');
|
||||||
|
await tf.ready();
|
||||||
|
logger.info('TFJS Flags:', tf.env().features);
|
||||||
|
logger.log('Loading:', input);
|
||||||
|
const buffer = fs.readFileSync(input);
|
||||||
|
const image = tf.node.decodeImage(buffer);
|
||||||
|
logger.log('Processing:', image.shape);
|
||||||
|
const result = await human.detect(image, config);
|
||||||
|
logger.log(result);
|
||||||
|
// Draw detected data and save processed image
|
||||||
|
logger.log('Saving:', output);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
if (process.argv.length !== 4) logger.error('Parameters: <input image> <output image>');
|
||||||
|
else if (!fs.existsSync(process.argv[2])) logger.error(`File not found: ${process.argv[2]}`);
|
||||||
|
else detect(process.argv[2], process.argv[3]);
|
||||||
|
}
|
||||||
|
|
||||||
|
main();
|
|
@ -0,0 +1,22 @@
|
||||||
|
import human from '../dist/human.esm.js';
|
||||||
|
|
||||||
|
onmessage = async (msg) => {
|
||||||
|
const result = await human.detect(msg.data.image, msg.data.config);
|
||||||
|
postMessage(result);
|
||||||
|
};
|
||||||
|
|
||||||
|
/*
|
||||||
|
|
||||||
|
web workers are finicky
|
||||||
|
- cannot pass HTMLImage or HTMLVideo to web worker, so need to pass canvas instead
|
||||||
|
- canvases can execute transferControlToOffscreen() and then become offscreenCanvas which can be passed to worker, but...
|
||||||
|
cannot transfer canvas that has a rendering context (basically, first time you execute getContext() on it)
|
||||||
|
|
||||||
|
which means that if we pass main Canvas that will be used to render results on,
|
||||||
|
then all operations on it must be within webworker and we cannot touch it in the main thread at all.
|
||||||
|
doable, but...how to paint a video frame on it before we pass it?
|
||||||
|
|
||||||
|
and we create new offscreenCanvas that we drew video frame on and pass it's imageData and return results from worker
|
||||||
|
then there is an overhead of creating it and it ends up being slower than executing in the main thread
|
||||||
|
|
||||||
|
*/
|
|
@ -0,0 +1,12 @@
|
||||||
|
<head>
|
||||||
|
<script src="https://cdn.jsdelivr.net/npm/quicksettings"></script>
|
||||||
|
<script src="./demo-webworker.js" type="module"></script>
|
||||||
|
</head>
|
||||||
|
<body style="margin: 0; background: black; color: white; font-family: 'Segoe UI'">
|
||||||
|
<div id="main">
|
||||||
|
<video id="video" playsinline style="display: none"></video>
|
||||||
|
<image id="image" src="" style="display: none"></video>
|
||||||
|
<canvas id="canvas"></canvas>
|
||||||
|
<div id="log">Starting Human library</div>
|
||||||
|
</div>
|
||||||
|
</body>
|
|
@ -0,0 +1,339 @@
|
||||||
|
/* global QuickSettings */
|
||||||
|
|
||||||
|
import human from '../dist/human.esm.js';
|
||||||
|
|
||||||
|
const ui = {
|
||||||
|
baseColor: 'rgba(255, 200, 255, 0.3)',
|
||||||
|
baseFont: 'small-caps 1.2rem "Segoe UI"',
|
||||||
|
baseLineWidth: 16,
|
||||||
|
};
|
||||||
|
|
||||||
|
const config = {
|
||||||
|
face: {
|
||||||
|
enabled: true,
|
||||||
|
detector: { maxFaces: 10, skipFrames: 5, minConfidence: 0.8, iouThreshold: 0.3, scoreThreshold: 0.75 },
|
||||||
|
mesh: { enabled: true },
|
||||||
|
iris: { enabled: true },
|
||||||
|
age: { enabled: true, skipFrames: 5 },
|
||||||
|
gender: { enabled: true },
|
||||||
|
},
|
||||||
|
body: { enabled: true, maxDetections: 5, scoreThreshold: 0.75, nmsRadius: 20 },
|
||||||
|
hand: { enabled: true, skipFrames: 5, minConfidence: 0.8, iouThreshold: 0.3, scoreThreshold: 0.75 },
|
||||||
|
};
|
||||||
|
let settings;
|
||||||
|
let worker;
|
||||||
|
let timeStamp;
|
||||||
|
|
||||||
|
async function drawFace(result, canvas) {
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
ctx.fillStyle = ui.baseColor;
|
||||||
|
ctx.strokeStyle = ui.baseColor;
|
||||||
|
ctx.font = ui.baseFont;
|
||||||
|
for (const face of result) {
|
||||||
|
ctx.lineWidth = ui.baseLineWidth;
|
||||||
|
ctx.beginPath();
|
||||||
|
if (settings.getValue('Draw Boxes')) {
|
||||||
|
ctx.rect(face.box[0], face.box[1], face.box[2], face.box[3]);
|
||||||
|
}
|
||||||
|
ctx.fillText(`face ${face.gender || ''} ${face.age || ''} ${face.iris ? 'iris: ' + face.iris : ''}`, face.box[0] + 2, face.box[1] + 22, face.box[2]);
|
||||||
|
ctx.stroke();
|
||||||
|
ctx.lineWidth = 1;
|
||||||
|
if (face.mesh) {
|
||||||
|
if (settings.getValue('Draw Points')) {
|
||||||
|
for (const point of face.mesh) {
|
||||||
|
ctx.fillStyle = `rgba(${127.5 + (2 * point[2])}, ${127.5 - (2 * point[2])}, 255, 0.5)`;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(point[0], point[1], 2, 0, 2 * Math.PI);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (settings.getValue('Draw Polygons')) {
|
||||||
|
for (let i = 0; i < human.facemesh.triangulation.length / 3; i++) {
|
||||||
|
const points = [
|
||||||
|
human.facemesh.triangulation[i * 3 + 0],
|
||||||
|
human.facemesh.triangulation[i * 3 + 1],
|
||||||
|
human.facemesh.triangulation[i * 3 + 2],
|
||||||
|
].map((index) => face.mesh[index]);
|
||||||
|
const path = new Path2D();
|
||||||
|
path.moveTo(points[0][0], points[0][1]);
|
||||||
|
for (const point of points) {
|
||||||
|
path.lineTo(point[0], point[1]);
|
||||||
|
}
|
||||||
|
path.closePath();
|
||||||
|
ctx.strokeStyle = `rgba(${127.5 + (2 * points[0][2])}, ${127.5 - (2 * points[0][2])}, 255, 0.3)`;
|
||||||
|
ctx.stroke(path);
|
||||||
|
if (settings.getValue('Fill Polygons')) {
|
||||||
|
ctx.fillStyle = `rgba(${127.5 + (2 * points[0][2])}, ${127.5 - (2 * points[0][2])}, 255, 0.3)`;
|
||||||
|
ctx.fill(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function drawBody(result, canvas) {
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
ctx.fillStyle = ui.baseColor;
|
||||||
|
ctx.strokeStyle = ui.baseColor;
|
||||||
|
ctx.font = ui.baseFont;
|
||||||
|
ctx.lineWidth = ui.baseLineWidth;
|
||||||
|
for (const pose of result) {
|
||||||
|
if (settings.getValue('Draw Points')) {
|
||||||
|
for (const point of pose.keypoints) {
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(point.position.x, point.position.y, 2, 0, 2 * Math.PI);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (settings.getValue('Draw Polygons')) {
|
||||||
|
const path = new Path2D();
|
||||||
|
let part;
|
||||||
|
// torso
|
||||||
|
part = pose.keypoints.find((a) => a.part === 'leftShoulder');
|
||||||
|
path.moveTo(part.position.x, part.position.y);
|
||||||
|
part = pose.keypoints.find((a) => a.part === 'rightShoulder');
|
||||||
|
path.lineTo(part.position.x, part.position.y);
|
||||||
|
part = pose.keypoints.find((a) => a.part === 'rightHip');
|
||||||
|
path.lineTo(part.position.x, part.position.y);
|
||||||
|
part = pose.keypoints.find((a) => a.part === 'leftHip');
|
||||||
|
path.lineTo(part.position.x, part.position.y);
|
||||||
|
part = pose.keypoints.find((a) => a.part === 'leftShoulder');
|
||||||
|
path.lineTo(part.position.x, part.position.y);
|
||||||
|
// legs
|
||||||
|
part = pose.keypoints.find((a) => a.part === 'leftHip');
|
||||||
|
path.moveTo(part.position.x, part.position.y);
|
||||||
|
part = pose.keypoints.find((a) => a.part === 'leftKnee');
|
||||||
|
path.lineTo(part.position.x, part.position.y);
|
||||||
|
part = pose.keypoints.find((a) => a.part === 'leftAnkle');
|
||||||
|
path.lineTo(part.position.x, part.position.y);
|
||||||
|
part = pose.keypoints.find((a) => a.part === 'rightHip');
|
||||||
|
path.moveTo(part.position.x, part.position.y);
|
||||||
|
part = pose.keypoints.find((a) => a.part === 'rightKnee');
|
||||||
|
path.lineTo(part.position.x, part.position.y);
|
||||||
|
part = pose.keypoints.find((a) => a.part === 'rightAnkle');
|
||||||
|
path.lineTo(part.position.x, part.position.y);
|
||||||
|
// arms
|
||||||
|
part = pose.keypoints.find((a) => a.part === 'leftShoulder');
|
||||||
|
path.moveTo(part.position.x, part.position.y);
|
||||||
|
part = pose.keypoints.find((a) => a.part === 'leftElbow');
|
||||||
|
path.lineTo(part.position.x, part.position.y);
|
||||||
|
part = pose.keypoints.find((a) => a.part === 'leftWrist');
|
||||||
|
path.lineTo(part.position.x, part.position.y);
|
||||||
|
// arms
|
||||||
|
part = pose.keypoints.find((a) => a.part === 'rightShoulder');
|
||||||
|
path.moveTo(part.position.x, part.position.y);
|
||||||
|
part = pose.keypoints.find((a) => a.part === 'rightElbow');
|
||||||
|
path.lineTo(part.position.x, part.position.y);
|
||||||
|
part = pose.keypoints.find((a) => a.part === 'rightWrist');
|
||||||
|
path.lineTo(part.position.x, part.position.y);
|
||||||
|
// draw all
|
||||||
|
ctx.stroke(path);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function drawHand(result, canvas) {
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
ctx.font = ui.baseFont;
|
||||||
|
ctx.lineWidth = ui.baseLineWidth;
|
||||||
|
window.result = result;
|
||||||
|
for (const hand of result) {
|
||||||
|
if (settings.getValue('Draw Boxes')) {
|
||||||
|
ctx.lineWidth = ui.baseLineWidth;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.rect(hand.box[0], hand.box[1], hand.box[2], hand.box[3]);
|
||||||
|
ctx.fillText('hand', hand.box[0] + 2, hand.box[1] + 22, hand.box[2]);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
if (settings.getValue('Draw Points')) {
|
||||||
|
for (const point of hand.landmarks) {
|
||||||
|
ctx.fillStyle = `rgba(${127.5 + (2 * point[2])}, ${127.5 - (2 * point[2])}, 255, 0.5)`;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.arc(point[0], point[1], 2, 0, 2 * Math.PI);
|
||||||
|
ctx.fill();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (settings.getValue('Draw Polygons')) {
|
||||||
|
const addPart = (part) => {
|
||||||
|
for (let i = 1; i < part.length; i++) {
|
||||||
|
ctx.lineWidth = ui.baseLineWidth;
|
||||||
|
ctx.beginPath();
|
||||||
|
ctx.strokeStyle = `rgba(${127.5 + (2 * part[i][2])}, ${127.5 - (2 * part[i][2])}, 255, 0.5)`;
|
||||||
|
ctx.moveTo(part[i - 1][0], part[i - 1][1]);
|
||||||
|
ctx.lineTo(part[i][0], part[i][1]);
|
||||||
|
ctx.stroke();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
addPart(hand.annotations.indexFinger);
|
||||||
|
addPart(hand.annotations.middleFinger);
|
||||||
|
addPart(hand.annotations.ringFinger);
|
||||||
|
addPart(hand.annotations.pinky);
|
||||||
|
addPart(hand.annotations.thumb);
|
||||||
|
addPart(hand.annotations.palmBase);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function drawResults(input, result, canvas) {
|
||||||
|
// draw image
|
||||||
|
const ctx = canvas.getContext('2d');
|
||||||
|
ctx.drawImage(input, 0, 0, input.width, input.height, 0, 0, canvas.width, canvas.height);
|
||||||
|
// update fps
|
||||||
|
settings.setValue('FPS', Math.round(1000 / (performance.now() - timeStamp)));
|
||||||
|
// draw all results
|
||||||
|
drawFace(result.face, canvas);
|
||||||
|
drawBody(result.body, canvas);
|
||||||
|
drawHand(result.hand, canvas);
|
||||||
|
// update log
|
||||||
|
const engine = await human.tf.engine();
|
||||||
|
const log = document.getElementById('log');
|
||||||
|
log.innerText = `
|
||||||
|
TFJS Version: ${human.tf.version_core} Memory: ${engine.state.numBytes.toLocaleString()} bytes ${engine.state.numDataBuffers.toLocaleString()} buffers ${engine.state.numTensors.toLocaleString()} tensors
|
||||||
|
GPU Memory: used ${engine.backendInstance.numBytesInGPU.toLocaleString()} bytes free ${Math.floor(1024 * 1024 * engine.backendInstance.numMBBeforeWarning).toLocaleString()} bytes
|
||||||
|
Result: Face: ${(JSON.stringify(result.face)).length.toLocaleString()} bytes Body: ${(JSON.stringify(result.body)).length.toLocaleString()} bytes Hand: ${(JSON.stringify(result.hand)).length.toLocaleString()} bytes
|
||||||
|
`;
|
||||||
|
}
|
||||||
|
|
||||||
|
async function webWorker(input, image, canvas) {
|
||||||
|
if (!worker) {
|
||||||
|
// create new webworker
|
||||||
|
worker = new Worker('demo-webworker-worker.js', { type: 'module' });
|
||||||
|
// after receiving message from webworker, parse&draw results and send new frame for processing
|
||||||
|
worker.addEventListener('message', (msg) => {
|
||||||
|
drawResults(input, msg.data, canvas);
|
||||||
|
// eslint-disable-next-line no-use-before-define
|
||||||
|
requestAnimationFrame(() => runHumanDetect(input, canvas)); // immediate loop
|
||||||
|
});
|
||||||
|
}
|
||||||
|
timeStamp = performance.now();
|
||||||
|
// const offscreen = image.transferControlToOffscreen();
|
||||||
|
worker.postMessage({ image, config });
|
||||||
|
}
|
||||||
|
|
||||||
|
async function runHumanDetect(input, canvas) {
|
||||||
|
const live = input.srcObject ? ((input.srcObject.getVideoTracks()[0].readyState === 'live') && (input.readyState > 2) && (!input.paused)) : false;
|
||||||
|
// perform detect if live video or not video at all
|
||||||
|
if (live || !(input instanceof HTMLVideoElement)) {
|
||||||
|
// get image data from video as we cannot send html objects to webworker
|
||||||
|
const offscreen = new OffscreenCanvas(canvas.width, canvas.height);
|
||||||
|
const ctx = offscreen.getContext('2d');
|
||||||
|
ctx.drawImage(input, 0, 0, input.width, input.height, 0, 0, canvas.width, canvas.height);
|
||||||
|
const data = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
||||||
|
// perform detection
|
||||||
|
webWorker(input, data, canvas);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupGUI() {
|
||||||
|
// add all variables to ui control panel
|
||||||
|
settings = QuickSettings.create(10, 10, 'Settings', document.getElementById('main'));
|
||||||
|
settings.addRange('FPS', 0, 100, 0, 1);
|
||||||
|
settings.addBoolean('Pause', false, (val) => {
|
||||||
|
const video = document.getElementById('video');
|
||||||
|
const canvas = document.getElementById('canvas');
|
||||||
|
if (val) video.pause();
|
||||||
|
else video.play();
|
||||||
|
runHumanDetect(video, canvas);
|
||||||
|
});
|
||||||
|
settings.addHTML('line1', '<hr>'); settings.hideTitle('line1');
|
||||||
|
settings.addBoolean('Draw Boxes', false);
|
||||||
|
settings.addBoolean('Draw Points', true);
|
||||||
|
settings.addBoolean('Draw Polygons', true);
|
||||||
|
settings.addBoolean('Fill Polygons', true);
|
||||||
|
settings.bindText('baseColor', ui.baseColor, config);
|
||||||
|
settings.bindText('baseFont', ui.baseFont, config);
|
||||||
|
settings.bindRange('baseLineWidth', 1, 100, ui.baseLineWidth, 1, config);
|
||||||
|
settings.addHTML('line2', '<hr>'); settings.hideTitle('line2');
|
||||||
|
settings.addBoolean('Face Detect', config.face.enabled, (val) => config.face.enabled = val);
|
||||||
|
settings.addBoolean('Face Mesh', config.face.mesh.enabled, (val) => config.face.mesh.enabled = val);
|
||||||
|
settings.addBoolean('Face Iris', config.face.iris.enabled, (val) => config.face.iris.enabled = val);
|
||||||
|
settings.addBoolean('Face Age', config.face.age.enabled, (val) => config.face.age.enabled = val);
|
||||||
|
settings.addBoolean('Face Gender', config.face.gender.enabled, (val) => config.face.gender.enabled = val);
|
||||||
|
settings.addBoolean('Body Pose', config.body.enabled, (val) => config.body.enabled = val);
|
||||||
|
settings.addBoolean('Hand Pose', config.hand.enabled, (val) => config.hand.enabled = val);
|
||||||
|
settings.addHTML('line3', '<hr>'); settings.hideTitle('line3');
|
||||||
|
settings.addRange('Max Objects', 1, 20, 5, 1, (val) => {
|
||||||
|
config.face.detector.maxFaces = parseInt(val);
|
||||||
|
config.body.maxDetections = parseInt(val);
|
||||||
|
});
|
||||||
|
settings.addRange('Skip Frames', 1, 20, config.face.detector.skipFrames, 1, (val) => {
|
||||||
|
config.face.detector.skipFrames = parseInt(val);
|
||||||
|
config.face.age.skipFrames = parseInt(val);
|
||||||
|
config.hand.skipFrames = parseInt(val);
|
||||||
|
});
|
||||||
|
settings.addRange('Min Confidence', 0.1, 1.0, config.face.detector.minConfidence, 0.05, (val) => {
|
||||||
|
config.face.detector.minConfidence = parseFloat(val);
|
||||||
|
config.hand.minConfidence = parseFloat(val);
|
||||||
|
});
|
||||||
|
settings.addRange('Score Threshold', 0.1, 1.0, config.face.detector.scoreThreshold, 0.05, (val) => {
|
||||||
|
config.face.detector.scoreThreshold = parseFloat(val);
|
||||||
|
config.hand.scoreThreshold = parseFloat(val);
|
||||||
|
config.body.scoreThreshold = parseFloat(val);
|
||||||
|
});
|
||||||
|
settings.addRange('IOU Threshold', 0.1, 1.0, config.face.detector.iouThreshold, 0.05, (val) => {
|
||||||
|
config.face.detector.iouThreshold = parseFloat(val);
|
||||||
|
config.hand.iouThreshold = parseFloat(val);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function setupCanvas(input) {
|
||||||
|
// setup canvas object to same size as input as camera resolution may change
|
||||||
|
const canvas = document.getElementById('canvas');
|
||||||
|
canvas.width = input.width;
|
||||||
|
canvas.height = input.height;
|
||||||
|
return canvas;
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
async function setupCamera() {
|
||||||
|
// setup webcam. note that navigator.mediaDevices requires that page is accessed via https
|
||||||
|
const video = document.getElementById('video');
|
||||||
|
if (!navigator.mediaDevices) {
|
||||||
|
document.getElementById('log').innerText = 'Video not supported';
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
const stream = await navigator.mediaDevices.getUserMedia({
|
||||||
|
audio: false,
|
||||||
|
video: { facingMode: 'user', width: window.innerWidth, height: window.innerHeight },
|
||||||
|
});
|
||||||
|
video.srcObject = stream;
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
video.onloadedmetadata = () => {
|
||||||
|
video.width = video.videoWidth;
|
||||||
|
video.height = video.videoHeight;
|
||||||
|
video.play();
|
||||||
|
resolve(video);
|
||||||
|
};
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// eslint-disable-next-line no-unused-vars
|
||||||
|
async function setupImage() {
|
||||||
|
const image = document.getElementById('image');
|
||||||
|
image.width = window.innerWidth;
|
||||||
|
image.height = window.innerHeight;
|
||||||
|
return new Promise((resolve) => {
|
||||||
|
image.onload = () => resolve(image);
|
||||||
|
image.src = 'sample.jpg';
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
async function main() {
|
||||||
|
// initialize tensorflow
|
||||||
|
await human.tf.setBackend('webgl');
|
||||||
|
await human.tf.ready();
|
||||||
|
// setup ui control panel
|
||||||
|
await setupGUI();
|
||||||
|
// setup webcam
|
||||||
|
const video = await setupCamera();
|
||||||
|
// or setup image
|
||||||
|
// const image = await setupImage();
|
||||||
|
// setup output canvas from input object, select video or image
|
||||||
|
const canvas = await setupCanvas(video);
|
||||||
|
// run actual detection. if input is video, it will run in a loop else it will run only once
|
||||||
|
runHumanDetect(video, canvas);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.onload = main;
|
||||||
|
window.onresize = main;
|
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 it is too large
Load Diff
File diff suppressed because one or more lines are too long
|
@ -172,6 +172,32 @@
|
||||||
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-layers/-/tfjs-layers-2.6.0.tgz",
|
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-layers/-/tfjs-layers-2.6.0.tgz",
|
||||||
"integrity": "sha512-nU9WNSGpEU6GzKo5bvJBMa/OZRe1bR5Z2W6T0XiEY8CBiPNS+oJFJNm0NY8kQj/WnDS0Hfue38P46q7gV/9XMA=="
|
"integrity": "sha512-nU9WNSGpEU6GzKo5bvJBMa/OZRe1bR5Z2W6T0XiEY8CBiPNS+oJFJNm0NY8kQj/WnDS0Hfue38P46q7gV/9XMA=="
|
||||||
},
|
},
|
||||||
|
"@tensorflow/tfjs-node": {
|
||||||
|
"version": "2.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@tensorflow/tfjs-node/-/tfjs-node-2.6.0.tgz",
|
||||||
|
"integrity": "sha512-Yp1PICAVD3jBhqEShlzZHC9uOtT8axpFeciw8TeI4KxnIydWQOnrisI09z6uR7shCwNY4TM6txhpkO5b/RDyvw==",
|
||||||
|
"requires": {
|
||||||
|
"@tensorflow/tfjs": "2.6.0",
|
||||||
|
"@tensorflow/tfjs-core": "2.6.0",
|
||||||
|
"adm-zip": "^0.4.11",
|
||||||
|
"google-protobuf": "^3.9.2",
|
||||||
|
"https-proxy-agent": "^2.2.1",
|
||||||
|
"node-pre-gyp": "0.14.0",
|
||||||
|
"progress": "^2.0.0",
|
||||||
|
"rimraf": "^2.6.2",
|
||||||
|
"tar": "^4.4.6"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"rimraf": {
|
||||||
|
"version": "2.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
||||||
|
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
|
||||||
|
"requires": {
|
||||||
|
"glob": "^7.1.3"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/json5": {
|
"@types/json5": {
|
||||||
"version": "0.0.29",
|
"version": "0.0.29",
|
||||||
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
|
"resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz",
|
||||||
|
@ -212,6 +238,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/@types/webgl2/-/webgl2-0.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/@types/webgl2/-/webgl2-0.0.4.tgz",
|
||||||
"integrity": "sha512-PACt1xdErJbMUOUweSrbVM7gSIYm1vTncW2hF6Os/EeWi6TXYAYMPp+8v6rzHmypE5gHrxaxZNXgMkJVIdZpHw=="
|
"integrity": "sha512-PACt1xdErJbMUOUweSrbVM7gSIYm1vTncW2hF6Os/EeWi6TXYAYMPp+8v6rzHmypE5gHrxaxZNXgMkJVIdZpHw=="
|
||||||
},
|
},
|
||||||
|
"abbrev": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q=="
|
||||||
|
},
|
||||||
"acorn": {
|
"acorn": {
|
||||||
"version": "7.4.1",
|
"version": "7.4.1",
|
||||||
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz",
|
||||||
|
@ -224,6 +255,19 @@
|
||||||
"integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
|
"integrity": "sha512-K0Ptm/47OKfQRpNQ2J/oIN/3QYiK6FwW+eJbILhsdxh2WTLdl+30o8aGdTbm5JbffpFFAg/g+zi1E+jvJha5ng==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"adm-zip": {
|
||||||
|
"version": "0.4.16",
|
||||||
|
"resolved": "https://registry.npmjs.org/adm-zip/-/adm-zip-0.4.16.tgz",
|
||||||
|
"integrity": "sha512-TFi4HBKSGfIKsK5YCkKaaFG2m4PEDyViZmEwof3MTIgzimHLto6muaHVpbrljdIvIrFZzEq/p4nafOeLcYegrg=="
|
||||||
|
},
|
||||||
|
"agent-base": {
|
||||||
|
"version": "4.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/agent-base/-/agent-base-4.3.0.tgz",
|
||||||
|
"integrity": "sha512-salcGninV0nPrwpGNn4VTXBb1SOuXQBiqbrNXoeizJsHrsL6ERFM2Ne3JUSBWRE6aeNJI2ROP/WEEIDUiDe3cg==",
|
||||||
|
"requires": {
|
||||||
|
"es6-promisify": "^5.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ajv": {
|
"ajv": {
|
||||||
"version": "6.12.6",
|
"version": "6.12.6",
|
||||||
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
|
||||||
|
@ -255,6 +299,20 @@
|
||||||
"color-convert": "^2.0.1"
|
"color-convert": "^2.0.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"aproba": {
|
||||||
|
"version": "1.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz",
|
||||||
|
"integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw=="
|
||||||
|
},
|
||||||
|
"are-we-there-yet": {
|
||||||
|
"version": "1.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz",
|
||||||
|
"integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==",
|
||||||
|
"requires": {
|
||||||
|
"delegates": "^1.0.0",
|
||||||
|
"readable-stream": "^2.0.6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"argparse": {
|
"argparse": {
|
||||||
"version": "1.0.10",
|
"version": "1.0.10",
|
||||||
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
"resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz",
|
||||||
|
@ -340,14 +398,12 @@
|
||||||
"balanced-match": {
|
"balanced-match": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz",
|
||||||
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=",
|
"integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"brace-expansion": {
|
"brace-expansion": {
|
||||||
"version": "1.1.11",
|
"version": "1.1.11",
|
||||||
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
|
||||||
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"balanced-match": "^1.0.0",
|
"balanced-match": "^1.0.0",
|
||||||
"concat-map": "0.0.1"
|
"concat-map": "0.0.1"
|
||||||
|
@ -368,6 +424,11 @@
|
||||||
"supports-color": "^7.1.0"
|
"supports-color": "^7.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"chownr": {
|
||||||
|
"version": "1.1.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.4.tgz",
|
||||||
|
"integrity": "sha512-jJ0bqzaylmJtVnNgzTeSOs8DPavpbYgEr/b0YL8/2GO3xJEhInFmhKMUnEJQjZumK7KXGFhUy89PrsJWlakBVg=="
|
||||||
|
},
|
||||||
"cliui": {
|
"cliui": {
|
||||||
"version": "7.0.1",
|
"version": "7.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.1.tgz",
|
||||||
|
@ -378,6 +439,11 @@
|
||||||
"wrap-ansi": "^7.0.0"
|
"wrap-ansi": "^7.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"code-point-at": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz",
|
||||||
|
"integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c="
|
||||||
|
},
|
||||||
"color-convert": {
|
"color-convert": {
|
||||||
"version": "2.0.1",
|
"version": "2.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
|
||||||
|
@ -402,8 +468,7 @@
|
||||||
"concat-map": {
|
"concat-map": {
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
|
||||||
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=",
|
"integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"confusing-browser-globals": {
|
"confusing-browser-globals": {
|
||||||
"version": "1.0.9",
|
"version": "1.0.9",
|
||||||
|
@ -411,6 +476,11 @@
|
||||||
"integrity": "sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==",
|
"integrity": "sha512-KbS1Y0jMtyPgIxjO7ZzMAuUpAKMt1SzCL9fsrKsX6b0zJPTaT0SiSPmewwVZg9UAO83HVIlEhZF84LIjZ0lmAw==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"console-control-strings": {
|
||||||
|
"version": "1.1.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz",
|
||||||
|
"integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4="
|
||||||
|
},
|
||||||
"contains-path": {
|
"contains-path": {
|
||||||
"version": "0.1.0",
|
"version": "0.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/contains-path/-/contains-path-0.1.0.tgz",
|
||||||
|
@ -422,6 +492,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz",
|
"resolved": "https://registry.npmjs.org/core-js/-/core-js-3.6.5.tgz",
|
||||||
"integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA=="
|
"integrity": "sha512-vZVEEwZoIsI+vPEuoF9Iqf5H7/M3eeQqWlQnYa8FSKKePuYTf5MWnxb5SDAzCa60b3JBRS5g9b+Dq7b1y/RCrA=="
|
||||||
},
|
},
|
||||||
|
"core-util-is": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac="
|
||||||
|
},
|
||||||
"cross-spawn": {
|
"cross-spawn": {
|
||||||
"version": "7.0.3",
|
"version": "7.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz",
|
||||||
|
@ -442,6 +517,11 @@
|
||||||
"ms": "2.1.2"
|
"ms": "2.1.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"deep-extend": {
|
||||||
|
"version": "0.6.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz",
|
||||||
|
"integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA=="
|
||||||
|
},
|
||||||
"deep-is": {
|
"deep-is": {
|
||||||
"version": "0.1.3",
|
"version": "0.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
|
"resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.3.tgz",
|
||||||
|
@ -462,6 +542,16 @@
|
||||||
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz",
|
||||||
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
"integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk="
|
||||||
},
|
},
|
||||||
|
"delegates": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o="
|
||||||
|
},
|
||||||
|
"detect-libc": {
|
||||||
|
"version": "1.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz",
|
||||||
|
"integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups="
|
||||||
|
},
|
||||||
"doctrine": {
|
"doctrine": {
|
||||||
"version": "3.0.0",
|
"version": "3.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
|
||||||
|
@ -525,6 +615,19 @@
|
||||||
"is-symbol": "^1.0.2"
|
"is-symbol": "^1.0.2"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"es6-promise": {
|
||||||
|
"version": "4.2.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
|
||||||
|
"integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
|
||||||
|
},
|
||||||
|
"es6-promisify": {
|
||||||
|
"version": "5.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/es6-promisify/-/es6-promisify-5.0.0.tgz",
|
||||||
|
"integrity": "sha1-UQnWLz5W6pZ8S2NQWu8IKRyKUgM=",
|
||||||
|
"requires": {
|
||||||
|
"es6-promise": "^4.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"esbuild": {
|
"esbuild": {
|
||||||
"version": "0.7.14",
|
"version": "0.7.14",
|
||||||
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.7.14.tgz",
|
"resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.7.14.tgz",
|
||||||
|
@ -932,11 +1035,18 @@
|
||||||
"mime-types": "^2.1.12"
|
"mime-types": "^2.1.12"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"fs-minipass": {
|
||||||
|
"version": "1.2.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.7.tgz",
|
||||||
|
"integrity": "sha512-GWSSJGFy4e9GUeCcbIkED+bgAoFyj7XF1mV8rma3QW4NIqX9Kyx79N/PF61H5udOV3aY1IaMLs6pGbH71nlCTA==",
|
||||||
|
"requires": {
|
||||||
|
"minipass": "^2.6.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"fs.realpath": {
|
"fs.realpath": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
|
||||||
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=",
|
"integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"function-bind": {
|
"function-bind": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.1",
|
||||||
|
@ -950,6 +1060,54 @@
|
||||||
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
|
"integrity": "sha1-GwqzvVU7Kg1jmdKcDj6gslIHgyc=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"gauge": {
|
||||||
|
"version": "2.7.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz",
|
||||||
|
"integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=",
|
||||||
|
"requires": {
|
||||||
|
"aproba": "^1.0.3",
|
||||||
|
"console-control-strings": "^1.0.0",
|
||||||
|
"has-unicode": "^2.0.0",
|
||||||
|
"object-assign": "^4.1.0",
|
||||||
|
"signal-exit": "^3.0.0",
|
||||||
|
"string-width": "^1.0.1",
|
||||||
|
"strip-ansi": "^3.0.1",
|
||||||
|
"wide-align": "^1.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-regex": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
|
||||||
|
"integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8="
|
||||||
|
},
|
||||||
|
"is-fullwidth-code-point": {
|
||||||
|
"version": "1.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz",
|
||||||
|
"integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=",
|
||||||
|
"requires": {
|
||||||
|
"number-is-nan": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"string-width": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=",
|
||||||
|
"requires": {
|
||||||
|
"code-point-at": "^1.0.0",
|
||||||
|
"is-fullwidth-code-point": "^1.0.0",
|
||||||
|
"strip-ansi": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"strip-ansi": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
|
||||||
|
"integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=",
|
||||||
|
"requires": {
|
||||||
|
"ansi-regex": "^2.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"get-caller-file": {
|
"get-caller-file": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||||
|
@ -959,7 +1117,6 @@
|
||||||
"version": "7.1.6",
|
"version": "7.1.6",
|
||||||
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
"resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz",
|
||||||
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
|
"integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"fs.realpath": "^1.0.0",
|
"fs.realpath": "^1.0.0",
|
||||||
"inflight": "^1.0.4",
|
"inflight": "^1.0.4",
|
||||||
|
@ -987,6 +1144,11 @@
|
||||||
"type-fest": "^0.8.1"
|
"type-fest": "^0.8.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"google-protobuf": {
|
||||||
|
"version": "3.13.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/google-protobuf/-/google-protobuf-3.13.0.tgz",
|
||||||
|
"integrity": "sha512-ZIf3qfLFayVrPvAjeKKxO5FRF1/NwRxt6Dko+fWEMuHwHbZx8/fcaAao9b0wCM6kr8qeg2te8XTpyuvKuD9aKw=="
|
||||||
|
},
|
||||||
"graceful-fs": {
|
"graceful-fs": {
|
||||||
"version": "4.2.4",
|
"version": "4.2.4",
|
||||||
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
|
"resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.4.tgz",
|
||||||
|
@ -1013,18 +1175,58 @@
|
||||||
"integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
|
"integrity": "sha512-PLcsoqu++dmEIZB+6totNFKq/7Do+Z0u4oT0zKOJNl3lYK6vGwwu2hjHs+68OEZbTjiUE9bgOABXbP/GvrS0Kg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"has-unicode": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz",
|
||||||
|
"integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk="
|
||||||
|
},
|
||||||
"hosted-git-info": {
|
"hosted-git-info": {
|
||||||
"version": "2.8.8",
|
"version": "2.8.8",
|
||||||
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
|
"resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.8.8.tgz",
|
||||||
"integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
|
"integrity": "sha512-f/wzC2QaWBs7t9IYqB4T3sR1xviIViXJRJTWBlx2Gf3g0Xi5vI7Yy4koXQ1c9OYDGHN9sBy1DQ2AB8fqZBWhUg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"https-proxy-agent": {
|
||||||
|
"version": "2.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-2.2.4.tgz",
|
||||||
|
"integrity": "sha512-OmvfoQ53WLjtA9HeYP9RNrWMJzzAz1JGaSFr1nijg0PVR1JaD/xbJq1mdEIIlxGpXp9eSe/O2LgU9DJmTPd0Eg==",
|
||||||
|
"requires": {
|
||||||
|
"agent-base": "^4.3.0",
|
||||||
|
"debug": "^3.1.0"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"debug": {
|
||||||
|
"version": "3.2.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
|
||||||
|
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
|
||||||
|
"requires": {
|
||||||
|
"ms": "^2.1.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"iconv-lite": {
|
||||||
|
"version": "0.4.24",
|
||||||
|
"resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz",
|
||||||
|
"integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==",
|
||||||
|
"requires": {
|
||||||
|
"safer-buffer": ">= 2.1.2 < 3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"ignore": {
|
"ignore": {
|
||||||
"version": "4.0.6",
|
"version": "4.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/ignore/-/ignore-4.0.6.tgz",
|
||||||
"integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
|
"integrity": "sha512-cyFDKrqc/YdcWFniJhzI42+AzS+gNwmUzOSFcRCQYwySuBBBy/KjuxWLZ/FHEH6Moq1NizMOBWyTcv8O4OZIMg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"ignore-walk": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-m7o6xuOaT1aqheYHKf8W6J5pYH85ZI9w077erOzLje3JsB1gkafkAhHHY19dqjulgIZHFm32Cp5uNZgcQqdJKw==",
|
||||||
|
"requires": {
|
||||||
|
"minimatch": "^3.0.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"import-fresh": {
|
"import-fresh": {
|
||||||
"version": "3.2.1",
|
"version": "3.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.2.1.tgz",
|
||||||
|
@ -1045,7 +1247,6 @@
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
"resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
|
||||||
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
"integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"once": "^1.3.0",
|
"once": "^1.3.0",
|
||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
|
@ -1054,8 +1255,12 @@
|
||||||
"inherits": {
|
"inherits": {
|
||||||
"version": "2.0.4",
|
"version": "2.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
|
||||||
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
|
"integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="
|
||||||
"dev": true
|
},
|
||||||
|
"ini": {
|
||||||
|
"version": "1.3.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz",
|
||||||
|
"integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw=="
|
||||||
},
|
},
|
||||||
"is-arrayish": {
|
"is-arrayish": {
|
||||||
"version": "0.2.1",
|
"version": "0.2.1",
|
||||||
|
@ -1128,8 +1333,7 @@
|
||||||
"isarray": {
|
"isarray": {
|
||||||
"version": "1.0.0",
|
"version": "1.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
|
||||||
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=",
|
"integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"isexe": {
|
"isexe": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
|
@ -1235,7 +1439,6 @@
|
||||||
"version": "3.0.4",
|
"version": "3.0.4",
|
||||||
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz",
|
||||||
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
"integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"brace-expansion": "^1.1.7"
|
"brace-expansion": "^1.1.7"
|
||||||
}
|
}
|
||||||
|
@ -1243,14 +1446,29 @@
|
||||||
"minimist": {
|
"minimist": {
|
||||||
"version": "1.2.5",
|
"version": "1.2.5",
|
||||||
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
|
||||||
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw==",
|
"integrity": "sha512-FM9nNUYrRBAELZQT3xeZQ7fmMOBg6nWNmJKTcgsJeaLstP/UODVpGsr5OhXhhXg6f+qtJ8uiZ+PUxkDWcgIXLw=="
|
||||||
"dev": true
|
},
|
||||||
|
"minipass": {
|
||||||
|
"version": "2.9.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/minipass/-/minipass-2.9.0.tgz",
|
||||||
|
"integrity": "sha512-wxfUjg9WebH+CUDX/CdbRlh5SmfZiy/hpkxaRI16Y9W56Pa75sWgd/rvFilSgrauD9NyFymP/+JFV3KwzIsJeg==",
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "^5.1.2",
|
||||||
|
"yallist": "^3.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"minizlib": {
|
||||||
|
"version": "1.3.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.3.3.tgz",
|
||||||
|
"integrity": "sha512-6ZYMOEnmVsdCeTJVE0W9ZD+pVnE8h9Hma/iOwwRDsdQoePpoX56/8B6z3P9VNwppJuBKNRuFDRNRqRWexT9G9Q==",
|
||||||
|
"requires": {
|
||||||
|
"minipass": "^2.9.0"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"mkdirp": {
|
"mkdirp": {
|
||||||
"version": "0.5.5",
|
"version": "0.5.5",
|
||||||
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz",
|
||||||
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
"integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"minimist": "^1.2.5"
|
"minimist": "^1.2.5"
|
||||||
}
|
}
|
||||||
|
@ -1258,8 +1476,7 @@
|
||||||
"ms": {
|
"ms": {
|
||||||
"version": "2.1.2",
|
"version": "2.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
|
||||||
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
|
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"natural-compare": {
|
"natural-compare": {
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
|
@ -1267,11 +1484,72 @@
|
||||||
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
|
"integrity": "sha1-Sr6/7tdUHywnrPspvbvRXI1bpPc=",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"needle": {
|
||||||
|
"version": "2.5.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/needle/-/needle-2.5.2.tgz",
|
||||||
|
"integrity": "sha512-LbRIwS9BfkPvNwNHlsA41Q29kL2L/6VaOJ0qisM5lLWsTV3nP15abO5ITL6L81zqFhzjRKDAYjpcBcwM0AVvLQ==",
|
||||||
|
"requires": {
|
||||||
|
"debug": "^3.2.6",
|
||||||
|
"iconv-lite": "^0.4.4",
|
||||||
|
"sax": "^1.2.4"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"debug": {
|
||||||
|
"version": "3.2.6",
|
||||||
|
"resolved": "https://registry.npmjs.org/debug/-/debug-3.2.6.tgz",
|
||||||
|
"integrity": "sha512-mel+jf7nrtEl5Pn1Qx46zARXKDpBbvzezse7p7LqINmdoIk8PYP5SySaxEmYv6TZ0JyEKA1hsCId6DIhgITtWQ==",
|
||||||
|
"requires": {
|
||||||
|
"ms": "^2.1.1"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"node-fetch": {
|
"node-fetch": {
|
||||||
"version": "2.6.1",
|
"version": "2.6.1",
|
||||||
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
"resolved": "https://registry.npmjs.org/node-fetch/-/node-fetch-2.6.1.tgz",
|
||||||
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
|
"integrity": "sha512-V4aYg89jEoVRxRb2fJdAg8FHvI7cEyYdVAh94HH0UIK8oJxUfkjlDQN9RbMx+bEjP7+ggMiFRprSti032Oipxw=="
|
||||||
},
|
},
|
||||||
|
"node-pre-gyp": {
|
||||||
|
"version": "0.14.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.14.0.tgz",
|
||||||
|
"integrity": "sha512-+CvDC7ZttU/sSt9rFjix/P05iS43qHCOOGzcr3Ry99bXG7VX953+vFyEuph/tfqoYu8dttBkE86JSKBO2OzcxA==",
|
||||||
|
"requires": {
|
||||||
|
"detect-libc": "^1.0.2",
|
||||||
|
"mkdirp": "^0.5.1",
|
||||||
|
"needle": "^2.2.1",
|
||||||
|
"nopt": "^4.0.1",
|
||||||
|
"npm-packlist": "^1.1.6",
|
||||||
|
"npmlog": "^4.0.2",
|
||||||
|
"rc": "^1.2.7",
|
||||||
|
"rimraf": "^2.6.1",
|
||||||
|
"semver": "^5.3.0",
|
||||||
|
"tar": "^4.4.2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"rimraf": {
|
||||||
|
"version": "2.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
|
||||||
|
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
|
||||||
|
"requires": {
|
||||||
|
"glob": "^7.1.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"semver": {
|
||||||
|
"version": "5.7.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/semver/-/semver-5.7.1.tgz",
|
||||||
|
"integrity": "sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ=="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"nopt": {
|
||||||
|
"version": "4.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.3.tgz",
|
||||||
|
"integrity": "sha512-CvaGwVMztSMJLOeXPrez7fyfObdZqNUK1cPAEzLHrTybIua9pMdmmPR5YwtfNftIOMv3DPUhFaxsZMNTQO20Kg==",
|
||||||
|
"requires": {
|
||||||
|
"abbrev": "1",
|
||||||
|
"osenv": "^0.1.4"
|
||||||
|
}
|
||||||
|
},
|
||||||
"normalize-package-data": {
|
"normalize-package-data": {
|
||||||
"version": "2.5.0",
|
"version": "2.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
|
"resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.5.0.tgz",
|
||||||
|
@ -1292,6 +1570,50 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"npm-bundled": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-gqkfgGePhTpAEgUsGEgcq1rqPXA+tv/aVBlgEzfXwA1yiUJF7xtEt3CtVwOjNYQOVknDk0F20w58Fnm3EtG0fA==",
|
||||||
|
"requires": {
|
||||||
|
"npm-normalize-package-bin": "^1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"npm-normalize-package-bin": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-1.0.1.tgz",
|
||||||
|
"integrity": "sha512-EPfafl6JL5/rU+ot6P3gRSCpPDW5VmIzX959Ob1+ySFUuuYHWHekXpwdUZcKP5C+DS4GEtdJluwBjnsNDl+fSA=="
|
||||||
|
},
|
||||||
|
"npm-packlist": {
|
||||||
|
"version": "1.4.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.4.8.tgz",
|
||||||
|
"integrity": "sha512-5+AZgwru5IevF5ZdnFglB5wNlHG1AOOuw28WhUq8/8emhBmLv6jX5by4WJCh7lW0uSYZYS6DXqIsyZVIXRZU9A==",
|
||||||
|
"requires": {
|
||||||
|
"ignore-walk": "^3.0.1",
|
||||||
|
"npm-bundled": "^1.0.1",
|
||||||
|
"npm-normalize-package-bin": "^1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"npmlog": {
|
||||||
|
"version": "4.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz",
|
||||||
|
"integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==",
|
||||||
|
"requires": {
|
||||||
|
"are-we-there-yet": "~1.1.2",
|
||||||
|
"console-control-strings": "~1.1.0",
|
||||||
|
"gauge": "~2.7.3",
|
||||||
|
"set-blocking": "~2.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"number-is-nan": {
|
||||||
|
"version": "1.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz",
|
||||||
|
"integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0="
|
||||||
|
},
|
||||||
|
"object-assign": {
|
||||||
|
"version": "4.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
|
||||||
|
"integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM="
|
||||||
|
},
|
||||||
"object-inspect": {
|
"object-inspect": {
|
||||||
"version": "1.8.0",
|
"version": "1.8.0",
|
||||||
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz",
|
"resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.8.0.tgz",
|
||||||
|
@ -1385,7 +1707,6 @@
|
||||||
"version": "1.4.0",
|
"version": "1.4.0",
|
||||||
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
|
||||||
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
"integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=",
|
||||||
"dev": true,
|
|
||||||
"requires": {
|
"requires": {
|
||||||
"wrappy": "1"
|
"wrappy": "1"
|
||||||
}
|
}
|
||||||
|
@ -1404,6 +1725,25 @@
|
||||||
"word-wrap": "^1.2.3"
|
"word-wrap": "^1.2.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"os-homedir": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M="
|
||||||
|
},
|
||||||
|
"os-tmpdir": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ="
|
||||||
|
},
|
||||||
|
"osenv": {
|
||||||
|
"version": "0.1.5",
|
||||||
|
"resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz",
|
||||||
|
"integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==",
|
||||||
|
"requires": {
|
||||||
|
"os-homedir": "^1.0.0",
|
||||||
|
"os-tmpdir": "^1.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"p-limit": {
|
"p-limit": {
|
||||||
"version": "1.3.0",
|
"version": "1.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/p-limit/-/p-limit-1.3.0.tgz",
|
||||||
|
@ -1455,8 +1795,7 @@
|
||||||
"path-is-absolute": {
|
"path-is-absolute": {
|
||||||
"version": "1.0.1",
|
"version": "1.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
|
||||||
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=",
|
"integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"path-key": {
|
"path-key": {
|
||||||
"version": "3.1.1",
|
"version": "3.1.1",
|
||||||
|
@ -1500,11 +1839,15 @@
|
||||||
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
|
"integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"process-nextick-args": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag=="
|
||||||
|
},
|
||||||
"progress": {
|
"progress": {
|
||||||
"version": "2.0.3",
|
"version": "2.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/progress/-/progress-2.0.3.tgz",
|
||||||
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA==",
|
"integrity": "sha512-7PiHtLll5LdnKIMw100I+8xJXR5gW2QwWYkT6iJva0bXitZKa/XMrSbdmg3r2Xnaidz9Qumd0VPaMrZlF9V9sA=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"punycode": {
|
"punycode": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
|
@ -1512,6 +1855,24 @@
|
||||||
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
|
"integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"rc": {
|
||||||
|
"version": "1.2.8",
|
||||||
|
"resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz",
|
||||||
|
"integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==",
|
||||||
|
"requires": {
|
||||||
|
"deep-extend": "^0.6.0",
|
||||||
|
"ini": "~1.3.0",
|
||||||
|
"minimist": "^1.2.0",
|
||||||
|
"strip-json-comments": "~2.0.1"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"strip-json-comments": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
|
||||||
|
"integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo="
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"read-pkg": {
|
"read-pkg": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-2.0.0.tgz",
|
||||||
|
@ -1533,6 +1894,20 @@
|
||||||
"read-pkg": "^2.0.0"
|
"read-pkg": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"readable-stream": {
|
||||||
|
"version": "2.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz",
|
||||||
|
"integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==",
|
||||||
|
"requires": {
|
||||||
|
"core-util-is": "~1.0.0",
|
||||||
|
"inherits": "~2.0.3",
|
||||||
|
"isarray": "~1.0.0",
|
||||||
|
"process-nextick-args": "~2.0.0",
|
||||||
|
"safe-buffer": "~5.1.1",
|
||||||
|
"string_decoder": "~1.1.1",
|
||||||
|
"util-deprecate": "~1.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
"regenerator-runtime": {
|
"regenerator-runtime": {
|
||||||
"version": "0.13.7",
|
"version": "0.13.7",
|
||||||
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
|
"resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.7.tgz",
|
||||||
|
@ -1573,6 +1948,21 @@
|
||||||
"glob": "^7.1.3"
|
"glob": "^7.1.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"safe-buffer": {
|
||||||
|
"version": "5.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
|
||||||
|
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g=="
|
||||||
|
},
|
||||||
|
"safer-buffer": {
|
||||||
|
"version": "2.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
|
||||||
|
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
|
||||||
|
},
|
||||||
|
"sax": {
|
||||||
|
"version": "1.2.4",
|
||||||
|
"resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz",
|
||||||
|
"integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw=="
|
||||||
|
},
|
||||||
"seedrandom": {
|
"seedrandom": {
|
||||||
"version": "2.4.3",
|
"version": "2.4.3",
|
||||||
"resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-2.4.3.tgz",
|
"resolved": "https://registry.npmjs.org/seedrandom/-/seedrandom-2.4.3.tgz",
|
||||||
|
@ -1584,6 +1974,11 @@
|
||||||
"integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
|
"integrity": "sha512-OrOb32TeeambH6UrhtShmF7CRDqhL6/5XpPNp2DuRH6+9QLw/orhp72j87v8Qa1ScDkvrrBNpZcDejAirJmfXQ==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"set-blocking": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc="
|
||||||
|
},
|
||||||
"shebang-command": {
|
"shebang-command": {
|
||||||
"version": "2.0.0",
|
"version": "2.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz",
|
||||||
|
@ -1599,6 +1994,11 @@
|
||||||
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
"integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"signal-exit": {
|
||||||
|
"version": "3.0.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.3.tgz",
|
||||||
|
"integrity": "sha512-VUJ49FC8U1OxwZLxIbTTrDvLnf/6TDgxZcK8wxR8zs13xpx7xbG60ndBlhNrFi2EMuFRoeDoJO7wthSLq42EjA=="
|
||||||
|
},
|
||||||
"slice-ansi": {
|
"slice-ansi": {
|
||||||
"version": "2.1.0",
|
"version": "2.1.0",
|
||||||
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
|
"resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-2.1.0.tgz",
|
||||||
|
@ -1751,6 +2151,14 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"string_decoder": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
|
||||||
|
"requires": {
|
||||||
|
"safe-buffer": "~5.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"strip-ansi": {
|
"strip-ansi": {
|
||||||
"version": "6.0.0",
|
"version": "6.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.0.tgz",
|
||||||
|
@ -1831,6 +2239,20 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"tar": {
|
||||||
|
"version": "4.4.13",
|
||||||
|
"resolved": "https://registry.npmjs.org/tar/-/tar-4.4.13.tgz",
|
||||||
|
"integrity": "sha512-w2VwSrBoHa5BsSyH+KxEqeQBAllHhccyMFVHtGtdMpF4W7IRWfZjFiQceJPChOeTsSDVUpER2T8FA93pr0L+QA==",
|
||||||
|
"requires": {
|
||||||
|
"chownr": "^1.1.1",
|
||||||
|
"fs-minipass": "^1.2.5",
|
||||||
|
"minipass": "^2.8.6",
|
||||||
|
"minizlib": "^1.2.1",
|
||||||
|
"mkdirp": "^0.5.0",
|
||||||
|
"safe-buffer": "^5.1.2",
|
||||||
|
"yallist": "^3.0.3"
|
||||||
|
}
|
||||||
|
},
|
||||||
"text-table": {
|
"text-table": {
|
||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz",
|
||||||
|
@ -1873,6 +2295,11 @@
|
||||||
"punycode": "^2.1.0"
|
"punycode": "^2.1.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"util-deprecate": {
|
||||||
|
"version": "1.0.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
|
||||||
|
"integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8="
|
||||||
|
},
|
||||||
"v8-compile-cache": {
|
"v8-compile-cache": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz",
|
||||||
|
@ -1935,6 +2362,43 @@
|
||||||
"isexe": "^2.0.0"
|
"isexe": "^2.0.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"wide-align": {
|
||||||
|
"version": "1.1.3",
|
||||||
|
"resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz",
|
||||||
|
"integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==",
|
||||||
|
"requires": {
|
||||||
|
"string-width": "^1.0.2 || 2"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"ansi-regex": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz",
|
||||||
|
"integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg="
|
||||||
|
},
|
||||||
|
"is-fullwidth-code-point": {
|
||||||
|
"version": "2.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-2.0.0.tgz",
|
||||||
|
"integrity": "sha1-o7MKXE8ZkYMWeqq5O+764937ZU8="
|
||||||
|
},
|
||||||
|
"string-width": {
|
||||||
|
"version": "2.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-2.1.1.tgz",
|
||||||
|
"integrity": "sha512-nOqH59deCq9SRHlxq1Aw85Jnt4w6KvLKqWVik6oA9ZklXLNIOlqg4F2yrT1MVaTjAqvVwdfeZ7w7aCvJD7ugkw==",
|
||||||
|
"requires": {
|
||||||
|
"is-fullwidth-code-point": "^2.0.0",
|
||||||
|
"strip-ansi": "^4.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"strip-ansi": {
|
||||||
|
"version": "4.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz",
|
||||||
|
"integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=",
|
||||||
|
"requires": {
|
||||||
|
"ansi-regex": "^3.0.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
"word-wrap": {
|
"word-wrap": {
|
||||||
"version": "1.2.3",
|
"version": "1.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/word-wrap/-/word-wrap-1.2.3.tgz",
|
||||||
|
@ -1954,8 +2418,7 @@
|
||||||
"wrappy": {
|
"wrappy": {
|
||||||
"version": "1.0.2",
|
"version": "1.0.2",
|
||||||
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz",
|
||||||
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=",
|
"integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"write": {
|
"write": {
|
||||||
"version": "1.0.3",
|
"version": "1.0.3",
|
||||||
|
@ -1971,6 +2434,11 @@
|
||||||
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.2.tgz",
|
"resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.2.tgz",
|
||||||
"integrity": "sha512-CkwaeZw6dQgqgPGeTWKMXCRmMcBgETFlTml1+ZOO+q7kGst8NREJ+eWwFNPVUQ4QGdAaklbqCZHH6Zuep1RjiA=="
|
"integrity": "sha512-CkwaeZw6dQgqgPGeTWKMXCRmMcBgETFlTml1+ZOO+q7kGst8NREJ+eWwFNPVUQ4QGdAaklbqCZHH6Zuep1RjiA=="
|
||||||
},
|
},
|
||||||
|
"yallist": {
|
||||||
|
"version": "3.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz",
|
||||||
|
"integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g=="
|
||||||
|
},
|
||||||
"yargs": {
|
"yargs": {
|
||||||
"version": "16.0.3",
|
"version": "16.0.3",
|
||||||
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.0.3.tgz",
|
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.0.3.tgz",
|
||||||
|
|
15
package.json
15
package.json
|
@ -3,7 +3,7 @@
|
||||||
"version": "0.2.8",
|
"version": "0.2.8",
|
||||||
"description": "human: 3D Face Detection, Iris Tracking and Age & Gender Prediction",
|
"description": "human: 3D Face Detection, Iris Tracking and Age & Gender Prediction",
|
||||||
"sideEffects": false,
|
"sideEffects": false,
|
||||||
"main": "src/index.js",
|
"main": "dist/human.node.js",
|
||||||
"module": "dist/human.esm.js",
|
"module": "dist/human.esm.js",
|
||||||
"browser": "dist/human.js",
|
"browser": "dist/human.js",
|
||||||
"author": "Vladimir Mandic <mandic00@live.com>",
|
"author": "Vladimir Mandic <mandic00@live.com>",
|
||||||
|
@ -20,7 +20,8 @@
|
||||||
"url": "git+https://github.com/vladmandic/human.git"
|
"url": "git+https://github.com/vladmandic/human.git"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@tensorflow/tfjs": "^2.6.0"
|
"@tensorflow/tfjs": "^2.6.0",
|
||||||
|
"@tensorflow/tfjs-node": "^2.6.0"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"esbuild": "^0.7.13",
|
"esbuild": "^0.7.13",
|
||||||
|
@ -33,10 +34,12 @@
|
||||||
"rimraf": "^3.0.2"
|
"rimraf": "^3.0.2"
|
||||||
},
|
},
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"lint": "eslint src/*",
|
"start": "node --trace-warnings --trace-uncaught --no-deprecation demo/demo-node.js",
|
||||||
"build": "rimraf dist/ && npm run build-esm && npm run build-iife",
|
"lint": "eslint src/*.js demo/*.js",
|
||||||
"build-esm": "esbuild --bundle --platform=browser --sourcemap --target=esnext --format=esm --minify --outfile=dist/human.esm.js src/index.js",
|
"build": "rimraf dist/ && npm run build-esm && npm run build-iife && npm run build-node",
|
||||||
"build-iife": "esbuild --bundle --platform=browser --sourcemap --target=esnext --format=iife --minify --global-name=human --outfile=dist/human.js src/index.js"
|
"build-esm": "esbuild --bundle --platform=browser --sourcemap --target=esnext --format=esm --minify --external:fs --outfile=dist/human.esm.js src/index.js",
|
||||||
|
"build-iife": "esbuild --bundle --platform=browser --sourcemap --target=esnext --format=iife --minify --external:fs --global-name=human --outfile=dist/human.js src/index.js",
|
||||||
|
"build-node": "esbuild --bundle --platform=node --sourcemap --target=esnext --format=cjs --external:@tensorflow --outfile=dist/human.node.js src/index.js"
|
||||||
},
|
},
|
||||||
"keywords": [
|
"keywords": [
|
||||||
"tensorflowjs",
|
"tensorflowjs",
|
||||||
|
|
|
@ -17,9 +17,13 @@ async function loadHandPoseModel(url) {
|
||||||
// of bounding boxes, each of which is assigned a score during prediction. The
|
// of bounding boxes, each of which is assigned a score during prediction. The
|
||||||
// anchors define the coordinates of these boxes.
|
// anchors define the coordinates of these boxes.
|
||||||
async function loadAnchors(url) {
|
async function loadAnchors(url) {
|
||||||
return tf.util
|
if (tf.env().features.IS_NODE) {
|
||||||
.fetch(url)
|
// eslint-disable-next-line global-require
|
||||||
.then((d) => d.json());
|
const fs = require('fs');
|
||||||
|
const data = await fs.readFileSync(url.replace('file://', ''));
|
||||||
|
return JSON.parse(data);
|
||||||
|
}
|
||||||
|
return tf.util.fetch(url).then((d) => d.json());
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
82
src/index.js
82
src/index.js
|
@ -31,53 +31,55 @@ function mergeDeep(...objects) {
|
||||||
}
|
}
|
||||||
|
|
||||||
async function detect(input, userConfig) {
|
async function detect(input, userConfig) {
|
||||||
const config = mergeDeep(defaults, userConfig);
|
// eslint-disable-next-line no-async-promise-executor
|
||||||
|
return new Promise(async (resolve) => {
|
||||||
|
const config = mergeDeep(defaults, userConfig);
|
||||||
|
|
||||||
// load models if enabled
|
// load models if enabled
|
||||||
if (config.body.enabled && !models.posenet) models.posenet = await posenet.load(config.body);
|
if (config.face.age.enabled) await ssrnet.loadAge(config);
|
||||||
if (config.hand.enabled && !models.handpose) models.handpose = await handpose.load(config.hand);
|
if (config.face.gender.enabled) await ssrnet.loadGender(config);
|
||||||
if (config.face.enabled && !models.facemesh) models.facemesh = await facemesh.load(config.face);
|
if (config.body.enabled && !models.posenet) models.posenet = await posenet.load(config.body);
|
||||||
if (config.face.age.enabled) await ssrnet.loadAge(config);
|
if (config.hand.enabled && !models.handpose) models.handpose = await handpose.load(config.hand);
|
||||||
if (config.face.gender.enabled) await ssrnet.loadGender(config);
|
if (config.face.enabled && !models.facemesh) models.facemesh = await facemesh.load(config.face);
|
||||||
|
|
||||||
tf.engine().startScope();
|
tf.engine().startScope();
|
||||||
|
|
||||||
// run posenet
|
// run posenet
|
||||||
let poseRes = [];
|
let poseRes = [];
|
||||||
if (config.body.enabled) poseRes = await models.posenet.estimateMultiplePoses(input, config.body);
|
if (config.body.enabled) poseRes = await models.posenet.estimateMultiplePoses(input, config.body);
|
||||||
|
|
||||||
// run handpose
|
// run handpose
|
||||||
let handRes = [];
|
let handRes = [];
|
||||||
if (config.hand.enabled) handRes = await models.handpose.estimateHands(input, config.hand);
|
if (config.hand.enabled) handRes = await models.handpose.estimateHands(input, config.hand);
|
||||||
|
|
||||||
// run facemesh, includes blazeface and iris
|
// run facemesh, includes blazeface and iris
|
||||||
const faceRes = [];
|
const faceRes = [];
|
||||||
if (config.face.enabled) {
|
if (config.face.enabled) {
|
||||||
const faces = await models.facemesh.estimateFaces(input, config.face);
|
const faces = await models.facemesh.estimateFaces(input, config.face);
|
||||||
for (const face of faces) {
|
for (const face of faces) {
|
||||||
// run ssr-net age & gender, inherits face from blazeface
|
// run ssr-net age & gender, inherits face from blazeface
|
||||||
const ssrdata = (config.face.age.enabled || config.face.gender.enabled) ? await ssrnet.predict(face.image, config) : {};
|
const ssrdata = (config.face.age.enabled || config.face.gender.enabled) ? await ssrnet.predict(face.image, config) : {};
|
||||||
face.image.dispose();
|
face.image.dispose();
|
||||||
// iris: array[ bottom, left, top, right, center ]
|
// iris: array[ bottom, left, top, right, center ]
|
||||||
const iris = (face.annotations.leftEyeIris && face.annotations.rightEyeIris)
|
const iris = (face.annotations.leftEyeIris && face.annotations.rightEyeIris)
|
||||||
? Math.max(face.annotations.leftEyeIris[3][0] - face.annotations.leftEyeIris[1][0], face.annotations.rightEyeIris[3][0] - face.annotations.rightEyeIris[1][0])
|
? Math.max(face.annotations.leftEyeIris[3][0] - face.annotations.leftEyeIris[1][0], face.annotations.rightEyeIris[3][0] - face.annotations.rightEyeIris[1][0])
|
||||||
: 0;
|
: 0;
|
||||||
faceRes.push({
|
faceRes.push({
|
||||||
confidence: face.confidence,
|
confidence: face.confidence,
|
||||||
box: face.box,
|
box: face.box,
|
||||||
mesh: face.mesh,
|
mesh: face.mesh,
|
||||||
annotations: face.annotations,
|
annotations: face.annotations,
|
||||||
age: ssrdata.age,
|
age: ssrdata.age,
|
||||||
gender: ssrdata.gender,
|
gender: ssrdata.gender,
|
||||||
iris: (iris !== 0) ? Math.trunc(100 * 11.7 / iris) / 100 : 0,
|
iris: (iris !== 0) ? Math.trunc(100 * 11.7 / iris) / 100 : 0,
|
||||||
});
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
tf.engine().endScope();
|
tf.engine().endScope();
|
||||||
|
// combine results
|
||||||
// combine results
|
resolve({ face: faceRes, body: poseRes, hand: handRes });
|
||||||
return { face: faceRes, body: poseRes, hand: handRes };
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.detect = detect;
|
exports.detect = detect;
|
||||||
|
|
Loading…
Reference in New Issue