rtmlib-ts 0.0.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.gitattributes +1 -0
- package/README.md +202 -0
- package/dist/core/base.d.ts +20 -0
- package/dist/core/base.d.ts.map +1 -0
- package/dist/core/base.js +40 -0
- package/dist/core/file.d.ts +11 -0
- package/dist/core/file.d.ts.map +1 -0
- package/dist/core/file.js +111 -0
- package/dist/core/modelCache.d.ts +35 -0
- package/dist/core/modelCache.d.ts.map +1 -0
- package/dist/core/modelCache.js +161 -0
- package/dist/core/posePostprocessing.d.ts +12 -0
- package/dist/core/posePostprocessing.d.ts.map +1 -0
- package/dist/core/posePostprocessing.js +76 -0
- package/dist/core/postprocessing.d.ts +10 -0
- package/dist/core/postprocessing.d.ts.map +1 -0
- package/dist/core/postprocessing.js +70 -0
- package/dist/core/preprocessing.d.ts +14 -0
- package/dist/core/preprocessing.d.ts.map +1 -0
- package/dist/core/preprocessing.js +79 -0
- package/dist/index.d.ts +27 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +31 -0
- package/dist/models/rtmpose.d.ts +25 -0
- package/dist/models/rtmpose.d.ts.map +1 -0
- package/dist/models/rtmpose.js +185 -0
- package/dist/models/rtmpose3d.d.ts +28 -0
- package/dist/models/rtmpose3d.d.ts.map +1 -0
- package/dist/models/rtmpose3d.js +184 -0
- package/dist/models/yolo12.d.ts +23 -0
- package/dist/models/yolo12.d.ts.map +1 -0
- package/dist/models/yolo12.js +165 -0
- package/dist/models/yolox.d.ts +18 -0
- package/dist/models/yolox.d.ts.map +1 -0
- package/dist/models/yolox.js +167 -0
- package/dist/solution/animalDetector.d.ts +229 -0
- package/dist/solution/animalDetector.d.ts.map +1 -0
- package/dist/solution/animalDetector.js +663 -0
- package/dist/solution/body.d.ts +16 -0
- package/dist/solution/body.d.ts.map +1 -0
- package/dist/solution/body.js +52 -0
- package/dist/solution/bodyWithFeet.d.ts +16 -0
- package/dist/solution/bodyWithFeet.d.ts.map +1 -0
- package/dist/solution/bodyWithFeet.js +52 -0
- package/dist/solution/customDetector.d.ts +137 -0
- package/dist/solution/customDetector.d.ts.map +1 -0
- package/dist/solution/customDetector.js +342 -0
- package/dist/solution/hand.d.ts +14 -0
- package/dist/solution/hand.d.ts.map +1 -0
- package/dist/solution/hand.js +20 -0
- package/dist/solution/index.d.ts +10 -0
- package/dist/solution/index.d.ts.map +1 -0
- package/dist/solution/index.js +9 -0
- package/dist/solution/objectDetector.d.ts +172 -0
- package/dist/solution/objectDetector.d.ts.map +1 -0
- package/dist/solution/objectDetector.js +606 -0
- package/dist/solution/pose3dDetector.d.ts +145 -0
- package/dist/solution/pose3dDetector.d.ts.map +1 -0
- package/dist/solution/pose3dDetector.js +611 -0
- package/dist/solution/poseDetector.d.ts +198 -0
- package/dist/solution/poseDetector.d.ts.map +1 -0
- package/dist/solution/poseDetector.js +622 -0
- package/dist/solution/poseTracker.d.ts +22 -0
- package/dist/solution/poseTracker.d.ts.map +1 -0
- package/dist/solution/poseTracker.js +106 -0
- package/dist/solution/wholebody.d.ts +19 -0
- package/dist/solution/wholebody.d.ts.map +1 -0
- package/dist/solution/wholebody.js +82 -0
- package/dist/solution/wholebody3d.d.ts +22 -0
- package/dist/solution/wholebody3d.d.ts.map +1 -0
- package/dist/solution/wholebody3d.js +75 -0
- package/dist/types/index.d.ts +52 -0
- package/dist/types/index.d.ts.map +1 -0
- package/dist/types/index.js +5 -0
- package/dist/visualization/draw.d.ts +57 -0
- package/dist/visualization/draw.d.ts.map +1 -0
- package/dist/visualization/draw.js +400 -0
- package/dist/visualization/skeleton/coco133.d.ts +350 -0
- package/dist/visualization/skeleton/coco133.d.ts.map +1 -0
- package/dist/visualization/skeleton/coco133.js +120 -0
- package/dist/visualization/skeleton/coco17.d.ts +180 -0
- package/dist/visualization/skeleton/coco17.d.ts.map +1 -0
- package/dist/visualization/skeleton/coco17.js +48 -0
- package/dist/visualization/skeleton/halpe26.d.ts +278 -0
- package/dist/visualization/skeleton/halpe26.d.ts.map +1 -0
- package/dist/visualization/skeleton/halpe26.js +70 -0
- package/dist/visualization/skeleton/hand21.d.ts +196 -0
- package/dist/visualization/skeleton/hand21.d.ts.map +1 -0
- package/dist/visualization/skeleton/hand21.js +51 -0
- package/dist/visualization/skeleton/index.d.ts +10 -0
- package/dist/visualization/skeleton/index.d.ts.map +1 -0
- package/dist/visualization/skeleton/index.js +9 -0
- package/dist/visualization/skeleton/openpose134.d.ts +357 -0
- package/dist/visualization/skeleton/openpose134.d.ts.map +1 -0
- package/dist/visualization/skeleton/openpose134.js +116 -0
- package/dist/visualization/skeleton/openpose18.d.ts +177 -0
- package/dist/visualization/skeleton/openpose18.d.ts.map +1 -0
- package/dist/visualization/skeleton/openpose18.js +47 -0
- package/docs/ANIMAL_DETECTOR.md +450 -0
- package/docs/CUSTOM_DETECTOR.md +568 -0
- package/docs/OBJECT_DETECTOR.md +373 -0
- package/docs/POSE3D_DETECTOR.md +458 -0
- package/docs/POSE_DETECTOR.md +442 -0
- package/examples/README.md +119 -0
- package/examples/index.html +746 -0
- package/package.json +51 -0
- package/playground/README.md +114 -0
- package/playground/app/favicon.ico +0 -0
- package/playground/app/globals.css +17 -0
- package/playground/app/layout.tsx +19 -0
- package/playground/app/page.tsx +1338 -0
- package/playground/eslint.config.mjs +18 -0
- package/playground/next.config.ts +34 -0
- package/playground/package-lock.json +6723 -0
- package/playground/package.json +27 -0
- package/playground/postcss.config.mjs +7 -0
- package/playground/tsconfig.json +34 -0
- package/src/core/base.ts +66 -0
- package/src/core/file.ts +141 -0
- package/src/core/modelCache.ts +189 -0
- package/src/core/posePostprocessing.ts +91 -0
- package/src/core/postprocessing.ts +93 -0
- package/src/core/preprocessing.ts +127 -0
- package/src/index.ts +69 -0
- package/src/models/rtmpose.ts +265 -0
- package/src/models/rtmpose3d.ts +289 -0
- package/src/models/yolo12.ts +220 -0
- package/src/models/yolox.ts +214 -0
- package/src/solution/animalDetector.ts +955 -0
- package/src/solution/body.ts +89 -0
- package/src/solution/bodyWithFeet.ts +89 -0
- package/src/solution/customDetector.ts +474 -0
- package/src/solution/hand.ts +52 -0
- package/src/solution/index.ts +10 -0
- package/src/solution/objectDetector.ts +816 -0
- package/src/solution/pose3dDetector.ts +890 -0
- package/src/solution/poseDetector.ts +892 -0
- package/src/solution/poseTracker.ts +172 -0
- package/src/solution/wholebody.ts +130 -0
- package/src/solution/wholebody3d.ts +125 -0
- package/src/types/index.ts +62 -0
- package/src/visualization/draw.ts +543 -0
- package/src/visualization/skeleton/coco133.ts +131 -0
- package/src/visualization/skeleton/coco17.ts +49 -0
- package/src/visualization/skeleton/halpe26.ts +71 -0
- package/src/visualization/skeleton/hand21.ts +52 -0
- package/src/visualization/skeleton/index.ts +10 -0
- package/src/visualization/skeleton/openpose134.ts +125 -0
- package/src/visualization/skeleton/openpose18.ts +48 -0
- package/tsconfig.json +32 -0
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Body solution - body pose estimation with 17 or 26 keypoints
|
|
3
|
+
*/
|
|
4
|
+
import { YOLOX } from '../models/yolox';
|
|
5
|
+
import { RTMPose } from '../models/rtmpose';
|
|
6
|
+
export class Body {
|
|
7
|
+
constructor(det = null, detInputSize = [640, 640], pose = null, poseInputSize = [288, 384], mode = 'balanced', toOpenpose = false, backend = 'onnxruntime', device = 'cpu') {
|
|
8
|
+
let finalDet = det;
|
|
9
|
+
let finalDetInputSize = detInputSize;
|
|
10
|
+
let finalPose = pose;
|
|
11
|
+
let finalPoseInputSize = poseInputSize;
|
|
12
|
+
if (det === null) {
|
|
13
|
+
finalDet = Body.MODE[mode].det;
|
|
14
|
+
finalDetInputSize = Body.MODE[mode].detInputSize;
|
|
15
|
+
}
|
|
16
|
+
if (pose === null) {
|
|
17
|
+
finalPose = Body.MODE[mode].pose;
|
|
18
|
+
finalPoseInputSize = Body.MODE[mode].poseInputSize;
|
|
19
|
+
}
|
|
20
|
+
this.detModel = new YOLOX(finalDet, finalDetInputSize, 0.45, 0.7, backend);
|
|
21
|
+
this.poseModel = new RTMPose(finalPose, finalPoseInputSize, toOpenpose, backend);
|
|
22
|
+
}
|
|
23
|
+
async init() {
|
|
24
|
+
await this.detModel.init();
|
|
25
|
+
await this.poseModel.init();
|
|
26
|
+
}
|
|
27
|
+
async call(image, imgWidth, imgHeight) {
|
|
28
|
+
const bboxes = await this.detModel.call(image, imgWidth, imgHeight);
|
|
29
|
+
const result = await this.poseModel.call(image, imgWidth, imgHeight, bboxes);
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
Body.MODE = {
|
|
34
|
+
performance: {
|
|
35
|
+
det: 'https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/onnx_sdk/yolox_l_8xb8-300e_humanart-ce1d7a62.zip',
|
|
36
|
+
detInputSize: [640, 640],
|
|
37
|
+
pose: 'https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/onnx_sdk/rtmpose-l_simcc-body7_pt-body7_420e-384x288-3f5a1437_20230504.zip',
|
|
38
|
+
poseInputSize: [288, 384],
|
|
39
|
+
},
|
|
40
|
+
lightweight: {
|
|
41
|
+
det: 'https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/onnx_sdk/yolox_nano_8xb8-300e_humanart-40f6f0d0.zip',
|
|
42
|
+
detInputSize: [416, 416],
|
|
43
|
+
pose: 'https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/onnx_sdk/rtmpose-t_simcc-body7_pt-body7_420e-256x192-026a1439_20230504.zip',
|
|
44
|
+
poseInputSize: [192, 256],
|
|
45
|
+
},
|
|
46
|
+
balanced: {
|
|
47
|
+
det: 'https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/onnx_sdk/yolox_m_8xb8-300e_humanart-c2c7a14a.zip',
|
|
48
|
+
detInputSize: [640, 640],
|
|
49
|
+
pose: 'https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/onnx_sdk/rtmpose-m_simcc-body7_pt-body7_420e-256x192-e48f03d0_20230504.zip',
|
|
50
|
+
poseInputSize: [192, 256],
|
|
51
|
+
},
|
|
52
|
+
};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BodyWithFeet solution - body pose estimation with 26 keypoints (including feet)
|
|
3
|
+
*/
|
|
4
|
+
import { ModeType } from '../types/index';
|
|
5
|
+
export declare class BodyWithFeet {
|
|
6
|
+
private detModel;
|
|
7
|
+
private poseModel;
|
|
8
|
+
private static readonly MODE;
|
|
9
|
+
constructor(det?: string | null, detInputSize?: [number, number], pose?: string | null, poseInputSize?: [number, number], mode?: ModeType, toOpenpose?: boolean, backend?: 'onnxruntime', device?: string);
|
|
10
|
+
init(): Promise<void>;
|
|
11
|
+
call(image: Uint8Array, imgWidth: number, imgHeight: number): Promise<{
|
|
12
|
+
keypoints: number[][];
|
|
13
|
+
scores: number[];
|
|
14
|
+
}>;
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=bodyWithFeet.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"bodyWithFeet.d.ts","sourceRoot":"","sources":["../../src/solution/bodyWithFeet.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH,OAAO,EAAE,QAAQ,EAAe,MAAM,gBAAgB,CAAC;AAEvD,qBAAa,YAAY;IACvB,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,SAAS,CAAU;IAE3B,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,IAAI,CAmB1B;gBAGA,GAAG,GAAE,MAAM,GAAG,IAAW,EACzB,YAAY,GAAE,CAAC,MAAM,EAAE,MAAM,CAAc,EAC3C,IAAI,GAAE,MAAM,GAAG,IAAW,EAC1B,aAAa,GAAE,CAAC,MAAM,EAAE,MAAM,CAAc,EAC5C,IAAI,GAAE,QAAqB,EAC3B,UAAU,GAAE,OAAe,EAC3B,OAAO,GAAE,aAA6B,EACtC,MAAM,GAAE,MAAc;IAiClB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAKrB,IAAI,CACR,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CAKxD"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* BodyWithFeet solution - body pose estimation with 26 keypoints (including feet)
|
|
3
|
+
*/
|
|
4
|
+
import { YOLOX } from '../models/yolox';
|
|
5
|
+
import { RTMPose } from '../models/rtmpose';
|
|
6
|
+
export class BodyWithFeet {
|
|
7
|
+
constructor(det = null, detInputSize = [640, 640], pose = null, poseInputSize = [288, 384], mode = 'balanced', toOpenpose = false, backend = 'onnxruntime', device = 'cpu') {
|
|
8
|
+
let finalDet = det;
|
|
9
|
+
let finalDetInputSize = detInputSize;
|
|
10
|
+
let finalPose = pose;
|
|
11
|
+
let finalPoseInputSize = poseInputSize;
|
|
12
|
+
if (det === null) {
|
|
13
|
+
finalDet = BodyWithFeet.MODE[mode].det;
|
|
14
|
+
finalDetInputSize = BodyWithFeet.MODE[mode].detInputSize;
|
|
15
|
+
}
|
|
16
|
+
if (pose === null) {
|
|
17
|
+
finalPose = BodyWithFeet.MODE[mode].pose;
|
|
18
|
+
finalPoseInputSize = BodyWithFeet.MODE[mode].poseInputSize;
|
|
19
|
+
}
|
|
20
|
+
this.detModel = new YOLOX(finalDet, finalDetInputSize, 0.45, 0.7, backend);
|
|
21
|
+
this.poseModel = new RTMPose(finalPose, finalPoseInputSize, toOpenpose, backend);
|
|
22
|
+
}
|
|
23
|
+
async init() {
|
|
24
|
+
await this.detModel.init();
|
|
25
|
+
await this.poseModel.init();
|
|
26
|
+
}
|
|
27
|
+
async call(image, imgWidth, imgHeight) {
|
|
28
|
+
const bboxes = await this.detModel.call(image, imgWidth, imgHeight);
|
|
29
|
+
const result = await this.poseModel.call(image, imgWidth, imgHeight, bboxes);
|
|
30
|
+
return result;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
BodyWithFeet.MODE = {
|
|
34
|
+
performance: {
|
|
35
|
+
det: 'https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/onnx_sdk/yolox_l_8xb8-300e_humanart-ce1d7a62.zip',
|
|
36
|
+
detInputSize: [640, 640],
|
|
37
|
+
pose: 'https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/onnx_sdk/rtmpose-l_simcc-body7_pt-body7-halpe26_700e-384x288-734182ce_20230605.zip',
|
|
38
|
+
poseInputSize: [288, 384],
|
|
39
|
+
},
|
|
40
|
+
lightweight: {
|
|
41
|
+
det: 'https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/onnx_sdk/yolox_nano_8xb8-300e_humanart-40f6f0d0.zip',
|
|
42
|
+
detInputSize: [416, 416],
|
|
43
|
+
pose: 'https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/onnx_sdk/rtmpose-t_simcc-body7_pt-body7-halpe26_700e-256x192-6020f8a6_20230605.zip',
|
|
44
|
+
poseInputSize: [192, 256],
|
|
45
|
+
},
|
|
46
|
+
balanced: {
|
|
47
|
+
det: 'https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/onnx_sdk/yolox_m_8xb8-300e_humanart-c2c7a14a.zip',
|
|
48
|
+
detInputSize: [640, 640],
|
|
49
|
+
pose: 'https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/onnx_sdk/rtmpose-m_simcc-body7_pt-body7-halpe26_700e-256x192-4d3e73dd_20230605.zip',
|
|
50
|
+
poseInputSize: [192, 256],
|
|
51
|
+
},
|
|
52
|
+
};
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CustomDetector - Maximum flexibility detector for any ONNX model
|
|
3
|
+
* Provides low-level API for custom model inference
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* // Simple usage with auto-config
|
|
8
|
+
* const detector = new CustomDetector({
|
|
9
|
+
* model: 'path/to/model.onnx',
|
|
10
|
+
* });
|
|
11
|
+
* await detector.init();
|
|
12
|
+
* const results = await detector.run(imageData, width, height);
|
|
13
|
+
*
|
|
14
|
+
* // Advanced usage with custom preprocessing
|
|
15
|
+
* const detector = new CustomDetector({
|
|
16
|
+
* model: 'path/to/model.onnx',
|
|
17
|
+
* inputName: 'input',
|
|
18
|
+
* outputNames: ['output1', 'output2'],
|
|
19
|
+
* preprocessing: (data) => customPreprocess(data),
|
|
20
|
+
* postprocessing: (outputs) => customPostprocess(outputs),
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
import * as ort from 'onnxruntime-web';
|
|
25
|
+
/**
|
|
26
|
+
* Configuration options for CustomDetector
|
|
27
|
+
*/
|
|
28
|
+
export interface CustomDetectorConfig {
|
|
29
|
+
/** Path to ONNX model (required) */
|
|
30
|
+
model: string;
|
|
31
|
+
/** Input tensor name (optional - auto-detected if not specified) */
|
|
32
|
+
inputName?: string;
|
|
33
|
+
/** Output tensor names (optional - auto-detected if not specified) */
|
|
34
|
+
outputNames?: string[];
|
|
35
|
+
/** Expected input shape [batch, channels, height, width] (optional) */
|
|
36
|
+
inputShape?: [number, number, number, number];
|
|
37
|
+
/** Custom preprocessing function */
|
|
38
|
+
preprocessing?: (data: ImageData, config: CustomDetectorConfig) => Float32Array | ort.Tensor;
|
|
39
|
+
/** Custom postprocessing function */
|
|
40
|
+
postprocessing?: (outputs: Record<string, ort.Tensor>, metadata: any) => any;
|
|
41
|
+
/** Execution backend (default: 'wasm') */
|
|
42
|
+
backend?: 'wasm' | 'webgpu';
|
|
43
|
+
/** Enable model caching (default: true) */
|
|
44
|
+
cache?: boolean;
|
|
45
|
+
/** Custom metadata for postprocessing */
|
|
46
|
+
metadata?: any;
|
|
47
|
+
/** Input normalization (default: { mean: [0, 0, 0], std: [1, 1, 1] }) */
|
|
48
|
+
normalization?: {
|
|
49
|
+
mean: number[];
|
|
50
|
+
std: number[];
|
|
51
|
+
};
|
|
52
|
+
/** Input size for automatic preprocessing (optional) */
|
|
53
|
+
inputSize?: [number, number];
|
|
54
|
+
/** Keep aspect ratio during preprocessing (default: true) */
|
|
55
|
+
keepAspectRatio?: boolean;
|
|
56
|
+
/** Background color for letterbox (default: black) */
|
|
57
|
+
backgroundColor?: string;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Detection result with metadata
|
|
61
|
+
*/
|
|
62
|
+
export interface DetectionResult<T = any> {
|
|
63
|
+
/** Raw model outputs */
|
|
64
|
+
outputs: Record<string, ort.Tensor>;
|
|
65
|
+
/** Processed results */
|
|
66
|
+
data: T;
|
|
67
|
+
/** Inference time in ms */
|
|
68
|
+
inferenceTime: number;
|
|
69
|
+
/** Input shape used */
|
|
70
|
+
inputShape: number[];
|
|
71
|
+
}
|
|
72
|
+
export declare class CustomDetector {
|
|
73
|
+
private config;
|
|
74
|
+
private session;
|
|
75
|
+
private initialized;
|
|
76
|
+
private canvas;
|
|
77
|
+
private ctx;
|
|
78
|
+
constructor(config: CustomDetectorConfig);
|
|
79
|
+
/**
|
|
80
|
+
* Initialize the model
|
|
81
|
+
*/
|
|
82
|
+
init(): Promise<void>;
|
|
83
|
+
/**
|
|
84
|
+
* Run inference on canvas
|
|
85
|
+
*/
|
|
86
|
+
runFromCanvas<T = any>(canvas: HTMLCanvasElement): Promise<DetectionResult<T>>;
|
|
87
|
+
/**
|
|
88
|
+
* Run inference on video
|
|
89
|
+
*/
|
|
90
|
+
runFromVideo<T = any>(video: HTMLVideoElement, targetCanvas?: HTMLCanvasElement): Promise<DetectionResult<T>>;
|
|
91
|
+
/**
|
|
92
|
+
* Run inference on image
|
|
93
|
+
*/
|
|
94
|
+
runFromImage<T = any>(image: HTMLImageElement, targetCanvas?: HTMLCanvasElement): Promise<DetectionResult<T>>;
|
|
95
|
+
/**
|
|
96
|
+
* Run inference on bitmap
|
|
97
|
+
*/
|
|
98
|
+
runFromBitmap<T = any>(bitmap: ImageBitmap, targetCanvas?: HTMLCanvasElement): Promise<DetectionResult<T>>;
|
|
99
|
+
/**
|
|
100
|
+
* Run inference on file
|
|
101
|
+
*/
|
|
102
|
+
runFromFile<T = any>(file: File, targetCanvas?: HTMLCanvasElement): Promise<DetectionResult<T>>;
|
|
103
|
+
/**
|
|
104
|
+
* Run inference on blob
|
|
105
|
+
*/
|
|
106
|
+
runFromBlob<T = any>(blob: Blob, targetCanvas?: HTMLCanvasElement): Promise<DetectionResult<T>>;
|
|
107
|
+
/**
|
|
108
|
+
* Run inference with custom preprocessing
|
|
109
|
+
*/
|
|
110
|
+
run<T = any>(imageData: ImageData, width: number, height: number, metadata?: any): Promise<DetectionResult<T>>;
|
|
111
|
+
/**
|
|
112
|
+
* Get model info
|
|
113
|
+
*/
|
|
114
|
+
getModelInfo(): {
|
|
115
|
+
inputNames: string[];
|
|
116
|
+
outputNames: string[];
|
|
117
|
+
inputCount: number;
|
|
118
|
+
outputCount: number;
|
|
119
|
+
};
|
|
120
|
+
/**
|
|
121
|
+
* Get tensor by name from outputs
|
|
122
|
+
*/
|
|
123
|
+
getOutputTensor<T extends ort.Tensor = ort.Tensor>(outputs: Record<string, ort.Tensor>, name?: string): T;
|
|
124
|
+
/**
|
|
125
|
+
* Simple preprocessing - just normalize to [0, 1] and convert to CHW
|
|
126
|
+
*/
|
|
127
|
+
private simplePreprocess;
|
|
128
|
+
/**
|
|
129
|
+
* Preprocess with letterbox and normalization
|
|
130
|
+
*/
|
|
131
|
+
private preprocess;
|
|
132
|
+
/**
|
|
133
|
+
* Dispose resources
|
|
134
|
+
*/
|
|
135
|
+
dispose(): void;
|
|
136
|
+
}
|
|
137
|
+
//# sourceMappingURL=customDetector.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"customDetector.d.ts","sourceRoot":"","sources":["../../src/solution/customDetector.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,342 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* CustomDetector - Maximum flexibility detector for any ONNX model
|
|
3
|
+
* Provides low-level API for custom model inference
|
|
4
|
+
*
|
|
5
|
+
* @example
|
|
6
|
+
* ```typescript
|
|
7
|
+
* // Simple usage with auto-config
|
|
8
|
+
* const detector = new CustomDetector({
|
|
9
|
+
* model: 'path/to/model.onnx',
|
|
10
|
+
* });
|
|
11
|
+
* await detector.init();
|
|
12
|
+
* const results = await detector.run(imageData, width, height);
|
|
13
|
+
*
|
|
14
|
+
* // Advanced usage with custom preprocessing
|
|
15
|
+
* const detector = new CustomDetector({
|
|
16
|
+
* model: 'path/to/model.onnx',
|
|
17
|
+
* inputName: 'input',
|
|
18
|
+
* outputNames: ['output1', 'output2'],
|
|
19
|
+
* preprocessing: (data) => customPreprocess(data),
|
|
20
|
+
* postprocessing: (outputs) => customPostprocess(outputs),
|
|
21
|
+
* });
|
|
22
|
+
* ```
|
|
23
|
+
*/
|
|
24
|
+
import * as ort from 'onnxruntime-web';
|
|
25
|
+
import { getCachedModel, isModelCached } from '../core/modelCache';
|
|
26
|
+
// Configure ONNX Runtime Web
|
|
27
|
+
ort.env.wasm.wasmPaths = 'https://cdn.jsdelivr.net/npm/onnxruntime-web@1.23.0/dist/';
|
|
28
|
+
ort.env.wasm.simd = true;
|
|
29
|
+
ort.env.wasm.proxy = false;
|
|
30
|
+
/**
|
|
31
|
+
* Default configuration
|
|
32
|
+
*/
|
|
33
|
+
const DEFAULT_CONFIG = {
|
|
34
|
+
backend: 'webgpu', // Default to WebGPU for better performance
|
|
35
|
+
cache: true,
|
|
36
|
+
keepAspectRatio: true,
|
|
37
|
+
backgroundColor: '#000000',
|
|
38
|
+
normalization: {
|
|
39
|
+
mean: [0, 0, 0],
|
|
40
|
+
std: [1, 1, 1],
|
|
41
|
+
},
|
|
42
|
+
};
|
|
43
|
+
export class CustomDetector {
|
|
44
|
+
constructor(config) {
|
|
45
|
+
this.session = null;
|
|
46
|
+
this.initialized = false;
|
|
47
|
+
this.canvas = null;
|
|
48
|
+
this.ctx = null;
|
|
49
|
+
this.config = {
|
|
50
|
+
...DEFAULT_CONFIG,
|
|
51
|
+
...config,
|
|
52
|
+
outputNames: config.outputNames || [],
|
|
53
|
+
inputShape: config.inputShape || [1, 3, 224, 224],
|
|
54
|
+
normalization: config.normalization || { mean: [0, 0, 0], std: [1, 1, 1] },
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
/**
|
|
58
|
+
* Initialize the model
|
|
59
|
+
*/
|
|
60
|
+
async init() {
|
|
61
|
+
if (this.initialized)
|
|
62
|
+
return;
|
|
63
|
+
try {
|
|
64
|
+
console.log(`[CustomDetector] Loading model from: ${this.config.model}`);
|
|
65
|
+
let modelBuffer;
|
|
66
|
+
if (this.config.cache) {
|
|
67
|
+
const cached = await isModelCached(this.config.model);
|
|
68
|
+
console.log(`[CustomDetector] Cache ${cached ? 'hit' : 'miss'}`);
|
|
69
|
+
modelBuffer = await getCachedModel(this.config.model);
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
const response = await fetch(this.config.model);
|
|
73
|
+
if (!response.ok) {
|
|
74
|
+
throw new Error(`Failed to fetch model: HTTP ${response.status}`);
|
|
75
|
+
}
|
|
76
|
+
modelBuffer = await response.arrayBuffer();
|
|
77
|
+
}
|
|
78
|
+
this.session = await ort.InferenceSession.create(modelBuffer, {
|
|
79
|
+
executionProviders: [this.config.backend],
|
|
80
|
+
graphOptimizationLevel: 'all',
|
|
81
|
+
});
|
|
82
|
+
// Auto-detect input/output names if not specified
|
|
83
|
+
if (!this.config.inputName && this.session.inputNames.length > 0) {
|
|
84
|
+
console.log(`[CustomDetector] Auto-detected input name: ${this.session.inputNames[0]}`);
|
|
85
|
+
}
|
|
86
|
+
if (this.config.outputNames.length === 0 && this.session.outputNames.length > 0) {
|
|
87
|
+
this.config.outputNames = [...this.session.outputNames];
|
|
88
|
+
console.log(`[CustomDetector] Auto-detected output names: ${this.config.outputNames}`);
|
|
89
|
+
}
|
|
90
|
+
console.log(`[CustomDetector] ✅ Initialized (${this.config.backend})`);
|
|
91
|
+
this.initialized = true;
|
|
92
|
+
}
|
|
93
|
+
catch (error) {
|
|
94
|
+
console.error('[CustomDetector] ❌ Initialization failed:', error);
|
|
95
|
+
throw error;
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
/**
|
|
99
|
+
* Run inference on canvas
|
|
100
|
+
*/
|
|
101
|
+
async runFromCanvas(canvas) {
|
|
102
|
+
const ctx = canvas.getContext('2d');
|
|
103
|
+
if (!ctx) {
|
|
104
|
+
throw new Error('Could not get 2D context from canvas');
|
|
105
|
+
}
|
|
106
|
+
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
107
|
+
return this.run(imageData, canvas.width, canvas.height);
|
|
108
|
+
}
|
|
109
|
+
/**
|
|
110
|
+
* Run inference on video
|
|
111
|
+
*/
|
|
112
|
+
async runFromVideo(video, targetCanvas) {
|
|
113
|
+
if (video.readyState < 2) {
|
|
114
|
+
throw new Error('Video not ready');
|
|
115
|
+
}
|
|
116
|
+
const canvas = targetCanvas || document.createElement('canvas');
|
|
117
|
+
canvas.width = video.videoWidth;
|
|
118
|
+
canvas.height = video.videoHeight;
|
|
119
|
+
const ctx = canvas.getContext('2d');
|
|
120
|
+
if (!ctx) {
|
|
121
|
+
throw new Error('Could not get 2D context from canvas');
|
|
122
|
+
}
|
|
123
|
+
ctx.drawImage(video, 0, 0, canvas.width, canvas.height);
|
|
124
|
+
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
125
|
+
return this.run(imageData, canvas.width, canvas.height);
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Run inference on image
|
|
129
|
+
*/
|
|
130
|
+
async runFromImage(image, targetCanvas) {
|
|
131
|
+
if (!image.complete || !image.naturalWidth) {
|
|
132
|
+
throw new Error('Image not loaded');
|
|
133
|
+
}
|
|
134
|
+
const canvas = targetCanvas || document.createElement('canvas');
|
|
135
|
+
canvas.width = image.naturalWidth;
|
|
136
|
+
canvas.height = image.naturalHeight;
|
|
137
|
+
const ctx = canvas.getContext('2d');
|
|
138
|
+
if (!ctx) {
|
|
139
|
+
throw new Error('Could not get 2D context from canvas');
|
|
140
|
+
}
|
|
141
|
+
ctx.drawImage(image, 0, 0);
|
|
142
|
+
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
143
|
+
return this.run(imageData, canvas.width, canvas.height);
|
|
144
|
+
}
|
|
145
|
+
/**
|
|
146
|
+
* Run inference on bitmap
|
|
147
|
+
*/
|
|
148
|
+
async runFromBitmap(bitmap, targetCanvas) {
|
|
149
|
+
const canvas = targetCanvas || document.createElement('canvas');
|
|
150
|
+
canvas.width = bitmap.width;
|
|
151
|
+
canvas.height = bitmap.height;
|
|
152
|
+
const ctx = canvas.getContext('2d');
|
|
153
|
+
if (!ctx) {
|
|
154
|
+
throw new Error('Could not get 2D context from canvas');
|
|
155
|
+
}
|
|
156
|
+
ctx.drawImage(bitmap, 0, 0);
|
|
157
|
+
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
|
|
158
|
+
return this.run(imageData, canvas.width, canvas.height);
|
|
159
|
+
}
|
|
160
|
+
/**
|
|
161
|
+
* Run inference on file
|
|
162
|
+
*/
|
|
163
|
+
async runFromFile(file, targetCanvas) {
|
|
164
|
+
return new Promise((resolve, reject) => {
|
|
165
|
+
const img = new Image();
|
|
166
|
+
img.onload = async () => {
|
|
167
|
+
try {
|
|
168
|
+
const result = await this.runFromImage(img, targetCanvas);
|
|
169
|
+
resolve(result);
|
|
170
|
+
}
|
|
171
|
+
catch (error) {
|
|
172
|
+
reject(error);
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
img.onerror = () => reject(new Error('Failed to load image'));
|
|
176
|
+
img.src = URL.createObjectURL(file);
|
|
177
|
+
});
|
|
178
|
+
}
|
|
179
|
+
/**
|
|
180
|
+
* Run inference on blob
|
|
181
|
+
*/
|
|
182
|
+
async runFromBlob(blob, targetCanvas) {
|
|
183
|
+
const bitmap = await createImageBitmap(blob);
|
|
184
|
+
const result = await this.runFromBitmap(bitmap, targetCanvas);
|
|
185
|
+
bitmap.close();
|
|
186
|
+
return result;
|
|
187
|
+
}
|
|
188
|
+
/**
|
|
189
|
+
* Run inference with custom preprocessing
|
|
190
|
+
*/
|
|
191
|
+
async run(imageData, width, height, metadata) {
|
|
192
|
+
if (!this.initialized) {
|
|
193
|
+
await this.init();
|
|
194
|
+
}
|
|
195
|
+
const startTime = performance.now();
|
|
196
|
+
// Preprocess
|
|
197
|
+
let inputTensor;
|
|
198
|
+
if (this.config.preprocessing) {
|
|
199
|
+
// Custom preprocessing
|
|
200
|
+
const result = this.config.preprocessing(imageData, this.config);
|
|
201
|
+
if (result instanceof Float32Array) {
|
|
202
|
+
const [h, w] = this.config.inputSize || [height, width];
|
|
203
|
+
inputTensor = new ort.Tensor('float32', result, [1, 3, h, w]);
|
|
204
|
+
}
|
|
205
|
+
else {
|
|
206
|
+
inputTensor = result;
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
else if (this.config.inputSize) {
|
|
210
|
+
// Automatic preprocessing with letterbox
|
|
211
|
+
inputTensor = this.preprocess(imageData, width, height, this.config.inputSize);
|
|
212
|
+
}
|
|
213
|
+
else {
|
|
214
|
+
// Simple preprocessing - just normalize
|
|
215
|
+
inputTensor = this.simplePreprocess(imageData);
|
|
216
|
+
}
|
|
217
|
+
// Get input name
|
|
218
|
+
const inputName = this.config.inputName || this.session.inputNames[0];
|
|
219
|
+
// Run inference
|
|
220
|
+
const feeds = {};
|
|
221
|
+
feeds[inputName] = inputTensor;
|
|
222
|
+
const results = await this.session.run(feeds);
|
|
223
|
+
// Postprocess
|
|
224
|
+
let data;
|
|
225
|
+
if (this.config.postprocessing) {
|
|
226
|
+
data = this.config.postprocessing(results, metadata || this.config.metadata);
|
|
227
|
+
}
|
|
228
|
+
else {
|
|
229
|
+
// Return raw outputs
|
|
230
|
+
data = results;
|
|
231
|
+
}
|
|
232
|
+
const inferenceTime = performance.now() - startTime;
|
|
233
|
+
return {
|
|
234
|
+
outputs: results,
|
|
235
|
+
data,
|
|
236
|
+
inferenceTime,
|
|
237
|
+
inputShape: [...inputTensor.dims],
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
/**
|
|
241
|
+
* Get model info
|
|
242
|
+
*/
|
|
243
|
+
getModelInfo() {
|
|
244
|
+
if (!this.session) {
|
|
245
|
+
throw new Error('Model not initialized. Call init() first.');
|
|
246
|
+
}
|
|
247
|
+
return {
|
|
248
|
+
inputNames: [...this.session.inputNames],
|
|
249
|
+
outputNames: [...this.session.outputNames],
|
|
250
|
+
inputCount: this.session.inputNames.length,
|
|
251
|
+
outputCount: this.session.outputNames.length,
|
|
252
|
+
};
|
|
253
|
+
}
|
|
254
|
+
/**
|
|
255
|
+
* Get tensor by name from outputs
|
|
256
|
+
*/
|
|
257
|
+
getOutputTensor(outputs, name) {
|
|
258
|
+
const tensorName = name || this.config.outputNames[0] || this.session.outputNames[0];
|
|
259
|
+
return outputs[tensorName];
|
|
260
|
+
}
|
|
261
|
+
/**
|
|
262
|
+
* Simple preprocessing - just normalize to [0, 1] and convert to CHW
|
|
263
|
+
*/
|
|
264
|
+
simplePreprocess(imageData) {
|
|
265
|
+
const { width, height, data } = imageData;
|
|
266
|
+
const tensor = new Float32Array(3 * width * height);
|
|
267
|
+
for (let i = 0; i < data.length; i += 4) {
|
|
268
|
+
const pixelIdx = i / 4;
|
|
269
|
+
tensor[pixelIdx] = data[i] / 255;
|
|
270
|
+
tensor[pixelIdx + width * height] = data[i + 1] / 255;
|
|
271
|
+
tensor[pixelIdx + 2 * width * height] = data[i + 2] / 255;
|
|
272
|
+
}
|
|
273
|
+
return new ort.Tensor('float32', tensor, [1, 3, height, width]);
|
|
274
|
+
}
|
|
275
|
+
/**
|
|
276
|
+
* Preprocess with letterbox and normalization
|
|
277
|
+
*/
|
|
278
|
+
preprocess(imageData, imgWidth, imgHeight, inputSize) {
|
|
279
|
+
const [inputW, inputH] = inputSize;
|
|
280
|
+
if (!this.canvas || !this.ctx) {
|
|
281
|
+
this.canvas = document.createElement('canvas');
|
|
282
|
+
this.canvas.width = inputW;
|
|
283
|
+
this.canvas.height = inputH;
|
|
284
|
+
this.ctx = this.canvas.getContext('2d', { willReadFrequently: true, alpha: false });
|
|
285
|
+
}
|
|
286
|
+
const ctx = this.ctx;
|
|
287
|
+
ctx.fillStyle = this.config.backgroundColor;
|
|
288
|
+
ctx.fillRect(0, 0, inputW, inputH);
|
|
289
|
+
// Calculate letterbox
|
|
290
|
+
const aspectRatio = imgWidth / imgHeight;
|
|
291
|
+
const targetAspectRatio = inputW / inputH;
|
|
292
|
+
let drawWidth, drawHeight, offsetX, offsetY;
|
|
293
|
+
if (this.config.keepAspectRatio) {
|
|
294
|
+
if (aspectRatio > targetAspectRatio) {
|
|
295
|
+
drawWidth = inputW;
|
|
296
|
+
drawHeight = Math.floor(inputW / aspectRatio);
|
|
297
|
+
offsetX = 0;
|
|
298
|
+
offsetY = Math.floor((inputH - drawHeight) / 2);
|
|
299
|
+
}
|
|
300
|
+
else {
|
|
301
|
+
drawHeight = inputH;
|
|
302
|
+
drawWidth = Math.floor(inputH * aspectRatio);
|
|
303
|
+
offsetX = Math.floor((inputW - drawWidth) / 2);
|
|
304
|
+
offsetY = 0;
|
|
305
|
+
}
|
|
306
|
+
}
|
|
307
|
+
else {
|
|
308
|
+
drawWidth = inputW;
|
|
309
|
+
drawHeight = inputH;
|
|
310
|
+
offsetX = 0;
|
|
311
|
+
offsetY = 0;
|
|
312
|
+
}
|
|
313
|
+
// Create source canvas
|
|
314
|
+
const srcCanvas = document.createElement('canvas');
|
|
315
|
+
const srcCtx = srcCanvas.getContext('2d');
|
|
316
|
+
srcCanvas.width = imgWidth;
|
|
317
|
+
srcCanvas.height = imgHeight;
|
|
318
|
+
srcCtx.putImageData(imageData, 0, 0);
|
|
319
|
+
// Draw with letterbox
|
|
320
|
+
ctx.drawImage(srcCanvas, 0, 0, imgWidth, imgHeight, offsetX, offsetY, drawWidth, drawHeight);
|
|
321
|
+
const paddedData = ctx.getImageData(0, 0, inputW, inputH);
|
|
322
|
+
const tensor = new Float32Array(inputW * inputH * 3);
|
|
323
|
+
const { mean, std } = this.config.normalization;
|
|
324
|
+
for (let i = 0; i < paddedData.data.length; i += 4) {
|
|
325
|
+
const pixelIdx = i / 4;
|
|
326
|
+
tensor[pixelIdx] = (paddedData.data[i] - mean[0]) / std[0];
|
|
327
|
+
tensor[pixelIdx + inputW * inputH] = (paddedData.data[i + 1] - mean[1]) / std[1];
|
|
328
|
+
tensor[pixelIdx + 2 * inputW * inputH] = (paddedData.data[i + 2] - mean[2]) / std[2];
|
|
329
|
+
}
|
|
330
|
+
return new ort.Tensor('float32', tensor, [1, 3, inputH, inputW]);
|
|
331
|
+
}
|
|
332
|
+
/**
|
|
333
|
+
* Dispose resources
|
|
334
|
+
*/
|
|
335
|
+
dispose() {
|
|
336
|
+
if (this.session) {
|
|
337
|
+
this.session.release();
|
|
338
|
+
this.session = null;
|
|
339
|
+
}
|
|
340
|
+
this.initialized = false;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hand solution - hand pose estimation with 21 keypoints
|
|
3
|
+
*/
|
|
4
|
+
export declare class Hand {
|
|
5
|
+
private detModel;
|
|
6
|
+
private poseModel;
|
|
7
|
+
constructor(det?: string, detInputSize?: [number, number], pose?: string, poseInputSize?: [number, number], toOpenpose?: boolean, backend?: 'onnxruntime', device?: string);
|
|
8
|
+
init(): Promise<void>;
|
|
9
|
+
call(image: Uint8Array, imgWidth: number, imgHeight: number): Promise<{
|
|
10
|
+
keypoints: number[][];
|
|
11
|
+
scores: number[];
|
|
12
|
+
}>;
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=hand.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hand.d.ts","sourceRoot":"","sources":["../../src/solution/hand.ts"],"names":[],"mappings":"AAAA;;GAEG;AAMH,qBAAa,IAAI;IACf,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,SAAS,CAAU;gBAGzB,GAAG,GAAE,MAAwH,EAC7H,YAAY,GAAE,CAAC,MAAM,EAAE,MAAM,CAAc,EAC3C,IAAI,GAAE,MAAmJ,EACzJ,aAAa,GAAE,CAAC,MAAM,EAAE,MAAM,CAAc,EAC5C,UAAU,GAAE,OAAe,EAC3B,OAAO,GAAE,aAA6B,EACtC,MAAM,GAAE,MAAc;IAkBlB,IAAI,IAAI,OAAO,CAAC,IAAI,CAAC;IAKrB,IAAI,CACR,KAAK,EAAE,UAAU,EACjB,QAAQ,EAAE,MAAM,EAChB,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;QAAE,SAAS,EAAE,MAAM,EAAE,EAAE,CAAC;QAAC,MAAM,EAAE,MAAM,EAAE,CAAA;KAAE,CAAC;CAKxD"}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hand solution - hand pose estimation with 21 keypoints
|
|
3
|
+
*/
|
|
4
|
+
import { YOLOX } from '../models/yolox';
|
|
5
|
+
import { RTMPose } from '../models/rtmpose';
|
|
6
|
+
export class Hand {
|
|
7
|
+
constructor(det = 'https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/onnx_sdk/rtmdet_nano_8xb32-300e_hand-267f9c8f.zip', detInputSize = [320, 320], pose = 'https://download.openmmlab.com/mmpose/v1/projects/rtmposev1/onnx_sdk/rtmpose-m_simcc-hand5_pt-aic-coco_210e-256x256-74fb594_20230320.zip', poseInputSize = [256, 256], toOpenpose = false, backend = 'onnxruntime', device = 'cpu') {
|
|
8
|
+
this.detModel = new YOLOX(det, detInputSize, 0.45, 0.5, backend);
|
|
9
|
+
this.poseModel = new RTMPose(pose, poseInputSize, toOpenpose, backend);
|
|
10
|
+
}
|
|
11
|
+
async init() {
|
|
12
|
+
await this.detModel.init();
|
|
13
|
+
await this.poseModel.init();
|
|
14
|
+
}
|
|
15
|
+
async call(image, imgWidth, imgHeight) {
|
|
16
|
+
const bboxes = await this.detModel.call(image, imgWidth, imgHeight);
|
|
17
|
+
const result = await this.poseModel.call(image, imgWidth, imgHeight, bboxes);
|
|
18
|
+
return result;
|
|
19
|
+
}
|
|
20
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Solution exports
|
|
3
|
+
*/
|
|
4
|
+
export { Wholebody } from './wholebody';
|
|
5
|
+
export { Wholebody3D, type Wholebody3DResult } from './wholebody3d';
|
|
6
|
+
export { Body } from './body';
|
|
7
|
+
export { Hand } from './hand';
|
|
8
|
+
export { BodyWithFeet } from './bodyWithFeet';
|
|
9
|
+
export { PoseTracker } from './poseTracker';
|
|
10
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/solution/index.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AACxC,OAAO,EAAE,WAAW,EAAE,KAAK,iBAAiB,EAAE,MAAM,eAAe,CAAC;AACpE,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC;AAC9B,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,WAAW,EAAE,MAAM,eAAe,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Solution exports
|
|
3
|
+
*/
|
|
4
|
+
export { Wholebody } from './wholebody';
|
|
5
|
+
export { Wholebody3D } from './wholebody3d';
|
|
6
|
+
export { Body } from './body';
|
|
7
|
+
export { Hand } from './hand';
|
|
8
|
+
export { BodyWithFeet } from './bodyWithFeet';
|
|
9
|
+
export { PoseTracker } from './poseTracker';
|