Raspberry face recognition

Raspberry pie face recognition access control requirements

Face recognition access control application has been very popular. This paper will describe in detail how to realize face recognition access control application with raspberry pie. There are two functions to be realized:
1. Detect the face, draw the recognition frame and track it in real time
2. Face recognition

Environment construction

Realize face recognition in raspberry pie. The programming language is python. The version can be python2 or python3. opencv and face are required_ Recognition library.

Install Cmake

Installing opencv and face_ Before recognition, to confirm whether a newer version of cmake has been installed in raspberry pie, use the following instructions to install the latest version of cmake:

sudo apt install cmake

Install OpenCV

If it is based on python2 and pip is installed, you can install it directly by using the following instructions:

sudo pip install opencv-python  -i https://pypi.tuna.tsinghua.edu.cn/simple

If you are using python3 and pip3, you can use the following instructions:

sudo pip3 install opencv-python  -i https://pypi.tuna.tsinghua.edu.cn/simple

If the installation fails unfortunately, the latest version of opencv may not support raspberry pie. You can try to specify the version. In order to avoid the problem of slow network speed of foreign image source, the installation of this paper is based on Tsinghua image source.

sudo pip3 install opencv-python==3.4.3.18  -i https://pypi.tuna.tsinghua.edu.cn/simple

If the lib dependency is missing, you need to install the dependency first:

sudo apt install libatlas-base-dev
 
sudo apt install libjasper-dev
 
sudo apt install libqtgui4
 
sudo apt install libqt4-test

sudo apt install libhdf5-dev

You can also refer to the article of cmake installing opencv, which is very troublesome and not easy to succeed.

Installing dlib

Installing face_ dlib needs to be installed before recognition. To determine_ dlib version of recognition requirements, you can go to github View, or try installing:

sudo pip install face_recognition #If it is Python 3, remember to replace it with pip3, which will not be repeated in this article

Although install face_ dlib will be installed automatically during recognition, but it will not succeed. If it succeeds, congratulations on completing the stage of environment construction. Otherwise, you need to go Official website Download the corresponding version of dlib and select the latest version. It's basically right. At least it should exceed face_ The version required by recognition.

After downloading to the local, perform the following steps:

  1. Open the terminal and input instructions to view the virtual memory size
 sudo nano /etc/dphys-swapfile

Because installing dlib requires a large amount of memory, if you open the desktop GUI, 1GB of memory is not enough. You need to set aside a part of the disk as virtual memory. The default virtual memory size of 100MB is not enough. As shown in the figure, the installation of dlib will fail.

It is recommended to change it to 2048MB. If you open the GUI for dlib installation. After modification, Ctrl+O to save, enter enter, and Ctrl+X to exit.

  1. Update virtual memory configuration
sudo /etc/init.d/dphys-swapfile stop
sudo /etc/init.d/dphys-swapfile start
  1. Unzip the downloaded dlib file and enter the unzipped folder
sudo python setup.py install
  1. Just wait patiently. The installation is very time-consuming. You can have a cup of coffee first.

Install face_recognition

Due to the previous steps, this step is very simple. You only need to enter the following instructions.

sudo pip install face_recognition

Check whether it is installed:

pip list

At this point, the environment construction is completed. If you don't want to watch me talk, you can directly jump to Complete code and achievement display.

Face detection and tracking

Get video

A video can be regarded as a continuous picture. To obtain video from the camera is to obtain a frame of pictures. First, the program needs to obtain camera resources. The code is as follows.

import cv2
camera = cv2.VideoCapture(0)

Parameter 0 is the default camera. If there are multiple cameras, it can be changed to the corresponding drive number in / dev.

ret,frame = camera.read()
cv2.flip(frame,1)

frame is the picture read from the camera. Due to the problem of self photographing and mirroring of the camera, I turned it horizontally, which is optional and does not affect the result.

cv2.imshow("window_name",frame)#Window name arbitrary
cv2.waitKey(1)

imshow function can display the obtained picture in the window. waitKey function must be added to raspberry pie, otherwise the window may not be created. Through a while loop, you can continuously read frames of pictures from the camera and display them in the window, which constitutes the video. If the number of pictures displayed on the window is less than 24FPS, a Caton visible to human eyes will appear. This number of frames is also an indicator to consider the performance. The higher the number of frames, the smoother, the faster the recognition algorithm, and the better the performance.

Face detection

The requirement of face detection and tracking is to find the position of face in the picture and mark it. There are many ways to realize this function:

  1. Use face_ Functions of recognition library
  • Detect the face and obtain the face position. The return value is list type
faces = face_recognition.face_locations(frame)
  • Draw a rectangle on the picture to identify the position of the face
