Tìm hiểu MTCNN và áp dụng để xác định vị trí các khuôn mặt.

Vài ngày trước mình có tìm hiểu một số cách để detect khuôn mặt trong một bức hình. Kết quả search google đưa ra một số phương pháp khá phổ biến. Mình thử áp dụng việc detect dựa theo model Haar Cascades và đến MTCNN. Có vẻ như việc áp dụng MTCNN đưa ra kết quả có độ chính xác cao hơn đáng kể.

Bài viết này, mình sẽ hướng dẫn các bạn sử dụng MTCNN để detect khuôn mặt một cách đơn giản từ một bước ảnh và 1 video đang chạy nhé.

MTCNN Workflow

MTCNN hoạt động theo 3 bước, mỗi bước có một mạng neural riêng lần lượt là: P-Net, R-Net và O-net Với mỗi bức ảnh đầu vào, nó sẽ tạo ra nhiều bản sao của hình ảnh đó với các kích thước khác nhau.

Tại P-Net, thuật toán sử dụng 1 kernel 12x12 chạy qua mỗi bức hình để tìm kiếm khuôn mặt. Sau lớp convolution thứ 3, mạng chia thành 2 lớp. Convolution 4-1 đưa ra xác suất của một khuôn mặt nằm trong mỗi bounding boxes, và Convolution 4-2 cung cấp tọa độ của các bounding boxes.

R-Net có cấu trúc tương tự vói P-Net. Tuy nhiên sử dụng nhiều layer hơn. Tại đây, network sẽ sử dụng các bounding boxes đc cung cấp từ P-Net và tinh chỉnh là tọa độ. Tương tự R-Net chia ra làm 2 layers ở bước cuối,cung cấp 2 đầu ra đó là tọa độ mới của các bounding boxes, cùng độ tin tưởng của nó.

O-Net lấy các bounding boxes từ R-Net làm đầu vào và đánh dấu các tọa độ của các mốc trên khuôn mặt.

Ở bước này, thuật toán đưa ra 3 kết quả đầu ra khác nhau bao gồm: xác suất của khuôn mặt nằm trong bounding box, tọa độ của bounding box và tọa độ của các mốc trên khuôn mặt (vị trí mắt, mũi, miệng)

Xác định vị trí khuôn mặt

Đây là hướng dẫn nho nhỏ từ thư viện MTCNN có sẵn để xác định vị trí khuôn mặt, hy vọng có thể một phần giúp các bạn thực hiện được việc này. Đầu tiên, bạn cần import thư viện OpenCV để đọc, ghi, và show hình ảnh. Và dĩ nhiên rồi, bạn cần import MTCNN nữa

import cv2
from mtcnn.mtcnn import MTCNN

Tạo 1 detector từ class MTCNN. Hàm detect_faces để phát hiện các khuôn mặt trong bức hình mà chỉnh ta sử dụng.

detector = MTCNN()
image = cv2.imread("t-ara.jpg")
result = detector.detect_faces(image)

Kết cả result trả về bao gồm 1 list các bouding boxes trong đó có tọa độ 2 mắt, mũi, miệng. Và kèm theo cả độ tin tưởng của các bounding boxes này nữa

[{'confidence': 0.9969762563705444, 'keypoints': {'mouth_right': (314, 186), 'nose': (303, 176), 'left_eye': (280, 167), 'right_eye': (305, 157), 'mouth_left': (290, 195)}, 'box': [260, 131, 61, 81]}, {'confidence': 0.9960743188858032, 'keypoints': {'mouth_right': (927, 218), 'nose': (915, 203), 'left_eye': (905, 184), 'right_eye': (933, 186), 'mouth_left': (905, 216)}, 'box': [888, 151, 61, 83]}, {'confidence': 0.9958836436271667, 'keypoints': {'mouth_right': (158, 212), 'nose': (149, 198), 'left_eye': (134, 180), 'right_eye': (163, 179), 'mouth_left': (136, 212)}, 'box': [115, 148, 61, 81]}, {'confidence': 0.9955955147743225, 'keypoints': {'mouth_right': (454, 228), 'nose': (449, 214), 'left_eye': (436, 193), 'right_eye': (463, 200), 'mouth_left': (431, 223)}, 'box': [416, 164, 56, 79]}, {'confidence': 0.9930985569953918, 'keypoints': {'mouth_right': (741, 236), 'nose': (726, 221), 'left_eye': (713, 203), 'right_eye': (744, 204), 'mouth_left': (715, 235)}, 'box': [696, 174, 65, 82]}, {'confidence': 0.9929332733154297, 'keypoints': {'mouth_right': (591, 262), 'nose': (580, 250), 'left_eye': (567, 231), 'right_eye': (596, 231), 'mouth_left': (569, 261)}, 'box': [551, 202, 59, 77]}, {'confidence': 0.9779009222984314, 'keypoints': {'mouth_right': (1068, 203), 'nose': (1050, 191), 'left_eye': (1042, 173), 'right_eye': (1070, 173), 'mouth_left': (1043, 203)}, 'box': [1031, 144, 61, 79]}]

