Sử dụng Facemesh kết hợp SVM để dự đoán hướng nhìn khuôn mặt

Trong bài toán nhận diện khuôn mặt, việc khuôn mặt không nhìn trực diện có thể dẫn đến kết quả nhận diện kém. Do đó cần phải có bước xử lý để xác dịnh khuôn mặt có đang ở hướng trực diện hay không. Trong bài viết này, chúng tôi sẽ hướng dẫn sử dụng SVM để dự đoán hướng khuôn mặt bằng Python.

Trong website thigiacmaytinh.com đã có hướng dẫn xác định góc bằng cách xác định tọa độ các điểm. Tuy nhiên thuật toán này quá đơn giản dẫn đến nhiều trường hợp bị sai. Bài viết này tích hợp SVM để cho ra kết quả nhận diện hướng nhìn chính xác trên 99%.

Phần 1: Lý thuyết

1. Giới thiệu về thuật toán SVM

SVM (Support Vector Machine) là một trong những thuật toán học máy được sử dụng phổ biến cho các bài toán phân loại và hồi quy. Mục tiêu của SVM là tìm một siêu phẳng (hyperplane) tối ưu để phân tách dữ liệu thành các nhóm riêng biệt trong không gian đa chiều.

Siêu phẳng tối ưu là một siêu phẳng mà khoảng cách (margin) giữa siêu phẳng đó và những điểm dữ liệu gần nó nhất (các support vectors) là lớn nhất.

SVM tìm siêu phẳng tối ưu bằng cách giải một bài toán tối ưu hóa. Nó cần tìm một siêu phẳng có phương trình dạng:
𝑤⋅𝑥 + 𝑏 = 0
Trong đó:

  • 𝑤 là vector trọng số (weight vector) vuông góc với siêu phẳng.
  • 𝑥 là điểm dữ liệu.
  • 𝑏 là bias (độ dời của siêu phẳng so với gốc tọa độ).

✅ Lý do chọn SVM là vì tốc độ nhanh & kết quả chính xác.

Bài viết này sử dụng thư viện Scikit-learn để implement thuật toán SVM

2. Giới thiệu về Facemesh

Facemesh hay còn gọi là landmark là tập hợp các điểm (point) trên khuôn mặt. Thư viện mediapipe cung cấp function detect 468 điểm trên khuôn mặt rất nhanh & chính xác.

Đọc thêm về Facemesh tại: https://thigiacmaytinh.com/phat-hien-cu-dong-khuon-mat-bang-facemesh/

Trong thư viện Mediapipe mỗi điểm gồm 3 giá trị x, y, z trong không gian 3 chiều. Tuy nhiên chỉ cần x, y là đủ để phát hiện hướng nhìn, không cần đến z.

Dữ liệu mà SVM chấp nhận là array có giá trị từ 0-255, tuy nhiên mesh detect được có giá trị x, y từ 0->image width và 0->image height. Vì vậy cần normalize mesh về giá trị 0-255 để SVM chấp nhận.

Đầu tiên bạn cần resize facemesh về 256px, sau đó tịnh tiến về gốc tọa độ để giá trị x,y của mesh nằm trong khoảng 0-255.

Sau đó bạn cần nối các điểm của facemesh thành vector theo thứ tự, với 0 là class ID

x0 y 0x1 y1 x2 y2 x3 y3....x467 y467

Phần 2: thu thập dữ liệu khuôn mặt

Để training được hướng nhìn bạn cần tạo 5 folder với 5 hướng nhìn: Straight, Up, Down, Left, Right. Tương ứng là 5 class ID 0,1,2,3,4.

Số lượng ảnh cần khoảng 30 ảnh cho mỗi class, sau đó trong quá trình thử nghiệm nếu nhìn sai thì cần bổ sung tiếp.

Các bạn cần tạo matrix data với số lượng dòng bằng số lượng ảnh, số lượng cột bằng 468 x 2 = 936 (1 point có 2 giá trị) để training.

Và 1 mảng labels chứa class ID, là số đầu tiên của folder.

Phần 3: Hướng dẫn thực hiện

Chuẩn bị

  1. Cài đặt Python 3.8.0
  2. Cài đặt Visual Studio Code
  3. Cài đăt các packages cần thiết: opencv-python, scikit-learn, numpy, mediapipe, pickle
    pip install scikit-learn, opencv-python, numpy, mediapipe, pickle

Thực hiện

Full code ở cuối bài viết

  1. Khởi tạo Mediapipe FaceMesh
  2. Trích xuất 468 điểm của Face Landmarks bằng MediaPipe

    Bước này tìm facemesh và normalize về giá trị SVM chấp nhận.

  3. Load ảnh và labels

    Bước này load tất cả ảnh trong 5 folder và tạo thành 2 array để training

  4. Training SVM model

    Training và save model, test độ chính xác của model, đạt hơn 99% là được.

  5. Train model
  6. Test bằng webcam

Source code

🔗 https://github.com/thigiacmaytinh/mediapipe_application/tree/main/1.Face_angle