cv2.rectangle(frame,(faces[0][1],faces[0][0]),(faces[0][3],faces[0][2]),(255,255,0),2)
  1. Face detection is realized by using haarcascade in opencv:
  • First, load the xml model of harr cascade classifier, which can be downloaded in github or trained by yourself.
faceCascade = cv2.CascadeClassifier("haarcascade_frontalface_default.xml")
  • Face detection
def get_faces(frame):
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)#Convert the picture to gray image to reduce the amount of calculation
    faces = faceCascade.detectMultiScale(gray)
    return faces, frame
  • Draw a rectangle on the picture to identify the position of the face
 cv2.rectangle(img, (faces[0][0],faces[0][1]),(faces[0][2]+faces[0][0],faces[0][3]+faces[0][1]),(255,255,0),2)

Summary: face_recognition is based on neural network model, while harr cascade classifier can be understood as:

Haar classifier = Haar like feature + integral graph method + AdaBoost + cascade;
a) Haar like feature is used for detection.
b) The evaluation of Haar like features is accelerated by using integral image.
c) AdaBoost algorithm is used to train a strong classifier to distinguish face and non face.
d) The classifier is cascaded together by filter cascade to improve the accuracy.

harr cascade classifier has the problem of high re recognition and false recognition, that is, a face is recognized multiple times and a non face is recognized as a face, which is collectively referred to as the error rate (missing recognition is not considered here). The error rate can be found in Comparison of several xml models based on harr cascade classifier github.

Face tracking

To realize the face detection on the picture, we need to further realize the face tracking on the video. The biggest difficulty is how to ensure the tracking of the face while ensuring the fluency of the video. Here, the number of frames is used to measure fluency.

  1. Single thread
  • Test code of harr cascade classifier:
import cv2
import time


######################
########config########
######################

faceCascade = cv2.CascadeClassifier('/home/pi/haarcascade_frontalface_default.xml')
start = time.time()
frame_num = 0 


#check the exist and location of the face

def get_faces(frame):
   gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
   faces = faceCascade.detectMultiScale(gray)
   return faces, frame
   
   
#sign the face location in the image

def sign_faces(img,faces):
  for (x,y,w,h) in faces:
    cv2.rectangle(img, (x,y),(x+w,y+h),(255,0,0),2)
    cv2.imshow("frame",img)
    cv2.waitKey(1)


# main function
    
if __name__ == "__main__":
   camera = cv2.VideoCapture(0)
   while True:
        ret,frame = camera.read()
        faces,frame=get_faces(frame)
        sign_faces(frame,faces)
        frame_num = frame_num+1
        fps = frame_num/(time.time()-start)
        print(fps)

The number of frames fluctuates in the range of 6-10 frames, and the video is obviously stuck.

  • face_ Test code of recognition:
import cv2
import face_recognition
import time

######################
########config########
######################

start = time.time()
frame_num = 0


# check the exist and location of the face

def get_faces(frame):
    faces = face_recognition.face_locations(frame)
    return faces, frame


# sign the face location in the image

def sign_faces(img, faces):
    if(len(faces)>0):
        cv2.rectangle(frame, (faces[0][1], faces[0][0]), (faces[0][3], faces[0][2]), (255, 255, 0), 2)
        cv2.imshow("frame", img)
        cv2.waitKey(1)


# main function

if __name__ == "__main__":
    camera = cv2.VideoCapture(0)
    while True:
        ret, frame = camera.read()
        faces, frame = get_faces(frame)
        sign_faces(frame, faces)
        frame_num = frame_num + 1
        fps = frame_num / (time.time() - start)
        print(fps)

FPS < 1, the video is similar to ppt, but there is almost no detection error (excluding missing recognition).
Summary: single thread can't reach 24 frames per second when the camera has the largest pixel, which can't meet the demand. Therefore, it is necessary to increase the number of frames by reducing the pixels of each frame and extracting frames.

  • Reduce the image quality and detect one image every four images
def get_faces(frame):
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
    faces = faceCascade.detectMultiScale(gray)
    return faces, frame


# sign the face location in the image

def sign_faces(img, faces):
    for (x, y, w, h) in faces:
        cv2.rectangle(img, (x, y), (x + w, y + h), (255, 0, 0), 2)
        cv2.imshow("frame", img)
        cv2.waitKey(1)


# main function

if __name__ == "__main__":
    camera = cv2.VideoCapture(0)
    #Reduce image quality
    camera.set(3,320)
    camera.set(4,240)

    i = 0
    while True:
        ret, frame = camera.read()
        if(i==0):
            faces, frame = get_faces(frame)
        sign_faces(frame, faces)
        frame_num = frame_num + 1
        fps = frame_num / (time.time() - start)
        print(fps)
        i=(i+1)%4

