@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.js
CHANGED
|
@@ -373,16 +373,16 @@
|
|
|
373
373
|
*/
|
|
374
374
|
async function _initializeOpenCV(timeout) {
|
|
375
375
|
const initStartTime = performance.now();
|
|
376
|
-
console.log('
|
|
376
|
+
console.log('Waiting for OpenCV WASM initialization...');
|
|
377
377
|
// 快速路径:检查是否已经初始化
|
|
378
378
|
if (cvModule.Mat) {
|
|
379
379
|
const initTime = performance.now() - initStartTime;
|
|
380
|
-
console.log(`
|
|
380
|
+
console.log(`OpenCV.js already initialized, took ${initTime.toFixed(2)}ms`);
|
|
381
381
|
return cvModule;
|
|
382
382
|
}
|
|
383
383
|
if (typeof globalThis !== 'undefined' && globalThis.cv && globalThis.cv.Mat) {
|
|
384
384
|
const initTime = performance.now() - initStartTime;
|
|
385
|
-
console.log(`
|
|
385
|
+
console.log(`OpenCV.js already initialized (from global), took ${initTime.toFixed(2)}ms`);
|
|
386
386
|
cvModule = globalThis.cv;
|
|
387
387
|
return cvModule;
|
|
388
388
|
}
|
|
@@ -390,10 +390,10 @@
|
|
|
390
390
|
if (typeof globalThis !== 'undefined' && !globalThis.cv) {
|
|
391
391
|
if (cvModule && Object.isExtensible(cvModule)) {
|
|
392
392
|
globalThis.cv = cvModule;
|
|
393
|
-
console.log('
|
|
393
|
+
console.log('cvModule assigned to globalThis.cv');
|
|
394
394
|
}
|
|
395
395
|
else {
|
|
396
|
-
console.log('
|
|
396
|
+
console.log('cvModule is not extensible or globalThis already has cv');
|
|
397
397
|
}
|
|
398
398
|
}
|
|
399
399
|
return new Promise((resolve, reject) => {
|
|
@@ -402,7 +402,7 @@
|
|
|
402
402
|
// 防止多次调用 resolve/reject
|
|
403
403
|
let finished = false;
|
|
404
404
|
const timeoutId = setTimeout(() => {
|
|
405
|
-
console.error('
|
|
405
|
+
console.error('OpenCV.js initialization timeout after ' + timeout + 'ms');
|
|
406
406
|
finished = true;
|
|
407
407
|
if (pollInterval) {
|
|
408
408
|
clearInterval(pollInterval);
|
|
@@ -411,65 +411,65 @@
|
|
|
411
411
|
}, timeout);
|
|
412
412
|
const resolveOnce = (source) => {
|
|
413
413
|
if (finished) {
|
|
414
|
-
console.log('[
|
|
414
|
+
console.log('[resolveOnce] Already finished, ignoring call from:', source);
|
|
415
415
|
return;
|
|
416
416
|
}
|
|
417
417
|
finished = true;
|
|
418
|
-
console.log('[
|
|
418
|
+
console.log('[resolveOnce] Marking as finished');
|
|
419
419
|
// 立即停止所有定时器和轮询
|
|
420
420
|
clearTimeout(timeoutId);
|
|
421
421
|
if (pollInterval !== null) {
|
|
422
422
|
clearInterval(pollInterval);
|
|
423
423
|
pollInterval = null;
|
|
424
|
-
console.log('[
|
|
424
|
+
console.log('[resolveOnce] Poll interval cleared');
|
|
425
425
|
}
|
|
426
426
|
const initTime = performance.now() - initStartTime;
|
|
427
|
-
console.log(`
|
|
427
|
+
console.log(`OpenCV.js initialized (${source}), took ${initTime.toFixed(2)}ms`);
|
|
428
428
|
// 标记初始化完成
|
|
429
429
|
opencvInitialized = true;
|
|
430
430
|
// 返回简单的标记,实际的 cv 对象已经在 globalThis.cv 上了
|
|
431
431
|
// 通过 getCvSync() 获取
|
|
432
432
|
resolve(initTime);
|
|
433
|
-
console.log('[
|
|
433
|
+
console.log('[resolveOnce] Promise resolved');
|
|
434
434
|
};
|
|
435
435
|
// 尝试设置回调(只有在 cvModule 可扩展时才尝试)
|
|
436
436
|
const canSetCallback = cvModule && Object.isExtensible(cvModule);
|
|
437
437
|
if (canSetCallback) {
|
|
438
438
|
try {
|
|
439
439
|
const originalOnRuntimeInitialized = cvModule.onRuntimeInitialized(cvModule).onRuntimeInitialized = () => {
|
|
440
|
-
console.log('[
|
|
440
|
+
console.log('[onRuntimeInitialized] callback triggered');
|
|
441
441
|
// 调用原始回调(如果存在)
|
|
442
442
|
if (originalOnRuntimeInitialized && typeof originalOnRuntimeInitialized === 'function') {
|
|
443
443
|
try {
|
|
444
444
|
originalOnRuntimeInitialized();
|
|
445
445
|
}
|
|
446
446
|
catch (e) {
|
|
447
|
-
console.warn('[
|
|
447
|
+
console.warn('[onRuntimeInitialized] callback failed:', e);
|
|
448
448
|
}
|
|
449
449
|
}
|
|
450
450
|
resolveOnce('callback');
|
|
451
451
|
};
|
|
452
|
-
console.log('[
|
|
452
|
+
console.log('[onRuntimeInitialized] callback set successfully');
|
|
453
453
|
}
|
|
454
454
|
catch (e) {
|
|
455
|
-
console.warn('[
|
|
455
|
+
console.warn('[onRuntimeInitialized] Failed to set callback, will use polling:', e);
|
|
456
456
|
}
|
|
457
457
|
}
|
|
458
458
|
else {
|
|
459
|
-
console.log('[
|
|
459
|
+
console.log('[polling] cvModule is not extensible, using polling mode');
|
|
460
460
|
}
|
|
461
461
|
// 启动轮询作为备用方案或主要方案
|
|
462
462
|
pollInterval = setInterval(() => {
|
|
463
|
-
console.log('[
|
|
463
|
+
console.log('[polling] Checking for Mat class...');
|
|
464
464
|
// 优先检查 cvModule 中是否有 Mat
|
|
465
465
|
if (cvModule.Mat) {
|
|
466
|
-
console.log('[
|
|
466
|
+
console.log('[polling] Found Mat in cvModule');
|
|
467
467
|
resolveOnce('cvModule polling');
|
|
468
468
|
return;
|
|
469
469
|
}
|
|
470
470
|
// 其次检查 globalThis.cv 中是否有 Mat
|
|
471
471
|
if (typeof globalThis !== 'undefined' && globalThis.cv && globalThis.cv.Mat) {
|
|
472
|
-
console.log('[
|
|
472
|
+
console.log('[polling] Found Mat in globalThis.cv');
|
|
473
473
|
cvModule = globalThis.cv;
|
|
474
474
|
resolveOnce('globalThis.cv polling');
|
|
475
475
|
return;
|
|
@@ -483,38 +483,39 @@
|
|
|
483
483
|
* @returns Promise that resolves with cv module
|
|
484
484
|
*/
|
|
485
485
|
async function loadOpenCV(timeout = 30000) {
|
|
486
|
-
console.log('[FaceDetectionEngine] loadOpenCV: START');
|
|
487
486
|
try {
|
|
488
487
|
// 快速检查是否已经初始化完成
|
|
489
488
|
if (opencvInitialized) {
|
|
490
|
-
console.log('[
|
|
489
|
+
console.log('[loadOpenCV] Already initialized, returning immediately');
|
|
491
490
|
const cv = getCvSync();
|
|
492
491
|
if (cv) {
|
|
493
492
|
return { cv };
|
|
494
493
|
}
|
|
495
494
|
}
|
|
496
495
|
// 等待初始化
|
|
497
|
-
console.log('[
|
|
496
|
+
console.log('[loadOpenCV] Waiting for initialization...');
|
|
498
497
|
if (!opencvInitPromise) {
|
|
499
|
-
console.log('[
|
|
498
|
+
console.log('[loadOpenCV] Starting new initialization');
|
|
500
499
|
opencvInitPromise = _initializeOpenCV(timeout);
|
|
501
500
|
}
|
|
502
|
-
console.log('[
|
|
501
|
+
console.log('[loadOpenCV] Awaiting opencvInitPromise');
|
|
503
502
|
const initTime = await opencvInitPromise;
|
|
504
|
-
console.log('[FaceDetectionEngine] loadOpenCV: After await, Promise resolved, cost :', initTime.toFixed(0), 'ms');
|
|
505
503
|
// 清除 Promise 缓存
|
|
506
504
|
opencvInitPromise = null;
|
|
507
505
|
// 获取初始化后的 cv 对象
|
|
508
506
|
const cv = getCvSync();
|
|
509
507
|
if (!cv) {
|
|
510
|
-
console.error('[
|
|
508
|
+
console.error('[loadOpenCV] getCvSync returned null');
|
|
511
509
|
throw new Error('OpenCV module is invalid');
|
|
512
510
|
}
|
|
513
|
-
console.log('[
|
|
514
|
-
|
|
511
|
+
console.log('[loadOpenCV] OpenCV.js load successfully', {
|
|
512
|
+
initTime: `${initTime.toFixed(2)}ms`,
|
|
513
|
+
version: getOpenCVVersion()
|
|
514
|
+
});
|
|
515
|
+
return cv;
|
|
515
516
|
}
|
|
516
517
|
catch (error) {
|
|
517
|
-
console.error('[
|
|
518
|
+
console.error('[loadOpenCV] OpenCV.js load failed', error);
|
|
518
519
|
opencvInitPromise = null;
|
|
519
520
|
throw error;
|
|
520
521
|
}
|
|
@@ -534,6 +535,35 @@
|
|
|
534
535
|
}
|
|
535
536
|
return null;
|
|
536
537
|
}
|
|
538
|
+
/**
|
|
539
|
+
* Extract OpenCV version from getBuildInformation
|
|
540
|
+
* @returns version string like "4.12.0"
|
|
541
|
+
*/
|
|
542
|
+
function getOpenCVVersion() {
|
|
543
|
+
try {
|
|
544
|
+
const cv = getCvSync();
|
|
545
|
+
if (!cv || !cv.getBuildInformation) {
|
|
546
|
+
return 'unknown';
|
|
547
|
+
}
|
|
548
|
+
const buildInfo = cv.getBuildInformation();
|
|
549
|
+
// 查找 "Version control:" 或 "OpenCV" 开头的行
|
|
550
|
+
// 格式: "Version control: 4.12.0"
|
|
551
|
+
const versionMatch = buildInfo.match(/Version\s+control:\s+(\d+\.\d+\.\d+)/i);
|
|
552
|
+
if (versionMatch && versionMatch[1]) {
|
|
553
|
+
return versionMatch[1];
|
|
554
|
+
}
|
|
555
|
+
// 备用方案:查找 "OpenCV X.X.X" 格式
|
|
556
|
+
const opencvMatch = buildInfo.match(/OpenCV\s+(\d+\.\d+\.\d+)/i);
|
|
557
|
+
if (opencvMatch && opencvMatch[1]) {
|
|
558
|
+
return opencvMatch[1];
|
|
559
|
+
}
|
|
560
|
+
return 'unknown';
|
|
561
|
+
}
|
|
562
|
+
catch (error) {
|
|
563
|
+
console.error('[getOpenCVVersion] Failed to get version:', error);
|
|
564
|
+
return 'unknown';
|
|
565
|
+
}
|
|
566
|
+
}
|
|
537
567
|
/**
|
|
538
568
|
* Load Human.js
|
|
539
569
|
* @param modelPath - Path to model files (optional)
|
|
@@ -563,24 +593,17 @@
|
|
|
563
593
|
if (wasmPath) {
|
|
564
594
|
config.wasmPath = wasmPath;
|
|
565
595
|
}
|
|
566
|
-
console.log('[
|
|
596
|
+
console.log('[loadHuman] Config:', {
|
|
567
597
|
backend: config.backend,
|
|
568
598
|
modelBasePath: config.modelBasePath || '(using default)',
|
|
569
599
|
wasmPath: config.wasmPath || '(using default)'
|
|
570
600
|
});
|
|
571
601
|
const initStartTime = performance.now();
|
|
572
|
-
console.log('[FaceDetectionEngine] Creating Human instance...');
|
|
573
602
|
const human = new Human(config);
|
|
574
|
-
const instanceCreateTime = performance.now() - initStartTime;
|
|
575
|
-
console.log(`[FaceDetectionEngine] Human instance created, took ${instanceCreateTime.toFixed(2)}ms`);
|
|
576
|
-
console.log('[FaceDetectionEngine] Loading Human.js models...');
|
|
577
|
-
const modelLoadStartTime = performance.now();
|
|
578
603
|
try {
|
|
579
604
|
await human.load();
|
|
580
|
-
const loadTime = performance.now() - modelLoadStartTime;
|
|
581
605
|
const totalTime = performance.now() - initStartTime;
|
|
582
|
-
console.log('[
|
|
583
|
-
modelLoadTime: `${loadTime.toFixed(2)}ms`,
|
|
606
|
+
console.log('[loadHuman] Loaded successfully', {
|
|
584
607
|
totalInitTime: `${totalTime.toFixed(2)}ms`,
|
|
585
608
|
version: human.version
|
|
586
609
|
});
|
|
@@ -588,7 +611,32 @@
|
|
|
588
611
|
}
|
|
589
612
|
catch (error) {
|
|
590
613
|
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
591
|
-
console.error('[
|
|
614
|
+
console.error('[loadHuman] Load failed:', errorMsg);
|
|
615
|
+
throw error;
|
|
616
|
+
}
|
|
617
|
+
}
|
|
618
|
+
async function loadLibraries(modelPath, wasmPath, timeout) {
|
|
619
|
+
console.log('[loadLibraries] Starting parallel load of OpenCV and Human...');
|
|
620
|
+
const startTime = performance.now();
|
|
621
|
+
if (timeout == undefined) {
|
|
622
|
+
timeout = 30000;
|
|
623
|
+
}
|
|
624
|
+
try {
|
|
625
|
+
// 并行加载 OpenCV 和 Human
|
|
626
|
+
const [cv, human] = await Promise.all([
|
|
627
|
+
loadOpenCV(timeout),
|
|
628
|
+
loadHuman(modelPath, wasmPath)
|
|
629
|
+
]);
|
|
630
|
+
const totalTime = performance.now() - startTime;
|
|
631
|
+
console.log('[loadLibraries] Both libraries loaded successfully in', totalTime.toFixed(2), 'ms');
|
|
632
|
+
return {
|
|
633
|
+
cv,
|
|
634
|
+
human
|
|
635
|
+
};
|
|
636
|
+
}
|
|
637
|
+
catch (error) {
|
|
638
|
+
const errorMsg = error instanceof Error ? error.message : 'Unknown error';
|
|
639
|
+
console.error('[loadLibraries] Failed to load libraries:', errorMsg);
|
|
592
640
|
throw error;
|
|
593
641
|
}
|
|
594
642
|
}
|
|
@@ -1570,12 +1618,13 @@
|
|
|
1570
1618
|
this.isInitializing = true;
|
|
1571
1619
|
this.emitDebug('initialization', 'Starting to load detection libraries...');
|
|
1572
1620
|
try {
|
|
1573
|
-
// Load
|
|
1574
|
-
this.emitDebug('initialization', 'Loading
|
|
1575
|
-
const
|
|
1621
|
+
// Load Libraries
|
|
1622
|
+
this.emitDebug('initialization', 'Loading Libraries...');
|
|
1623
|
+
const startLoadTime = performance.now();
|
|
1624
|
+
const { cv, human } = await loadLibraries(this.config.human_model_path, this.config.tensorflow_wasm_path, 30000);
|
|
1576
1625
|
if (!cv || !cv.Mat) {
|
|
1577
1626
|
console.log('[FaceDetectionEngine] Failed to load OpenCV.js: module is null or invalid');
|
|
1578
|
-
this.emit('detector-
|
|
1627
|
+
this.emit('detector-loaded', {
|
|
1579
1628
|
success: false,
|
|
1580
1629
|
error: 'Failed to load OpenCV.js: module is null or invalid'
|
|
1581
1630
|
});
|
|
@@ -1585,22 +1634,9 @@
|
|
|
1585
1634
|
});
|
|
1586
1635
|
return;
|
|
1587
1636
|
}
|
|
1588
|
-
this.emitDebug('initialization', 'OpenCV loaded successfully', {
|
|
1589
|
-
version: cv?.getBuildInformation?.() || 'unknown'
|
|
1590
|
-
});
|
|
1591
|
-
console.log('[FaceDetectionEngine] OpenCV loaded successfully', {
|
|
1592
|
-
version: cv?.getBuildInformation?.() || 'unknown'
|
|
1593
|
-
});
|
|
1594
|
-
// Load Human.js
|
|
1595
|
-
console.log('[FaceDetectionEngine] Loading Human.js models...');
|
|
1596
|
-
this.emitDebug('initialization', 'Loading Human.js...');
|
|
1597
|
-
const humanStartTime = performance.now();
|
|
1598
|
-
this.human = await loadHuman(this.config.human_model_path, this.config.tensorflow_wasm_path);
|
|
1599
|
-
const humanLoadTime = performance.now() - humanStartTime;
|
|
1600
1637
|
if (!this.human) {
|
|
1601
1638
|
const errorMsg = 'Failed to load Human.js: instance is null';
|
|
1602
1639
|
console.log('[FaceDetectionEngine] ' + errorMsg);
|
|
1603
|
-
this.emitDebug('initialization', errorMsg, { loadTime: humanLoadTime }, 'error');
|
|
1604
1640
|
this.emit('detector-loaded', {
|
|
1605
1641
|
success: false,
|
|
1606
1642
|
error: errorMsg
|
|
@@ -1611,21 +1647,14 @@
|
|
|
1611
1647
|
});
|
|
1612
1648
|
return;
|
|
1613
1649
|
}
|
|
1614
|
-
this.emitDebug('initialization', 'Human.js loaded successfully', {
|
|
1615
|
-
loadTime: `${humanLoadTime.toFixed(2)}ms`,
|
|
1616
|
-
version: this.human.version
|
|
1617
|
-
});
|
|
1618
|
-
console.log('[FaceDetectionEngine] Human.js loaded successfully', {
|
|
1619
|
-
loadTime: `${humanLoadTime.toFixed(2)}ms`,
|
|
1620
|
-
version: this.human.version
|
|
1621
|
-
});
|
|
1622
1650
|
this.isReady = true;
|
|
1623
1651
|
const loadedData = {
|
|
1624
1652
|
success: true,
|
|
1625
|
-
opencv_version:
|
|
1653
|
+
opencv_version: getOpenCVVersion(),
|
|
1626
1654
|
human_version: this.human.version
|
|
1627
1655
|
};
|
|
1628
1656
|
console.log('[FaceDetectionEngine] Engine initialized and ready', {
|
|
1657
|
+
initCostTime: (performance.now() - startLoadTime).toFixed(2),
|
|
1629
1658
|
opencv_version: loadedData.opencv_version,
|
|
1630
1659
|
human_version: loadedData.human_version
|
|
1631
1660
|
});
|
|
@@ -2398,6 +2427,7 @@
|
|
|
2398
2427
|
exports.FaceDetectionEngine = FaceDetectionEngine;
|
|
2399
2428
|
exports.default = FaceDetectionEngine;
|
|
2400
2429
|
exports.getCvSync = getCvSync;
|
|
2430
|
+
exports.getOpenCVVersion = getOpenCVVersion;
|
|
2401
2431
|
exports.loadOpenCV = loadOpenCV;
|
|
2402
2432
|
exports.preloadOpenCV = preloadOpenCV;
|
|
2403
2433
|
|