@vladmandic/human
Version:
Human: AI-powered 3D Face Detection & Rotation Tracking, Face Description & Recognition, Body Pose Tracking, 3D Hand & Finger Tracking, Iris Analysis, Age & Gender & Emotion Prediction, Gesture Recognition
1,259 lines (1,181 loc) • 93.1 kB
TypeScript
/// <reference types="offscreencanvas" />
/** meta-function that performs draw for: canvas, face, body, hand */
declare function all(inCanvas: AnyCanvas, result: Result, drawOptions?: Partial<DrawOptions>): Promise<[void, void, void, void, void] | null>;
/** Defines all possible canvas types */
export declare type AnyCanvas = HTMLCanvasElement | OffscreenCanvas;
/** Defines all possible image types */
export declare type AnyImage = HTMLImageElement | typeof Image;
/** Defines all possible video types */
export declare type AnyVideo = HTMLMediaElement | HTMLVideoElement;
/** @docalias number[] */
declare interface ArrayMap {
R0: number;
R1: number[];
R2: number[][];
R3: number[][][];
R4: number[][][][];
R5: number[][][][][];
R6: number[][][][][][];
}
/** Possible TensorFlow backends */
export declare type BackendType = ['cpu', 'wasm', 'webgl', 'humangl', 'tensorflow', 'webgpu'];
/** draw detected bodies */
declare function body(inCanvas: AnyCanvas, result: Array<BodyResult>, drawOptions?: Partial<DrawOptions>): Promise<void>;
export declare type BodyAnnotation = BodyAnnotationBlazePose | BodyAnnotationEfficientPose;
export declare type BodyAnnotationBlazePose = 'leftLeg' | 'rightLeg' | 'torso' | 'leftArm' | 'rightArm' | 'leftEye' | 'rightEye' | 'mouth';
export declare type BodyAnnotationEfficientPose = 'leftLeg' | 'rightLeg' | 'torso' | 'leftArm' | 'rightArm' | 'head';
/** Configures all body detection specific options */
export declare interface BodyConfig extends GenericConfig {
/** maximum number of detected bodies */
maxDetected: number;
/** minimum confidence for a detected body before results are discarded */
minConfidence: number;
}
/** body gesture type */
export declare type BodyGesture = `leaning ${'left' | 'right'}` | `raise ${'left' | 'right'} hand` | 'i give up';
/** Body Result keypoints */
export declare interface BodyKeypoint {
/** body part name */
part: BodyLandmark;
/** body part position */
position: Point;
/** body part position normalized to 0..1 */
positionRaw: Point;
/** body part position relative to body center in meters */
distance?: Point;
/** body part detection score */
score: number;
}
export declare type BodyLandmark = BodyLandmarkPoseNet | BodyLandmarkMoveNet | BodyLandmarkEfficientNet | BodyLandmarkBlazePose;
export declare type BodyLandmarkBlazePose = 'nose' | 'leftEyeInside' | 'leftEye' | 'leftEyeOutside' | 'rightEyeInside' | 'rightEye' | 'rightEyeOutside' | 'leftEar' | 'rightEar' | 'leftMouth' | 'rightMouth' | 'leftShoulder' | 'rightShoulder' | 'leftElbow' | 'rightElbow' | 'leftWrist' | 'rightWrist' | 'leftPinky' | 'rightPinky' | 'leftIndex' | 'rightIndex' | 'leftThumb' | 'rightThumb' | 'leftHip' | 'rightHip' | 'leftKnee' | 'rightKnee' | 'leftAnkle' | 'rightAnkle' | 'leftHeel' | 'rightHeel' | 'leftFoot' | 'rightFoot' | 'bodyCenter' | 'bodyTop' | 'leftPalm' | 'leftHand' | 'rightPalm' | 'rightHand';
export declare type BodyLandmarkEfficientNet = 'head' | 'neck' | 'rightShoulder' | 'rightElbow' | 'rightWrist' | 'chest' | 'leftShoulder' | 'leftElbow' | 'leftWrist' | 'bodyCenter' | 'rightHip' | 'rightKnee' | 'rightAnkle' | 'leftHip' | 'leftKnee' | 'leftAnkle';
export declare type BodyLandmarkMoveNet = 'nose' | 'leftEye' | 'rightEye' | 'leftEar' | 'rightEar' | 'leftShoulder' | 'rightShoulder' | 'leftElbow' | 'rightElbow' | 'leftWrist' | 'rightWrist' | 'leftHip' | 'rightHip' | 'leftKnee' | 'rightKnee' | 'leftAnkle' | 'rightAnkle';
export declare type BodyLandmarkPoseNet = 'nose' | 'leftEye' | 'rightEye' | 'leftEar' | 'rightEar' | 'leftShoulder' | 'rightShoulder' | 'leftElbow' | 'rightElbow' | 'leftWrist' | 'rightWrist' | 'leftHip' | 'rightHip' | 'leftKnee' | 'rightKnee' | 'leftAnkle' | 'rightAnkle';
/** Body results */
export declare interface BodyResult {
/** body id */
id: number;
/** body detection score */
score: number;
/** detected body box */
box: Box;
/** detected body box normalized to 0..1 */
boxRaw: Box;
/** detected body keypoints */
keypoints: Array<BodyKeypoint>;
/** detected body keypoints combined into annotated parts */
annotations: Record<BodyAnnotation, Point[][]>;
}
/** generic box as [x, y, width, height] */
export declare type Box = [number, number, number, number];
/**
* Creates an IOHandler that loads model artifacts from user-selected files.
*
* This method can be used for loading from files such as user-selected files
* in the browser.
* When used in conjunction with `tf.loadLayersModel`, an instance of
* `tf.LayersModel` (Keras-style) can be constructed from the loaded artifacts.
*
* ```js
* // Note: This code snippet won't run properly without the actual file input
* // elements in the HTML DOM.
*
* // Suppose there are two HTML file input (`<input type="file" ...>`)
* // elements.
* const uploadJSONInput = document.getElementById('upload-json');
* const uploadWeightsInput = document.getElementById('upload-weights');
* const model = await tf.loadLayersModel(tf.io.browserFiles(
* [uploadJSONInput.files[0], uploadWeightsInput.files[0]]));
* ```
*
* @param files `File`s to load from. Currently, this function supports only
* loading from files that contain Keras-style models (i.e., `tf.Model`s), for
* which an `Array` of `File`s is expected (in that order):
* - A JSON file containing the model topology and weight manifest.
* - Optionally, One or more binary files containing the binary weights.
* These files must have names that match the paths in the `weightsManifest`
* contained by the aforementioned JSON file, or errors will be thrown
* during loading. These weights files have the same format as the ones
* generated by `tensorflowjs_converter` that comes with the `tensorflowjs`
* Python PIP package. If no weights files are provided, only the model
* topology will be loaded from the JSON file above.
* @returns An instance of `Files` `IOHandler`.
*
* @doc {
* heading: 'Models',
* subheading: 'Loading',
* namespace: 'io',
* ignoreCI: true
* }
*/
declare function browserFiles(files: File[]): IOHandler;
/**
* Deprecated. Use `tf.io.http`.
* @param path
* @param loadOptions
*/
declare function browserHTTPRequest(path: string, loadOptions?: LoadOptions): IOHandler;
/** draw processed canvas */
declare function canvas(input: AnyCanvas | HTMLImageElement | HTMLVideoElement, output: AnyCanvas): Promise<void>;
/**
* Concatenate a number of ArrayBuffers into one.
*
* @param buffers A number of array buffers to concatenate.
* @returns Result of concatenating `buffers` in order.
*/
declare function concatenateArrayBuffers(buffers: ArrayBuffer[]): ArrayBuffer;
/**
* Configuration interface definition for **Human** library
* Contains all configurable parameters
* Defaults: [config](https://github.com/vladmandic/human/blob/main/src/config.ts#L262)
*/
export declare interface Config {
/** Backend used for TFJS operations
* valid build-in backends are:
* - Browser: `cpu`, `wasm`, `webgl`, `humangl`, `webgpu`
* - NodeJS: `cpu`, `wasm`, `tensorflow`
* default: `humangl` for browser and `tensorflow` for nodejs
*/
backend: '' | 'cpu' | 'wasm' | 'webgl' | 'humangl' | 'tensorflow' | 'webgpu';
/** Path to *.wasm files if backend is set to `wasm`
*
* default: auto-detects to link to CDN `jsdelivr` when running in browser
*/
wasmPath: string;
/** Print debug statements to console
*
* default: `true`
*/
debug: boolean;
/** Perform model loading and inference concurrently or sequentially
*
* default: `true`
*/
async: boolean;
/** What to use for `human.warmup()`
* - warmup pre-initializes all models for faster inference but can take significant time on startup
* - used by `webgl`, `humangl` and `webgpu` backends
*
* default: `full`
*/
warmup: '' | 'none' | 'face' | 'full' | 'body';
/** Base model path (typically starting with file://, http:// or https://) for all models
* - individual modelPath values are relative to this path
*
* default: `../models/` for browsers and `file://models/` for nodejs
*/
modelBasePath: string;
/** Cache models in IndexDB on first sucessfull load
* default: true if indexdb is available (browsers), false if its not (nodejs)
*/
cacheModels: boolean;
/** Cache sensitivity
* - values 0..1 where 0.01 means reset cache if input changed more than 1%
* - set to 0 to disable caching
*
* default: 0.7
*/
cacheSensitivity: number;
/** Perform immediate garbage collection on deallocated tensors instead of caching them */
deallocate: boolean;
/** Internal Variable */
skipAllowed: boolean;
/** Filter config {@link FilterConfig} */
filter: Partial<FilterConfig>;
/** Gesture config {@link GestureConfig} */
gesture: Partial<GestureConfig>;
/** Face config {@link FaceConfig} */
face: Partial<FaceConfig>;
/** Body config {@link BodyConfig} */
body: Partial<BodyConfig>;
/** Hand config {@link HandConfig} */
hand: Partial<HandConfig>;
/** Object config {@link ObjectConfig} */
object: Partial<ObjectConfig>;
/** Segmentation config {@link SegmentationConfig} */
segmentation: Partial<SegmentationConfig>;
}
/**
* Copy a model from one URL to another.
*
* This function supports:
*
* 1. Copying within a storage medium, e.g.,
* `tf.io.copyModel('localstorage://model-1', 'localstorage://model-2')`
* 2. Copying between two storage mediums, e.g.,
* `tf.io.copyModel('localstorage://model-1', 'indexeddb://model-1')`
*
* ```js
* // First create and save a model.
* const model = tf.sequential();
* model.add(tf.layers.dense(
* {units: 1, inputShape: [10], activation: 'sigmoid'}));
* await model.save('localstorage://demo/management/model1');
*
* // Then list existing models.
* console.log(JSON.stringify(await tf.io.listModels()));
*
* // Copy the model, from Local Storage to IndexedDB.
* await tf.io.copyModel(
* 'localstorage://demo/management/model1',
* 'indexeddb://demo/management/model1');
*
* // List models again.
* console.log(JSON.stringify(await tf.io.listModels()));
*
* // Remove both models.
* await tf.io.removeModel('localstorage://demo/management/model1');
* await tf.io.removeModel('indexeddb://demo/management/model1');
* ```
*
* @param sourceURL Source URL of copying.
* @param destURL Destination URL of copying.
* @returns ModelArtifactsInfo of the copied model (if and only if copying
* is successful).
* @throws Error if copying fails, e.g., if no model exists at `sourceURL`, or
* if `oldPath` and `newPath` are identical.
*
* @doc {
* heading: 'Models',
* subheading: 'Management',
* namespace: 'io',
* ignoreCI: true
* }
*/
declare function copyModel(sourceURL: string, destURL: string): Promise<ModelArtifactsInfo>;
/**
* We wrap data id since we use weak map to avoid memory leaks.
* Since we have our own memory management, we have a reference counter
* mapping a tensor to its data, so there is always a pointer (even if that
* data is otherwise garbage collectable).
* See https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/
* Global_Objects/WeakMap
*/
declare type DataId = object;
declare type DataToGPUOptions = DataToGPUWebGLOption;
declare interface DataToGPUWebGLOption {
customTexShape?: [number, number];
}
/** @docalias 'float32'|'int32'|'bool'|'complex64'|'string' */
declare type DataType = keyof DataTypeMap;
declare interface DataTypeMap {
float32: Float32Array;
int32: Int32Array;
bool: Uint8Array;
complex64: Float32Array;
string: string[];
}
/**
* Decode flat ArrayBuffer as weights.
*
* This function does not handle sharding.
*
* This function is the reverse of `encodeWeights`.
*
* @param buffer A flat ArrayBuffer carrying the binary values of the tensors
* concatenated in the order specified in `specs`.
* @param specs Specifications of the names, dtypes and shapes of the tensors
* whose value are encoded by `buffer`.
* @return A map from tensor name to tensor value, with the names corresponding
* to names in `specs`.
* @throws Error, if any of the tensors has unsupported dtype.
*/
declare function decodeWeights(buffer: ArrayBuffer, specs: WeightsManifestEntry[]): NamedTensorMap;
/** - [See all default Config values...](https://github.com/vladmandic/human/blob/main/src/config.ts#L262) */
export declare const defaults: Config;
/** Face descriptor type as number array */
export declare type Descriptor = Array<number>;
/** Calculates distance between two descriptors
* @param options - calculation options
* - order - algorithm to use
* Euclidean distance if `order` is 2 (default), Minkowski distance algorithm of nth order if `order` is higher than 2
* - multiplier - by how much to enhance difference analysis in range of 1..100
* default is 20 which normalizes results to similarity above 0.5 can be considered a match
*/
declare function distance(descriptor1: Descriptor, descriptor2: Descriptor, options?: MatchOptions): number;
declare namespace draw {
export {
gesture,
face,
body,
hand,
object,
person,
canvas,
all,
DrawOptions,
options
}
}
/** Draw Options
* - Accessed via `human.draw.options` or provided per each draw method as the drawOptions optional parameter
*/
export declare type DrawOptions = {
/** draw line color */
color: string;
/** label color */
labelColor: string;
/** label shadow color */
shadowColor: string;
/** label font */
font: string;
/** line spacing between labels */
lineHeight: number;
/** line width for drawn lines */
lineWidth: number;
/** size of drawn points */
pointSize: number;
/** draw rounded boxes by n pixels */
roundRect: number;
/** should points be drawn? */
drawPoints: boolean;
/** should labels be drawn? */
drawLabels: boolean;
/** should detected gestures be drawn? */
drawGestures: boolean;
/** should draw boxes around detection results? */
drawBoxes: boolean;
/** should draw polygons from detection points? */
drawPolygons: boolean;
/** should draw gaze arrows? */
drawGaze: boolean;
/** should fill polygons? */
fillPolygons: boolean;
/** use z-coordinate when available */
useDepth: boolean;
/** should lines be curved? */
useCurves: boolean;
};
export declare type Emotion = 'angry' | 'disgust' | 'fear' | 'happy' | 'sad' | 'surprise' | 'neutral';
/**
* Encode a map from names to weight values as an ArrayBuffer, along with an
* `Array` of `WeightsManifestEntry` as specification of the encoded weights.
*
* This function does not perform sharding.
*
* This function is the reverse of `decodeWeights`.
*
* @param tensors A map ("dict") from names to tensors.
* @param group Group to which the weights belong (optional).
* @returns A `Promise` of
* - A flat `ArrayBuffer` with all the binary values of the `Tensor`s
* concatenated.
* - An `Array` of `WeightManifestEntry`s, carrying information including
* tensor names, `dtype`s and shapes.
* @throws Error: on unsupported tensor `dtype`.
*/
declare function encodeWeights(tensors: NamedTensorMap | NamedTensor[], group?: WeightGroup): Promise<{
data: ArrayBuffer;
specs: WeightsManifestEntry[];
}>;
/** Env class that holds detected capabilities */
export declare class Env {
/** Running in Browser */
browser: boolean;
/** Running in NodeJS */
node: boolean;
/** Running in WebWorker thread */
worker: boolean;
/** Detected platform */
platform: string;
/** Detected agent */
agent: string;
/** List of supported backends */
backends: string[];
/** Has any work been performed so far */
initial: boolean;
/** Are image filters supported? */
filter: boolean | undefined;
/** TFJS instance details */
tfjs: {
version: undefined | string;
};
/** Is offscreenCanvas supported? */
offscreen: undefined | boolean;
/** Are performance counter instant values or additive */
perfadd: boolean;
/** WASM detected capabilities */
wasm: {
supported: undefined | boolean;
backend: undefined | boolean;
simd: undefined | boolean;
multithread: undefined | boolean;
};
/** WebGL detected capabilities */
webgl: {
supported: undefined | boolean;
backend: undefined | boolean;
version: undefined | string;
renderer: undefined | string;
};
/** WebGPU detected capabilities */
webgpu: {
supported: undefined | boolean;
backend: undefined | boolean;
adapter: undefined | string;
};
/** CPU info */
cpu: {
model: undefined | string;
flags: string[];
};
/** List of supported kernels for current backend */
kernels: string[];
/** MonkeyPatch for Canvas */
Canvas: undefined;
/** MonkeyPatch for Image */
Image: undefined;
/** MonkeyPatch for ImageData */
ImageData: undefined;
constructor();
/** update backend information */
updateBackend(): Promise<void>;
/** update cpu information */
updateCPU(): Promise<void>;
}
export declare const env: Env;
/** Events dispatched by `human.events`
* - `create`: triggered when Human object is instantiated
* - `load`: triggered when models are loaded (explicitly or on-demand)
* - `image`: triggered when input image is processed
* - `result`: triggered when detection is complete
* - `warmup`: triggered when warmup is complete
*/
export declare type Events = 'create' | 'load' | 'image' | 'result' | 'warmup' | 'error';
/** Defines possible externally defined canvas */
export declare type ExternalCanvas = typeof env.Canvas;
/** draw detected faces */
declare function face(inCanvas: AnyCanvas, result: Array<FaceResult>, drawOptions?: Partial<DrawOptions>): Promise<void>;
/** Anti-spoofing part of face configuration */
export declare interface FaceAntiSpoofConfig extends GenericConfig {
}
/** Configures all face-specific options: face detection, mesh analysis, age, gender, emotion detection and face description */
export declare interface FaceConfig extends GenericConfig {
detector: Partial<FaceDetectorConfig>;
mesh: Partial<FaceMeshConfig>;
iris: Partial<FaceIrisConfig>;
description: Partial<FaceDescriptionConfig>;
emotion: Partial<FaceEmotionConfig>;
antispoof: Partial<FaceAntiSpoofConfig>;
liveness: Partial<FaceLivenessConfig>;
}
/** Description or face embedding part of face configuration
* - also used by age and gender detection
*/
export declare interface FaceDescriptionConfig extends GenericConfig {
/** minimum confidence for a detected face before results are discarded */
minConfidence: number;
}
/** Detector part of face configuration */
export declare interface FaceDetectorConfig extends GenericConfig {
/** is face rotation correction performed after detecting face?
* used to correctly analyze faces under high angles
*/
rotation: boolean;
/** maximum number of detected faces */
maxDetected: number;
/** minimum confidence for a detected face before results are discarded */
minConfidence: number;
/** minimum overlap between two detected faces before one is discarded */
iouThreshold: number;
/** should child models perform on masked image of a face */
mask: boolean;
/** should face detection return processed and cropped face tensor that can with an external model for addtional processing?
* if enabled it must be manually deallocated to avoid memory leak */
return: boolean;
}
/** Emotion part of face configuration */
export declare interface FaceEmotionConfig extends GenericConfig {
/** minimum confidence for a detected face before results are discarded */
minConfidence: number;
}
/** face gesture type */
export declare type FaceGesture = `facing ${'left' | 'center' | 'right'}` | `blink ${'left' | 'right'} eye` | `mouth ${number}% open` | `head ${'up' | 'down'}`;
/** Iris part of face configuration */
export declare interface FaceIrisConfig extends GenericConfig {
}
export declare type FaceLandmark = 'leftEye' | 'rightEye' | 'nose' | 'mouth' | 'leftEar' | 'rightEar' | 'symmetryLine' | 'silhouette' | 'lipsUpperOuter' | 'lipsLowerOuter' | 'lipsUpperInner' | 'lipsLowerInner' | 'rightEyeUpper0' | 'rightEyeLower0' | 'rightEyeUpper1' | 'rightEyeLower1' | 'rightEyeUpper2' | 'rightEyeLower2' | 'rightEyeLower3' | 'rightEyebrowUpper' | 'rightEyebrowLower' | 'rightEyeIris' | 'leftEyeUpper0' | 'leftEyeLower0' | 'leftEyeUpper1' | 'leftEyeLower1' | 'leftEyeUpper2' | 'leftEyeLower2' | 'leftEyeLower3' | 'leftEyebrowUpper' | 'leftEyebrowLower' | 'leftEyeIris' | 'midwayBetweenEyes' | 'noseTip' | 'noseBottom' | 'noseRightCorner' | 'noseLeftCorner' | 'rightCheek' | 'leftCheek';
/** Liveness part of face configuration */
export declare interface FaceLivenessConfig extends GenericConfig {
}
/** Mesh part of face configuration */
export declare interface FaceMeshConfig extends GenericConfig {
}
/** Face results
* - Combined results of face detector, face mesh, age, gender, emotion, embedding, iris models
* - Some values may be null if specific model is not enabled
*/
export declare interface FaceResult {
/** face id */
id: number;
/** overall face score */
score: number;
/** detection score */
boxScore: number;
/** mesh score */
faceScore: number;
/** detected face box */
box: Box;
/** detected face box normalized to 0..1 */
boxRaw: Box;
/** detected face mesh */
mesh: Array<Point>;
/** detected face mesh normalized to 0..1 */
meshRaw: Array<Point>;
/** mesh keypoints combined into annotated results */
annotations: Record<FaceLandmark, Point[]>;
/** detected age */
age?: number;
/** detected gender */
gender?: Gender;
/** gender detection score */
genderScore?: number;
/** detected emotions */
emotion?: Array<{
score: number;
emotion: Emotion;
}>;
/** detected race */
race?: Array<{
score: number;
race: Race;
}>;
/** face descriptor */
embedding?: Array<number>;
/** face iris distance from camera */
iris?: number;
/** face anti-spoofing result confidence */
real?: number;
/** face liveness result confidence */
live?: number;
/** face rotation details */
rotation?: {
angle: {
roll: number;
yaw: number;
pitch: number;
};
matrix: [number, number, number, number, number, number, number, number, number];
gaze: {
bearing: number;
strength: number;
};
} | null;
/** detected face as tensor that can be used in further pipelines */
tensor?: Tensor;
}
/** Run input through image filters before inference
* - available only in Browser environments
* - image filters run with near-zero latency as they are executed on the GPU using WebGL
*/
export declare interface FilterConfig {
/** are image filters enabled? */
enabled: boolean;
/** perform image histogram equalization
* - equalization is performed on input as a whole and detected face before its passed for further analysis
*/
equalization: boolean;
/** resize input width
* - if both width and height are set to 0, there is no resizing
* - if just one is set, second one is scaled automatically
* - if both are set, values are used as-is
*/
width: number;
/** resize input height
* - if both width and height are set to 0, there is no resizing
* - if just one is set, second one is scaled automatically
* - if both are set, values are used as-is
*/
height: number;
/** return processed canvas imagedata in result */
return: boolean;
/** flip input as mirror image */
flip: boolean;
/** range: -1 (darken) to 1 (lighten) */
brightness: number;
/** range: -1 (reduce contrast) to 1 (increase contrast) */
contrast: number;
/** range: 0 (no sharpening) to 1 (maximum sharpening) */
sharpness: number;
/** range: 0 (no blur) to N (blur radius in pixels) */
blur: number;
/** range: -1 (reduce saturation) to 1 (increase saturation) */
saturation: number;
/** range: 0 (no change) to 360 (hue rotation in degrees) */
hue: number;
/** image negative */
negative: boolean;
/** image sepia colors */
sepia: boolean;
/** image vintage colors */
vintage: boolean;
/** image kodachrome colors */
kodachrome: boolean;
/** image technicolor colors */
technicolor: boolean;
/** image polaroid camera effect */
polaroid: boolean;
/** range: 0 (no pixelate) to N (number of pixels to pixelate) */
pixelate: number;
}
export declare type Finger = 'index' | 'middle' | 'pinky' | 'ring' | 'thumb' | 'palm';
export declare type FingerCurl = 'none' | 'half' | 'full';
export declare type FingerDirection = 'verticalUp' | 'verticalDown' | 'horizontalLeft' | 'horizontalRight' | 'diagonalUpRight' | 'diagonalUpLeft' | 'diagonalDownRight' | 'diagonalDownLeft';
/**
* Creates an IOHandler that loads model artifacts from memory.
*
* When used in conjunction with `tf.loadLayersModel`, an instance of
* `tf.LayersModel` (Keras-style) can be constructed from the loaded artifacts.
*
* ```js
* const model = await tf.loadLayersModel(tf.io.fromMemory(
* modelTopology, weightSpecs, weightData));
* ```
*
* @param modelArtifacts a object containing model topology (i.e., parsed from
* the JSON format).
* @param weightSpecs An array of `WeightsManifestEntry` objects describing the
* names, shapes, types, and quantization of the weight data.
* @param weightData A single `ArrayBuffer` containing the weight data,
* concatenated in the order described by the weightSpecs.
* @param trainingConfig Model training configuration. Optional.
*
* @returns A passthrough `IOHandler` that simply loads the provided data.
*/
declare function fromMemory(modelArtifacts: {} | ModelArtifacts, weightSpecs?: WeightsManifestEntry[], weightData?: ArrayBuffer, trainingConfig?: TrainingConfig): IOHandler;
export declare type Gender = 'male' | 'female' | 'unknown';
/** Generic config type inherited by all module types */
export declare interface GenericConfig {
/** is module enabled? */
enabled: boolean;
/** path to model json file (relative to `modelBasePath` */
modelPath: string;
/** how many max frames to go without re-running model if cached results are acceptable
* for two-phase models such as face and hand caching applies to bounding boxes detection only */
skipFrames: number;
/** how many max milliseconds to go without re-running model if cached results are acceptable
* for two-phase models such as face and hand caching applies to bounding boxes detection only */
skipTime: number;
}
/** draw detected gestures */
declare function gesture(inCanvas: AnyCanvas, result: Array<GestureResult>, drawOptions?: Partial<DrawOptions>): Promise<void>;
/** Controlls gesture detection */
export declare interface GestureConfig {
/** is gesture detection enabled? */
enabled: boolean;
}
/** Gesture combined results
* Each result has:
* - part: part name and number where gesture was detected: `face`, `iris`, `body`, `hand`
* - gesture: gesture detected
*/
export declare type GestureResult = {
'face': number;
gesture: FaceGesture;
} | {
'iris': number;
gesture: IrisGesture;
} | {
'body': number;
gesture: BodyGesture;
} | {
'hand': number;
gesture: HandGesture;
};
declare const getLoadHandlers: (url: string | string[], loadOptions?: LoadOptions) => IOHandler[];
/**
* Create `ModelArtifacts` from a JSON file.
*
* @param modelJSON Object containing the parsed JSON of `model.json`
* @param loadWeights Function that takes the JSON file's weights manifest,
* reads weights from the listed path(s), and returns a Promise of the
* weight manifest entries along with the weights data.
* @returns A Promise of the `ModelArtifacts`, as described by the JSON file.
*/
declare function getModelArtifactsForJSON(modelJSON: ModelJSON, loadWeights: (weightsManifest: WeightsManifestConfig) => Promise<[WeightsManifestEntry[], /* weightData */ ArrayBuffer]>): Promise<ModelArtifacts>;
/**
* Populate ModelArtifactsInfo fields for a model with JSON topology.
* @param modelArtifacts
* @returns A ModelArtifactsInfo object.
*/
declare function getModelArtifactsInfoForJSON(modelArtifacts: ModelArtifacts): ModelArtifactsInfo;
declare const getSaveHandlers: (url: string | string[]) => IOHandler[];
declare interface GPUData {
tensorRef: Tensor;
texture?: WebGLTexture;
texShape?: [number, number];
}
/**
* A `tf.GraphModel` is a directed, acyclic graph built from a
* SavedModel GraphDef and allows inference execution.
*
* A `tf.GraphModel` can only be created by loading from a model converted from
* a [TensorFlow SavedModel](https://www.tensorflow.org/guide/saved_model) using
* the command line converter tool and loaded via `tf.loadGraphModel`.
*
* @doc {heading: 'Models', subheading: 'Classes'}
*/
export declare class GraphModel implements InferenceModel {
private modelUrl;
private loadOptions;
private executor;
private version;
private handler;
private artifacts;
private initializer;
private resourceManager;
private signature;
readonly modelVersion: string;
readonly inputNodes: string[];
readonly outputNodes: string[];
readonly inputs: TensorInfo[];
readonly outputs: TensorInfo[];
readonly weights: NamedTensorsMap;
readonly metadata: {};
readonly modelSignature: {};
/**
* @param modelUrl url for the model, or an `io.IOHandler`.
* @param weightManifestUrl url for the weight file generated by
* scripts/convert.py script.
* @param requestOption options for Request, which allows to send credentials
* and custom headers.
* @param onProgress Optional, progress callback function, fired periodically
* before the load is completed.
*/
constructor(modelUrl: string | io.IOHandler, loadOptions?: io.LoadOptions);
private findIOHandler;
/**
* Loads the model and weight files, construct the in memory weight map and
* compile the inference graph.
*/
load(): Promise<boolean>;
/**
* Synchronously construct the in memory weight map and
* compile the inference graph. Also initialize hashtable if any.
*
* @doc {heading: 'Models', subheading: 'Classes', ignoreCI: true}
*/
loadSync(artifacts: io.ModelArtifacts): boolean;
/**
* Save the configuration and/or weights of the GraphModel.
*
* An `IOHandler` is an object that has a `save` method of the proper
* signature defined. The `save` method manages the storing or
* transmission of serialized data ("artifacts") that represent the
* model's topology and weights onto or via a specific medium, such as
* file downloads, local storage, IndexedDB in the web browser and HTTP
* requests to a server. TensorFlow.js provides `IOHandler`
* implementations for a number of frequently used saving mediums, such as
* `tf.io.browserDownloads` and `tf.io.browserLocalStorage`. See `tf.io`
* for more details.
*
* This method also allows you to refer to certain types of `IOHandler`s
* as URL-like string shortcuts, such as 'localstorage://' and
* 'indexeddb://'.
*
* Example 1: Save `model`'s topology and weights to browser [local
* storage](https://developer.mozilla.org/en-US/docs/Web/API/Window/localStorage);
* then load it back.
*
* ```js
* const modelUrl =
* 'https://storage.googleapis.com/tfjs-models/savedmodel/mobilenet_v2_1.0_224/model.json';
* const model = await tf.loadGraphModel(modelUrl);
* const zeros = tf.zeros([1, 224, 224, 3]);
* model.predict(zeros).print();
*
* const saveResults = await model.save('localstorage://my-model-1');
*
* const loadedModel = await tf.loadGraphModel('localstorage://my-model-1');
* console.log('Prediction from loaded model:');
* model.predict(zeros).print();
* ```
*
* @param handlerOrURL An instance of `IOHandler` or a URL-like,
* scheme-based string shortcut for `IOHandler`.
* @param config Options for saving the model.
* @returns A `Promise` of `SaveResult`, which summarizes the result of
* the saving, such as byte sizes of the saved artifacts for the model's
* topology and weight values.
*
* @doc {heading: 'Models', subheading: 'Classes', ignoreCI: true}
*/
save(handlerOrURL: io.IOHandler | string, config?: io.SaveConfig): Promise<io.SaveResult>;
/**
* Execute the inference for the input tensors.
*
* @param input The input tensors, when there is single input for the model,
* inputs param should be a `tf.Tensor`. For models with mutliple inputs,
* inputs params should be in either `tf.Tensor`[] if the input order is
* fixed, or otherwise NamedTensorMap format.
*
* For model with multiple inputs, we recommend you use NamedTensorMap as the
* input type, if you use `tf.Tensor`[], the order of the array needs to
* follow the
* order of inputNodes array. @see {@link GraphModel.inputNodes}
*
* You can also feed any intermediate nodes using the NamedTensorMap as the
* input type. For example, given the graph
* InputNode => Intermediate => OutputNode,
* you can execute the subgraph Intermediate => OutputNode by calling
* model.execute('IntermediateNode' : tf.tensor(...));
*
* This is useful for models that uses tf.dynamic_rnn, where the intermediate
* state needs to be fed manually.
*
* For batch inference execution, the tensors for each input need to be
* concatenated together. For example with mobilenet, the required input shape
* is [1, 244, 244, 3], which represents the [batch, height, width, channel].
* If we are provide a batched data of 100 images, the input tensor should be
* in the shape of [100, 244, 244, 3].
*
* @param config Prediction configuration for specifying the batch size and
* output node names. Currently the batch size option is ignored for graph
* model.
*
* @returns Inference result tensors. The output would be single `tf.Tensor`
* if model has single output node, otherwise Tensor[] or NamedTensorMap[]
* will be returned for model with multiple outputs.
*
* @doc {heading: 'Models', subheading: 'Classes'}
*/
predict(inputs: Tensor | Tensor[] | NamedTensorMap, config?: ModelPredictConfig): Tensor | Tensor[] | NamedTensorMap;
private normalizeInputs;
private normalizeOutputs;
/**
* Executes inference for the model for given input tensors.
* @param inputs tensor, tensor array or tensor map of the inputs for the
* model, keyed by the input node names.
* @param outputs output node name from the Tensorflow model, if no
* outputs are specified, the default outputs of the model would be used.
* You can inspect intermediate nodes of the model by adding them to the
* outputs array.
*
* @returns A single tensor if provided with a single output or no outputs
* are provided and there is only one default output, otherwise return a
* tensor array. The order of the tensor array is the same as the outputs
* if provided, otherwise the order of outputNodes attribute of the model.
*
* @doc {heading: 'Models', subheading: 'Classes'}
*/
execute(inputs: Tensor | Tensor[] | NamedTensorMap, outputs?: string | string[]): Tensor | Tensor[];
/**
* Executes inference for the model for given input tensors in async
* fashion, use this method when your model contains control flow ops.
* @param inputs tensor, tensor array or tensor map of the inputs for the
* model, keyed by the input node names.
* @param outputs output node name from the Tensorflow model, if no outputs
* are specified, the default outputs of the model would be used. You can
* inspect intermediate nodes of the model by adding them to the outputs
* array.
*
* @returns A Promise of single tensor if provided with a single output or
* no outputs are provided and there is only one default output, otherwise
* return a tensor map.
*
* @doc {heading: 'Models', subheading: 'Classes'}
*/
executeAsync(inputs: Tensor | Tensor[] | NamedTensorMap, outputs?: string | string[]): Promise<Tensor | Tensor[]>;
/**
* Get intermediate tensors for model debugging mode (flag
* KEEP_INTERMEDIATE_TENSORS is true).
*
* @doc {heading: 'Models', subheading: 'Classes'}
*/
getIntermediateTensors(): NamedTensorsMap;
/**
* Dispose intermediate tensors for model debugging mode (flag
* KEEP_INTERMEDIATE_TENSORS is true).
*
* @doc {heading: 'Models', subheading: 'Classes'}
*/
disposeIntermediateTensors(): void;
private convertTensorMapToTensorsMap;
/**
* Releases the memory used by the weight tensors and resourceManager.
*
* @doc {heading: 'Models', subheading: 'Classes'}
*/
dispose(): void;
}
/** draw detected hands */
declare function hand(inCanvas: AnyCanvas, result: Array<HandResult>, drawOptions?: Partial<DrawOptions>): Promise<void>;
/** Configures all hand detection specific options */
export declare interface HandConfig extends GenericConfig {
/** should hand rotation correction be performed after hand detection? */
rotation: boolean;
/** minimum confidence for a detected hand before results are discarded */
minConfidence: number;
/** minimum overlap between two detected hands before one is discarded */
iouThreshold: number;
/** maximum number of detected hands */
maxDetected: number;
/** should hand landmarks be detected or just return detected hand box */
landmarks: boolean;
detector: {
/** path to hand detector model json */
modelPath?: string;
};
skeleton: {
/** path to hand skeleton model json */
modelPath?: string;
};
}
/** hand gesture type */
export declare type HandGesture = `${'thumb' | 'index' | 'middle' | 'ring' | 'pinky'} forward` | `${'thumb' | 'index' | 'middle' | 'ring' | 'pinky'} up` | 'victory' | 'thumbs up';
/** Hand results */
export declare interface HandResult {
/** hand id */
id: number;
/** hand overal score */
score: number;
/** hand detection score */
boxScore: number;
/** hand skelton score */
fingerScore: number;
/** detected hand box */
box: Box;
/** detected hand box normalized to 0..1 */
boxRaw: Box;
/** detected hand keypoints */
keypoints: Array<Point>;
/** detected hand class */
label: HandType;
/** detected hand keypoints combined into annotated parts */
annotations: Record<Finger, Array<Point>>;
/** detected hand parts annotated with part gestures */
landmarks: Record<Finger, {
curl: FingerCurl;
direction: FingerDirection;
}>;
}
export declare type HandType = 'hand' | 'fist' | 'pinch' | 'point' | 'face' | 'tip' | 'pinchtip';
/**
* Creates an IOHandler subtype that sends model artifacts to HTTP server.
*
* An HTTP request of the `multipart/form-data` mime type will be sent to the
* `path` URL. The form data includes artifacts that represent the topology
* and/or weights of the model. In the case of Keras-style `tf.Model`, two
* blobs (files) exist in form-data:
* - A JSON file consisting of `modelTopology` and `weightsManifest`.
* - A binary weights file consisting of the concatenated weight values.
* These files are in the same format as the one generated by
* [tfjs_converter](https://js.tensorflow.org/tutorials/import-keras.html).
*
* The following code snippet exemplifies the client-side code that uses this
* function:
*
* ```js
* const model = tf.sequential();
* model.add(
* tf.layers.dense({units: 1, inputShape: [100], activation: 'sigmoid'}));
*
* const saveResult = await model.save(tf.io.http(
* 'http://model-server:5000/upload', {requestInit: {method: 'PUT'}}));
* console.log(saveResult);
* ```
*
* If the default `POST` method is to be used, without any custom parameters
* such as headers, you can simply pass an HTTP or HTTPS URL to `model.save`:
*
* ```js
* const saveResult = await model.save('http://model-server:5000/upload');
* ```
*
* The following GitHub Gist
* https://gist.github.com/dsmilkov/1b6046fd6132d7408d5257b0976f7864
* implements a server based on [flask](https://github.com/pallets/flask) that
* can receive the request. Upon receiving the model artifacts via the requst,
* this particular server reconsistutes instances of [Keras
* Models](https://keras.io/models/model/) in memory.
*
*
* @param path A URL path to the model.
* Can be an absolute HTTP path (e.g.,
* 'http://localhost:8000/model-upload)') or a relative path (e.g.,
* './model-upload').
* @param requestInit Request configurations to be used when sending
* HTTP request to server using `fetch`. It can contain fields such as
* `method`, `credentials`, `headers`, `mode`, etc. See
* https://developer.mozilla.org/en-US/docs/Web/API/Request/Request
* for more information. `requestInit` must not have a body, because the
* body will be set by TensorFlow.js. File blobs representing the model
* topology (filename: 'model.json') and the weights of the model (filename:
* 'model.weights.bin') will be appended to the body. If `requestInit` has a
* `body`, an Error will be thrown.
* @param loadOptions Optional configuration for the loading. It includes the
* following fields:
* - weightPathPrefix Optional, this specifies the path prefix for weight
* files, by default this is calculated from the path param.
* - fetchFunc Optional, custom `fetch` function. E.g., in Node.js,
* the `fetch` from node-fetch can be used here.
* - onProgress Optional, progress callback function, fired periodically
* before the load is completed.
* @returns An instance of `IOHandler`.
*
* @doc {
* heading: 'Models',
* subheading: 'Loading',
* namespace: 'io',
* ignoreCI: true
* }
*/
declare function http(path: string, loadOptions?: LoadOptions): IOHandler;
/** **Human** library main class
*
* All methods and properties are available only as members of Human class
*
* - Configuration object definition: {@link Config}
* - Results object definition: {@link Result}
* - Possible inputs: {@link Input}
*
* @param userConfig - {@link Config}
* @returns instance of {@link Human}
*/
declare class Human {
#private;
/** Current version of Human library in *semver* format */
version: string;
/** Current configuration
* - Defaults: [config](https://github.com/vladmandic/human/blob/main/src/config.ts#L262)
*/
config: Config;
/** Last known result of detect run
* - Can be accessed anytime after initial detection
*/
result: Result;
/** Current state of Human library
* - Can be polled to determine operations that are currently executed
* - Progresses through: 'config', 'check', 'backend', 'load', 'run:<model>', 'idle'
*/
state: string;
/** currenty processed image tensor and canvas */
process: {
tensor: Tensor | null;
canvas: AnyCanvas | null;
};
/** Instance of TensorFlow/JS used by Human
* - Can be embedded or externally provided
* [TFJS API]: {@link https://js.tensorflow.org/api/latest/}
*/
tf: any;
/** Object containing environment information used for diagnostics */
env: Env;
/** Draw helper classes that can draw detected objects on canvas using specified draw
* - canvas: draws input to canvas
* - options: are global settings for all draw operations, can be overriden for each draw method {@link DrawOptions}
* - face, body, hand, gesture, object, person: draws detected results as overlays on canvas
*/
draw: {
canvas: typeof draw.canvas;
face: typeof draw.face;
body: typeof draw.body;
hand: typeof draw.hand;
gesture: typeof draw.gesture;
object: typeof draw.object;
person: typeof draw.person;
all: typeof draw.all;
options: DrawOptions;
};
/** Currently loaded models
* @internal
* {@link Models}
*/
models: models.Models;
/** Container for events dispatched by Human
* Possible events:
* - `create`: triggered when Human object is instantiated
* - `load`: triggered when models are loaded (explicitly or on-demand)
* - `image`: triggered when input image is processed
* - `result`: triggered when detection is complete
* - `warmup`: triggered when warmup is complete
* - `error`: triggered on some errors
*/
events: EventTarget | undefined;
/** Reference face triangualtion array of 468 points, used for triangle references between points */
faceTriangulation: number[];
/** Refernce UV map of 468 values, used for 3D mapping of the face mesh */
faceUVMap: [number, number][];
/** Performance object that contains values for all recently performed operations */
performance: Record<string, number>;
/** WebGL debug info */
gl: Record<string, unknown>;
/** Constructor for **Human** library that is futher used for all operations
* @param userConfig - user configuration object {@link Config}
*/
constructor(userConfig?: Partial<Config>);
/** internal function to measure tensor leaks */
analyze: (...msg: string[]) => void;
/** Reset configuration to default values */
reset(): void;
/** Validate current configuration schema */
validate(userConfig?: Partial<Config>): {
reason: string;
where: string;
expected?: string;
}[];
/** Exports face matching methods {@link match#similarity} */
similarity: typeof match.similarity;
/** Exports face matching methods {@link match#distance} */
distance: typeof match.distance;
/** Exports face matching methods {@link match#match} */
match: typeof match.match;
/** Utility wrapper for performance.now() */
now(): number;
/** Process input as return canvas and tensor
*
* @param input - any input {@link Input}
* @param getTensor - should image processing also return tensor or just canvas
* Returns object with `tensor` and `canvas`
*/
image(input: Input, getTensor?: boolean): Promise<{
tensor: Tensor<Rank> | null;
canvas: AnyCanvas | null;
}>;
/** Segmentation method takes any input and returns processed canvas with body segmentation
* - Segmentation is not triggered as part of detect process
* @param input - {@link Input}
* @param background - {@link Input}
* - Optional parameter background is used to fill the background with specific input
* Returns:
* - `data` as raw data array with per-pixel segmentation values
* - `canvas` as canvas which is input image filtered with segementation data and optionally merged with background image. canvas alpha values are set to segmentation values for easy merging
* - `alpha` as grayscale canvas that represents segmentation alpha values
*/
segmentation(input: Input, background?: Input): Promise<{
data: number[] | Tensor;
canvas: AnyCanvas | null;
alpha: AnyCanvas | null;
}>;
/** Enhance method performs additional enhacements to face image previously detected for futher processing
*
* @param input - Tensor as provided in human.result.face[n].tensor
* @returns Tensor
*/
enhance(input: Tensor): Tensor | null;
/** Compare two input tensors for pixel simmilarity
* - use `human.image` to process any valid input and get a tensor that can be used for compare
* - when passing manually generated tensors:
* - both input tensors must be in format [1, height, width, 3]
* - if resolution of tensors does not match, second tensor will be resized to match resolution of the first tensor
* - return value is pixel similarity score normalized by input resolution and rgb channels
*/
compare(firstImageTensor: Tensor, secondImageTensor: Tensor): Promise<number>;
/** Explicit backend initialization
* - Normally done implicitly during initial load phase
* - Call to explictly register and initialize TFJS backend without any other operations
* - Use when changing backend during runtime
*/
init(): Promise<void>;
/** Load method preloads all configured models on-demand
* - Not explicitly required as any required model is load implicitly on it's first run
*
* @param userConfig - {@link Config}
*/
load(userConfig?: Partial<Config>): Promise<void>;
/** emit event */
emit: (event: string) => void;
/** Runs interpolation using last known result and returns smoothened result
* Interpolation is based on time since last known result so can be called independently
*
* @param result - {@link Result} op