Nhược điểm của mô hình Haar Cascade (có sẵn trong OpenCV) không nhận diện được khuôn mặt nghiêng hay bị che và cần phải tinh chỉnh cẩn thận cho từng trường hợp. Bên cạnh đó, mô hình này còn rất hay “báo động giả” khi xác định những khu vực không liên quan trên ảnh là khuôn mặt (dương tính giả - false positive). Bài hôm nay chúng ta sẽ tìm hiểu 2 mô hình khác hoạt động tốt hơn (vừa nhanh vừa chính xác), đó là mô hình dựa trên đặc trưng HOG và Deep Neural Net.

Ví dụ về Haar Cascade hoạt động chưa tốt khi chỉ nhận diện được 7/12 khuôn mặt và nhầm lẫn 1 bàn tay là khuôn mặt (bức ảnh được retweets nhiều nhất năm 2014 của Ellen Degeneres)

Histogram of Oriented Gradients (HOG) - thư viện dlib

Histogram of Oriented Gradients (HOG) là một phương pháp trích xuất đặc trưng từ ảnh được dùng trong Object Detection (không biết dịch ra sao nên mình xin giữ bản gốc tiếng Anh). Như chúng ta đã biết, mỗi bức ảnh được hình thành từ rất nhiều điểm ảnh (pixel). Phương pháp HOG về cơ bản sẽ tính toán sự thay đổi của mỗi điểm ảnh so với các điểm ảnh xung quanh để tạo ra đặc trưng riêng cho ảnh.

Ví dụ về trích xuất đặc trưng HOG

Phương pháp này trở nên phổ biến từ năm 2005 khi đã cho thấy hiệu quả rất cao trong mô hình nhận diện người qua đường khi kết hợp HOG và mô hình Support Vector Machine (SVM). Kể từ đó, rất nhiều mô hình Object Detection được xây dựng một cách tương tự và những mô hình nhận diện khuôn mặt cũng không phải là ngoại lệ. Trong số đó, chúng ta không thể không kể đến mô hình trong thư viện dlib, (theo cá nhân mình) đây là mô hình nhận diện khuôn mặt tốt nhất nếu không kể đến các mô hình học sâu (Deep Learning). Áp dụng mô hình này cho bức ảnh ở trên, chúng ta có kết quả tốt hơn một chút với 8/12 khuôn mặt được xác định đúng.

Kết quả khi dùng mô hình dlib dựa trên đặc trưng HOG

Deep Neural Network (DNN) - thư viện OpenCV

Vào năm 2017, OpenCV cho ra mắt mô-đun DNN (Deep Neural Network) để hỗ trợ việc sử dụng các mô hình học sâu trực tiếp trên OpenCV thay vì phải dùng một thư viện khác (như tensoflow, pytorch, …). Đây là một điểm cộng lớn cho OpenCV vì các mô hình tốt nhất trong thị giác máy tính thường là một mô hình học sâu nào đó. Về nhận diện khuôn mặt, trong OpenCV đã có sẵn mô hình được huấn luyện theo phương pháp Single Shot Multibox Detector (SSD). Mô hình này hoạt động tốt hơn mô hình Haar và HOG cho bức ảnh ở trên khi nhận diện đúng 11/12 khuôn mặt.

Kết quả khi dùng mô hình DNN trong OpenCV

Thực hành

Cấu trúc code

.
├── face_detection_dnn.py
├── face_detection_haar.py
├── face_detection_hog.py
├── utils.py
├── images
│   └── ellen_oscar.jpeg
└── models
    ├── haarcascade_frontalface_default.xml
    ├── opencv_face_detector.pbtxt
    └── opencv_face_detector_uint8.pb
  • 3 files chính face_detection_haar.py, face_detection_hog.pyface_detection_dnn.py tương ứng với 3 mô hình dựa trên Haar Cascade, HOG và Deep Neural Net
  • File utils.py chứa các hàm để giúp chúng ta xử lý đầu ra của các mô hình trên (do mỗi mô hình lại có đầu ra khác nhau nên cần chuẩn hoá lại cho tiện dùng)
  • Thư mục images chứa các file ảnh
  • Thư mục models bao gồm
    • File mô hình Haar Cascade haarcascade_frontalface_default.xml
    • File mô hình DNN opencv_face_detector_uint8.pbopencv_face_detector.pbtxt

Để chạy mô hình cho một bức ảnh mới, chúng ta chỉ cần dùng đoạn code sau:

$ python face_detection_[haar, hog, dnn].py --image [đường dẫn đến ảnh của bạn]

Đây là ví dụ dùng mô hình dựa trên đặc trưng HOG

$ python face_detection_hog.py --image images/ellen_oscar.jpeg

Cách áp dụng HOG và DNN

