ageitgey / face_recognition

The world's simplest facial recognition api for Python and the command line
MIT License
53.42k stars 13.49k forks source link

How can I use the knn algorithm with OpenCV? #463

Closed leonardofmed closed 6 years ago

leonardofmed commented 6 years ago

Is it possible to use this algorithm with OpenCV in real time? The KNN files available as an example worked correctly, as did the facerec_from_webcam files. If it is possible, can you show me an example or tell me what I should do to achieve what I want?

I tried to "join" the ideas of the two files, but I can not make the predict / show part work with OpenCV.

(Edited: Now it shows the frame until it detect some face, them crashes) What I tried so far:

import numpy as np
import cv2
import face_recognition
import pickle

def predict(frame, knn_clf=None, model_path=None, distance_threshold=0.6):
    """
    Recognizes faces in given image using a trained KNN classifier
    :param knn_clf: (optional) a knn classifier object. if not specified, model_save_path must be specified.
    :param model_path: (optional) path to a pickled knn classifier. if not specified, model_save_path must be knn_clf.
    :param distance_threshold: (optional) distance threshold for face classification. the larger it is, the more chance
           of mis-classifying an unknown person as a known one.
    :return: a list of names and face locations for the recognized faces in the image: [(name, bounding box), ...].
        For faces of unrecognized persons, the name 'unknown' will be returned.
    """

    if knn_clf is None and model_path is None:
        raise Exception("Must supply knn classifier either thourgh knn_clf or model_path")

    # Load a trained KNN model (if one was passed in)
    if knn_clf is None:
        with open(model_path, 'rb') as f:
            knn_clf = pickle.load(f)

    # find face locations from frame
    X_face_locations = face_recognition.face_locations(frame)

    # If no faces are found in the image, return an empty result.
    if len(X_face_locations) == 0:
        return []

    # Find encodings for faces in the frame
    faces_encodings = face_recognition.face_encodings(frame, known_face_locations=X_face_locations)

    # Use the KNN model to find the best matches for the test face
    closest_distances = knn_clf.kneighbors(faces_encodings, n_neighbors=1)
    are_matches = [closest_distances[0][i][0] <= distance_threshold for i in range(len(X_face_locations))]

    # Predict classes and remove classifications that aren't within the threshold
    return [(pred, loc) if rec else ("unknown", loc) for pred, loc, rec in zip(knn_clf.predict(faces_encodings), X_face_locations, are_matches)]

def show_labels_on_webcam(RGBFrame, predictions):
    """
    Shows the face recognition results visually.
    :param img_path: path to image to be recognized
    :param predictions: results of the predict function
    :return:
    """
    frame = RGBFrame

    for name, (top, right, bottom, left) in predictions:
        # Scale back up face locations since the frame we detected in was scaled to 1/4 size
        top *= 4
        right *= 4
        bottom *= 4
        left *= 4

        # Draw a box around the face
        cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)

        # Draw a label with a name below the face
        cv2.rectangle(frame, (left, bottom - 35), (right, bottom), (0, 0, 255), cv2.FILLED)
        font = cv2.FONT_HERSHEY_DUPLEX
        cv2.putText(frame, name, (left + 6, bottom - 6), font, 1.0, (255, 255, 255), 1)

    # Display the resulting image
    cv2.imshow('Video', frame)

# Get a reference to webcam #0 (the default one)
video_capture = cv2.VideoCapture(0)

while True:
    # Grab a single frame of video
    ret, frame = video_capture.read()

    # Resize frame of video to 1/4 size for faster face recognition processing
    small_frame = cv2.resize(frame, (0, 0), fx=0.25, fy=0.25)

    # Convert the image from BGR color (which OpenCV uses) to RGB color (which face_recognition uses)
    rgb_small_frame = small_frame[:, :, ::-1]

    predictions = predict(rgb_small_frame, model_path="trained_knn_model_1.clf")

    # Display results overlaid on webcam video
    #print (rgb_small_frame.shape)
    #print (rgb_small_frame.dtype)
    show_labels_on_webcam(rgb_small_frame, predictions)

    # Hit 'q' on the keyboard to quit!
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# Release handle to the webcam
video_capture.release()
cv2.destroyAllWindows()

The error I'm getting:

Traceback (most recent call last):
  File "withOpenCV.py", line 89, in <module>
    show_labels_on_webcam(rgb_small_frame, predictions)
  File "withOpenCV.py", line 60, in show_labels_on_webcam
    cv2.rectangle(frame, (left, top), (right, bottom), (0, 0, 255), 2)
TypeError: Layout of the output array img is incompatible with cv::Mat (step[ndims-1] != elemsize or step[1] != elemsize*nchannels)

Thank you in advance and great work!

leonardofmed commented 6 years ago

I solved the error by changing the show_labels_on_webcam(rgb_small_frame, predictions) by show_labels_on_webcam(frame, predictions).