Dlib: Phần 2 - Xác định facial landmark với dlib và python

Qua Phần 1, chúng ta đã cài đặt được dlib trên Ubuntu, sang phần 2 này, chúng ta sẽ tìm hiểu cách sử dụng dlib để xác định facial landmark.

1. Facial landmark là gì?

Xác định facial landmark là một bài toán con của bài toán dự đoán hình dạng (shape prediction). Vậy bài toán dự đoán hình dạng là gì? Đó chính là việc chúng ta phải xác định được những điểm chính tạo nên hình dạng của đối tượng trong một bức ảnh. Trong bài toán xác định facial landmark, chúng ta sẽ phải xác định được những điểm chính trong bức ảnh tạo nên hình dạng khuôn mặt người. Facial landmark là đầu vào cho nhiều bài toán khác như dự đoán tư thế đầu, tráo đổi khuôn mặt, phát hiện nháy mắt, xoay chỉnh lại khuôn mặt và điển hình là công nghệ nhận dạng khuôn mặt FaceID được Apple trang bị trên iphone X.

Việc xác định facial landmark gồm có hai bước:

  • Bước 1: Xác định được vị trí khuôn mặt trong bức ảnh
  • Bước 2: Xác định được các điểm tạo nên cấu trúc của khuôn mặt

Việc xác định vị trí khuôn mặt có thể được thực hiện bằng nhiều cách từ đơn giản như thuật toán Haar cascades đến phức tạp như các thuật toán dựa trên deep-learning. Tuy nhiên dù sử dụng thuật toán nào, mục đích cuối cùng là ta sẽ thu được một vùng (thường là hình vuông) được xác định bởi tọa độ (x,y) bao quanh khuôn mặt trong bức ảnh.

Sau khi xác định được khuôn mặt trong bức ảnh, chúng ta sẽ xác định cấu trúc của khuôn mặt. Có rất nhiều kiểu cấu trúc khuôn mặt khác nhau nhưng về cơ bản, chúng ta sẽ phải xác định được những phần sau:

  • Miệng
  • Lông mày phải
  • Lông mày trái
  • Mắt phải
  • Mắt trái
  • Mũi
  • Hàm

2. Tìm hiểu bộ xác định facial landmark của dlib

Bộ xác định facial landmark của dlib là cài đặt của thuật toán được mô tả trong bài báo One Millisecond Face Alignment with an Ensemble of Regression Trees của Kazemi và Sullivan (2014).

Bộ xác định facial landmark này sẽ xác định 68 điểm chính theo tọa độ (x,y) cấu tạo nên khuôn mặt người như hình bên dưới.

Để có thể xác định được 68 điểm này trên khuôn mặt người, bộ xác định facial landmark của dlib được huấn luyện với bộ dữ liệu iBUG 300-W

Xác định được càng nhiều điểm landmark thì khuôn mặt người càng cụ thể, rõ ràng và chính xác hơn. Ví dụ FaceID đã sử dụng bộ cảm biến hồng ngoại với 30 triệu điểm để dựng lên cấu trúc khuôn mặt 3D của người sử dụng điện thoại.

3. Cách sử dụng bộ xác định facial landmark của dlib

3.1 Xác định khuôn mặt (face detector)

Như đã giới thiệu ở mục trên, bài toán xác định khuôn mặt có thể giải quyết bằng nhiều thuật toán từ đơn giản đến phức tạp ứng với yêu cầu sử dụng trong thực tế. Ở đây với mục đích demo đơn giản cho blog, chúng ta sẽ sử dụng bộ xác định khuôn mặt của dlib. Bộ xác định khuôn mặt này chỉ hoạt động chính xác với những khuôn mặt hướng về phía trước, mắt nhìn vào máy ảnh (như khi chụp ảnh chân dung hồ sơ). Nó sử dụng HOG (Histogram of Oriented Gradients) feature và bộ phân loại Linear SVM.

Và tất nhiên ở mọi bài toán computer vision, việc đầu tiên ta phải đọc và biểu diễn lại bức ảnh thành một ma trận lưu các thông tin của từng pixel của bức ảnh (sẽ có một bài viết chi tiết hơn về vấn đề này). Có rất nhiều thư viện python hỗ trợ bởi đây là thao tác cơ bản nhất của computer-vison như OpenCV, Scipy, Pillow và thư viện scikit-image mà chúng ta sẽ sử dụng.

Để sử dụng được thư viện scikit-image, trước hết ta cần phải cài đặt nó bằng công cụ quản lý package của Python - pip:

pip install scikit-image

hoặc có thể tải về và cài đặt thủ công từ trang chủ của thư viện.

Và cách sử dụng thì thật đơn giản với method io.imread như sau:

import sys
from skimage import io
image_path = sys.argv[1] //input parameter của script
img = io.imread(image_path)
win = dlib.image_window()
win.clear_overlay()
win.set_image(img)

Tất nhiên đây là cách sử dụng cơ bản nhất của io.imread, bạn có thể tham khảo thêm về các cách sử dụng khác của io.imread với nhiều parameter hơn trong bài tổng hợp 50 python code-snippet từ các project khác nhau.

