Haarcascade_frontalface_default.xml là gì

Face Detection [Phát hiện khuôn mặt] là một ứng dụng của Computer Vision được sử dụng trong nhiều lĩnh vực, với chức năng phát hiện khuôn mặt con người trong một bức ảnh kỹ thuật số.

Mặc dù Deep Learning ngày càng có nhiều đột phá [thực thế thì OpenCV 3 đã cung cấp bộ Face Detection dựa trên Deep Learning], nhưng Cascade Classifier vẫn là một thuật toán được sử dụng phổ biến cho bài toán Object Detection vì tốc độ cao và độ chính xác khá ổn. Bài viết này sẽ giới thiệu về Cascade Classifier với Haar-like features được cung cấp sẵn bởi OpenCV.

VIOLA-JOHN DETECTOR

Ở phần này chúng ta sẽ tìm hiểu khái quát về Viola-John detector, giải thuật được sử dụng trong Cascade Classifier. Ban đầu giải thuật này chỉ hỗ trợ Haar-like features [Haar Cascade Classifier], nhưng kể từ OpenCV 3.x thì đã hỗ trợ thêm Local Binary Pattern Histogram [LBP Cascade Classifier].

Với bài toán Face Detection, mỗi bức ảnh được đưa vào detector sẽ được “scan” bởi một “sliding window” có kích thước cố định ở nhiều tỉ lệ của bức ảnh, hình 1.

Hình 1 – Sliding window

Tại mỗi “window”, các Haar-like features [hình 2] có trong vùng hình ảnh đó sẽ được tính toán bằng cách áp dụng Summed Area Tables [còn gọi là Integral Image].

Hình 2 – Haar-like featues

Từ mỗi “window” có thể tính toán ra rất nhiều Haar-like features [khoảng 180000 features cho “window” có kích thước 24×24]. Để có thể xử lý hết số lượng feature khổng lồ này, Viola-John detector sử dụng một phương pháp gọi là Rejection Cascade, hình 3.

Hình 3 – Rejection Cascade được sử dụng trong Viola-John detector.

Bản chất mỗi node [F1, F2,…, Fn] trong Rejection Cascade là một AdaBoosted Decision Tree classifier được train từ một dataset rất lớn gồm hàng [chục] nghìn bức ảnh chứa và không chứa khuôn mặt [OpenCV đã cung cấp sẵn một số file cascade classifier để phát hiện khuôn mặt nên chúng ta không cần phải tự train nữa!]. Thông thường, mỗi node sẽ dựa trên 1 feature [và tối đa không quá 3 features] để đưa ra quyết định xem vùng “window” đó có thể chứa khuôn mặt hay không. Nếu có, nó sẽ được đưa tới node tiếp theo để xử lý; ngược lại thì quá trình xử lý kết thúc. Chỉ những “window” nào vượt qua tất cả n nodes thì mới được công nhận là chứa khuôn mặt. Viola-John detector có tốc độ xử lý rất nhanh, vì đa số “window” không chứa khuôn mặt sẽ bị loại bỏ ngay từ một vài node đầu tiên của Rejection Cascade.

Nhờ áp dụng Summed Area Tables, AdaBoost algorithm và Rejection Cascade nên Haar cascade tính toán rất nhanh và có thể phát hiện khuôn mặt ở nhiều vị trí và tỉ lệ, cũng như rất phù hợp cho các ứng dụng real-time.

Tuy nhiên Haar cascade có những điểm yếu sau:

  • Thời gian training cho cascade rất lớn, vì phải train cho hàng chục node, mỗi node lại là một AdaBoosted Decision Tree classifier;
  • Tỉ lệ False-positive và False-negative cao do khó tìm được các tham số tối ưu;
  • Cần tinh chỉnh các tham số cho phù hợp với từng bức ảnh để đạt được kết quả tốt nhất.

FACE DETECTION IN OPENCV

Cùng tìm hiểu một số function của OpenCV 3 sẽ được sử dụng trong Face Detection nào.

  • CascadeClassifier = cv2.CascadeClassifier[cascadeFile] – Load a classifier from a file.

Trong đó:

cascadeFile – Cascade file, thường nằm tại folder ..\opencv\build\share\OpenCV. Trong bài viết này chúng ta sẽ sử dụng Haarcascades.

  • detectedObjects = CascadeClassifier.detectMultiScale[image, scaleFactor,  minNeighbors, flags, minSize] – Phát hiện các đối tượng [được qui định trong Classifier] với các kích thước khác nhau có trong bức ảnh. Các đối tượng được phát hiện sẽ được trả về ở dạng “a list of rectangles“.