The number of frames jumped to nearly 30, but due to the rush process of the print function, the picture is not displayed. The code for calculating fps is commented out, and the video still does not reach the ideal fluency. There is a certain error in the calculation of the number of frames. Considering the face recognition function, there should be a large margin for the number of frames.

  • Four thread

Considering that raspberry pie is a 4-core cpu, you can also increase the number of frames through multithreading. The code is a little long, so I won't post the code here.
Test results: the number of frames has not increased as much as expected, but the most important thing is that the video will not be blocked in a certain frame during face detection. If face is used_ Recognition face detection can only use multithreading, otherwise it can not meet the requirements.

Face recognition

Selection of identification methods

Face recognition can also use harr cascade classifier and face_recognition has two methods. The former is a traditional computer vision algorithm, and the latter is a neural network model.

Recognition speederror rate
harr<2shigher
face_recognitionAbout 2 secondsLower

By analyzing the business logic, it can be seen that from a user entering the camera picture to leaving the picture is a recognition task. In the same recognition task, only one face recognition is required, rather than face recognition for each picture. Then the difference between the recognition speed of the two implementation methods is not a decisive factor, but considering the needs of security, the error rate is the most critical factor. So face_recognition is better than harr cascade classifier.

Business logic

Such business logic also solves the problem that harr cascade classifiers attach importance to recognition, but it still can not solve the problem of false recognition. If raspberry pie performs well, you can use face_recognition for face detection, under the scheme of multithreading + frame extraction + pixel reduction, can meet the fluency of video, but the Caton is more obvious in face recognition.

Complete code and achievement display

  • The storage path of the photos (folders) of the user's face and the storage path of the xml model are configured in the config module.
  • The code function in Init module is to read the photo of the user's face and encode it.
  • Note: the photos of the user's face only support jpg format. If necessary, you can modify the code in Init module.
import multiprocessing as mp
import cv2
import face_recognition
import os

######################
########config########
######################

face_path="/home/pi/Pictures"  #your_bface_dir
faceCascade = cv2.CascadeClassifier('/home/pi/haarcascade_frontalface_default.xml')


######################
########Init##########
######################

faces = [] # face  list
names = [] # name  list
flist = os.listdir(face_path)
for fstr in flist:
  s = fstr.split('.')
  if s[len(s)-1]=="jpg":
    face = face_recognition.load_image_file(face_path+"/"+fstr) # load jpg file in face_path
    face_code = face_recognition.face_encodings(face)[0]#get face code 
    face_name = s[0]#get face name 
    faces.append(face_code)#put into faces
    names.append(face_name)#put into names





#check the exist and location of the face by harr
#def get_faces(frame):
 #   gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
  #  faces = faceCascade.detectMultiScale(gray)
   # return faces, frame


#check the exist and location of the face by face_recognition
def get_faces(frame):
    
    faces = face_recognition.face_locations(frame)
    return faces, frame

#sign the face location in the image
def sign_faces(img,faces,name):
    if(len(faces)==1):
      for (x,y,w,h) in faces:
        #cv2.rectangle(img, (x,y),(x+w,y+h),(255,0,0),2)   # harr uses this
        cv2.rectangle(img, (y,x),(h,w),(255,0,0),2)#face_recognition this line is used for face detection
        if(name!="not a face"):
          # cv2.putText(img,name,(x,y),cv2.FONT_HERSHEY_SIMPLEX,0.5,(0,0,255),2)  # harr uses this line
           cv2.putText(img,name,(y,x),cv2.FONT_HERSHEY_SIMPLEX,0.5,(0,0,255),2)#face_recognition this line is used for face detection
        else:
            name = "not a face"
    cv2.imshow("frame",img)
    cv2.waitKey(1)

#detect face and recognition  
def face_recog(frame):

   name = "not a face"
   #encoding 
   frame_codes = face_recognition.face_encodings(frame)#encoding frame
   # if frmae not face ,skip
   if(len(frame_codes)>0):
     uface_code = frame_codes[0]#get uface code 
     name = "unkonw"
     result = face_recognition.compare_faces(faces,uface_code,tolerance=0.45)
     for index,i in enumerate(result):
       if i:
         name = names[index]
         break
     #show face_location and recognition_result 
   return name



# main function
    
