@sssxyd/face-liveness-detector 0.2.22 → 0.2.23
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/dist/index.esm.js +95 -66
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +95 -65
- package/dist/index.js.map +1 -1
- package/dist/types/index.d.ts +1 -1
- package/dist/types/index.d.ts.map +1 -1
- package/dist/types/library-loader.d.ts +10 -3
- package/dist/types/library-loader.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -351,16 +351,16 @@ async function preloadOpenCV(timeout = 30000) {
|
|
|
351
351
|
*/
|
|
352
352
|
async function _initializeOpenCV(timeout) {
|
|
353
353
|
const initStartTime = performance.now();
|
|
354
|
-
console.log('
|
|
354
|
+
console.log('Waiting for OpenCV WASM initialization...');
|
|
355
355
|
// 快速路径:检查是否已经初始化
|
|
356
356
|
if (cvModule.Mat) {
|
|
357
357
|
const initTime = performance.now() - initStartTime;
|
|
358
|
-
console.log(`
|
|
358
|
+
console.log(`OpenCV.js already initialized, took ${initTime.toFixed(2)}ms`);
|
|
359
359
|
return cvModule;
|
|
360
360
|
}
|
|
361
361
|
if (typeof globalThis !== 'undefined' && globalThis.cv && globalThis.cv.Mat) {
|
|
362
362
|
const initTime = performance.now() - initStartTime;
|
|
363
|
-
console.log(`
|
|
363
|
+
console.log(`OpenCV.js already initialized (from global), took ${initTime.toFixed(2)}ms`);
|
|
364
364
|
cvModule = globalThis.cv;
|
|
365
365
|
return cvModule;
|
|
366
366
|
}
|
|
@@ -368,10 +368,10 @@ async function _initializeOpenCV(timeout) {
|
|
|
368
368
|
if (typeof globalThis !== 'undefined' && !globalThis.cv) {
|
|
369
369
|
if (cvModule && Object.isExtensible(cvModule)) {
|
|
370
370
|
globalThis.cv = cvModule;
|
|
371
|
-
console.log('
|
|
371
|
+
console.log('cvModule assigned to globalThis.cv');
|
|
372
372
|
}
|
|
373
373
|
else {
|
|
374
|
-
console.log('
|
|
374
|
+
console.log('cvModule is not extensible or globalThis already has cv');
|
|
375
375
|
}
|
|
376
376
|
}
|
|
377
377
|
return new Promise((resolve, reject) => {
|
|
@@ -380,7 +380,7 @@ async function _initializeOpenCV(timeout) {
|
|
|
380
380
|
// 防止多次调用 resolve/reject
|
|
381
381
|
let finished = false;
|
|
382
382
|
const timeoutId = setTimeout(() => {
|
|
383
|
-
console.error('
|
|
383
|
+
console.error('OpenCV.js initialization timeout after ' + timeout + 'ms');
|
|
384
384
|
finished = true;
|
|
385
385
|
if (pollInterval) {
|
|
386
386
|
clearInterval(pollInterval);
|
|
@@ -389,65 +389,65 @@ async function _initializeOpenCV(timeout) {
|
|
|
389
389
|
}, timeout);
|
|
390
390
|
const resolveOnce = (source) => {
|
|
391
391
|
if (finished) {
|
|
392
|
-
console.log('[
|
|
392
|
+
console.log('[resolveOnce] Already finished, ignoring call from:', source);
|
|
393
393
|
return;
|
|
394
394
|
}
|
|
395
395
|
finished = true;
|
|
396
|
-
console.log('[
|
|
396
|
+
console.log('[resolveOnce] Marking as finished');
|
|
397
397
|
// 立即停止所有定时器和轮询
|
|
398
398
|
clearTimeout(timeoutId);
|
|
399
399
|
if (pollInterval !== null) {
|
|
400
400
|
clearInterval(pollInterval);
|
|
401
401
|
pollInterval = null;
|
|
402
|
-
console.log('[
|
|
402
|
+
console.log('[resolveOnce] Poll interval cleared');
|
|
403
403
|
}
|
|
404
404
|
const initTime = performance.now() - initStartTime;
|
|
405
|
-
console.log(`
|
|
405
|
+
console.log(`OpenCV.js initialized (${source}), took ${initTime.toFixed(2)}ms`);
|
|
406
406
|
// 标记初始化完成
|
|
407
407
|
opencvInitialized = true;
|
|
408
408
|
// 返回简单的标记,实际的 cv 对象已经在 globalThis.cv 上了
|
|
409
409
|
// 通过 getCvSync() 获取
|
|
410
410
|
resolve(initTime);
|
|
411
|
-
console.log('[
|
|
411
|
+
console.log('[resolveOnce] Promise resolved');
|
|
412
412
|
};
|
|
413
413
|
// 尝试设置回调(只有在 cvModule 可扩展时才尝试)
|
|
414
414
|
const canSetCallback = cvModule && Object.isExtensible(cvModule);
|
|
415
415
|
if (canSetCallback) {
|
|
416
416
|
try {
|
|
417
417
|
const originalOnRuntimeInitialized = cvModule.onRuntimeInitialized(cvModule).onRuntimeInitialized = () => {
|
|
418
|
-
console.log('[
|
|
418
|
+
console.log('[onRuntimeInitialized] callback triggered');
|
|
419
419
|
// 调用原始回调(如果存在)
|
|
420
420
|
if (originalOnRuntimeInitialized && typeof originalOnRuntimeInitialized === 'function') {
|
|
421
421
|
try {
|
|
422
422
|
originalOnRuntimeInitialized();
|
|
423
423
|
}
|
|
424
424
|
catch (e) {
|
|
425
|
-
console.warn('[
|
|
425
|
+
console.warn('[onRuntimeInitialized] callback failed:', e);
|
|
426
426
|
}
|
|
427
427
|
}
|
|
428
428
|
resolveOnce('callback');
|
|
429
429
|
};
|
|
430
|
-
console.log('[
|
|
430
|
+
console.log('[onRuntimeInitialized] callback set successfully');
|
|
431
431
|
}
|
|
432
432
|
catch (e) {
|
|
433
|
-
console.warn('[
|
|
433
|
+
console.warn('[onRuntimeInitialized] Failed to set callback, will use polling:', e);
|
|
434
434
|
}
|
|
435
435
|
}
|
|
436
436
|
else {
|
|
437
|
-
console.log('[
|
|
437
|
+
console.log('[polling] cvModule is not extensible, using polling mode');
|
|
438
438
|
}
|
|
439
439
|
// 启动轮询作为备用方案或主要方案
|
|
440
440
|
pollInterval = setInterval(() => {
|
|
441
|
-
console.log('[
|
|
441
|
+
console.log('[polling] Checking for Mat class...');
|
|
442
442
|
// 优先检查 cvModule 中是否有 Mat
|
|
443
443
|
if (cvModule.Mat) {
|
|
444
|
-
console.log('[
|
|
444
|
+
console.log('[polling] Found Mat in cvModule');
|
|
445
445
|
resolveOnce('cvModule polling');
|
|
446
446
|
return;
|
|
447
447
|
}
|
|
448
448
|
// 其次检查 globalThis.cv 中是否有 Mat
|
|
449
449
|
if (typeof globalThis !== 'undefined' && globalThis.cv && globalThis.cv.Mat) {
|
|
450
|
-
console.log('[
|
|
450
|
+
console.log('[polling] Found Mat in globalThis.cv');
|
|
451
451
|
cvModule = globalThis.cv;
|
|
452
452
|
resolveOnce('globalThis.cv polling');
|
|
453
453
|
return;
|
|
@@ -461,38 +461,39 @@ async function _initializeOpenCV(timeout) {
|
|
|
461
461
|
* @returns Promise that resolves with cv module
|
|
462
462
|
*/
|
|
463
463
|
async function loadOpenCV(timeout = 30000) {
|
|
464
|
-
console.log('[FaceDetectionEngine] loadOpenCV: START');
|
|
465
464
|
try {
|
|
466
465
|
// 快速检查是否已经初始化完成
|
|
467
466
|
if (opencvInitialized) {
|
|
468
|
-
console.log('[
|
|
467
|
+
console.log('[loadOpenCV] Already initialized, returning immediately');
|
|
469
468
|
const cv = getCvSync();
|
|
470
469
|
if (cv) {
|
|
471
470
|
return { cv };
|
|
472
471
|
}
|
|
473
472
|
}
|
|
474
473
|
// 等待初始化
|
|
475
|
-
console.log('[
|
|
474
|
+
console.log('[loadOpenCV] Waiting for initialization...');
|
|
476
475
|
if (!opencvInitPromise) {
|
|
477
|
-
console.log('[
|
|
476
|
+
console.log('[loadOpenCV] Starting new initialization');
|
|
478
477
|
opencvInitPromise = _initializeOpenCV(timeout);
|
|
479
478
|
}
|
|
480
|
-
console.log('[
|
|
479
|
+
console.log('[loadOpenCV] Awaiting opencvInitPromise');
|
|
481
480
|
const initTime = await opencvInitPromise;
|
|
482
|
-
console.log('[FaceDetectionEngine] loadOpenCV: After await, Promise resolved, cost :', initTime.toFixed(0), 'ms');
|
|
483
481
|
// 清除 Promise 缓存
|
|
484
482
|
opencvInitPromise = null;
|
|
485
483
|
// 获取初始化后的 cv 对象
|
|
486
484
|
const cv = getCvSync();
|
|
487
485
|
if (!cv) {
|
|
488
|
-
console.error('[
|
|
486
|
+
console.error('[loadOpenCV] getCvSync returned null');
|
|
489
487
|
throw new Error('OpenCV module is invalid');
|
|
490
488
|
}
|
|
491
|
-
console.log('[
|
|
492
|
-
|
|
489
|
+
console.log('[loadOpenCV] OpenCV.js load successfully', {
|
|
490
|
+
initTime: `${initTime.toFixed(2)}ms`,
|
|
491
|
+
version: getOpenCVVersion()
|
|
492
|
+
});
|
|
493
|
+
return cv;
|
|
493
494
|
}
|
|
494
495
|
catch (error) {
|
|
495
|
-
console.error('[
|
|
496
|
+
console.error('[loadOpenCV] OpenCV.js load failed', error);
|
|
496
497
|
opencvInitPromise = null;
|
|
497
498
|
throw error;
|
|
498
499
|
}
|
|
@@ -512,6 +513,35 @@ function getCvSync() {
|
|
|
512
513
|
}
|
|
513
514
|
return null;
|
|
514
515
|
}
|
|
516
|
+
/**
|
|
517
|
+
* Extract OpenCV version from getBuildInformation
|
|
518
|
+
* @returns version string like "4.12.0"
|
|
519
|
+
*/
|
|
520
|
+
function getOpenCVVersion() {
|
|
521
|
+
try {
|
|
522
|
+
const cv = getCvSync();
|
|
523
|
+
if (!cv || !cv.getBuildInformation) {
|
|
524
|
+
return 'unknown';
|
|
525
|
+
}
|
|
526
|
+
const buildInfo = cv.getBuildInformation();
|
|
527
|
+
// 查找 "Version control:" 或 "OpenCV" 开头的行
|
|
528
|
+
// 格式: "Version control: 4.12.0"
|
|
529
|
+
const versionMatch = buildInfo.match(/Version\s+control:\s+(\d+\.\d+\.\d+)/i);
|
|
530
|
+
if (versionMatch && versionMatch[1]) {
|
|
531
|
+
return versionMatch[1];
|
|
532
|
+
}
|
|
533
|
+
// 备用方案:查找 "OpenCV X.X.X" 格式
|
|
534
|
+
const opencvMatch = buildInfo.match(/OpenCV\s+(\d+\.\d+\.\d+)/i);
|
|
535
|
+
if (opencvMatch && opencvMatch[1]) {
|
|
536
|
+
return opencvMatch[1];
|
|
537
|
+
}
|
|
538
|
+
return 'unknown';
|
|
539
|
+
}
|
|
540
|
+
catch (error) {
|
|
541
|
+
console.error('[getOpenCVVersion] Failed to get version:', error);
|
|
542
|
+
return 'unknown';
|
|
543
|
+
}
|
|
544
|
+
}
|
|
515
545
|
/**
|
|
516
546
|
* Load Human.js
|
|
517
547
|
* @param modelPath - Path to model files (optional)
|
|
@@ -541,24 +571,17 @@ async function loadHuman(modelPath, wasmPath) {
|
|
|
541
571
|
if (wasmPath) {
|
|
542
572
|
config.wasmPath = wasmPath;
|
|
543
573
|
}
|
|
544
|
-
console.log('[
|
|
574
|
+
console.log('[loadHuman] Config:', {
|
|
545
575
|
backend: config.backend,
|
|
546
576
|
modelBasePath: config.modelBasePath || '(using default)',
|
|
547
577
|
wasmPath: config.wasmPath || '(using default)'
|
|
548
578
|
});
|
|
549
579
|
const initStartTime = performance.now();
|
|
550
|
-
console.log('[FaceDetectionEngine] Creating Human instance...');
|
|
551
580
|
const human = new Human(config);
|
|
552
|
-
const instanceCreateTime = performance.now() - initStartTime;
|
|
553
|
-
console.log(`[FaceDetectionEngine] Human instance created, took ${instanceCreateTime.toFixed(2)}ms`);
|
|
554
|
-
console.log('[FaceDetectionEngine] Loading Human.js models...');
|
|
555
|
-
const modelLoadStartTime = performance.now();
|
|
556
581
|
try {
|
|
557
582
|
await human.load();
|
|
558
|
-
const loadTime = performance.now() - modelLoadStartTime;
|
|
559
583
|
const totalTime = performance.now() - initStartTime;
|
|
560
|
-
console.log('[
|
|
561
|
-
modelLoadTime: `${loadTime.toFixed(2)}ms`,
|
|
584
|
+
console.log('[loadHuman] Loaded successfully', {
|
|
562
585
|
totalInitTime: `${totalTime.toFixed(2)}ms`,
|
|
563
586
|
version: human.version
|
|
564
587
|
});
|
|
@@ -566,7 +589,32 @@ async function loadHuman(modelPath, wasmPath) {
|
|
|
566
589
|
}
|
|
567
590
|
catch (error) {
|
|
568
591
|
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
569
|
-
console.error('[
|
|
592
|
+
console.error('[loadHuman] Load failed:', errorMsg);
|
|
593
|
+
throw error;
|
|
594
|
+
}
|
|
595
|
+
}
|
|
596
|
+
async function loadLibraries(modelPath, wasmPath, timeout) {
|
|
597
|
+
console.log('[loadLibraries] Starting parallel load of OpenCV and Human...');
|
|
598
|
+
const startTime = performance.now();
|
|
599
|
+
if (timeout == undefined) {
|
|
600
|
+
timeout = 30000;
|
|
601
|
+
}
|
|
602
|
+
try {
|
|
603
|
+
// 并行加载 OpenCV 和 Human
|
|
604
|
+
const [cv, human] = await Promise.all([
|
|
605
|
+
loadOpenCV(timeout),
|
|
606
|
+
loadHuman(modelPath, wasmPath)
|
|
607
|
+
]);
|
|
608
|
+
const totalTime = performance.now() - startTime;
|
|
609
|
+
console.log('[loadLibraries] Both libraries loaded successfully in', totalTime.toFixed(2), 'ms');
|
|
610
|
+
return {
|
|
611
|
+
cv,
|
|
612
|
+
human
|
|
613
|
+
};
|
|
614
|
+
}
|
|
615
|
+
catch (error) {
|
|
616
|
+
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
617
|
+
console.error('[loadLibraries] Failed to load libraries:', errorMsg);
|
|
570
618
|
throw error;
|
|
571
619
|
}
|
|
572
620
|
}
|
|
@@ -1548,12 +1596,13 @@ class FaceDetectionEngine extends SimpleEventEmitter {
|
|
|
1548
1596
|
this.isInitializing = true;
|
|
1549
1597
|
this.emitDebug('initialization', 'Starting to load detection libraries...');
|
|
1550
1598
|
try {
|
|
1551
|
-
// Load
|
|
1552
|
-
this.emitDebug('initialization', 'Loading
|
|
1553
|
-
const
|
|
1599
|
+
// Load Libraries
|
|
1600
|
+
this.emitDebug('initialization', 'Loading Libraries...');
|
|
1601
|
+
const startLoadTime = performance.now();
|
|
1602
|
+
const { cv, human } = await loadLibraries(this.config.human_model_path, this.config.tensorflow_wasm_path, 30000);
|
|
1554
1603
|
if (!cv || !cv.Mat) {
|
|
1555
1604
|
console.log('[FaceDetectionEngine] Failed to load OpenCV.js: module is null or invalid');
|
|
1556
|
-
this.emit('detector-
|
|
1605
|
+
this.emit('detector-loaded', {
|
|
1557
1606
|
success: false,
|
|
1558
1607
|
error: 'Failed to load OpenCV.js: module is null or invalid'
|
|
1559
1608
|
});
|
|
@@ -1563,22 +1612,9 @@ class FaceDetectionEngine extends SimpleEventEmitter {
|
|
|
1563
1612
|
});
|
|
1564
1613
|
return;
|
|
1565
1614
|
}
|
|
1566
|
-
this.emitDebug('initialization', 'OpenCV loaded successfully', {
|
|
1567
|
-
version: cv?.getBuildInformation?.() || 'unknown'
|
|
1568
|
-
});
|
|
1569
|
-
console.log('[FaceDetectionEngine] OpenCV loaded successfully', {
|
|
1570
|
-
version: cv?.getBuildInformation?.() || 'unknown'
|
|
1571
|
-
});
|
|
1572
|
-
// Load Human.js
|
|
1573
|
-
console.log('[FaceDetectionEngine] Loading Human.js models...');
|
|
1574
|
-
this.emitDebug('initialization', 'Loading Human.js...');
|
|
1575
|
-
const humanStartTime = performance.now();
|
|
1576
|
-
this.human = await loadHuman(this.config.human_model_path, this.config.tensorflow_wasm_path);
|
|
1577
|
-
const humanLoadTime = performance.now() - humanStartTime;
|
|
1578
1615
|
if (!this.human) {
|
|
1579
1616
|
const errorMsg = 'Failed to load Human.js: instance is null';
|
|
1580
1617
|
console.log('[FaceDetectionEngine] ' + errorMsg);
|
|
1581
|
-
this.emitDebug('initialization', errorMsg, { loadTime: humanLoadTime }, 'error');
|
|
1582
1618
|
this.emit('detector-loaded', {
|
|
1583
1619
|
success: false,
|
|
1584
1620
|
error: errorMsg
|
|
@@ -1589,21 +1625,14 @@ class FaceDetectionEngine extends SimpleEventEmitter {
|
|
|
1589
1625
|
});
|
|
1590
1626
|
return;
|
|
1591
1627
|
}
|
|
1592
|
-
this.emitDebug('initialization', 'Human.js loaded successfully', {
|
|
1593
|
-
loadTime: `${humanLoadTime.toFixed(2)}ms`,
|
|
1594
|
-
version: this.human.version
|
|
1595
|
-
});
|
|
1596
|
-
console.log('[FaceDetectionEngine] Human.js loaded successfully', {
|
|
1597
|
-
loadTime: `${humanLoadTime.toFixed(2)}ms`,
|
|
1598
|
-
version: this.human.version
|
|
1599
|
-
});
|
|
1600
1628
|
this.isReady = true;
|
|
1601
1629
|
const loadedData = {
|
|
1602
1630
|
success: true,
|
|
1603
|
-
opencv_version:
|
|
1631
|
+
opencv_version: getOpenCVVersion(),
|
|
1604
1632
|
human_version: this.human.version
|
|
1605
1633
|
};
|
|
1606
1634
|
console.log('[FaceDetectionEngine] Engine initialized and ready', {
|
|
1635
|
+
initCostTime: (performance.now() - startLoadTime).toFixed(2),
|
|
1607
1636
|
opencv_version: loadedData.opencv_version,
|
|
1608
1637
|
human_version: loadedData.human_version
|
|
1609
1638
|
});
|
|
@@ -2373,5 +2402,5 @@ class FaceDetectionEngine extends SimpleEventEmitter {
|
|
|
2373
2402
|
}
|
|
2374
2403
|
}
|
|
2375
2404
|
|
|
2376
|
-
export { DetectionPeriod, ErrorCode, FaceDetectionEngine, LivenessAction, LivenessActionStatus, PromptCode, FaceDetectionEngine as default, getCvSync, loadOpenCV, preloadOpenCV };
|
|
2405
|
+
export { DetectionPeriod, ErrorCode, FaceDetectionEngine, LivenessAction, LivenessActionStatus, PromptCode, FaceDetectionEngine as default, getCvSync, getOpenCVVersion, loadOpenCV, preloadOpenCV };
|
|
2377
2406
|
//# sourceMappingURL=index.esm.js.map
|