-1

I am currently creating a django face detection/recognition app to mark employee attendance, however I am facing some issues when capturing the camera feed and detecting the faces on the feed.

The functions below within the view.py are to detect the employee face and capture 300 images of the logged in employee - Essentially the aim of this question is to resolve the face detection issue and the issue is specifically lying within face_aligned = fa.align(frame, gray_frame, face).

views.py:

def create_dataset(username):
   

    id = username
    if (os.path.exists('Recog_Data/Train_Data/{}/'.format(id)) == False):
        os.makedirs('Recog_Data/Train_Data/{}/'.format(id))
    directory = 'Recog_Data/Train_Data/{}/'.format(id)

    # Detect face
    # Loading the HOG face detector and the shape predictpr for allignment

    print("[INFO] Loading the facial detector")
    detector = dlib.get_frontal_face_detector()
    predictor = dlib.shape_predictor('Recog_Data/shape_predictor_68_face_landmarks.dat')  # Add path to the shape predictor ######CHANGE TO RELATIVE PATH LATER
    fa = FaceAligner(predictor, desiredFaceWidth=256)
    # capture images from the webcam and process and detect the face
    # Initialize the video stream
    print("[INFO] Initializing Video stream")
    vs = VideoStream(src=0).start()
    # time.sleep(2.0) ####CHECK######

    # Our identifier
    # We will put the id here and we will store the id with a face, so that later we can identify whose face it is

    # Our dataset naming counter
    sampleNum = 0
    # Capturing the faces one by one and detect the faces and showing it on the window
    while (True):
        # Capturing the image
        # vs.read each frame
        frame = vs.read()
        # Resize each image
        frame = imutils.resize(frame, width=800)
        # the returned img is a colored image but for the classifier to work we need a greyscale image
        # to convert
        gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
        # To store the faces
        # This will detect all the images in the current frame, and it will return the coordinates of the faces
        # Takes in image and some other parameter for accurate result
        faces = detector(gray_frame, 2)
        # In above 'faces' variable there can be multiple faces so we have to get each and every face and draw a rectangle around it.

        for face in faces:
            print("inside for loop")
            (x, y, w, h) = face_utils.rect_to_bb(face)

            face_aligned = fa.align(frame, gray_frame, face)
            # Whenever the program captures the face, we will write that is a folder
            # Before capturing the face, we need to tell the script whose face it is
            # For that we will need an identifier, here we call it id
            # So now we captured a face, we need to write it in a file
            sampleNum = sampleNum + 1
            # Saving the image dataset, but only the face part, cropping the rest

            if face is None:
                print("face is none")
                continue

            cv2.imwrite(directory + '/' + str(sampleNum) + '.jpg', face_aligned)
            face_aligned = imutils.resize(face_aligned, width=400)
            # cv2.imshow("Image Captured",face_aligned)
            # @params the initial point of the rectangle will be x,y and
            # @params end point will be x+width and y+height
            # @params along with color of the rectangle
            # @params thickness of the rectangle
            cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 1)
            # Before continuing to the next loop, I want to give it a little pause
            # waitKey of 100 millisecond
            cv2.waitKey(50)

        # Showing the image in another window
        # Creates a window with window name "Face" and with the image img
        cv2.imshow("Add Images", frame)
        # Before closing it we need to give a wait command, otherwise the open cv wont work
        # @params with the millisecond of delay 1
        cv2.waitKey(1)
        # To get out of the loop
        if (sampleNum > 300):
            break

    # Stoping the videostream
    vs.stop()
    # destroying all the windows
    cv2.destroyAllWindows()

@login_required
def add_photos(request):
    if not request.user.is_authenticated:
        messages.warning(request, f'Employee not authorised')
        return redirect('dashboard')
    elif request.user.is_authenticated:
        user = request.user
        create_dataset(user)
        messages.success(request, f'Dataset Created')
        return redirect('dashboard')
    else:
        messages.warning(request, f'Error: dataset not created')
        return render(request, 'dashboard')

The stacktrace related to the error:

Traceback (most recent call last):
  File "/Users/xxxx/Desktop/djangoWebcamTest/venv/lib/python3.9/site-packages/django/core/handlers/exception.py", line 47, in inner
    response = get_response(request)
  File "/Users/xxxx/Desktop/djangoWebcamTest/venv/lib/python3.9/site-packages/django/core/handlers/base.py", line 181, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
  File "/Users/xxxx/Desktop/djangoWebcamTest/venv/lib/python3.9/site-packages/django/contrib/auth/decorators.py", line 21, in _wrapped_view
    return view_func(request, *args, **kwargs)
  File "/Users/xxxx/Desktop/djangoWebcamTest/users/views.py", line 204, in add_photos
    create_dataset(user)
  File "/Users/xxxx/Desktop/djangoWebcamTest/users/views.py", line 157, in create_dataset
    face_aligned = fa.align(frame, gray_frame, face)
  File "/Users/xxxx/Desktop/djangoWebcamTest/venv/lib/python3.9/site-packages/imutils/face_utils/facealigner.py", line 68, in align
    M = cv2.getRotationMatrix2D(eyesCenter, angle, scale)

Exception Type: TypeError at /vidstream/
Exception Value: Can't parse 'center'. Sequence item with index 0 has a wrong type

This is a screenshot of the variables being printed to console - face_aligned = fa.align(frame, gray_frame, face): variables

Any help with this issue would be greatly appreciated

rhys
  • 11
  • 5

1 Answers1

0

Check the value of the inputs to the:

face_aligned = fa.align(frame, gray_frame, face)

Although it is not mentioned in the documentation, fa.align() seems to expect data/objects, see: https://github.com/PyImageSearch/imutils/blob/master/imutils/face_utils/facealigner.py#L23

