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