Từ kết quả trả về này, bạn có thể vẽ, đánh dấu các vị trí mà MTCNN đã đưa ra để kiểm tra xem thuật toán phát hiện vị trí đúng chưa nhé.

for person in result:
    bounding_box = person['box']
    keypoints = person['keypoints']
    
    cv2.rectangle(image,
                  (bounding_box[0], bounding_box[1]),
                  (bounding_box[0]+bounding_box[2], bounding_box[1] + bounding_box[3]),
                  (0,155,255),
                  2)
    cv2.circle(image,(keypoints['left_eye']), 2, (0,155,255), 2)
    cv2.circle(image,(keypoints['right_eye']), 2, (0,155,255), 2)
    cv2.circle(image,(keypoints['nose']), 2, (0,155,255), 2)
    cv2.circle(image,(keypoints['mouth_left']), 2, (0,155,255), 2)
    cv2.circle(image,(keypoints['mouth_right']), 2, (0,155,255), 2)

Cuối cùng, hãy show bức hình của bạn lên xem nào.

cv2.imshow("image",image)
cv2.waitKey(0)

Và đây là kết quả:

Tương tự, bạn có thể áp dụng đối với các video hoặc camera livestream bằng các sử dụng hàm cv2.VideoCapture(0) của Open CV để đọc video. Đối với các video có sẵn bạn có thể cung cấp đường dẫn tới video ở đây.

Sửa lại một chút đoạn code trên ta có thể xác định các khuôn mặt trên 1 video như sau:

cap = cv2.VideoCapture(0)
while True: 
    #Capture frame-by-frame
    __, frame = cap.read()
    
    #Use MTCNN to detect faces
    result = detector.detect_faces(frame)
    if result != []:
        for person in result:
            bounding_box = person['box']
            keypoints = person['keypoints']
    
            cv2.rectangle(frame,
                          (bounding_box[0], bounding_box[1]),
                          (bounding_box[0]+bounding_box[2], bounding_box[1] + bounding_box[3]),
                          (0,155,255),
                          2)
    
            cv2.circle(frame,(keypoints['left_eye']), 2, (0,155,255), 2)
            cv2.circle(frame,(keypoints['right_eye']), 2, (0,155,255), 2)
            cv2.circle(frame,(keypoints['nose']), 2, (0,155,255), 2)
            cv2.circle(frame,(keypoints['mouth_left']), 2, (0,155,255), 2)
            cv2.circle(frame,(keypoints['mouth_right']), 2, (0,155,255), 2)
    #display resulting frame
    cv2.imshow('frame',frame)
    if cv2.waitKey(1) &0xFF == ord('q'):
        break
#When everything's done, release capture
cap.release()
cv2.destroyAllWindows()

Về bản chất mỗi 1 video đều được chia làm các frame nên việc của ta chỉ cần là xác định khuôn mặt trên các frame là xong. Đơn giản phải không ạ.

Hy vọng với bài viết đơn giản này của mình sẽ giúp ích được cho những bạn đang cần 1 công cụ để detect khuôn mặt. cám ơn các bạn rất nhiều.

Tài liệu tham khảo:

[1] https://towardsdatascience.com/face-detection-neural-network-structure-257b8f6f85d1

[2] https://towardsdatascience.com/mtcnn-face-detection-cdcb20448ce0