Nhận diện khuôn mặt với OpenCV trên Raspberry Pi (Phần 2)

Nhận diện khuôn mặt với OpenCV trên Raspberry Pi (Phần 2)

09:28 - 21/03/2019

Nhận diện khuôn mặt với OpenCV trên Raspberry Pi (Phần 2)

NVIDIA Jetson AGX Orin hiệu suất AI mạnh nhất của NVIDIA Jetson Family với 275 TOPS, 2048 NVIDIA® CUDA® cores, 64 Tensor Cores
NVIDIA Jetson AGX Orin Hardware Layout and GPIO Expansion Header Pinout
NVIDIA Jetson là nền tảng hàng đầu thế giới dành cho Trí tuệ nhân tạo (AI) và Deep Learning
Cách sử dụng Camera CSI với hệ điều hành Raspberry Pi Bulleyes mới nhất
Jetson Stats dùng cho Giám sát và Điều khiển trên NVIDIA Jetson Ecosystem [Xavier NX, Nano, AGX Xavier, TX1, TX2]

Nhận diện khuôn mặt với OpenCV trên Raspberry Pi (Phần 2)

Xin chào các bạn !!!

Tiếp tục loạt bài về xử lý ảnh trên Raspberry Pi với việc sử dụng thư viện OpenCV. Trong bài viết này chúng ta sẽ tiếp tục với việc nhận dạng khuôn mặt và ai là chủ sở hữu khuôn mặt với hình ảnh thu được trực tiếp từ Camera cho Raspberry Pi.


Bước 1: Thu thập dữ liệu


Đầu tiên chúng ta sẽ thu thập dữ liệu để phục vụ cho quá trình nhận dạng khuôn mặt.

Chúng ta cần tạo ra một bộ dữ liệu và chúng ta sẽ lưu trữ cho mỗi id một nhóm ảnh Gray với việc phát hiện khuôn mặt ở phần trước.

Chúng ta sẽ tạo một thư mục với tên "Face_recognition" trên Desktop bằng lệnh trên Terminal:

 

Trong thư mục này ngoài 3 tập lệnh mà chúng ta sẽ tạo ngay sau đây thì các bạn cần sử dụng thêm tệp "haarcascade_frontalface_default.xml" đã được chúng ta tải xuống ở phần trước.

Tiếp theo chúng ta cần tạo một thư mục con chứa tất cả các khuôn mặt của chúng ta với tên là "dataSet".

 

Giờ chúng ta cùng bắt đầu thu thập dữ liệu. Các bạn tạo một tệp với tên "dataSetGenerator.py"

 

Các bạn có thể gõ lại đoạn code phía dưới hoặc tải trực tiếp tệp xuống tại đây : https://github.com/DemoDoremon/Image-Processing/blob/master/dataSetGenerator.py


from picamera.array import PiRGBArray
from picamera import PiCamera
import cv2
 
