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

Result Accuracy of KNN #556

Closed ghost closed 6 years ago

ghost commented 6 years ago

How Can I get the accuracy result of the classifier?

jonathan-soll commented 6 years ago
from sklearn.metrics import accuracy_score 
acc_knn = accuracy_score(y, knn_model.predict(X)) 
print('KNN training accuracy = ' + str(100*acc_knn) + '%')
ghost commented 6 years ago

Thanks @jonathan-soll , I know but how to define X , y ? It needs to compare original labels with predicted ones and report accuracy of classifier,

Do you have any quick way?

ghost commented 6 years ago

use this code instead for accuracy:

import math from sklearn import neighbors import os from sklearn.metrics import accuracy_score import os.path import pickle from PIL import Image, ImageDraw import face_recognition from face_recognition.face_recognition_cli import image_files_in_folder

ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg'}

def train(train_dir, model_save_path=None, n_neighbors=None, knn_algo='ball_tree', verbose=False): """ Trains a k-nearest neighbors classifier for face recognition.

:param train_dir: directory that contains a sub-directory for each known person, with its name.

 (View in source code to see train_dir example tree structure)

 Structure:
    <train_dir>/
    ├── <person1>/
    │   ├── <somename1>.jpeg
    │   ├── <somename2>.jpeg
    │   ├── ...
    ├── <person2>/
    │   ├── <somename1>.jpeg
    │   └── <somename2>.jpeg
    └── ...

:param model_save_path: (optional) path to save model on disk
:param n_neighbors: (optional) number of neighbors to weigh in classification. Chosen automatically if not specified
:param knn_algo: (optional) underlying data structure to support knn.default is ball_tree
:param verbose: verbosity of training
:return: returns knn classifier that was trained on the given data.
"""
X = []
y = []

# Loop through each person in the training set
for class_dir in os.listdir(train_dir):
    if not os.path.isdir(os.path.join(train_dir, class_dir)):
        continue

    # Loop through each training image for the current person
    for img_path in image_files_in_folder(os.path.join(train_dir, class_dir)):
        image = face_recognition.load_image_file(img_path)
        face_bounding_boxes = face_recognition.face_locations(image)

        if len(face_bounding_boxes) != 1:
            # If there are no people (or too many people) in a training image, skip the image.
            if verbose:
                print("Image {} not suitable for training: {}".format(img_path, "Didn't find a face" if len(face_bounding_boxes) < 1 else "Found more than one face"))
        else:
            # Add face encoding for current image to the training set
            X.append(face_recognition.face_encodings(image, known_face_locations=face_bounding_boxes)[0])
            y.append(class_dir)

# Determine how many neighbors to use for weighting in the KNN classifier
if n_neighbors is None:
    n_neighbors = int(round(math.sqrt(len(X))))
    if verbose:
        print("Chose n_neighbors automatically:", n_neighbors)

# Create and train the KNN classifier
knn_clf = neighbors.KNeighborsClassifier(n_neighbors=n_neighbors, algorithm=knn_algo, weights='distance')
knn_clf.fit(X, y)

# Save the trained KNN classifier
if model_save_path is not None:
    with open(model_save_path, 'wb') as f:
        pickle.dump(knn_clf, f)

return knn_clf

def predict(X_img_path, knn_clf=None, model_path=None, distance_threshold=0.6): """ Recognizes faces in given image using a trained KNN classifier

:param X_img_path: path to image to be recognized
: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 not os.path.isfile(X_img_path) or os.path.splitext(X_img_path)[1][1:] not in ALLOWED_EXTENSIONS:
    raise Exception("Invalid image path: {}".format(X_img_path))

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)

# Load image file and find face locations
X_img = face_recognition.load_image_file(X_img_path)
X_face_locations = face_recognition.face_locations(X_img)

# 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 test iamge
faces_encodings = face_recognition.face_encodings(X_img, 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)  for pred in zip(knn_clf.predict(faces_encodings))]

"""
Shows the face recognition results visually.

:param img_path: path to image to be recognized
:param predictions: results of the predict function
:return:
"""
pil_image = Image.open(img_path).convert("RGB")
draw = ImageDraw.Draw(pil_image)

for name, (top, right, bottom, left) in predictions:
    # Draw a box around the face using the Pillow module
    draw.rectangle(((left, top), (right, bottom)), outline=(0, 0, 255))

    # There's a bug in Pillow where it blows up with non-UTF-8 text
    # when using the default bitmap font
    name = name.encode("UTF-8")

    # Draw a label with a name below the face
    text_width, text_height = draw.textsize(name)
    draw.rectangle(((left, bottom - text_height - 10), (right, bottom)), fill=(0, 0, 255), outline=(0, 0, 255))
    draw.text((left + 6, bottom - text_height - 5), name, fill=(255, 255, 255, 255))

# Remove the drawing library from memory as per the Pillow docs
del draw

# Display the resulting image
pil_image.show()

if name == "main": classifier = train("knn_examples/train", model_save_path="trained_knn_model.clf", n_neighbors=2) X1 = [] y1 = [] pathgen = "knn_examples/test/" f = os.listdir(pathgen) path = ["%s/" % item for item in f] pathxx = ["('%s',)" % item for item in f] for i in range(0,len(f)): pathdd = pathgen+path[i] f2 = os.listdir(pathdd) pictures = ["%s" % item for item in f2] for k in range(0,len(f2)): predictions = predict(pathdd+pictures[k], model_path="trained_knn_model.clf") for name in predictions: X1.append(1) if str(name)==str(pathxx[i]): y1.append(1) else: print(name,pathxx[i]) y1.append(0) print(X1,y1) acc_knn = accuracy_score(y1, X1) print('KNN training accuracy = ' + str(100*acc_knn) + '%')

jonathan-soll commented 6 years ago

It looks like X and y are defined in the code. X holds the face encodings, y holds the names of the people you are trying to predict which are the same as the 'class_dir'.

ghost commented 6 years ago

@jonathan-soll Thank you so much, I meant accuracy of results , you mentioned the accuracy of training,

if name == "main": classifier = train("knn_examples/train", model_save_path="trained_knn_model.clf", n_neighbors=2) X1 = [] y1 = [] pathgen = "knn_examples/test/" f = os.listdir(pathgen) path = ["%s/" % item for item in f] pathxx = ["('%s',)" % item for item in f] for i in range(0,len(f)): pathdd = pathgen+path[i] f2 = os.listdir(pathdd) pictures = ["%s" % item for item in f2] for k in range(0,len(f2)): predictions = predict(pathdd+pictures[k], model_path="trained_knn_model.clf") for name in predictions: X1.append(1) if str(name)==str(pathxx[i]): y1.append(1) else: print(name,pathxx[i]) y1.append(0) print(X1,y1) acc_knn = accuracy_score(y1, X1) print('KNN training accuracy = ' + str(100*acc_knn) + '%')