if __name__ == "__main__":
    global name
    name = "not a face"
    pool = mp.Pool(processes=4)
    i = 0
    r = [None] * 4 
    facesList = [None] * 4
    frame = [None] * 4
    imageList = [None] * 16
    
    cap = cv2.VideoCapture(0)
    #decrease its scale
    cap.set(3,320)
    cap.set(4,240)
    
    #assignment the process first
    ret,frame[0] = cap.read()    
    r[0] = pool.apply_async(get_faces,[frame[0]])
    ret,frame[1] = cap.read()
    r[1] = pool.apply_async(get_faces,[frame[1]])
    ret,frame[2] = cap.read()
    r[2] = pool.apply_async(get_faces,[frame[2]])
    ret,frame[3] = cap.read()
    r[3] = pool.apply_async(get_faces,[frame[3]])
    
    facesList[0],imageList[0] = r[0].get()
    facesList[1],imageList[4] = r[1].get()
    facesList[2],imageList[8] = r[2].get()
    facesList[3],imageList[12] = r[3].get()
    
    for j in range(4):
        imageList[4*j+1] = imageList[j]
        imageList[4*j+2] = imageList[j]
        imageList[4*j+3] = imageList[j]
        
    while(1):
        #whether to quit
        if cv2.waitKey(1) & 0xFF == ord('q'):
            #cv2.imwrite("camera.jpg",frame) #write image to file
            break
        
        
        if(i==0):
            ret,frame[0] = cap.read()
            r[0] = pool.apply_async(get_faces,[frame[0]])
            sign_faces(imageList[i+1],facesList[0],name)
        elif(i==1):
            ret,frame[0] = cap.read()
            imageList[i] = frame[0]
            sign_faces(imageList[i+1],facesList[0],name)
        elif(i==2):
            ret,frame[0] = cap.read()
            imageList[i] = frame[0]
            sign_faces(imageList[i+1],facesList[0],name)
        
        elif(i==3):
            ret,frame[1] = cap.read()
            imageList[i] = frame[1]
            facesList[1],imageList[i+1] = r[1].get()
            sign_faces(imageList[i+1],facesList[1],name)
        elif(i==4):
            ret,frame[1] = cap.read()
            r[1] = pool.apply_async(get_faces,[frame[1]],)
            sign_faces(imageList[i+1],facesList[1],name)
        elif(i==5):
            ret,frame[1] = cap.read()
            imageList[i] = frame[1]
            sign_faces(imageList[i+1],facesList[1],name)
        elif(i==6):
            ret,frame[1] = cap.read()
            imageList[i] = frame[1]
            sign_faces(imageList[i+1],facesList[1],name)
            
        elif(i==7):
            ret,frame[2] = cap.read()
            imageList[i] = frame[2]
            facesList[2],imageList[i+1] = r[2].get()
            sign_faces(imageList[i+1],facesList[2],name)
        elif(i==8):
            ret,frame[2] = cap.read()
            r[2] = pool.apply_async(get_faces,[frame[2]])
            sign_faces(imageList[i+1],facesList[2],name)
        elif(i==9):
            ret,frame[2] = cap.read()
            imageList[i] = frame[2]
            sign_faces(imageList[i+1],facesList[2],name)
        elif(i==10):
            ret,frame[2] = cap.read()
            imageList[i] = frame[2]
            sign_faces(imageList[i+1],facesList[2],name)
            
        elif(i==11):
            ret,frame[3] = cap.read()
            imageList[i] = frame[3]
            facesList[3],imageList[i+1] = r[3].get()
            sign_faces(imageList[i+1],facesList[3],name)
        elif(i==12):
            ret,frame[3] = cap.read()
            r[3] = pool.apply_async(get_faces,[frame[3]])
            sign_faces(imageList[i+1],facesList[3],name)
        elif(i==13):
            ret,frame[3] = cap.read()
            imageList[i] = frame[3]
            sign_faces(imageList[i+1],facesList[3],name)
        elif(i==14):
            ret,frame[3] = cap.read()
            imageList[i] = frame[3]
            sign_faces(imageList[i+1],facesList[3],name)
            
        elif(i==15):
            ret,frame[0] = cap.read()
            imageList[i] = frame[0]
            facesList[0],imageList[0] = r[0].get()
            if(name=="not a face"):
                if(len(facesList[0])==1):
                    name = face_recog(imageList[0])
            else:
                if(len(facesList[0])!=1):
                    name = "not a face"
            sign_faces(imageList[0],facesList[0],name)
            i = -1
        
        i += 1
        

    cap.release()
    cv2.destroyAllWindows()  


Result display:

zxPi (raspberrypi) - VNC Viewer 2021-06-14 00-09-33

Keywords: Python OpenCV face recognition

Added by scotte on Tue, 01 Feb 2022 03:06:27 +0200