Trong đó:

image – input image.
scaleFactor – được sử dụng để tạo “scale pyramid” cho phép phát hiện đối tượng ở multiple scales.
minNeighbors – số lượng overlap window ít nhất trên một vùng hình ảnh để vùng đó được công nhận là có chứa khuôn mặt, thường có giá trị trong khoảng [3, 4, 5, 6]. Tham số này giúp giảm “false detection”.
+ minSize – kích thước nhỏ nhất của đối tượng có thể được phát hiện, thường là [30, 30]. Các đối tượng có kích thước nhỏ hơn minSize sẽ bị bỏ qua.

FACE DETECTION IN IMAGES

Example 1 – faceDetection.py

import argparse import cv2 class FaceDetector: def __init__[self, faceCascadePath]: self.faceCascade = cv2.CascadeClassifier[faceCascadePath] def detect[self, image, scaleFactor=1.1, minNeighbors=5, minSize=[30, 30]]: rects = self.faceCascade.detectMultiScale[image, scaleFactor=scaleFactor, minNeighbors=minNeighbors, minSize=minSize, flags=cv2.CASCADE_SCALE_IMAGE] return rects ap = argparse.ArgumentParser[] ap.add_argument["-f", "--face"] ap.add_argument["-i", "--image"] args = vars[ap.parse_args[]] image = cv2.imread[args["image"]] gray = cv2.cvtColor[image, cv2.COLOR_BGR2GRAY] fd = FaceDetector[args["face"]] faceRects = fd.detect[gray, scaleFactor=1.1, minNeighbors=6, minSize=[30, 30]] print["I found {} face[s]".format[len[faceRects]]] for [x,y,w,h] in faceRects: cv2.rectangle[image, [x,y], [x+w, y+h], [0,255,0], 2] cv2.imshow["Faces", image] cv2.waitKey[0]

Execution:
$ python faceDetection.py -i images -f ..\haarcascades\haarcascade_frontalface_default.xml

Kết quả:

Hình 4 – Footballists

Hình 5 – Arsenal FC

Hình 6 – Cesc Fabregas

Với các tham số không đổi, ở Figure 4, cả 5 khuôn mặt đều được phát hiện, tuy nhiên ở Figure 5, chúng ta lại phát hiện sót khuôn mặt của anh da đen, còn ở Figure 6 có đến 2 khuôn mặt được phát hiện!!!.

Thử thay đổi scaleFactor = 1.05 xem nào:

Hình 7 – Footballists

Hình 8 – Arsenal FC

Hình 9 – Cesc Fabregas

Cuối cùng thì khuôn mặt của anh da đen cũng đã được phát hiện. Tuy nhiên trong bức ảnh của Cesc Fabregas lại phát hiện đến 3 khuôn mặt!!!

Chúng ta sẽ thay scaleFactor = 1.15 xem kết quả thay đổi thế nào:

Hình 10 – Footballists

Hình 11 – Arsenal FC

Hình 12 – Cesc Fabregas

Lần này thì chúng ta đã phát hiện đúng khuôn mặt trong bức ảnh của Cesc Fabregas, tuy nhiên bức ảnh của Arsenal FC đã bị phát hiện thiếu vài khuôn mặt.

Qua các ví dụ trên có thể thấy rằng Haarcascade mặc dù khá nhanh nhưng có 2 điểm yếu nổi bật là:

  1. Điểm yếu đầu tiên, để có được kết quả tốt nhất chúng ta buộc phải điều chỉnh các tham số như scaleFactor, minNeighbors cho phù hợp với riêng từng bức ảnh. Điều này là bất khả thi nếu chúng ta cần phải xử lý hàng ngàn tấm ảnh.
  2. Điểm yếu tiếp theo chính là “False positive“, có nghĩa là Haarcascade phát hiện ra các khuôn mặt trong bức ảnh mặc dù thực tế là chẳng có khuôn mặt nào ở vị trí đó. Figure 6 là một ví dụ. Tất nhiên các khuyết điểm này có thể được loại bỏ bằng cách “điều chỉnh các tham số như scaleFactor, minNeighbors cho phù hợp với riêng từng bức ảnh“.

Mình cũng rút ra một kinh nghiệm, nếu phát hiện thiếu các khuôn mặt thì hãy giảm giá trị scaleFactor, nếu gặp “False Positive” thì tăng giá trị scaleFactor. Giá trị minNeighbors tốt nhất là 5 hoặc 6.