# initialize the camera and grab a reference to the raw camera capture
camera = PiCamera()
camera.resolution = (320, 240)
camera.framerate = 24
rawCapture = PiRGBArray(camera, size=(320, 240))
#Load a cascade file for detecting faces
face_cascade = cv2.CascadeClassifier('/home/pi/Desktop/Face_recognition/haarcascade_frontalface_default.xml')
face_id = input("\n Enter user id :"
print ("\n [INFO] Initializing face capture. Look the camera and wait ...")
count = 0
# capture frames from the camera
for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
    # convert frame to array
    image = frame.array
    #Convert to grayscale
    gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
    #Look for faces in the image using the loaded cascade file
    faces = face_cascade.detectMultiScale(gray, scaleFactor = 1.2, minNeighbors = 5, minSize = (100, 100), flags = cv2.CASCADE_SCALE_IMAGE)
 
    print ("Found "+str(len(faces))+" face(s)")
    #Draw a rectangle around every found face
    for (x,y,w,h) in faces:
        roi_gray = gray[y:y + h, x:x + w]
        cv2.rectangle(image,(x,y),(x+w,y+h),(255,0,0),2)
        print(x,y,w,h)
    #Save the result image
    if len(faces):
        count = count + 1
        img_item = "dataSet/User."+ face_id + '.' + str(count) + ".jpg"
        cv2.imwrite(img_item,roi_gray)
    # display a frame    
    cv2.imshow("Frame", image)
    #wait for 'q' key was pressed and break from the loop
    if cv2.waitKey(1) & 0xff == ord("q"):
    exit()
    if count == 100:
        exit()
    # clear the stream in preparation for the next frame
    rawCapture.truncate(0)


 Đầu tiên chúng ta sẽ khởi tạo PiCamera và PiRGBArray object với kích thước frame là 320×240, framrate = 24.

camera = PiCamera()
camera.resolution = (320, 240)
camera.framerate = 24
rawCapture = PiRGBArray(camera, size=(320, 240))

Sau đó chúng ta có thêm một lệnh nhập id người dùng, cụ thể ở đây id là một số nguyên ( 1, 2, 3 …) 

face_id = input("\n Enter user id :")

Tiếp theo chúng ta truy cập vào video stream với method capture_continuous(). Method này trả về một infinite iterator của các frame nhận được từ RPi Camera.

for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True) :

Tiếp đến chúng ta chuyển frame thành dạng array và chuyển đổi nó sang dạng grayscale.

image = frame.array
gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)

Từ tệp mô hình đã tải lên chúng ta sẽ tìm kiếm khuôn mặt.

faces = face_cascade.detectMultiScale(gray, scaleFactor = 1.2, minNeighbors = 5, minSize = (100, 100), flags = cv2.CASCADE_SCALE_IMAGE)

Chúng ta sẽ vẽ một hình chữ nhật xung quanh khuôn mặt mà chúng ta tìm được bằng vòng lặp :

for (x,y,w,h) in faces:
        roi_gray = gray[y:y + h, x:x + w]
        cv2.rectangle(image,(x,y),(x+w,y+h),(255,0,0),2)

Với mỗi khung hình khuôn mặt mà chúng ta thu được sẽ được lưu dưới định dạng "jpg" trong thư mục "dataset/"

img_item = "dataSet/User."+ face_id + '.' + str(count) + ".jpg"
 
cv2.imwrite(img_item,roi_gray)

Tên của tệp sẽ theo cấu trúc : 

User.face_id.count.jpg

Với người dùng có face_id = 1, tệp lấy mẫu thứ 4  trong thư mục có dạng như sau :

User.1.4.jpg

Cuối cùng chúng ta bắt buộc phải xóa frame đang được hiển thị trước khi nhận frame tiếp theo.

rawCapture.truncate(0)

Kết quả sẽ như hình :

Trong đoạn code trên với mỗi id chúng ta sẽ chụp 100 tấm hình khuôn mặt để làm dữ liệu nhận dạng. Các bạn có thể điều chỉnh nếu muốn.

Các bạn chạy tập lệnh python và chụp một vài id nhé. Khi chụp đủ 100 tấm hình cho mỗi id thì tập lệnh sẽ dừng hoặc bạn có thể dừng việc chụp ảnh bằng cách nhấn phím "q". Bạn phải chạy tập lệnh mỗi lần bạn muốn thêm id mới.

 


Bước 2 Train data


Trong bước này chúng ta cần lấy tất cả dữ liệu người dùng từ bộ dữ liệu chúng ta thu được ở trên và train data với chức năng trên OpenCV. Kết quả sẽ là một tệp .yml sẽ được lưu trong thư mục” trainer/”.

Giờ chúng ta sẽ tạo một thư mục con với tên “trainer” :

 

Tiếp đến các bạn tạo một tệp có tên “train.py” :

 

