Pada artikel kali ini, kita akan belajar cara membuat fitur Face Detection dan Face Recognition menggunakan Face-API.js di Angular. Fitur-fitur yang akan dibuat meliputi:
- Pendeteksi senyum (smile detection)
- Deteksi berkedip (blink detection)
- Deteksi mulut terbuka/tertutup
- Deteksi pose kepala (head pose)
- Estimasi umur dan jenis kelamin
FaceApiComponent
untuk
menangani seluruh proses ini.
Instalasi Face-API.js
Untuk memulai, instal Face-API.js di proyek Angular Anda:
npm install face-api.js
Setelah itu, buatlah sebuah komponen baru bernama
FaceApiComponent
. Komponen ini akan menangani semua fungsi
terkait deteksi wajah dan menampilkan hasilnya di layar.
Persiapan Model
Face-API.js membutuhkan model pra-latih untuk mendeteksi wajah, landmark,
ekspresi, dll. Pastikan Anda telah mengunduh model-model berikut dan
menyimpannya di folder src/assets/models
:
- tinyFaceDetector
- faceLandmark68Net
- faceExpressionNet
- ageGenderNet
Model ini dapat diunduh dari repository resmi Face-API.js.
Membuat Komponen Face-API
Gunakan perintah Angular CLI untuk membuat komponen:
ng generate component face-api --standalone
Salin kode berikut pada komponen yang sudah di generate tadi.
1. face-api.component.ts
Berikut adalah kode TypeScript untuk komponen FaceApiComponent
:
import { Component, ElementRef, OnInit, ViewChild } from '@angular/core';
import { CommonModule } from '@angular/common';
import * as faceapi from 'face-api.js';
@Component({
selector: 'app-face-api',
standalone: true,
imports: [CommonModule],
templateUrl: './face-api.component.html',
styleUrls: ['./face-api.component.scss'],
})
export class FaceApiComponent implements OnInit {
@ViewChild('video') videoElement!: ElementRef<HTMLVideoElement>;
@ViewChild('canvas') canvasElement!: ElementRef<HTMLCanvasElement>;
smileValue: string = 'No face detected';
blinkStatus: string = 'Eyes open';
mouthStatus: string = 'Mouth closed';
headPose: string = 'Head position normal';
ageGender: string = 'Age: N/A, Gender: N/A';
async ngOnInit() {
await this.loadModels();
this.startVideo();
}
async loadModels() {
const MODEL_URL = '/assets/models';
await Promise.all([
faceapi.nets.tinyFaceDetector.loadFromUri(MODEL_URL),
faceapi.nets.faceLandmark68Net.loadFromUri(MODEL_URL),
faceapi.nets.faceExpressionNet.loadFromUri(MODEL_URL),
faceapi.nets.ageGenderNet.loadFromUri(MODEL_URL), // For age and gender detection
]);
console.log('Models loaded successfully');
}
startVideo() {
navigator.mediaDevices
.getUserMedia({ video: true })
.then((stream) => {
const video = this.videoElement.nativeElement;
video.srcObject = stream;
video.onloadedmetadata = () => {
video.play();
video.width = video.videoWidth;
video.height = video.videoHeight;
this.onPlay();
};
})
.catch((err) => console.error('Error accessing webcam: ', err));
}
async onPlay() {
const video = this.videoElement.nativeElement;
const canvas = this.canvasElement.nativeElement;
video.addEventListener('play', () => {
const displaySize = {
width: video.videoWidth,
height: video.videoHeight,
};
faceapi.matchDimensions(canvas, displaySize);
setInterval(async () => {
if (video.videoWidth === 0 || video.videoHeight === 0) {
console.error('Video dimensions are invalid.');
return;
}
const detections = await faceapi
.detectSingleFace(video, new faceapi.TinyFaceDetectorOptions())
.withFaceLandmarks()
.withFaceExpressions()
.withAgeAndGender();
const ctx = canvas.getContext('2d');
ctx?.clearRect(0, 0, canvas.width, canvas.height);
if (detections) {
const resizedDetections = faceapi.resizeResults(
detections,
displaySize
);
faceapi.draw.drawDetections(canvas, resizedDetections);
faceapi.draw.drawFaceLandmarks(canvas, resizedDetections);
// Smile Detection
const happyExpression = detections.expressions.happy || 0;
this.smileValue =
happyExpression > 0.5
? `Smiling: ${(happyExpression * 100).toFixed(1)}%`
: 'No smile detected';
// Blink Detection
const landmarks = detections.landmarks;
const leftEye = landmarks.getLeftEye();
const rightEye = landmarks.getRightEye();
const leftEyeBlink = this.calculateEyeAspectRatio(leftEye);
const rightEyeBlink = this.calculateEyeAspectRatio(rightEye);
this.blinkStatus =
leftEyeBlink < 0.2 && rightEyeBlink < 0.2
? 'Eyes closed'
: 'Eyes open';
// Mouth Openness Detection
const mouth = landmarks.getMouth();
const mouthOpenness = this.calculateMouthOpenness(mouth);
this.mouthStatus =
mouthOpenness > 0.3 ? 'Mouth open' : 'Mouth closed';
// Head Pose Detection
const nose = landmarks.getNose();
this.headPose = this.detectHeadPose(nose);
// Age and Gender Detection
this.ageGender = `Age: ${Math.round(detections.age)}, Gender: ${
detections.gender
}`;
} else {
this.smileValue = 'No face detected';
this.blinkStatus = 'No face detected';
this.mouthStatus = 'No face detected';
this.headPose = 'No face detected';
this.ageGender = 'Age: N/A, Gender: N/A';
}
}, 200);
});
}
calculateEyeAspectRatio(eye: faceapi.Point[]): number {
const vertical1 = this.distance(eye[1], eye[5]);
const vertical2 = this.distance(eye[2], eye[4]);
const horizontal = this.distance(eye[0], eye[3]);
return (vertical1 + vertical2) / (2 * horizontal);
}
calculateMouthOpenness(mouth: faceapi.Point[]): number {
const vertical = this.distance(mouth[13], mouth[19]); // Top and bottom lip
const horizontal = this.distance(mouth[12], mouth[16]); // Left and right corners
return vertical / horizontal;
}
detectHeadPose(nose: faceapi.Point[]): string {
const dx = nose[0].x - nose[3].x; // Horizontal distance
const dy = nose[0].y - nose[3].y; // Vertical distance
if (dx > 10) return 'Head tilted left';
if (dx < -10) return 'Head tilted right';
if (dy > 10) return 'Head tilted down';
if (dy < -10) return 'Head tilted up';
return 'Head position normal';
}
distance(point1: faceapi.Point, point2: faceapi.Point): number {
const dx = point1.x - point2.x;
const dy = point1.y - point2.y;
return Math.sqrt(dx * dx + dy * dy);
}
}
2. face-api.component.html
Berikut adalah kode HTML untuk tampilan dari komponen
FaceApiComponent
:
<div class="container">
<h2>
Face Detection and Face Recognition in the browser and nodejs with
tensorflow.js
</h2>
<table>
<tr>
<td>
<video #video autoplay muted></video>
</td>
<td>
<canvas #canvas></canvas>
</td>
</tr>
</table>
<table>
<tr>
<td>
<p>{{ smileValue }}</p>
</td>
<td> | </td>
<td>
<p>{{ blinkStatus }}</p>
</td>
<td> | </td>
<td>
<p>{{ mouthStatus }}</p>
</td>
<td> | </td>
<td>
<p>{{ headPose }}</p>
</td>
<td> | </td>
<td>
<p>{{ ageGender }}</p>
</td>
</tr>
</table>
</div>
3. face-api.component.scss
Berikut adalah kode SCSS untuk styling komponen:
.container {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
padding: 20px;
}
video {
width: 640px;
height: 480px;
border: 2px solid black;
}
canvas {
position: absolute;
width: 640px;
height: 480px;
top: 0;
left: 0;
border: 2px solid red;
}
table {
margin-top: 20px;
}
td {
padding: 5px;
}
Kode Lengkap
Untuk melihat kode lengkapnya bisa kunjungi langsung repositori ini : https://github.com/dyazincahya/angular-face-api
Pengujian Aplikasi
Untuk menguji aplikasi ini, pastikan Anda sudah mengakses kamera dengan izin yang sesuai. Aplikasi akan mendeteksi wajah, dan menampilkan informasi mengenai ekspresi wajah, status kedipan mata, status mulut, posisi kepala, serta perkiraan usia dan jenis kelamin langsung di layar. Untuk hasilnya ada pada gambar di atas.
Kesimpulan
Dengan menggunakan face-api.js
di Angular, kita bisa dengan mudah
melakukan deteksi dan pengenalan wajah dalam aplikasi web. Anda bisa
mengembangkan lebih lanjut aplikasi ini dengan menambahkan berbagai fitur
seperti deteksi lebih dari satu wajah atau analisis ekspresi wajah lebih
lanjut.
Mungkin cukup sekian dulu untuk pembahasan kali ini, Terimakasih :)
Posting Komentar