Tất nhiên không có gì là hoàn hảo, hãy cứ vui với kết quả chúng ta vừa nhận được nhé! Mọi thứ chỉ mới bắt đầu.

FACE DETECTION IN VIDEO

Để phát hiện khuôn mặt trên video [từ webcam], chúng ta sẽ xử lý từng frame của video đó, tương tự như đối với từng bức ảnh riêng biệt ở ví dụ trước.

Trong bài viết này mình sử dụng Webcam Logitech C270.

Example 2 – webcamFaceDetection.py

import argparse import cv2 from threading import Thread class FaceDetector: def __init__[self, faceCascadePath]: self.faceCascade = cv2.CascadeClassifier[faceCascadePath] def detect[self, image, scaleFactor=1.1, minNeighbors=5, minSize=[30, 30]]: rects = self.faceCascade.detectMultiScale[image, scaleFactor=scaleFactor, minNeighbors=minNeighbors, minSize=minSize, flags=cv2.CASCADE_SCALE_IMAGE] return rects class WebcamVideoCapture: def __init__[self, src=0]: # initialize the video camera stream and read the first frame # from the stream self.stream = cv2.VideoCapture[src] [self.grabbed, self.frame] = self.stream.read[] # initialize the variable used to indicate if the thread should # be stopped self.stopped = False def start[self]: # start the thread to read frames from the video stream Thread[target=self.update, args=[]].start[] return self def update[self]: # keep looping infinitely until the thread is stopped while True: # if the thread indicator variable is set, stop the thread if self.stopped: self.stream.release[] return # otherwise, read the next frame from the stream [self.grabbed, self.frame] = self.stream.read[] def read[self]: # return the frame most recently read return self.grabbed, self.frame def stop[self]: # indicate that the thread should be stopped self.stopped = True ap = argparse.ArgumentParser[] ap.add_argument["-f", "--face"] args = vars[ap.parse_args[]] video = WebcamVideoCapture[src=0].start[] fd = FaceDetector[args["face"]] while True: grabbed, frame = video.read[] if not grabbed: continue gray = cv2.cvtColor[frame, cv2.COLOR_BGR2GRAY] faceRects = fd.detect[gray, scaleFactor=1.1, minNeighbors=6, minSize=[30, 30]] count = 0 for [x,y,w,h] in faceRects: count += 1 cv2.rectangle[frame, [x,y], [x+w, y+h], [0,255,0], 2] cv2.putText[frame, "Face [{}]".format[count], [x,y-15], cv2.FONT_HERSHEY_SIMPLEX, 1, [0,255,0], 2, cv2.LINE_AA] cv2.imshow["Faces", frame] if cv2.waitKey[1] & 0xFF == ord['q']: break video.stop[] cv2.destroyAllWindows[]

Execution:
$ python faceDetection.py -f ..\haarcascades\haarcascade_frontalface_default.xml

Như các bạn thấy, các function xử lý hình ảnh đều tương tự ví dụ 1, chỉ khác ở chỗ chúng ta sẽ xử lý liên tiếp các frame nhận được từ webcam. Ngoài ra ở ví dụ này mình còn sử dụng class WebcamVideoCapture để capture hình ảnh từ webcam với một thread riêng biệt nhằm hạn chế độ trễ.

Tại dòng 66 mình có sử dụng function cv2.putText[] để thêm các ký tự lên bức ảnh:

cv2.putText[image, text, [x,y], font, size, color, thickness, lineType]

Trong đó:

  • image – hình ảnh cần chèn ký tự.
  • text – nội dung cần chèn vào bức ảnh.
  • [x,y] – tọa độ đoạn text.
  • font – thường sử dụng font cv2.FONT_HERSHEY_SIMPLEX.
  • color – màu chữ ở hệ [B,G,R].
  • thickness – độ dày của nét chữ.
  • lineType – thường dùng cv2.LINE_AA [đối với OpenCV3], cv2.CV_AA [đối với OpenCV 2.4]

Như vậy chúng ta đã làm quen với chức năng phát hiện khuôn mặt trên OpenCV, hãy tiếp tục khám phá nhé. Cảm ơn các bạn đã theo dõi bài viết.

Thân ái và quyết thắng.

Reference:
[1] StackOverFlow – Recommended values for OpenCV detectMultiScale[] parameters.
[2] Increasing webcam FPS with Python and OpenCV.
[3] Drawing functions OpenCV 3.
[4] Face Detection using Haar Cascades

Video liên quan

Chủ Đề