Trong một thử nghiệm vào năm 2017, một hệ thống camera giám sát ở Quế Dương, Trung Quốc chỉ mất 7 phút để xác định được vị trí một phóng viên dựa vào ảnh khuôn mặt của họ. Đây là kết quả của một mạng lưới camera quy mô lớn cùng với công nghệ nhận dạng khuôn mặt (Face Recognition). Nếu để ý một chút thì chúng ta sẽ thấy Face Recognition ngày càng được sử dụng rộng rãi trong đời sống hàng ngày như tự động tag ảnh trên facebook, mở điện thoại bằng FaceID trên Iphone, …

Hãy cùng mình tìm hiểu xem công nghệ này là gì, hoạt động như thế nào và thực hành với một ví dụ nho nhỏ ở cuối bài nha.

Face recognition hoạt động như thế nào

Nhận dạng khuôn mặt là công nghệ xác định danh tính của một cá nhân dựa trên khuôn mặt của họ. Một hệ thống hay phần mềm nhận dạng khuôn mặt thường bao gồm 3 bước chính:

  • Xác định vị trí khuôn mặt (Face Detection)
  • Trích xuất đặc trưng ảnh (Feature Extraction)
  • Nhận dạng khuôn mặt (Recognition)

Xác định vị trí khuôn mặt (Face Detection)

Bước 1: Xác định vị trí khuôn mặt

Đây là bước xác định khuôn mặt người từ những bức ảnh hoặc băng hình (images or videos). Những khuôn mặt này sẽ được “cắt” ra để dùng cho bước tiếp theo.

Đã có một vài bài viết liên quan đến Face Detection nên mình không đi sâu vào nữa, các bạn có thể tham khảo thêm những bài sau:

Trích xuất đặc trưng ảnh (Feature Extraction)

Bước 2: Trích xuất đặc trưng ảnh khuôn mặt

Ở bước này, chúng ta sẽ cần một mô hình để trích xuất đặc trưng từ ảnh khuôn mặt (Feature Extractor). Những đặc trưng được trích xuất từ mô hình này còn được gọi là Face Embeddings hay Face Encodings, chúng ta có thể hiểu là cách biểu diễn khác của ảnh khuôn mặt giúp cho việc nhận dạng khuôn mặt dễ dàng hơn (thay vì những điểm ảnh đơn thuần). Face Embeddings có một đặc tính rất thú vị: những khuôn mặt giống nhau sẽ có Face Embeddings “gần” nhau hơn (dựa trên khoảng cách Euclid).

Những khuôn mặt giống nhau sẽ có đặc trưng giống nhau

Điều này đạt được khi mô hình trích xuất đặc trưng được thiết kế riêng cho việc phân biệt / nhận dạng khuôn mặt. Bài hôm này không đi sâu vào cách xây dựng dạng mô hình này, các bạn có thể tìm hiểu thêm về mạng Siamese, mô hình FaceNet hay mô hình dlib ResNet.

Nhận dạng khuôn mặt (Recognition)

Bước 3: Phân loại / nhận dạng khuôn mặt dựa trên khoảng cách giữa Face Embeddings

Với đặc tính của Face Embeddings đề cập ở trên, một phương pháp đơn giản để nhận dạng khuôn mặt là dựa trên khoảng cách giữa các Face Embeddings với nhau. Hãy tưởng tượng mỗi khuôn mặt có thể được biểu diễn bằng một điểm toạ độ trên trục xy, nếu khoảng cách giữa 2 điểm càng gần nhau, khả năng 2 khuôn mặt thuộc về cùng 1 người càng cao. Ngược lại, nếu khoảng cách này quá lớn (vượt qua một ngưỡng nhất định), chúng ta có thể “tự tin” rằng 2 khuôn mặt thuộc về 2 người khác nhau.

Thực hành

Mục tiêu của bài thực hành hôm nay là viết một đoạn code có khả năng xác định được tên cầu thủ bóng đá. Chúng ta sẽ dùng thư viện face_recognition với các mô hình sau:

  • Xác định vị trí khuôn mặt với dlib HOG
  • Trích xuất đặc trưng ảnh với mô hình dlib ResNet Nếu các bạn để ý thì đây đều là các mô hình từ thư viện dlib. Thực ra face_recognition được xây dựng dựa trên dlib nhưng lại dễ sử dụng hơn nhiều cho “nhiệm vụ” nhận dạng khuôn mặt.

Cấu trúc code

.
├── images
│   ├── ronaldinho
│   │   ├── ronaldinho1.jpeg
│   │   └── ronaldinho2.jpeg
│   ├── zidane
│   │   ├── zidane1.jpeg
│   │   └── zidane2.jpeg
│   └── test
│       ├── test1.jpeg
│       └── test2.jpeg
├── recognize.py
└── utils.py
  • File recognize.py là file code chính được sử dụng
  • File utils chứa các hàm được dùng trong recognize.py
  • Thư mục images chứa ảnh của các cầu thủ đã biết (thư mục ronaldinhozidane) và ảnh mới để kiểm tra (trong thư mục test)

Để áp dụng nhận dạng khuôn mặt, chúng ta có thể dùng đoạn code sau

python recognize.py --image [đường dẫn đến ảnh]

Các bạn hãy thử áp dụng với ảnh trong thư mục test có sẵn trong bài hoặc thử nghiệm với ảnh của bạn nhé.