Và thành quả của đoạn code trên là một cửa sổ với bức ảnh về một thánh nữ được hiển thị. Chú ý khi bạn chạy đoạn code trên rất có thể xảy ra lỗi sau

Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
AttributeError: 'module' object has no attribute 'image_window'

Đó là do máy tính của bạn thiếu thư viện hỗ trợ GUI component (libX11). Để giải quyết lỗi này bạn cần phải xóa dlib đi, cài thư viện hỗ trợ GUI component (X11) và cài đặt lại dlib (Link stackoverflow)

Sau khi đã load bức ảnh của thánh nữ, ta dùng face detector của dlib để xác định khuôn mặt thiên thần của thánh nữ như sau:

import dlib
detector = dlib.get_frontal_face_detector() //Load face detector
dets = detector(img, 1)  //Xác định vị trí khuôn mặt trong bức ảnh
win.add_overlay(dets) //Vẽ khung hình bao quanh khuôn mặt

Có hai chú ý nho nhỏ ở đây:

  • Thứ nhất: tọa độ khung hình bao quanh khuôn mặt của dlib gồm 4 giá trị (top, left, bottom, right) tương ứng với điểm trên-bên trái và điểm dưới-bên phải đối nhau của khung hình. Khác với dlib, OpenCV không sử dụng cách biểu diễn này mà sử dụng cách biểu diễn (x, y, width, height) tương ứng với tọa độ điểm trên-bên trái (x, y) và chiều rộng (width) và chiều cao (height) của khung hình. Do đó khi sử dụng kết hợp dlib và OpenCV, bạn cần phải chuyển đổi hai cách biểu diễn này với nhau để đảm bảo sự tương thích. Và cách chuyển đổi rất đơn giản như sau:
// Chuyển đổi từ (top, left, bottom, right) sang (x, y, w, h)
def dlib_to_opencv(rect):
	x = rect.left()
	y = rect.top()
	w = rect.right() - x
	h = rect.bottom() - y
 
	# return a tuple of (x, y, w, h)
	return (x, y, w, h)
  • Thứ hai: ở dòng code dets = detector(img, 1), parameter thứ hai là số lần áp dụng upscaling với factor là 2 (tăng kích thước của bức ảnh lên 2 lần) trước khi áp dụng bộ xác định khuôn mặt. Lợi điểm của việc làm này là làm cho mọi thứ trong bức ảnh to lên, giúp cho chúng ta có thể xác định được nhiều khuôn mặt (nhỏ) hơn nếu có. Nhưng cũng đồng thời khiến cho việc tính toán nhiều hơn, mất thời gian hơn. Do đó giá trị của parameter thứ hai này cần phải được điều chỉnh sao cho phù hợp với bài toán trong thực tế.
3.2 Xác định facial landmark

Sau khi đã xác định được khuôn mặt trong bức ảnh, công việc tiếp theo là xác định các facial landmark của khuôn mặt đó. Và để làm được điều đó thì ta cần phải có model đã được huấn luyện. Trên trang dlib.net có cung cấp sẵn 2 model

  • shape-predictor-5-face-landmarks: xác định 5 facial landmark
  • shape-predictor-68_face-landmarks: xác định 68 facial landmark. Như đã giới thiệu ở mục trên, model này được huấn luyện với bộ dữ liệu iBUG 300-W và là model được dùng phổ biến nhất với dlib (chú ý nếu bạn dùng bộ dữ liệu iBUG 300-W cho các sản phẩm thương mại, bạn cần liên hệ với iBUG để xin phép)

Bên cạnh đó dlib cũng cho phép chúng ta tự xây dựng model riêng (cần tùy chỉnh parameter cho phù hợp) với bộ dữ liệu riêng (ví dụ bộ dữ liệu Helen với 194 facial landmark) - Tham khảo train-shape-predictor

Trong bài blog này, chúng ta sẽ tải về và sử dụng shape-predictor-68_face-landmarks sẵn có của dlib. Rất đơn giản như sau:

predictor = dlib.shape_predictor('./shape_predictor_68_face_landmarks.dat')
for k, d in enumerate(dets):
    # Xác định facial landmark trên khuôn mặt thánh nữ
    shape = predictor(img, d)
    # Vẽ facial landmark lên bức ảnh
    win.add_overlay(shape)

Nhìn vào facial landmark được vẽ lên khuôn mặt của thánh nữ, ta có thể thấy bộ xác định facial landmark của dlib hoạt động tốt, xác định được khá chính xác vị trí của lông mày, mắt, mũi, miệng và hàm của thánh nữ. So beautiful :X

4. Kết luận

Qua bài blog này, chúng ta đã nắm được facial landmark là gì và làm thế nào để xác định được chúng bằng dlib và python. Và quan trọng hơn là có dịp ngắm nhìn lại thánh nữ một thời của chúng ta ^_^ Trong bài blog tiếp theo của se-ri về dlib (nếu có) chúng ta sẽ tìm hiểu thêm nhiều ứng dụng hơn nữa của dlib.

Tài liệu tham khảo

Enso.