Nhận diện gương mặt bằng face-api.js

Nhận diện gương mặt bằng face-api.js

Hệ thống nhận dạng khuôn mặt là công nghệ có khả năng so khớp khuôn mặt người từ hình ảnh kỹ thuật số hoặc khung video với cơ sở dữ liệu khuôn mặt. Các nhà nghiên cứu hiện đang phát triển nhiều phương pháp mà hệ thống nhận dạng khuôn mặt hoạt động. Phương pháp nhận dạng khuôn mặt tiên tiến nhất, cũng được sử dụng để xác thực người dùng thông qua các dịch vụ xác minh ID, hoạt động bằng cách xác định và đo các đặc điểm khuôn mặt từ một hình ảnh nhất định.

Mặc dù ban đầu là một dạng ứng dụng máy tính, nhưng hệ thống nhận dạng khuôn mặt đã được sử dụng rộng rãi hơn trong thời gian gần đây trên điện thoại thông minh và các dạng công nghệ khác, chẳng hạn như robot. Bởi vì nhận dạng khuôn mặt trên máy tính liên quan đến việc đo lường các đặc điểm sinh lý của con người nên hệ thống nhận dạng khuôn mặt được phân loại là sinh trắc học. Mặc dù độ chính xác của hệ thống nhận dạng khuôn mặt như một công nghệ sinh trắc học thấp hơn so với nhận dạng mống mắt và nhận dạng vân tay, nhưng nó vẫn được chấp nhận rộng rãi. Hệ thống nhận dạng khuôn mặt đã được triển khai trong tương tác giữa người và máy tính tiên tiến, giám sát video và tự động lập chỉ mục hình ảnh.

(Theo wikipedia).

Có rất nhiều thư viện hỗ trợ thuật toán cho việc này nhưng trong bài viết này mình sẽ dùng thư viện face-api.js.

GIỚI THIỆU VỀ FACE-API.JS

Face-api.js là một Javascript API dùng để nhận diện gương mặt trên Browser cũng như NodeJS sử dụng Tensorflow.js.

Một số tính năng chính:

– Phát hiện khuôn mặt và nhận diện khuôn mặt

– Xác thực gương mặt

– Nhận diện cảm xúc của gương mặt

– Dự đoán tuổi và nhận diện giới tính

Bài viết này mình sẽ trình bày tính năng: nhận diện khuôn mặt.

Nhận diện gương mặt bao gồm 2 bước: phát hiện gương mặt và nhận diện gương mặt.

Nói một cách đơn giản, mục đích chúng ta muốn đạt được là xác định một người khi họ cung cấp  hình ảnh về khuôn mặt của họ. Chúng ta làm điều này bằng cách thu thập một (hoặc nhiều) hình ảnh  được gắn nhãn tên của mỗi người mà chúng ta muốn nhận diện ra. Sau đó so sánh hình ảnh đầu vào với dữ liệu tham chiếu và tìm ra hình ảnh tham chiếu tương tự nhất. Nếu cả hai hình ảnh đủ giống nhau chúng ta sẽ xuất ra tên của người đó và ngược lại thì xem như không xác định được.

Có thể bắt đầu xem ví dụ dưới đây:

Đầu tiên tạo một cấu trúc thư mục để quản lý.

mkdir face
touch index.html
touch script.js
mkdir data // Dùng để bỏ dữ liệu ảnh đầu vào
mkdir images // Ảnh dùng để test
mkdir models // Chứa các pre-trained model
face-api-js.min.js // Tải từ github.

Tiếp theo mình sẽ down cái models mà bộ face-api.js cung cấp.

Dữ liệu models tải ở: https://github.com/justadudewhohacks/face-api.js/tree/master/weights

Ở file html thì đơn giản mình chỉ để cái ảnh vào thôi. Và một thẻ canvas để hiển thị cái box của gương mặt.

<!DOCTYPE html>
<html lang="en">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <script src="./face-api.min.js"></script>
    <script src="./script.js"></script>
    <title>Face Recognition</title>
    <style>
        canvas {
            position: absolute;
            top: 0;
            left: 0;
        }
    </style>
</head>

<body>
    <img id="myImg" src="images/huu.jpg" />
    <canvas id="myCanvas">
</body>

</html>

Load Model vào trong dự án, ở đây sử dụng 3 model chính:

  • ssdMobilenetV1 Model: Đây là pre-trained model dùng để phát hiện gương mặt.
  • faceLandmark68Net Model: Đây là pre-trained model dùng để hiển thị được các điểm xung quanh mặt của mình.
  • FaceRecognitionNet Model: Đây là pre-trained model dùng để nhận dạng gương mặt.