Nhìn chung, cách áp dụng mô hình HOG hay DNN thì cũng bao gồm các bước tương tự như Haar Cascase: load mô hình, chạy mô hình và vẽ đường bao cho từng khuôn mặt. Tuy nhiên có 1 số điểm cần lưu ý khi áp dụng mô hình này.

Code HOG

1
2
3
4
5
6
7
8
9
10
11
# chuyển sang ảnh rgb (yêu cầu đầu vào của mô hình dlib)
rgb_image = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
# load mô hình nhận diện khuôn mặt
hog_face_detector = dlib.get_frontal_face_detector()
# nhận diện khuôn mặt trong ảnh
faces = hog_face_detector(rgb_image, upsample_num_times=0)
# vẽ đường bao cho từng khuôn mặt
green_color = (0, 255, 0)
for face in faces:
    x1, y1, x2, y2 = hog_face_to_points(face)
    cv2.rectangle(image, pt1=(x1, y1), pt2=(x2, y2), color=green_color, thickness=2)
  • Dòng 2: chuyển ảnh từ BGR (mặc định của OpenCV) sang RGB (yêu cầu đầu vào của mô hình HOG)
  • Dòng 4: load mô hình với dlib.get_frontal_face_detector (chúng ta không cần đưa đường dẫn đến mô hình vì nó đã có sẵn khi gọi get_frontal_face_detector)
  • Dòng 6: thực hiện nhận diện khuôn mặt. Tham số upsample_num_times 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
  • Dòng 8 - 11: vẽ đường bao cho từng khuôn mặt. Hàm hog_face_to_points chuyển đổi toạ độ của mô hình sang dạng (x1, y1), (x2, y2) để tiện cho việc vẽ hình

Code OpenCV DNN

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
# load mô hình nhận diện khuôn mặt
model_path = "models/opencv_face_detector_uint8.pb"
config_path = "models/opencv_face_detector.pbtxt"
net = cv2.dnn.readNetFromTensorflow(model_path, config_path)

# thay đổi độ phân giải của ảnh (yêu cầu đầu vào của mô hình)
input_size = (300, 300)
resized_image = cv2.resize(image, dsize=input_size)
# nhận diện khuôn mặt trong ảnh
blob = cv2.dnn.blobFromImage(resized_image, scalefactor=1.0, size=input_size, mean=[123, 117, 104])
net.setInput(blob)
detections = net.forward()

# vẽ đường bao cho từng khuôn mặt
green_color = (0, 255, 0)
for i in range(detections.shape[2]):
    detection = detections[0, 0, i]
    confidence = detection[2]
    if confidence > 0.4:
        x1, y1, x2, y2 = dnn_detection_to_points(detection, width, height)
        cv2.rectangle(image, pt1=(x1, y1), pt2=(x2, y2), color=green_color, thickness=2)
  • Dòng 2 - 4: load mô hình. Với mô hình DNN thì thường chúng ta cần 2 files mô hình lưu thông tin của mô hình (1 file lưu thông tin cấu trúc mạng neuron và 1 file lưu thông tin về mức độ liên kết giữa các neuron - weight). Ở đây chúng ta dùng mô hình được xây dựng trên Tensorflow nên hàm readNetFromTensorflow được sử dụng
  • Dòng 7 - 12: áp dụng mô hình nhận diện khuôn mặt
  • Dòng 15 - 21: vẽ đường bao cho từng khuôn mặt
    • Dòng 19: giữ lại những khuôn mặt có độ tin cậy cao (đây là một cách để giảm số lượng “báo động giả”)
    • Dòng 20: hàm dnn_detection_to_points chuyển đổi toạ độ của mô hình sang dạng (x1, y1), (x2, y2) để tiện lợi hơn cho việc vẽ hình

Mã nguồn và File mô hình

PandaML Blog github

Thảo luận

Mô hình tốt nhất về nhận diện khuôn mặt trên tập dữ liệu WIDER FACE (tổng hợp bởi paperswithcode)

Hiện nay có rất nhiều mô hình khác có độ chính xác tốt hơn (MMOD, MTCNN, RetinaFace, …) nhưng đây đều là những mô hình học sâu có cấu trúc tương đối phức tạp nên tốc độ khá chậm trên CPU (mình thử nghiệm với MMOD thì mất vài giây để xử lý 1 ảnh). Những mô hình này chỉ thực sự “toả sáng” (chạy đủ nhanh) khi chạy trên GPU. Do vậy nếu không có GPU, chúng ta nên lựa chọn dlib HOG hoặc OpenCV DNN (với cấu trúc mạng không quá phức tạp như mô hình trong bài hôm nay). Còn nếu đã có GPU, chúng ta có nhiều lựa chọn hơn nên cứ mạnh dạn chọn mô hình có độ chính xác cao nhất mà đạt được tốc độ cho phép.

P/S: bạn nào thích chơi game thì có thể lấy lý do là học Deep Learning để mua card màn hình xịn nhé

Tham khảo

Leave a comment