@utamuratov/ngx-face-id 0.4.0 → 0.4.2
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.
|
@@ -30,37 +30,39 @@ class LivenessService {
|
|
|
30
30
|
}
|
|
31
31
|
// ---------- HELPERS ----------
|
|
32
32
|
isFaceInsideOval(box, video) {
|
|
33
|
-
const
|
|
34
|
-
const
|
|
35
|
-
//
|
|
36
|
-
const
|
|
33
|
+
const vw = video.videoWidth;
|
|
34
|
+
const vh = video.videoHeight;
|
|
35
|
+
// Oval markazi
|
|
36
|
+
const cx = vw / 2;
|
|
37
|
+
const cy = vh / 2;
|
|
38
|
+
// Oval radius (x va y o'qlari bo'yicha)
|
|
39
|
+
// CSS: width = 80% → radius = 40%
|
|
40
|
+
const rx = vw * 0.4;
|
|
37
41
|
const ry = rx * (6 / 5); // aspect-ratio: 5/6
|
|
38
|
-
// 1️⃣
|
|
42
|
+
// 1️⃣ Face edge points
|
|
39
43
|
const points = [
|
|
40
|
-
{ x: box.x, y: box.y + box.height / 2 }, //
|
|
41
|
-
{ x: box.x + box.width, y: box.y + box.height / 2 }, //
|
|
42
|
-
{ x: box.x + box.width / 2, y: box.y }, //
|
|
43
|
-
{ x: box.x + box.width / 2, y: box.y + box.height }, //
|
|
44
|
+
{ x: box.x, y: box.y + box.height / 2 }, // left
|
|
45
|
+
{ x: box.x + box.width, y: box.y + box.height / 2 }, // right
|
|
46
|
+
{ x: box.x + box.width / 2, y: box.y }, // top
|
|
47
|
+
{ x: box.x + box.width / 2, y: box.y + box.height }, // bottom
|
|
44
48
|
];
|
|
45
49
|
const inside = points.every((p) => {
|
|
46
|
-
const v = Math.pow(p.x - cx
|
|
47
|
-
return v <= 1;
|
|
50
|
+
const v = Math.pow((p.x - cx) / rx, 2) + Math.pow((p.y - cy) / ry, 2);
|
|
51
|
+
return v <= 1.1;
|
|
48
52
|
});
|
|
49
53
|
if (!inside) {
|
|
50
54
|
this.faceInsideStatus.set('OUTSIDE_OVAL');
|
|
51
55
|
return false;
|
|
52
56
|
}
|
|
53
|
-
// 2️⃣
|
|
57
|
+
// 2️⃣ Fill ratio
|
|
54
58
|
const faceArea = box.width * box.height;
|
|
55
59
|
const ovalArea = Math.PI * rx * ry;
|
|
56
60
|
const fillRatio = faceArea / ovalArea;
|
|
57
|
-
|
|
58
|
-
if (fillRatio < 0.4) {
|
|
61
|
+
if (fillRatio < 0.42) {
|
|
59
62
|
this.faceInsideStatus.set('COME_CLOSE');
|
|
60
63
|
return false;
|
|
61
64
|
}
|
|
62
|
-
|
|
63
|
-
if (fillRatio > 0.59) {
|
|
65
|
+
if (fillRatio > 0.6) {
|
|
64
66
|
this.faceInsideStatus.set('VERY_CLOSE');
|
|
65
67
|
return false;
|
|
66
68
|
}
|
|
@@ -182,9 +184,9 @@ class NgxFaceLiveness {
|
|
|
182
184
|
}
|
|
183
185
|
switch (this.currentStep()) {
|
|
184
186
|
case 'BLINK':
|
|
185
|
-
return '👁 Ko‘zingizni yumib oching(
|
|
187
|
+
return '👁 Ko‘zingizni yumib oching(2 marta)';
|
|
186
188
|
case 'MOUTH':
|
|
187
|
-
return '🙂 Og‘zingizni ochib yuming
|
|
189
|
+
return '🙂 Og‘zingizni ochib yuming';
|
|
188
190
|
case 'HEAD':
|
|
189
191
|
return '↔️ Boshni chapga yoki o‘ngga burang';
|
|
190
192
|
case 'HOLD':
|
|
@@ -206,10 +208,30 @@ class NgxFaceLiveness {
|
|
|
206
208
|
}, 300);
|
|
207
209
|
}
|
|
208
210
|
async openCamera() {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
211
|
+
try {
|
|
212
|
+
const devices = await navigator.mediaDevices.enumerateDevices();
|
|
213
|
+
const videoDevices = devices.filter((d) => d.kind === 'videoinput');
|
|
214
|
+
if (!videoDevices.length) {
|
|
215
|
+
throw new Error('No video devices found');
|
|
216
|
+
}
|
|
217
|
+
// USB yoki default camera tanlash
|
|
218
|
+
const stream = await navigator.mediaDevices.getUserMedia({
|
|
219
|
+
video: {
|
|
220
|
+
deviceId: videoDevices[0].deviceId,
|
|
221
|
+
aspectRatio: 3 / 4,
|
|
222
|
+
width: { min: 480 },
|
|
223
|
+
height: { min: 640 },
|
|
224
|
+
}, // birinchi topilgan kamera
|
|
225
|
+
});
|
|
226
|
+
this.videoRef.nativeElement.srcObject = stream;
|
|
227
|
+
}
|
|
228
|
+
catch (err) {
|
|
229
|
+
console.error('Cannot access camera:', err);
|
|
230
|
+
}
|
|
231
|
+
// const stream = await navigator.mediaDevices.getUserMedia({
|
|
232
|
+
// video: { facingMode: 'user', aspectRatio: 3 / 4, width: { min: 480 }, height: { min: 640 } },
|
|
233
|
+
// });
|
|
234
|
+
// this.videoRef.nativeElement.srcObject = stream;
|
|
213
235
|
}
|
|
214
236
|
async capture() {
|
|
215
237
|
const video = this.videoRef.nativeElement;
|
|
@@ -265,7 +287,7 @@ class NgxFaceLiveness {
|
|
|
265
287
|
<p class="hint">{{ stepText() }}</p>
|
|
266
288
|
</div>
|
|
267
289
|
</div>
|
|
268
|
-
`, isInline: true, styles: [":host{display:flex;align-items:center;justify-content:center;height:100vh;padding:1rem}.camera-wrapper{position:relative;width:100%;max-width:
|
|
290
|
+
`, isInline: true, styles: [":host{display:flex;align-items:center;justify-content:center;height:100vh;padding:1rem}.camera-wrapper{position:relative;width:100%;max-width:480px;aspect-ratio:3/4;margin:auto;overflow:hidden;border-radius:1rem;background:#65a0f8}.camera-video{width:100%;height:100%;border-radius:12px}.overlay{position:absolute;inset:0;pointer-events:none;display:flex;flex-direction:column;align-items:center;justify-content:center}.oval-mask{width:80%;aspect-ratio:5/6;border-radius:50%;border:4px dashed #65a0f8;background:transparent;box-shadow:0 0 0 9999px #0009}.hint{margin-top:12px;color:#fff;font-size:14px;text-align:center;position:absolute;top:5px;background-color:#0000007a;padding:2px 4px;border-radius:5px}.captured-image{position:absolute;top:0;left:0;width:100%;height:100%;object-fit:cover;border-radius:12px}\n"] });
|
|
269
291
|
}
|
|
270
292
|
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImport: i0, type: NgxFaceLiveness, decorators: [{
|
|
271
293
|
type: Component,
|
|
@@ -282,7 +304,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.2", ngImpor
|
|
|
282
304
|
<p class="hint">{{ stepText() }}</p>
|
|
283
305
|
</div>
|
|
284
306
|
</div>
|
|
285
|
-
`, styles: [":host{display:flex;align-items:center;justify-content:center;height:100vh;padding:1rem}.camera-wrapper{position:relative;width:100%;max-width:
|
|
307
|
+
`, styles: [":host{display:flex;align-items:center;justify-content:center;height:100vh;padding:1rem}.camera-wrapper{position:relative;width:100%;max-width:480px;aspect-ratio:3/4;margin:auto;overflow:hidden;border-radius:1rem;background:#65a0f8}.camera-video{width:100%;height:100%;border-radius:12px}.overlay{position:absolute;inset:0;pointer-events:none;display:flex;flex-direction:column;align-items:center;justify-content:center}.oval-mask{width:80%;aspect-ratio:5/6;border-radius:50%;border:4px dashed #65a0f8;background:transparent;box-shadow:0 0 0 9999px #0009}.hint{margin-top:12px;color:#fff;font-size:14px;text-align:center;position:absolute;top:5px;background-color:#0000007a;padding:2px 4px;border-radius:5px}.captured-image{position:absolute;top:0;left:0;width:100%;height:100%;object-fit:cover;border-radius:12px}\n"] }]
|
|
286
308
|
}], ctorParameters: () => [{ type: LivenessService }], propDecorators: { videoRef: [{
|
|
287
309
|
type: ViewChild,
|
|
288
310
|
args: ['video']
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"utamuratov-ngx-face-id.mjs","sources":["../../../projects/ngx-face-id/src/lib/face-liveness/liveness.service.ts","../../../projects/ngx-face-id/src/lib/face-liveness/face-liveness.ts","../../../projects/ngx-face-id/src/public-api.ts","../../../projects/ngx-face-id/src/utamuratov-ngx-face-id.ts"],"sourcesContent":["import { computed, Injectable, signal } from '@angular/core';\nimport * as faceapi from 'face-api.js';\n\ntype Step =\n // | 'NO_FACE'\n // | 'OUTSIDE_OVAL'\n // | 'COME_CLOSE'\n // | 'VERY_CLOSE'\n 'BLINK' | 'MOUTH' | 'HEAD' | 'HOLD' | 'DONE';\n\ntype FaceInside = 'NO_FACE' | 'OUTSIDE_OVAL' | 'COME_CLOSE' | 'VERY_CLOSE' | 'VALID';\n\n@Injectable({ providedIn: 'root' })\nexport class LivenessService {\n private step = signal<Step>('BLINK');\n private faceInsideStatus = signal<FaceInside>('OUTSIDE_OVAL');\n currentStep = computed(() => this.step());\n currentFaceInsideStatus = computed(() => this.faceInsideStatus());\n\n private prevBlinkAvg = 0;\n private blinkCount = 0;\n private prevNoseX?: number;\n private holdStart?: number;\n\n async loadModels() {\n const MODEL_URL = '/models';\n await Promise.all([\n faceapi.nets.tinyFaceDetector.loadFromUri(MODEL_URL),\n faceapi.nets.faceLandmark68Net.loadFromUri(MODEL_URL),\n faceapi.nets.faceRecognitionNet.loadFromUri(MODEL_URL),\n ]);\n }\n\n reset() {\n this.faceInsideStatus.set('OUTSIDE_OVAL');\n this.step.set('BLINK');\n this.blinkCount = 0;\n this.prevBlinkAvg = 0;\n this.prevNoseX = undefined;\n this.holdStart = undefined;\n }\n\n // ---------- HELPERS ----------\n\n private isFaceInsideOval(box: faceapi.Box, video: HTMLVideoElement): boolean {\n const cx = video.videoWidth / 2;\n const cy = video.videoHeight / 2;\n\n // ✅ CSS: width: 50% → radius = 25%\n const rx = video.videoWidth * 0.25;\n const ry = rx * (6 / 5); // aspect-ratio: 5/6\n\n // 1️⃣ Yuzning 4 ta chekkasi oval ichida bo'lishi kerak\n const points = [\n { x: box.x, y: box.y + box.height / 2 }, // chap\n { x: box.x + box.width, y: box.y + box.height / 2 }, // o'ng\n { x: box.x + box.width / 2, y: box.y }, // tepa\n { x: box.x + box.width / 2, y: box.y + box.height }, // past\n ];\n\n const inside = points.every((p) => {\n const v = Math.pow(p.x - cx, 2) / Math.pow(rx, 2) + Math.pow(p.y - cy, 2) / Math.pow(ry, 2);\n return v <= 1;\n });\n\n if (!inside) {\n this.faceInsideStatus.set('OUTSIDE_OVAL');\n return false;\n }\n\n // 2️⃣ Yuz ovalni yaxshi to'ldirishi kerak (70-90%)\n const faceArea = box.width * box.height;\n const ovalArea = Math.PI * rx * ry;\n const fillRatio = faceArea / ovalArea;\n\n // Juda uzoq\n if (fillRatio < 0.4) {\n this.faceInsideStatus.set('COME_CLOSE');\n return false;\n }\n\n // Juda yaqin\n if (fillRatio > 0.59) {\n this.faceInsideStatus.set('VERY_CLOSE');\n return false;\n }\n\n this.faceInsideStatus.set('VALID');\n return true;\n }\n\n private dist(a: any, b: any) {\n return Math.hypot(a.x - b.x, a.y - b.y);\n }\n\n private eyeEAR(eye: faceapi.Point[]) {\n return (\n (this.dist(eye[1], eye[5]) + this.dist(eye[2], eye[4])) / (2 * this.dist(eye[0], eye[3]))\n );\n }\n\n private isBlink(lm: faceapi.FaceLandmarks68) {\n const left = this.eyeEAR(lm.getLeftEye());\n const right = this.eyeEAR(lm.getRightEye());\n const avg = (left + right) / 2;\n\n if (this.prevBlinkAvg === 0 || Math.abs(avg - this.prevBlinkAvg) < 0.01) {\n this.prevBlinkAvg = avg;\n return false;\n }\n\n this.prevBlinkAvg = avg;\n this.blinkCount++;\n return this.blinkCount > 2;\n }\n\n private isMouthOpen(lm: faceapi.FaceLandmarks68) {\n const mouth = lm.getMouth();\n return this.dist(mouth[13], mouth[19]) / this.dist(mouth[0], mouth[6]) > 0.4;\n }\n\n private isHeadMoved(lm: faceapi.FaceLandmarks68) {\n const nose = lm.getNose()[3];\n if (!this.prevNoseX) {\n this.prevNoseX = nose.x;\n return false;\n }\n const moved = Math.abs(nose.x - this.prevNoseX) > 30;\n\n this.prevNoseX = nose.x;\n return moved;\n }\n\n // ---------- MAIN CHECK ----------\n\n async process(video: HTMLVideoElement): Promise<boolean> {\n const result = await faceapi\n .detectSingleFace(video, new faceapi.TinyFaceDetectorOptions())\n .withFaceLandmarks();\n\n if (!result) {\n this.faceInsideStatus.set('NO_FACE');\n return false;\n }\n\n // 👇 OVAL CHECK\n const insideOval = this.isFaceInsideOval(result.detection.box, video);\n\n if (!insideOval) {\n if (this.step() === 'HOLD') {\n this.holdStart = Date.now();\n }\n return false;\n }\n\n const lm = result.landmarks;\n\n if (this.step() === 'BLINK' && this.isBlink(lm)) {\n this.step.set('MOUTH');\n } else if (this.step() === 'MOUTH' && this.isMouthOpen(lm)) {\n this.step.set('HEAD');\n } else if (this.step() === 'HEAD' && this.isHeadMoved(lm)) {\n this.step.set('HOLD');\n this.holdStart = Date.now();\n } else if (this.step() === 'HOLD') {\n if (!this.holdStart) this.holdStart = Date.now();\n if (Date.now() - this.holdStart > 3000) {\n this.step.set('DONE');\n return true; // 📸 CAPTURE SIGNAL\n }\n }\n\n return false;\n }\n}\n","import {\n Component,\n ElementRef,\n ViewChild,\n OnInit,\n computed,\n output,\n inject,\n PLATFORM_ID,\n signal,\n} from '@angular/core';\nimport { LivenessService } from './liveness.service';\nimport { isPlatformBrowser } from '@angular/common';\n\n@Component({\n selector: 'ngx-face-liveness',\n template: `\n <div class=\"camera-wrapper\">\n @if (capturesImageSrc()) {\n <img [src]=\"capturesImageSrc()\" alt=\"Captured Image\" class=\"captured-image\" />\n }\n <video #video autoplay muted playsinline class=\"camera-video\"></video>\n\n <!-- Overlay -->\n <div class=\"overlay\">\n <div class=\"oval-mask\" [style.borderColor]=\"isNotValidOval() ? '#fb2c36' : '#65a0f8'\"></div>\n <p class=\"hint\">{{ stepText() }}</p>\n </div>\n </div>\n `,\n styleUrls: ['./face-liveness.scss'],\n})\nexport class NgxFaceLiveness implements OnInit {\n private platformId = inject(PLATFORM_ID);\n private isBrowser = isPlatformBrowser(this.platformId);\n\n @ViewChild('video') videoRef!: ElementRef<HTMLVideoElement>;\n intervalId: any;\n\n capturedImage = output<Blob>();\n capturesImageSrc = signal<string | null>(null);\n\n constructor(private liveness: LivenessService) {}\n\n async ngOnInit() {\n if (!this.isBrowser) return;\n\n await this.liveness.loadModels();\n await this.start();\n }\n\n currentStep = computed(() => this.liveness.currentStep());\n currentFaceInsideStatus = computed(() => this.liveness.currentFaceInsideStatus());\n isNotValidOval = computed(\n () =>\n this.currentFaceInsideStatus() === 'OUTSIDE_OVAL' ||\n this.currentFaceInsideStatus() === 'NO_FACE',\n );\n stepText = computed(() => {\n const currentFaceStatus = this.currentFaceInsideStatus();\n\n if (currentFaceStatus === 'NO_FACE') {\n return '❌ Yuz aniqlanmadi, iltimos, kameraga qarang';\n }\n if (currentFaceStatus === 'OUTSIDE_OVAL') {\n return '📐 Iltimos, yuzingizni oval ichiga joylashtiring';\n }\n if (currentFaceStatus === 'COME_CLOSE') {\n return '🔍 Iltimos, kameraga yaqinroq turing';\n }\n if (currentFaceStatus === 'VERY_CLOSE') {\n return '📷 Juda yaqin, kamerani orqaroq oling';\n }\n\n switch (this.currentStep()) {\n case 'BLINK':\n return '👁 Ko‘zingizni yumib oching(kamida 2 marta)';\n case 'MOUTH':\n return '🙂 Og‘zingizni ochib yuming (kamida yarim ochish kerak)';\n case 'HEAD':\n return '↔️ Boshni chapga yoki o‘ngga burang';\n case 'HOLD':\n return '✋ Barqaror turing (2 soniya)';\n default:\n return '✅ Tayyor!';\n }\n });\n\n async start() {\n this.liveness.reset();\n await this.openCamera();\n\n this.intervalId = setInterval(async () => {\n const done = await this.liveness.process(this.videoRef.nativeElement);\n\n if (done) {\n clearInterval(this.intervalId);\n const blob = await this.capture();\n this.sendToBackend(blob);\n }\n }, 300);\n }\n\n async openCamera() {\n const stream = await navigator.mediaDevices.getUserMedia({\n video: { facingMode: 'user' },\n });\n this.videoRef.nativeElement.srcObject = stream;\n }\n\n async capture(): Promise<Blob> {\n const video = this.videoRef.nativeElement;\n const canvas = document.createElement('canvas');\n\n canvas.width = video.videoWidth;\n canvas.height = video.videoHeight;\n\n canvas.getContext('2d')!.drawImage(video, 0, 0);\n\n return new Promise((res) => canvas.toBlob((b) => res(b!), 'image/jpeg', 0.9));\n }\n\n sendToBackend(blob: Blob) {\n this.capturedImage.emit(blob);\n this.capturesImageSrc.set(URL.createObjectURL(blob));\n console.log(blob);\n\n // const fd = new FormData();\n // fd.append('file', blob, 'face.jpg');\n // this.http.post('/api/face/verify', fd).subscribe();\n }\n\n ngOnDestroy(): void {\n if (!this.isBrowser) return;\n\n this.cleanup();\n }\n\n private cleanup() {\n // 1️⃣ Interval\n if (this.intervalId) {\n clearInterval(this.intervalId);\n this.intervalId = null;\n }\n\n // 2️⃣ Kamera\n const video = this.videoRef?.nativeElement;\n if (video) {\n video.pause();\n\n const stream = video.srcObject as MediaStream | null;\n if (stream) {\n stream.getTracks().forEach((track) => track.stop());\n }\n\n video.srcObject = null;\n }\n\n // 3️⃣ Service state\n this.liveness.reset();\n }\n}\n","/*\r\n * Public API Surface of ngx-face-id\r\n */\r\n\r\nexport * from './lib/face-liveness/face-liveness';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.LivenessService"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"utamuratov-ngx-face-id.mjs","sources":["../../../projects/ngx-face-id/src/lib/face-liveness/liveness.service.ts","../../../projects/ngx-face-id/src/lib/face-liveness/face-liveness.ts","../../../projects/ngx-face-id/src/public-api.ts","../../../projects/ngx-face-id/src/utamuratov-ngx-face-id.ts"],"sourcesContent":["import { computed, Injectable, signal } from '@angular/core';\nimport * as faceapi from 'face-api.js';\n\ntype Step = 'BLINK' | 'MOUTH' | 'HEAD' | 'HOLD' | 'DONE';\n\ntype FaceInside = 'NO_FACE' | 'OUTSIDE_OVAL' | 'COME_CLOSE' | 'VERY_CLOSE' | 'VALID';\n\n@Injectable({ providedIn: 'root' })\nexport class LivenessService {\n private step = signal<Step>('BLINK');\n private faceInsideStatus = signal<FaceInside>('OUTSIDE_OVAL');\n currentStep = computed(() => this.step());\n currentFaceInsideStatus = computed(() => this.faceInsideStatus());\n\n private prevBlinkAvg = 0;\n private blinkCount = 0;\n private prevNoseX?: number;\n private holdStart?: number;\n\n async loadModels() {\n const MODEL_URL = '/models';\n await Promise.all([\n faceapi.nets.tinyFaceDetector.loadFromUri(MODEL_URL),\n faceapi.nets.faceLandmark68Net.loadFromUri(MODEL_URL),\n faceapi.nets.faceRecognitionNet.loadFromUri(MODEL_URL),\n ]);\n }\n\n reset() {\n this.faceInsideStatus.set('OUTSIDE_OVAL');\n this.step.set('BLINK');\n this.blinkCount = 0;\n this.prevBlinkAvg = 0;\n this.prevNoseX = undefined;\n this.holdStart = undefined;\n }\n\n // ---------- HELPERS ----------\n\n private isFaceInsideOval(box: faceapi.Box, video: HTMLVideoElement): boolean {\n const vw = video.videoWidth;\n const vh = video.videoHeight;\n\n // Oval markazi\n const cx = vw / 2;\n const cy = vh / 2;\n\n // Oval radius (x va y o'qlari bo'yicha)\n // CSS: width = 80% → radius = 40%\n const rx = vw * 0.4;\n const ry = rx * (6 / 5); // aspect-ratio: 5/6\n\n // 1️⃣ Face edge points\n const points = [\n { x: box.x, y: box.y + box.height / 2 }, // left\n { x: box.x + box.width, y: box.y + box.height / 2 }, // right\n { x: box.x + box.width / 2, y: box.y }, // top\n { x: box.x + box.width / 2, y: box.y + box.height }, // bottom\n ];\n\n const inside = points.every((p) => {\n const v = Math.pow((p.x - cx) / rx, 2) + Math.pow((p.y - cy) / ry, 2);\n return v <= 1.1;\n });\n\n if (!inside) {\n this.faceInsideStatus.set('OUTSIDE_OVAL');\n return false;\n }\n\n // 2️⃣ Fill ratio\n const faceArea = box.width * box.height;\n const ovalArea = Math.PI * rx * ry;\n const fillRatio = faceArea / ovalArea;\n\n if (fillRatio < 0.42) {\n this.faceInsideStatus.set('COME_CLOSE');\n return false;\n }\n\n if (fillRatio > 0.6) {\n this.faceInsideStatus.set('VERY_CLOSE');\n return false;\n }\n\n this.faceInsideStatus.set('VALID');\n return true;\n }\n\n private dist(a: any, b: any) {\n return Math.hypot(a.x - b.x, a.y - b.y);\n }\n\n private eyeEAR(eye: faceapi.Point[]) {\n return (\n (this.dist(eye[1], eye[5]) + this.dist(eye[2], eye[4])) / (2 * this.dist(eye[0], eye[3]))\n );\n }\n\n private isBlink(lm: faceapi.FaceLandmarks68) {\n const left = this.eyeEAR(lm.getLeftEye());\n const right = this.eyeEAR(lm.getRightEye());\n const avg = (left + right) / 2;\n\n if (this.prevBlinkAvg === 0 || Math.abs(avg - this.prevBlinkAvg) < 0.01) {\n this.prevBlinkAvg = avg;\n return false;\n }\n\n this.prevBlinkAvg = avg;\n this.blinkCount++;\n return this.blinkCount > 2;\n }\n\n private isMouthOpen(lm: faceapi.FaceLandmarks68) {\n const mouth = lm.getMouth();\n return this.dist(mouth[13], mouth[19]) / this.dist(mouth[0], mouth[6]) > 0.4;\n }\n\n private isHeadMoved(lm: faceapi.FaceLandmarks68) {\n const nose = lm.getNose()[3];\n if (!this.prevNoseX) {\n this.prevNoseX = nose.x;\n return false;\n }\n const moved = Math.abs(nose.x - this.prevNoseX) > 30;\n\n this.prevNoseX = nose.x;\n return moved;\n }\n\n // ---------- MAIN CHECK ----------\n\n async process(video: HTMLVideoElement): Promise<boolean> {\n const result = await faceapi\n .detectSingleFace(video, new faceapi.TinyFaceDetectorOptions())\n .withFaceLandmarks();\n\n if (!result) {\n this.faceInsideStatus.set('NO_FACE');\n return false;\n }\n\n // 👇 OVAL CHECK\n const insideOval = this.isFaceInsideOval(result.detection.box, video);\n\n if (!insideOval) {\n if (this.step() === 'HOLD') {\n this.holdStart = Date.now();\n }\n return false;\n }\n\n const lm = result.landmarks;\n\n if (this.step() === 'BLINK' && this.isBlink(lm)) {\n this.step.set('MOUTH');\n } else if (this.step() === 'MOUTH' && this.isMouthOpen(lm)) {\n this.step.set('HEAD');\n } else if (this.step() === 'HEAD' && this.isHeadMoved(lm)) {\n this.step.set('HOLD');\n this.holdStart = Date.now();\n } else if (this.step() === 'HOLD') {\n if (!this.holdStart) this.holdStart = Date.now();\n if (Date.now() - this.holdStart > 3000) {\n this.step.set('DONE');\n return true; // 📸 CAPTURE SIGNAL\n }\n }\n\n return false;\n }\n}\n","import {\n Component,\n ElementRef,\n ViewChild,\n OnInit,\n computed,\n output,\n inject,\n PLATFORM_ID,\n signal,\n} from '@angular/core';\nimport { LivenessService } from './liveness.service';\nimport { isPlatformBrowser } from '@angular/common';\n\n@Component({\n selector: 'ngx-face-liveness',\n template: `\n <div class=\"camera-wrapper\">\n @if (capturesImageSrc()) {\n <img [src]=\"capturesImageSrc()\" alt=\"Captured Image\" class=\"captured-image\" />\n }\n <video #video autoplay muted playsinline class=\"camera-video\"></video>\n\n <!-- Overlay -->\n <div class=\"overlay\">\n <div class=\"oval-mask\" [style.borderColor]=\"isNotValidOval() ? '#fb2c36' : '#65a0f8'\"></div>\n <p class=\"hint\">{{ stepText() }}</p>\n </div>\n </div>\n `,\n styleUrls: ['./face-liveness.scss'],\n})\nexport class NgxFaceLiveness implements OnInit {\n private platformId = inject(PLATFORM_ID);\n private isBrowser = isPlatformBrowser(this.platformId);\n\n @ViewChild('video') videoRef!: ElementRef<HTMLVideoElement>;\n intervalId: any;\n\n capturedImage = output<Blob>();\n capturesImageSrc = signal<string | null>(null);\n\n constructor(private liveness: LivenessService) {}\n\n async ngOnInit() {\n if (!this.isBrowser) return;\n\n await this.liveness.loadModels();\n await this.start();\n }\n\n currentStep = computed(() => this.liveness.currentStep());\n currentFaceInsideStatus = computed(() => this.liveness.currentFaceInsideStatus());\n isNotValidOval = computed(\n () =>\n this.currentFaceInsideStatus() === 'OUTSIDE_OVAL' ||\n this.currentFaceInsideStatus() === 'NO_FACE',\n );\n stepText = computed(() => {\n const currentFaceStatus = this.currentFaceInsideStatus();\n\n if (currentFaceStatus === 'NO_FACE') {\n return '❌ Yuz aniqlanmadi, iltimos, kameraga qarang';\n }\n if (currentFaceStatus === 'OUTSIDE_OVAL') {\n return '📐 Iltimos, yuzingizni oval ichiga joylashtiring';\n }\n if (currentFaceStatus === 'COME_CLOSE') {\n return '🔍 Iltimos, kameraga yaqinroq turing';\n }\n if (currentFaceStatus === 'VERY_CLOSE') {\n return '📷 Juda yaqin, kamerani orqaroq oling';\n }\n\n switch (this.currentStep()) {\n case 'BLINK':\n return '👁 Ko‘zingizni yumib oching(2 marta)';\n case 'MOUTH':\n return '🙂 Og‘zingizni ochib yuming';\n case 'HEAD':\n return '↔️ Boshni chapga yoki o‘ngga burang';\n case 'HOLD':\n return '✋ Barqaror turing (2 soniya)';\n default:\n return '✅ Tayyor!';\n }\n });\n\n async start() {\n this.liveness.reset();\n await this.openCamera();\n\n this.intervalId = setInterval(async () => {\n const done = await this.liveness.process(this.videoRef.nativeElement);\n\n if (done) {\n clearInterval(this.intervalId);\n const blob = await this.capture();\n this.sendToBackend(blob);\n }\n }, 300);\n }\n\n async openCamera() {\n try {\n const devices = await navigator.mediaDevices.enumerateDevices();\n const videoDevices = devices.filter((d) => d.kind === 'videoinput');\n\n if (!videoDevices.length) {\n throw new Error('No video devices found');\n }\n\n // USB yoki default camera tanlash\n const stream = await navigator.mediaDevices.getUserMedia({\n video: {\n deviceId: videoDevices[0].deviceId,\n aspectRatio: 3 / 4,\n width: { min: 480 },\n height: { min: 640 },\n }, // birinchi topilgan kamera\n });\n\n this.videoRef.nativeElement.srcObject = stream;\n } catch (err) {\n console.error('Cannot access camera:', err);\n }\n\n // const stream = await navigator.mediaDevices.getUserMedia({\n // video: { facingMode: 'user', aspectRatio: 3 / 4, width: { min: 480 }, height: { min: 640 } },\n // });\n // this.videoRef.nativeElement.srcObject = stream;\n }\n\n async capture(): Promise<Blob> {\n const video = this.videoRef.nativeElement;\n const canvas = document.createElement('canvas');\n\n canvas.width = video.videoWidth;\n canvas.height = video.videoHeight;\n\n canvas.getContext('2d')!.drawImage(video, 0, 0);\n\n return new Promise((res) => canvas.toBlob((b) => res(b!), 'image/jpeg', 0.9));\n }\n\n sendToBackend(blob: Blob) {\n this.capturedImage.emit(blob);\n this.capturesImageSrc.set(URL.createObjectURL(blob));\n console.log(blob);\n\n // const fd = new FormData();\n // fd.append('file', blob, 'face.jpg');\n // this.http.post('/api/face/verify', fd).subscribe();\n }\n\n ngOnDestroy(): void {\n if (!this.isBrowser) return;\n\n this.cleanup();\n }\n\n private cleanup() {\n // 1️⃣ Interval\n if (this.intervalId) {\n clearInterval(this.intervalId);\n this.intervalId = null;\n }\n\n // 2️⃣ Kamera\n const video = this.videoRef?.nativeElement;\n if (video) {\n video.pause();\n\n const stream = video.srcObject as MediaStream | null;\n if (stream) {\n stream.getTracks().forEach((track) => track.stop());\n }\n\n video.srcObject = null;\n }\n\n // 3️⃣ Service state\n this.liveness.reset();\n }\n}\n","/*\r\n * Public API Surface of ngx-face-id\r\n */\r\n\r\nexport * from './lib/face-liveness/face-liveness';\r\n","/**\n * Generated bundle index. Do not edit.\n */\n\nexport * from './public-api';\n"],"names":["i1.LivenessService"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -38,7 +38,7 @@ declare class NgxFaceLiveness implements OnInit {
|
|
|
38
38
|
currentStep: _angular_core.Signal<"BLINK" | "MOUTH" | "HEAD" | "HOLD" | "DONE">;
|
|
39
39
|
currentFaceInsideStatus: _angular_core.Signal<"NO_FACE" | "OUTSIDE_OVAL" | "COME_CLOSE" | "VERY_CLOSE" | "VALID">;
|
|
40
40
|
isNotValidOval: _angular_core.Signal<boolean>;
|
|
41
|
-
stepText: _angular_core.Signal<"❌ Yuz aniqlanmadi, iltimos, kameraga qarang" | "📐 Iltimos, yuzingizni oval ichiga joylashtiring" | "🔍 Iltimos, kameraga yaqinroq turing" | "📷 Juda yaqin, kamerani orqaroq oling" | "👁 Ko‘zingizni yumib oching(
|
|
41
|
+
stepText: _angular_core.Signal<"❌ Yuz aniqlanmadi, iltimos, kameraga qarang" | "📐 Iltimos, yuzingizni oval ichiga joylashtiring" | "🔍 Iltimos, kameraga yaqinroq turing" | "📷 Juda yaqin, kamerani orqaroq oling" | "👁 Ko‘zingizni yumib oching(2 marta)" | "🙂 Og‘zingizni ochib yuming" | "↔️ Boshni chapga yoki o‘ngga burang" | "✋ Barqaror turing (2 soniya)" | "✅ Tayyor!">;
|
|
42
42
|
start(): Promise<void>;
|
|
43
43
|
openCamera(): Promise<void>;
|
|
44
44
|
capture(): Promise<Blob>;
|