Trong file script.jsthì mình sẽ load 3 model này vào trước.

(async () => {
  // Load model
  await faceapi.nets.ssdMobilenetv1.loadFromUri("/models");
  await faceapi.nets.faceRecognitionNet.loadFromUri("/models");
  await faceapi.nets.faceLandmark68Net.loadFromUri("/models");
})();

Dùng hàm detectSingleFace() để phát hiện ra gương mặt ở trong ảnh.

Sau khi load xong model thì mình bắt đầu viết phần phát hiện gương mặt.

(async () => {
  // Load model
  await faceapi.nets.ssdMobilenetv1.loadFromUri("/models");
  await faceapi.nets.faceRecognitionNet.loadFromUri("/models");
  await faceapi.nets.faceLandmark68Net.loadFromUri("/models");

  // Detect Face
  const input = document.getElementById("myImg");
  const result = await faceapi
    .detectSingleFace(input, new faceapi.SsdMobilenetv1Options())
    .withFaceLandmarks()
    .withFaceDescriptor();
  const displaySize = { width: input.width, height: input.height };
  // resize the overlay canvas to the input dimensions
  const canvas = document.getElementById("myCanvas");
  faceapi.matchDimensions(canvas, displaySize);
  const resizedDetections = faceapi.resizeResults(result, displaySize);
  console.log(resizedDetections);
})();

Hàm detectSingleFace()sẽ trả về kết quả là phát hiện được gương mặt và trả về tọa độ của gương mặt.

Dùng hàm FaceMatcher() và findBestMatch() để nhận diện gương mặt.

Sau khi phát hiện được gương mặt thì lúc này mình sẽ viết hàm detectFace() dùng để nhận diện gương mặt.

async function detectFace() {
  const label = "Huu";
  const numberImage = 5;
  const descriptions = [];
  for (let i = 1; i <= numberImage; i++) {
    const img = await faceapi.fetchImage(
      `/data/Huu/${i}.jpg`
    );
    const detection = await faceapi
      .detectSingleFace(img)
      .withFaceLandmarks()
      .withFaceDescriptor();
    descriptions.push(detection.descriptor);
  }
  return new faceapi.LabeledFaceDescriptors(label, descriptions);
}

Sau đó, mình sử dụng hàm detectFace()để nhận diện gương mặt và vẽ cái box quanh gương mặt.

(async () => {
  // Load model
  await faceapi.nets.ssdMobilenetv1.loadFromUri("/models");
  await faceapi.nets.faceRecognitionNet.loadFromUri("/models");
  await faceapi.nets.faceLandmark68Net.loadFromUri("/models");

  // Detect Face
  const input = document.getElementById("myImg");
  const result = await faceapi
    .detectSingleFace(input, new faceapi.SsdMobilenetv1Options())
    .withFaceLandmarks()
    .withFaceDescriptor();
  const displaySize = { width: input.width, height: input.height };
  // resize the overlay canvas to the input dimensions
  const canvas = document.getElementById("myCanvas");
  faceapi.matchDimensions(canvas, displaySize);
  const resizedDetections = faceapi.resizeResults(result, displaySize);
  console.log(resizedDetections);

  // Recognize Face
  const labeledFaceDescriptors = await detectFace();
  const faceMatcher = new faceapi.FaceMatcher(labeledFaceDescriptors, 0.7);
  if (result) {
    const bestMatch = faceMatcher.findBestMatch(result.descriptor);
    const box = resizedDetections.detection.box;
    const drawBox = new faceapi.draw.DrawBox(box, { label: bestMatch.label });
    drawBox.draw(canvas);
  }
})();

Đến đây thì chúng ta đã hoàn thành hệ thống nhận diện đơn giản chỉ bằng Javascript.

Các bạn có thể xem source code tại link Gitlab .

KẾT LUẬN

Trên đây là bài viết giới thiệu về face-api.js và cách sử dụng đơn giản của nó. Chúng ta có thể mở rộng nghiên cứu thêm một số chức năng chưa giới thiệu trên đây như : xác định độ tuổi, giới tính , cảm xúc.  Chú ý là hệ thống nhận diện này được sử dụng bằng các pre-trained model mà không qua bất kì một bước phức tạp nào để tranfer dữ liệu từ pre-trained model nên độ chính xác ở mức tương đối.

TÀI LIỆU THAM KHẢO

https://en.wikipedia.org/wiki/Facial_recognition_system

https://github.com/justadudewhohacks/face-api.js#getting-started

https://itnext.io/face-api-js-javascript-api-for-face-recognition-in-the-browser-with-tensorflow-js-bcc2a6c4cf07

Nguồn hình ảnh: https://www.pexels.com/license/