@sssxyd/face-liveness-detector 0.4.0-alpha.10 → 0.4.0-alpha.11
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 +63 -50
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +63 -50
- package/dist/index.js.map +1 -1
- package/dist/types/face-detection-engine.d.ts.map +1 -1
- package/dist/types/screen-capture-detector.d.ts.map +1 -1
- package/dist/types/screen-moire-pattern-detect.d.ts.map +1 -1
- package/dist/types/screen-rgb-emission-detect.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -2752,36 +2752,39 @@ function calculateCorrelation(mat1, mat2) {
|
|
|
2752
2752
|
* 计算综合屏幕拍摄置信度
|
|
2753
2753
|
* 基于各项特征指标的加权平均
|
|
2754
2754
|
*
|
|
2755
|
-
*
|
|
2756
|
-
* -
|
|
2757
|
-
* -
|
|
2758
|
-
* -
|
|
2759
|
-
*
|
|
2760
|
-
* 删除梯度特征原因:
|
|
2761
|
-
* - 梯度特征对分辨率敏感,是主要噪声源
|
|
2762
|
-
* - 权重仅 17%,且可靠性最低(⭐⭐⭐)
|
|
2763
|
-
* - 删除后准确率反而提升 1-3%(去掉噪声)
|
|
2764
|
-
* - 代码简化 40%,性能提升 40%(少 80ms 计算)
|
|
2765
|
-
* - RGB相关性 + 饱和度 已足以识别屏幕特性
|
|
2755
|
+
* 针对完整高分辨率图像(1920×1080+)优化:
|
|
2756
|
+
* - 足够的屏幕像素采样,所有特征都清晰
|
|
2757
|
+
* - RGB相关性权重提升(屏幕同质性强)
|
|
2758
|
+
* - 饱和度权重平衡(屏幕特征明显)
|
|
2759
|
+
* - 像素熵权重保持
|
|
2766
2760
|
*/
|
|
2767
2761
|
function calculateScreenConfidence(saturation, rgbCorrelation, entropy) {
|
|
2768
|
-
// 加权平均:各特征的贡献度
|
|
2769
|
-
// 权重自动归一化:35/83 : 30/83 : 18/83
|
|
2770
2762
|
const weights = {
|
|
2771
|
-
rgbCorrelation: 0.42, // RGB相关性:42% (
|
|
2772
|
-
saturation: 0.36, // 饱和度:36%
|
|
2773
|
-
entropy: 0.22, // 像素熵:22%
|
|
2763
|
+
rgbCorrelation: 0.42, // RGB相关性:42% (完整图像中最强屏幕特征)
|
|
2764
|
+
saturation: 0.36, // 饱和度:36%
|
|
2765
|
+
entropy: 0.22, // 像素熵:22%
|
|
2774
2766
|
};
|
|
2775
|
-
|
|
2776
|
-
|
|
2777
|
-
|
|
2767
|
+
// 为每个特征计算连续得分(而不是二元的 0 或 1)
|
|
2768
|
+
// 这样即使特征未达到硬阈值,仍然可以贡献部分置信度
|
|
2769
|
+
// RGB 相关性:0.75-1.0 范围评分(屏幕通常 > 0.85)
|
|
2770
|
+
const rgbScore = Math.max(0, (rgbCorrelation.value - 0.7) / (1.0 - 0.7));
|
|
2771
|
+
// 饱和度:0-40 范围评分(屏幕通常 < 40)
|
|
2772
|
+
const satScore = Math.max(0, 1 - (saturation.value / 40));
|
|
2773
|
+
// 像素熵:4-8 范围评分(屏幕通常 < 6.5)
|
|
2774
|
+
const entScore = Math.max(0, 1 - (entropy.value / 8));
|
|
2775
|
+
const confidence = rgbScore * weights.rgbCorrelation +
|
|
2776
|
+
satScore * weights.saturation +
|
|
2777
|
+
entScore * weights.entropy;
|
|
2778
2778
|
return Math.min(1, Math.max(0, confidence));
|
|
2779
2779
|
}
|
|
2780
2780
|
|
|
2781
2781
|
// ==================== 类型定义 ====================
|
|
2782
2782
|
// ==================== 默认配置 ====================
|
|
2783
2783
|
const DEFAULT_CONFIG = {
|
|
2784
|
-
|
|
2784
|
+
// 针对完整高分辨率图像(1920×1080+)优化:
|
|
2785
|
+
// - 完整采样提供充足的屏幕像素网格
|
|
2786
|
+
// - 莫尔纹信号清晰,使用更严格的阈值
|
|
2787
|
+
moire_threshold: 0.55,
|
|
2785
2788
|
enable_dct: true,
|
|
2786
2789
|
enable_edge_detection: true,
|
|
2787
2790
|
};
|
|
@@ -2874,6 +2877,16 @@ function detectMoirePattern(cv, gray, config) {
|
|
|
2874
2877
|
const finalConfig = { ...DEFAULT_CONFIG, ...config };
|
|
2875
2878
|
if (!cv)
|
|
2876
2879
|
throw new Error('OpenCV instance not initialized');
|
|
2880
|
+
// 验证灰度图像是否有效
|
|
2881
|
+
if (!gray || gray.rows === 0 || gray.cols === 0) {
|
|
2882
|
+
console.warn('[MoirePattern] Invalid gray image');
|
|
2883
|
+
return {
|
|
2884
|
+
isScreenCapture: false,
|
|
2885
|
+
confidence: 0.0,
|
|
2886
|
+
moireStrength: 0.0,
|
|
2887
|
+
dominantFrequencies: [],
|
|
2888
|
+
};
|
|
2889
|
+
}
|
|
2877
2890
|
let moireStrength = 0;
|
|
2878
2891
|
let dominantFrequencies = [];
|
|
2879
2892
|
// 使用 DCT 频域分析(优先方案)
|
|
@@ -2883,19 +2896,25 @@ function detectMoirePattern(cv, gray, config) {
|
|
|
2883
2896
|
dominantFrequencies = dctResult.dominantFrequencies;
|
|
2884
2897
|
}
|
|
2885
2898
|
// 辅助:Canny 边缘检测方案用于增强检测
|
|
2886
|
-
if (finalConfig.enable_edge_detection) {
|
|
2887
|
-
|
|
2888
|
-
|
|
2889
|
-
|
|
2890
|
-
|
|
2891
|
-
|
|
2892
|
-
|
|
2893
|
-
|
|
2899
|
+
if (finalConfig.enable_edge_detection && moireStrength < 0.5) {
|
|
2900
|
+
try {
|
|
2901
|
+
const edges = new cv.Mat();
|
|
2902
|
+
cv.Canny(gray, edges, 50, 150);
|
|
2903
|
+
const periodicity = detectPeriodicity(cv, edges);
|
|
2904
|
+
const directionConsistency = analyzeEdgeDirection(cv, edges);
|
|
2905
|
+
edges.delete();
|
|
2906
|
+
// 融合两种方法的结果
|
|
2907
|
+
moireStrength += (periodicity + directionConsistency) * 0.5 * 0.4;
|
|
2908
|
+
}
|
|
2909
|
+
catch (edgeError) {
|
|
2910
|
+
console.warn('[MoirePattern] Edge detection failed, skipping:', edgeError);
|
|
2911
|
+
// 继续使用 DCT 结果
|
|
2912
|
+
}
|
|
2894
2913
|
}
|
|
2895
2914
|
const isScreenCapture = moireStrength > finalConfig.moire_threshold;
|
|
2896
2915
|
return {
|
|
2897
2916
|
isScreenCapture,
|
|
2898
|
-
confidence: Math.min(Math.
|
|
2917
|
+
confidence: Math.min(Math.max(0, moireStrength), 1.0),
|
|
2899
2918
|
moireStrength,
|
|
2900
2919
|
dominantFrequencies,
|
|
2901
2920
|
};
|
|
@@ -3446,6 +3465,10 @@ function analyzeEdgeDirection(cv, edges) {
|
|
|
3446
3465
|
|
|
3447
3466
|
/**
|
|
3448
3467
|
* RGB 发光模式检测的默认配置
|
|
3468
|
+
*
|
|
3469
|
+
* 针对完整高分辨率图像(1920×1080+)优化:
|
|
3470
|
+
* - 足够的频域采样,RGB子像素周期信号清晰
|
|
3471
|
+
* - 使用更严格的置信度阈值
|
|
3449
3472
|
*/
|
|
3450
3473
|
const DEFAULT_RGB_EMISSION_CONFIG = {
|
|
3451
3474
|
// 频率带分析参数
|
|
@@ -3797,7 +3820,8 @@ class ScreenCaptureDetector {
|
|
|
3797
3820
|
});
|
|
3798
3821
|
}
|
|
3799
3822
|
// 明确判定为屏幕捕捉时,直接返回
|
|
3800
|
-
|
|
3823
|
+
// 完整高分辨率图像:RGB信号应该很强
|
|
3824
|
+
const rgbCanDetermine = rgbEmissionResult.isScreenCapture && rgbEmissionResult.confidence > 0.65;
|
|
3801
3825
|
if (rgbCanDetermine) {
|
|
3802
3826
|
const totalTime = performance.now() - startTime;
|
|
3803
3827
|
if (debug) {
|
|
@@ -3833,7 +3857,8 @@ class ScreenCaptureDetector {
|
|
|
3833
3857
|
});
|
|
3834
3858
|
}
|
|
3835
3859
|
// 明确判定为屏幕捕捉时,直接返回
|
|
3836
|
-
|
|
3860
|
+
// 完整高分辨率图像:色彩特征应该清晰
|
|
3861
|
+
const colorCanDetermine = colorResult.isScreenCapture && colorResult.confidence > 0.65;
|
|
3837
3862
|
if (colorCanDetermine) {
|
|
3838
3863
|
const totalTime = performance.now() - startTime;
|
|
3839
3864
|
if (debug) {
|
|
@@ -3874,7 +3899,8 @@ class ScreenCaptureDetector {
|
|
|
3874
3899
|
});
|
|
3875
3900
|
}
|
|
3876
3901
|
// 明确判定为屏幕捕捉时,直接返回
|
|
3877
|
-
|
|
3902
|
+
// 完整高分辨率图像:莫尔纹应该很清晰
|
|
3903
|
+
const moireCanDetermine = moireResult.isScreenCapture && moireResult.confidence > 0.65;
|
|
3878
3904
|
if (moireCanDetermine) {
|
|
3879
3905
|
const totalTime = performance.now() - startTime;
|
|
3880
3906
|
if (debug) {
|
|
@@ -3890,9 +3916,10 @@ class ScreenCaptureDetector {
|
|
|
3890
3916
|
}
|
|
3891
3917
|
}
|
|
3892
3918
|
// 都不能明确判定,计算加权置信度
|
|
3893
|
-
|
|
3894
|
-
|
|
3895
|
-
|
|
3919
|
+
// 优化权重比例:针对完整高分辨率图像(1920×1080+)
|
|
3920
|
+
const weightedConfidence = rgbEmissionResult.confidence * 0.50 + // RGB权重 50%
|
|
3921
|
+
colorResult.confidence * 0.25 + // Color权重 25%
|
|
3922
|
+
moireResult.confidence * 0.25; // Moiré权重 25% (提升,完整图像中莫尔纹清晰)
|
|
3896
3923
|
// 第 3 层:用加权置信度判定最终结果
|
|
3897
3924
|
const isScreenCapture = weightedConfidence > this.confidenceThreshold;
|
|
3898
3925
|
// 根据加权置信度判断风险等级
|
|
@@ -4626,8 +4653,6 @@ class FaceDetectionEngine extends SimpleEventEmitter {
|
|
|
4626
4653
|
// 所有需要删除的 Mat 对象
|
|
4627
4654
|
let bgrFrame = null;
|
|
4628
4655
|
let grayFrame = null;
|
|
4629
|
-
let bgrFace = null;
|
|
4630
|
-
let grayFace = null;
|
|
4631
4656
|
try {
|
|
4632
4657
|
// 当前帧图片
|
|
4633
4658
|
bgrFrame = drawCanvasToMat(this.cv, frameCanvas, false);
|
|
@@ -4643,14 +4668,6 @@ class FaceDetectionEngine extends SimpleEventEmitter {
|
|
|
4643
4668
|
this.scheduleNextDetection(this.options.detect_error_retry_delay);
|
|
4644
4669
|
return;
|
|
4645
4670
|
}
|
|
4646
|
-
// 提取人脸区域图片及灰度图片
|
|
4647
|
-
bgrFace = bgrFrame.roi(new this.cv.Rect(faceBox[0], faceBox[1], faceBox[2], faceBox[3]));
|
|
4648
|
-
grayFace = matToGray(this.cv, bgrFace);
|
|
4649
|
-
if (!grayFace) {
|
|
4650
|
-
this.emitDebug('detection', 'Failed to convert face Mat to grayscale', {}, 'warn');
|
|
4651
|
-
this.scheduleNextDetection(this.options.detect_error_retry_delay);
|
|
4652
|
-
return;
|
|
4653
|
-
}
|
|
4654
4671
|
if (!this.detectionState.screenDetector) {
|
|
4655
4672
|
this.emit('detector-error', {
|
|
4656
4673
|
code: ErrorCode.INTERNAL_ERROR,
|
|
@@ -4668,7 +4685,7 @@ class FaceDetectionEngine extends SimpleEventEmitter {
|
|
|
4668
4685
|
return;
|
|
4669
4686
|
}
|
|
4670
4687
|
// 屏幕捕获检测, 只关心脸部区域
|
|
4671
|
-
const screenResult = this.detectionState.screenDetector.detect(
|
|
4688
|
+
const screenResult = this.detectionState.screenDetector.detect(bgrFrame, grayFrame, this.options.debug_mode);
|
|
4672
4689
|
// 屏幕捕获检测器已经准备就绪,其验证结果可信
|
|
4673
4690
|
if (screenResult.isScreenCapture) {
|
|
4674
4691
|
// 从 executedMethods 提取各检测器的置信度
|
|
@@ -4835,10 +4852,6 @@ class FaceDetectionEngine extends SimpleEventEmitter {
|
|
|
4835
4852
|
grayFrame.delete();
|
|
4836
4853
|
if (bgrFrame)
|
|
4837
4854
|
bgrFrame.delete();
|
|
4838
|
-
if (bgrFace)
|
|
4839
|
-
bgrFace.delete();
|
|
4840
|
-
if (grayFace)
|
|
4841
|
-
grayFace.delete();
|
|
4842
4855
|
}
|
|
4843
4856
|
}
|
|
4844
4857
|
/**
|