Nội dung code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
# trích xuất face embeddings / encodings của ảnh khuôn mặt đã biết
known_faces = [
    ("ronaldinho", "images/ronaldinho/ronaldinho1.jpeg"),
    ("ronaldinho", "images/ronaldinho/ronaldinho2.jpeg"),
    ("zidane", "images/zidane/zidane1.jpeg"),
    ("zidane", "images/zidane/zidane2.jpeg"),
]

known_names = []
known_encodings = []
for name, image_path in known_faces:
    image = load_image(image_path)
    encoding = face_image_to_encoding(image)
    known_names.append(name)
    known_encodings.append(encoding)
# trích xuất face embeddings / encodings của ảnh mới
new_image = load_image(new_image_path)
new_encoding = face_image_to_encoding(new_image)
# tính khoảng cách từ embeddings của ảnh mới đến tất cả embeddings 
# của ảnh đã biết và tìm ảnh có khoảng cách gần nhất
face_distances = compute_face_distances(known_encodings, new_encoding)
name, distance = get_most_similar_face(face_distances, known_names)
# xác định tên trong ảnh mới
if distance > 0.6:
    print("Unknown face")
else:
    print("New image was recognized as: {}".format(name))
  • Dòng 2 - 15: trích xuất đặc trưng khuôn mặt của những ảnh đã biết với hàm face_image_to_encoding. Ở đây chúng ta chỉ dùng ảnh của 2 cầu thủ bóng đá, Ronaldinho và Zidane, còn trong thực tế thì số lượng này lớn hơn nhiều (có thể lên tới vài nghìn đến vài triệu tuỳ ứng dụng). Do đó, thường thì các đặc trưng này được trích xuất trước để tăng tốc độ chạy code.
  • Dòng 17 - 18 : trích xuất Face Embeddings của ảnh mới
  • Dòng 21 - 22: tính khoảng cách giữa Face Embeddings của ảnh mới với những ảnh đã biết và tìm ảnh có khoảng cách gần nhất
  • Dòng 40 - 43: xác định tên trong ảnh mới dựa trên khoảng cách đến ảnh gần nhất. Nếu khoảng cách này nhỏ hơn 0.6 thì lấy tên của ảnh gần nhất, còn không thì xác định đây là một người mới, chưa có trong cơ sở dữ liệu của chúng ta. Ngưỡng 0.6 ở đây được chọn theo mô hình dlib ResNet, tuy nhiên khi áp dụng với một tập dữ liệu mới, chúng ta cần tinh chỉnh lại để đạt được độ chính xác cao nhất.

Một số lưu ý với hàm face_image_to_encoding

1
2
3
4
5
6
7
8
9
10
11
def face_image_to_encoding(rgb_image):
    """ Find the face in an image and extract its encoding """
    face_locations = face_recognition.face_locations(rgb_image, number_of_times_to_upsample=0, model='hog')
    assert len(face_locations) > 0, "Found no face, please use a different image"
    encoding = face_recognition.face_encodings(
      rgb_image, known_face_locations=face_locations, num_jitters=0, model='small'
    )
    if len(encoding) > 1:
        print('Warning: Found more than 1 face, the first one will be used.')
        
    return encoding[0]
  • Dòng 3: xác định vị trí khuôn mặt với hàm face_locations, trong đó:
    • number_of_times_to_upsample là số lần tăng cỡ ảnh trước khi áp dụng mô hình, cỡ ảnh càng lớn thì mô hình chạy càng lâu nên ở đây mình để giá trị là 0
    • model là mô hình được áp dụng, chúng ta có thể dùng hog (Hisrogram of Oriented Gradients) hoặc cnn (Convolutional Neural Net - mô hình Max-Margin Object Detection). Dùng cnn tất nhiên sẽ chính xác hơn, nhưng mình ưu tiên code chạy nhanh cho ví dụ nhỏ này nên chọn mô hình hog.
  • Dòng 5: trích xuất đặc trưng ảnh với hàm face_encodings, trong đó:
    • num_jitters là số lần dịch chuyển ảnh ngẫu nhiên trước khi chạy mô hình rồi lấy kết quả trung bình. num_jitters càng lớn thì chạy càng chậm nên mình chọn giá trị là 0.
    • model là mô hình được áp dụng, chúng ta có thể dùng small hoặc large, ở đây mình chọn small để code chạy cho nhanh.
    • known_face_locations là vị trí đã biết của khuôn mặt, chúng ta có thể dùng face_detections đã tìm được ở bước trên. Thực ra nếu chúng dùng giá trị None ở đây, hàm face_encodings vẫn chạy face_locations nên chúng ta không cần phải có bước riêng ở dòng 3, mình muốn các bạn hiểu rõ hơn một chút nên chia ra 2 bước riêng lẻ như vậy.

Mã nguồn (source code)

PandaML Blog GitHub

Tạm kết

Bài hôm nay giới thiệu đến các bạn về cách xây dựng một phần mềm nhận dạng khuôn mặt dựa trên thư viện face_recognition với hai mô hình được sử dụng là HOG và dlib ResNet. Mình chọn 2 mô hình này chủ yếu là để chạy cho nhanh chứ thực ra có rất nhiều mô hình khác có thể được sử dụng như Haar Cascade, MTCNN, RetinaNet, …

Còn bạn dùng mô hình nào? Bạn có kinh nghiệm gì thú vị với Face Recognition thì chia sẻ để mọi người cùng tham khảo với nhé.

Tham khảo

Leave a comment