There is not much going on with the arguments of the .align() function within its body. Most probably the face variable in your fa.align(frame, gray_frame, face) function call is a 'center' string (or a list of such strings), while it should be a list with bounding boxes or something like that.

You are getting an error at: M = cv2.getRotationMatrix2D(eyesCenter, angle, scale), see: https://github.com/PyImageSearch/imutils/blob/master/imutils/face_utils/facealigner.py#L68 . One of the following: eyesCenter, angle, scale has a value of 'center', while it probably expects a list or an array (not a string).


EDIT

I reanalyzed the problem.

Here is a code to recreate the problem in you local environment:

import cv2
import dlib
import imutils
import time

from imutils import face_utils
from imutils.face_utils import FaceAligner
from imutils.video import VideoStream

detector = dlib.get_frontal_face_detector()
# Shape predictor: https://github.com/italojs/facial-landmarks-recognition/blob/master/shape_predictor_68_face_landmarks.dat
predictor = dlib.shape_predictor('shape_predictor_68_face_landmarks.dat')
fa = FaceAligner(predictor, desiredFaceWidth=256)


print("[INFO] Initializing Video stream")
vs = VideoStream(src=0).start()
time.sleep(2.0)

frame = vs.read()
#print(frame)
frame = imutils.resize(frame, width=800)

gray_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = detector(gray_frame, 2)
print(faces)


for face in faces:
    print("inside for loop")

    if face is None:
        print("face is none")
        continue

    (x, y, w, h) = face_utils.rect_to_bb(face)

    #cv2.imwrite('1.jpg', face_aligned)
    #face_aligned = imutils.resize(face_aligned, width=400)
    cv2.rectangle(frame, (x, y), (x + w, y + h), (0, 255, 0), 1)
    cv2.waitKey(2000)

    cv2.imshow("Add Images", frame)
    cv2.waitKey(2000)

    vs.stop()
    cv2.destroyAllWindows()



    #########################
    #                       #
    #  HERE IS THE PROBLEM  #
    #                       #
    #########################
    #print(gray_frame)
    #print(face)
    # Your code
    face_aligned = fa.align(frame, gray_frame, face)

You probably have a wrong predictor, or there is something wrong with the imutils source code (there are some "hacks" there ;) ). Anyways, what is happening inside the fa.align function is that there is a wrong object passed as eyesCenter to the M = cv2.getRotationMatrix2D(eyesCenter, angle, scale) (ref).

I would suggest to edit your copy of the imutils source code to print the value of the eyesCenter in order to check what is wrong with this data structure. In your example, the eyesCenter value is not what the getRotationMatrix2D function expects. Refer also to this example, which seems to work.

Hope that helps!

Mikolaj Buchwald
  • 160
  • 4
  • 14
  • Hey @Mikolaj Buchwald, I am printing the values of (frame, gray_frame, face) to the console and I am seeing the following: frame: `[[[ 7 7 7] [ 0 0 0] [ 10 7 7] ... [ 17 37 44] [ 21 40 49] [ 5 16 25]] [[ 12 12 13] [ 1 1 1] [ 0 0 0] ... etc ` gray_frame: `[[ 0 0 1 ... 20 19 15] [ 0 0 0 ... 19 20 12] [ 0 0 1 ... 19 21 11] ... [ 0 0 0 ... 214 216 218] [ 0 0 0 ... 215 217 219] [ 0 0 0 ... 212 213 213]] ` face: `[(473, 214) (652, 393)] ` – rhys Jan 12 '22 at 01:47
  • Apologies about the formatting on my previous post, however I am new around here and I am new to these facial recognition/detection techniques. However, does the above look correct to you? The arrays seem to be seperated with `...` - I have never seen this before @mikolaj-buchwald – rhys Jan 12 '22 at 01:49
  • @rhys, can you also please post a screenshot of the console? The variables are numeric values, not strings, ok. Now that I look at that, it is possible that the `'center'` from you error stack trace refers to the name of the argument to the OpenCV's `getRotationMatrix2D` function: https://docs.opencv.org/3.4/da/d54/group__imgproc__transform.html#gafbbc470ce83812914a70abfb604f4326 In other words, `frame` is supposed to has type `Point2f` in OpenCV, which is a touple of (x, y) in Python: https://github.com/PyImageSearch/imutils/blob/master/imutils/face_utils/facealigner.py#L61-L65 – Mikolaj Buchwald Jan 12 '22 at 10:06
  • Meanwhile, it seems that you have something else stored in the `frame` variable: `: [[[ 7 7 7] [ 0 0 0] [ 10 7 7] ... [ 17 37 44] [ 21 40 49] [ 5 16 25]] [[ 12 12 13] [ 1 1 1] [ 0 0 0]` – Mikolaj Buchwald Jan 12 '22 at 10:06
  • Hey @mikolaj-buchwald, I uploaded a screenshot to my original post. You can see each of the outputs of the variables listed above. In regards to the Point2f type, the console error: `Exception Value: Can't parse 'center'. Sequence item with index 0 has a wrong type` - Would indicate that `frame` has the wrong type, however I am not entirely sure how to manipulate it and get it to the correct type, any ideas? – rhys Jan 12 '22 at 11:08
  • Ok, @rhys, I edited my answer. I hope that it will help you to find the source of the error. It is hard for me to help you any further, as I am not an expert on `predictor`s for the `imutils`. I guess that if you will follow the example I linked in the edit and you will try maybe different predictors, you will come up with the proper configuration. For face-detection tasks in web-based solutions I personally recommend [Google's MediaPipe](https://google.github.io/mediapipe/), however `imutils` also seems like a decent choice. Please, remember to upvote the answer, if you like it :) – Mikolaj Buchwald Jan 12 '22 at 16:13