@sssxyd/face-liveness-detector 0.4.1-beta.3 → 0.4.1-beta.4
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 +49 -33
- package/dist/index.esm.js.map +1 -1
- package/dist/index.js +49 -33
- package/dist/index.js.map +1 -1
- package/dist/types/library-loader.d.ts.map +1 -1
- package/dist/types/motion-liveness-detector.d.ts +32 -21
- package/dist/types/motion-liveness-detector.d.ts.map +1 -1
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -1231,7 +1231,8 @@ function _createHumanConfig(backend, modelPath, wasmPath) {
|
|
|
1231
1231
|
return: true
|
|
1232
1232
|
},
|
|
1233
1233
|
mesh: {
|
|
1234
|
-
enabled: true // facemesh 脸部关键点(包含表情特征)
|
|
1234
|
+
enabled: true, // facemesh 脸部关键点(包含表情特征)
|
|
1235
|
+
keepInvalid: false // 只保留有效的网格数据
|
|
1235
1236
|
},
|
|
1236
1237
|
iris: { enabled: false },
|
|
1237
1238
|
antispoof: { enabled: false },
|
|
@@ -1664,9 +1665,18 @@ class MotionLivenessDetector {
|
|
|
1664
1665
|
}
|
|
1665
1666
|
}
|
|
1666
1667
|
else {
|
|
1668
|
+
const lm = currentKeypoints.landmarks || [];
|
|
1669
|
+
const debug = {
|
|
1670
|
+
'faceResult.mesh存在': !!faceResult.mesh,
|
|
1671
|
+
'mesh长度': faceResult.mesh?.length || 0,
|
|
1672
|
+
'faceResult.annotations存在': !!faceResult.annotations,
|
|
1673
|
+
'annotations键数': Object.keys(faceResult.annotations || {}).length,
|
|
1674
|
+
'currentKeypoints.landmarks长度': lm.length
|
|
1675
|
+
};
|
|
1667
1676
|
return this.createEmptyResult({
|
|
1668
1677
|
reason: '缺少面部关键点,无法进行活体检测',
|
|
1669
|
-
landmarks: currentKeypoints.landmarks
|
|
1678
|
+
landmarks: currentKeypoints.landmarks,
|
|
1679
|
+
debug
|
|
1670
1680
|
});
|
|
1671
1681
|
}
|
|
1672
1682
|
// 数据不足时,继续收集
|
|
@@ -1971,8 +1981,9 @@ class MotionLivenessDetector {
|
|
|
1971
1981
|
];
|
|
1972
1982
|
const zValues = [];
|
|
1973
1983
|
for (const ptIdx of samplePoints) {
|
|
1974
|
-
|
|
1975
|
-
|
|
1984
|
+
const point = latestFrame[ptIdx];
|
|
1985
|
+
if (point && point.length >= 3 && typeof point[2] === 'number') {
|
|
1986
|
+
zValues.push(point[2]);
|
|
1976
1987
|
}
|
|
1977
1988
|
}
|
|
1978
1989
|
if (zValues.length < 5) {
|
|
@@ -2484,7 +2495,7 @@ class MotionLivenessDetector {
|
|
|
2484
2495
|
detectHomographyConstraint() {
|
|
2485
2496
|
// 【关键】使用归一化坐标历史
|
|
2486
2497
|
if (this.normalizedLandmarksHistory.length < 2) {
|
|
2487
|
-
return { planarScore: 0
|
|
2498
|
+
return { planarScore: 0 };
|
|
2488
2499
|
}
|
|
2489
2500
|
const frame1 = this.normalizedLandmarksHistory[0];
|
|
2490
2501
|
const frame2 = this.normalizedLandmarksHistory[this.normalizedLandmarksHistory.length - 1];
|
|
@@ -2601,7 +2612,7 @@ class MotionLivenessDetector {
|
|
|
2601
2612
|
detectDepthConsistency() {
|
|
2602
2613
|
const latestFrame = this.faceLandmarksHistory[this.faceLandmarksHistory.length - 1];
|
|
2603
2614
|
if (!latestFrame || latestFrame.length < 468) {
|
|
2604
|
-
return { depthVariation: 0.5
|
|
2615
|
+
return { depthVariation: 0.5 };
|
|
2605
2616
|
}
|
|
2606
2617
|
// 采样不同深度区域的点
|
|
2607
2618
|
const nosePoints = [1, 4, 5, 6]; // 鼻子(应该凸出)
|
|
@@ -2611,8 +2622,9 @@ class MotionLivenessDetector {
|
|
|
2611
2622
|
const getAvgZ = (points) => {
|
|
2612
2623
|
let sum = 0, count = 0;
|
|
2613
2624
|
for (const idx of points) {
|
|
2614
|
-
|
|
2615
|
-
|
|
2625
|
+
const point = latestFrame[idx];
|
|
2626
|
+
if (point && point.length >= 3 && typeof point[2] === 'number') {
|
|
2627
|
+
sum += point[2];
|
|
2616
2628
|
count++;
|
|
2617
2629
|
}
|
|
2618
2630
|
}
|
|
@@ -2666,8 +2678,10 @@ class MotionLivenessDetector {
|
|
|
2666
2678
|
const curr = this.faceLandmarksHistory[i];
|
|
2667
2679
|
const changes = [];
|
|
2668
2680
|
for (const idx of samplePoints) {
|
|
2669
|
-
|
|
2670
|
-
|
|
2681
|
+
const prevPoint = prev[idx];
|
|
2682
|
+
const currPoint = curr[idx];
|
|
2683
|
+
if (prevPoint && currPoint && prevPoint.length >= 3 && currPoint.length >= 3 && typeof prevPoint[2] === 'number' && typeof currPoint[2] === 'number') {
|
|
2684
|
+
changes.push(currPoint[2] - prevPoint[2]);
|
|
2671
2685
|
}
|
|
2672
2686
|
}
|
|
2673
2687
|
if (changes.length >= 3) {
|
|
@@ -2894,38 +2908,40 @@ class MotionLivenessDetector {
|
|
|
2894
2908
|
if (face.mesh && Array.isArray(face.mesh)) {
|
|
2895
2909
|
keypoints.landmarks = face.mesh;
|
|
2896
2910
|
}
|
|
2897
|
-
|
|
2911
|
+
// 类型守卫:确保landmarks存在且长度足够
|
|
2912
|
+
const landmarks = keypoints.landmarks;
|
|
2913
|
+
if (landmarks && Array.isArray(landmarks) && landmarks.length >= 468) {
|
|
2898
2914
|
// 左眼关键点 (MediaPipe Face Mesh 标准索引)
|
|
2899
2915
|
// 按顺序:外眼角、上眼睑上、上眼睑、内眼角、下眼睑、下眼睑下
|
|
2900
2916
|
keypoints.leftEye = [
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2917
|
+
landmarks[362], // 外眼角
|
|
2918
|
+
landmarks[385], // 上眼睑上
|
|
2919
|
+
landmarks[387], // 上眼睑
|
|
2920
|
+
landmarks[263], // 内眼角
|
|
2921
|
+
landmarks[373], // 下眼睑
|
|
2922
|
+
landmarks[380] // 下眼睑下
|
|
2907
2923
|
].filter(p => p !== undefined);
|
|
2908
2924
|
// 右眼关键点 (MediaPipe Face Mesh 标准索引)
|
|
2909
2925
|
keypoints.rightEye = [
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2913
|
-
|
|
2914
|
-
|
|
2915
|
-
|
|
2926
|
+
landmarks[33], // 外眼角
|
|
2927
|
+
landmarks[160], // 上眼睑上
|
|
2928
|
+
landmarks[158], // 上眼睑
|
|
2929
|
+
landmarks[133], // 内眼角
|
|
2930
|
+
landmarks[153], // 下眼睑
|
|
2931
|
+
landmarks[144] // 下眼睑下
|
|
2916
2932
|
].filter(p => p !== undefined);
|
|
2917
2933
|
// 嘴巴关键点
|
|
2918
2934
|
keypoints.mouth = [
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2922
|
-
|
|
2923
|
-
|
|
2924
|
-
|
|
2925
|
-
|
|
2926
|
-
|
|
2927
|
-
|
|
2928
|
-
|
|
2935
|
+
landmarks[61], // 左嘴角
|
|
2936
|
+
landmarks[185], // 上嘴唇左
|
|
2937
|
+
landmarks[40], // 上嘴唇中左
|
|
2938
|
+
landmarks[39], // 上嘴唇中
|
|
2939
|
+
landmarks[37], // 上嘴唇中右
|
|
2940
|
+
landmarks[0], // 上嘴唇右
|
|
2941
|
+
landmarks[267], // 下嘴唇右
|
|
2942
|
+
landmarks[269], // 下嘴唇中右
|
|
2943
|
+
landmarks[270], // 下嘴唇中
|
|
2944
|
+
landmarks[409] // 下嘴唇左
|
|
2929
2945
|
].filter(p => p !== undefined);
|
|
2930
2946
|
}
|
|
2931
2947
|
return keypoints;
|