Các bạn có thể gõ lại đoạn code phía dưới hoặc tải trực tiếp tệp xuống tại đây : https://github.com/DemoDoremon/Image-Processing/blob/master/train.py


import cv2
import numpy as np
from PIL import Image
import os
# Path for face image database
path = 'dataSet'
 
#use Local Binary Patterns Histograms
recognizer = cv2.face.LBPHFaceRecognizer_create()
detector = cv2.CascadeClassifier('/home/pi/Desktop/Face_recognition/haarcascade_frontalface_default.xml')
# function to get the images and label data
def getImagesAndLabels(path):
    imagePaths = [os.path.join(path,f) for f in os.listdir(path)]     
    faceSamples=[]
    ids = []
    for imagePath in imagePaths:
        PIL_img = Image.open(imagePath).convert('L'# convert it to grayscale
        img_numpy = np.array(PIL_img,'uint8')
        id = int(os.path.split(imagePath)[-1].split(".")[1])
        faces = detector.detectMultiScale(img_numpy)
        for (x,y,w,h) in faces:
            faceSamples.append(img_numpy[y:y+h,x:x+w])
            ids.append(id)
    return faceSamples,ids
print ("\n [INFO] Training faces. It will take a few seconds. Wait ...")
faces,ids = getImagesAndLabels(path)
recognizer.train(faces, np.array(ids))
# Save the model into trainer/trainer.yml
recognizer.write('/home/pi/Desktop/Face_recognition/trainer/trainer.yml'# recognizer.save() worked on Mac, but not on Pi
# Print the numer of faces trained and end program
print("\n [INFO] {0} faces trained. Exiting Program".format(len(np.unique(ids))))

Lưu ý : Các bạn cần cài đặt thêm thư viện PIL nếu các bạn chưa cài đặt trước đó với câu lệnh : 

 

Tiếp theo chúng ta sẽ sử dụng cô cụ nhận dạng khuôn mặt LBPH (LOCAL BINARY PATTERNS HISTOGRAMS) nằm trong thư viện OpenCV.

recognizer = cv2.face.LBPHFaceRecognizer_create()

Hàm "getImagesAndLabels(path)" sẽ lấy tất cả ảnh trong thư mục "dataSet/" và trả về 2 mảng : "id" và "face". Với các mảng này chúng ta sẽ dùng để train data.

recognizer.train(faces, np.array(ids))

Tệp có tên "trainer.yml" sẽ được lưu trong thư mục "trainer/" đã được chúng ta tạo ra trước đó.

Mỗi lần thêm mới id thì chúng ta cần thực thi tập lệnh ở bước 1 sau đó là thực thi tập lệnh ở bước 2. Kết của sau khi train :

 


Bước 3. Nhận dạng


Đây là bước cuối cùng để nhận dạng khuôn mặt ứng với người nào. Giờ chúng ta sẽ nhận dạng với hình ảnh thu trực tiếp từ camera và kết quả trả về là id và tên của người chủ sở hữu khuôn mặt đó đi kèm là mức độ tin cậy của việc nhận dạng.

Các bạn tạo một tệp với tên "recognition.py" :

Các bạn có thể gõ lại đoạn code phía dưới hoặc tải trực tiếp tệp xuống tại đây : https://github.com/DemoDoremon/Image-Processing/blob/master/recognition.py


from picamera.array import PiRGBArray
from picamera import PiCamera
import cv2
# initialize the camera and grab a reference to the raw camera capture
camera = PiCamera()
camera.resolution = (320, 240)
camera.framerate = 24
rawCapture = PiRGBArray(camera, size=(320, 240))
#use Local Binary Patterns Histograms
recognizer = cv2.face.LBPHFaceRecognizer_create()
#Load a trainer file
recognizer.read('/home/pi/Desktop/Face_recognition/trainer/trainer.yml')
#Load a cascade file for detecting faces
face_cascade = cv2.CascadeClassifier('/home/pi/Desktop/Face_recognition/haarcascade_frontalface_default.xml')
font = cv2.FONT_HERSHEY_SIMPLEX
#iniciate id counter
id = 0
# names related to ids: example ==> Marcelo: id=1,  etc
names = ['none', 'Demodoremon', 'Obama'
# capture frames from the camera
for frame in camera.capture_continuous(rawCapture, format="bgr", use_video_port=True):
    # convert frame to array
    image = frame.array
    #Convert to grayscale
    gray = cv2.cvtColor(image,cv2.COLOR_BGR2GRAY)
    #Look for faces in the image using the loaded cascade file
    faces = face_cascade.detectMultiScale(gray, scaleFactor = 1.2, minNeighbors = 5, minSize = (100, 100), flags = cv2.CASCADE_SCALE_IMAGE)
 
    print ("Found "+str(len(faces))+" face(s)")
    #Draw a rectangle around every found face
    for (x,y,w,h) in faces:
        roi_gray = gray[y:y + h, x:x + w]
        cv2.rectangle(image,(x,y),(x+w,y+h),(255,0,0),2)
        id, confidence = recognizer.predict(gray[y:y+h,x:x+w])
        # Check if confidence is less them 100 ==> "0" is perfect match 
        if (confidence < 100):
            id = names[id]
            confidence = "  {0}%".format(round(100 - confidence))
        else:
            id = "unknown"
            confidence = "  {0}%".format(round(100 - confidence))
 
        cv2.putText(image, str(id), (x+5,y-5), font, 1, (255,255,255), 2)
        cv2.putText(image, str(confidence), (x+5,y+h-5), font, 1, (255,255,0), 1)  
        print(x,y,w,h)
    # display a frame    
    cv2.imshow("Frame", image)
    if cv2.waitKey(1) & 0xff == ord("q"):
    exit()
    # clear the stream in preparation for the next frame
    rawCapture.truncate(0)

Chúng ta sẽ thêm vào một mảng với để hiển thị "names" thay vì "id" được đánh số :

names = ['none', 'Demomoremon', 'Obama']

Do đó Demodoremon sẽ là người có id=1, Obama : id =2,…

Tiếp theo chúng ta sẽ phát hiện khuôn mặt như ở trên với việc sử dụng mô hình hassCascade

id, confidence = recognizer.predict(gray[y:y+h,x:x+w])

Công cụ nhận dạng .predict() sẽ lấy tham số là một phần của hình ảnh được chụp của khuôn mặt cần phân tích và sẽ trả về chủ sở hữu của khuôn mặt đó, cho biết id và mức độ tin cậy của việc nhận dạng.

Kết quả thu được như hình :

 

Tổng kết : Các thư mục và tệp chúng ta cần dùng cho quá trình xử lý ảnh như trên.

Các bạn hãy làm theo các bước mà mình hướng dẫn và trải nghiệm kết quả thu được nhé !

Trong thời gian tới mình sẽ sử dụng thêm một số kỹ thuật khác để nâng cao hiệu quả của quá trình nhận dạng.

Nếu các bạn có bất kỳ ý tưởng mới nào đừng ngần ngại mà hãy inbox trực tiếp cho fanpage . Xin chào và hẹn gặp lại các bạn trong các bài viết tiếp theo !!!

PIVIETNAM.COM.VN CHÚC CÁC BẠN THÀNH CÔNG !!!

Thực hiện bài viết : Đào Văn Hậu


Để cập nhật các tin tức công nghệ mới các bạn làm theo hướng dẫn sau đây :

Các bạn vào Trang chủ >> Tin tức. ở mục này có các bài viết kỹ thuật thuộc các lĩnh vực khác nhau các bạn có thể lựa chọn lĩnh vực mà mình quan tâm để đọc nhé !!!

Các bạn cũng có thế kéo xuống cuối trang để xem những tin tức công nghệ mới nhất.