├── Realtime_FacialRecognition ├── knn_examples │ ├── test │ │ ├── obama1.jpg │ │ ├── johnsnow_test1.jpg │ │ ├── kit_with_rose.jpg │ │ ├── alex_lacamoire1.jpg │ │ └── obama_and_biden.jpg │ └── train │ │ ├── Parsa │ │ └── Parsa3.jpg │ │ ├── biden │ │ ├── biden.jpg │ │ └── biden2.jpg │ │ ├── obama │ │ ├── obama.jpg │ │ └── obama2.jpg │ │ ├── rose_leslie │ │ ├── img1.jpg │ │ └── img2.jpg │ │ ├── alex_lacamoire │ │ └── img1.jpg │ │ └── kit_harington │ │ ├── john1.jpeg │ │ └── john2.jpeg ├── Extras │ └── face_recognition_rnc.py ├── facerec_ipcamera_knn.py └── threaded_facerec_ipcamera_knn.py ├── LICENSE └── README.md /Realtime_FacialRecognition/knn_examples/test/obama1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiLJ4EdeN/Realtime_FacialRecognition/HEAD/Realtime_FacialRecognition/knn_examples/test/obama1.jpg -------------------------------------------------------------------------------- /Realtime_FacialRecognition/knn_examples/test/johnsnow_test1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiLJ4EdeN/Realtime_FacialRecognition/HEAD/Realtime_FacialRecognition/knn_examples/test/johnsnow_test1.jpg -------------------------------------------------------------------------------- /Realtime_FacialRecognition/knn_examples/test/kit_with_rose.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiLJ4EdeN/Realtime_FacialRecognition/HEAD/Realtime_FacialRecognition/knn_examples/test/kit_with_rose.jpg -------------------------------------------------------------------------------- /Realtime_FacialRecognition/knn_examples/train/Parsa/Parsa3.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiLJ4EdeN/Realtime_FacialRecognition/HEAD/Realtime_FacialRecognition/knn_examples/train/Parsa/Parsa3.jpg -------------------------------------------------------------------------------- /Realtime_FacialRecognition/knn_examples/train/biden/biden.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiLJ4EdeN/Realtime_FacialRecognition/HEAD/Realtime_FacialRecognition/knn_examples/train/biden/biden.jpg -------------------------------------------------------------------------------- /Realtime_FacialRecognition/knn_examples/train/biden/biden2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiLJ4EdeN/Realtime_FacialRecognition/HEAD/Realtime_FacialRecognition/knn_examples/train/biden/biden2.jpg -------------------------------------------------------------------------------- /Realtime_FacialRecognition/knn_examples/train/obama/obama.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiLJ4EdeN/Realtime_FacialRecognition/HEAD/Realtime_FacialRecognition/knn_examples/train/obama/obama.jpg -------------------------------------------------------------------------------- /Realtime_FacialRecognition/knn_examples/train/obama/obama2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiLJ4EdeN/Realtime_FacialRecognition/HEAD/Realtime_FacialRecognition/knn_examples/train/obama/obama2.jpg -------------------------------------------------------------------------------- /Realtime_FacialRecognition/knn_examples/test/alex_lacamoire1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiLJ4EdeN/Realtime_FacialRecognition/HEAD/Realtime_FacialRecognition/knn_examples/test/alex_lacamoire1.jpg -------------------------------------------------------------------------------- /Realtime_FacialRecognition/knn_examples/test/obama_and_biden.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiLJ4EdeN/Realtime_FacialRecognition/HEAD/Realtime_FacialRecognition/knn_examples/test/obama_and_biden.jpg -------------------------------------------------------------------------------- /Realtime_FacialRecognition/knn_examples/train/rose_leslie/img1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiLJ4EdeN/Realtime_FacialRecognition/HEAD/Realtime_FacialRecognition/knn_examples/train/rose_leslie/img1.jpg -------------------------------------------------------------------------------- /Realtime_FacialRecognition/knn_examples/train/rose_leslie/img2.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiLJ4EdeN/Realtime_FacialRecognition/HEAD/Realtime_FacialRecognition/knn_examples/train/rose_leslie/img2.jpg -------------------------------------------------------------------------------- /Realtime_FacialRecognition/knn_examples/train/alex_lacamoire/img1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiLJ4EdeN/Realtime_FacialRecognition/HEAD/Realtime_FacialRecognition/knn_examples/train/alex_lacamoire/img1.jpg -------------------------------------------------------------------------------- /Realtime_FacialRecognition/knn_examples/train/kit_harington/john1.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiLJ4EdeN/Realtime_FacialRecognition/HEAD/Realtime_FacialRecognition/knn_examples/train/kit_harington/john1.jpeg -------------------------------------------------------------------------------- /Realtime_FacialRecognition/knn_examples/train/kit_harington/john2.jpeg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/KiLJ4EdeN/Realtime_FacialRecognition/HEAD/Realtime_FacialRecognition/knn_examples/train/kit_harington/john2.jpeg -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Abdolkarim Saeedi 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Realtime_FacialRecognition 2 | Real time Facial Recognition using the face_recognition module and ip cameras. 3 | 4 | 5 | [![License](https://img.shields.io/github/license/KiLJ4EdeN/Realtime_FacialRecognition)](https://img.shields.io/github/license/KiLJ4EdeN/Realtime_FacialRecognition) [![Version](https://img.shields.io/github/v/tag/KiLJ4EdeN/Realtime_FacialRecognition)](https://img.shields.io/github/v/tag/KiLJ4EdeN/Realtime_FacialRecognition) [![Code size](https://img.shields.io/github/languages/code-size/KiLJ4EdeN/Realtime_FacialRecognition)](https://img.shields.io/github/languages/code-size/KiLJ4EdeN/Realtime_FacialRecognition) [![Repo size](https://img.shields.io/github/repo-size/KiLJ4EdeN/Realtime_FacialRecognition)](https://img.shields.io/github/repo-size/KiLJ4EdeN/Realtime_FacialRecognition) [![Issue open](https://img.shields.io/github/issues/KiLJ4EdeN/Realtime_FacialRecognition)](https://img.shields.io/github/issues/KiLJ4EdeN/Realtime_FacialRecognition) 6 | ![Issue closed](https://img.shields.io/github/issues-closed/KiLJ4EdeN/Realtime_FacialRecognition) 7 | 8 | ## Prerequisites: 9 | 10 | 1 - Python 11 | 12 | 2 - OpenCV 13 | 14 | 3 - Sklearn 15 | 16 | 4 - PIL (pillow) 17 | 18 | 5 - numpy 19 | 20 | 21 | ## How to Use: 22 | 23 | 1 - Clone the repo. 24 | 25 | 2 - Install the required libraries. 26 | 27 | 3 - Find your camera ip and change it in the code, in a rare case when opencv can't crack open your ip camera url, use specific my repo for acquiring images from ip cams using urrlib at https://github.com/KiLJ4EdeN/IPCAM_urllib. 28 | 29 | 4 - To add training examples of your own, Go to knn_examples/train, 30 | each folder name represents a person and inside that folder will be images related to that person for the knn to be trained. 31 | 32 | 5 - Run facerec_ipcamera_knn.py. 33 | 34 | 6 - Use q to quit the stream anytime. 35 | -------------------------------------------------------------------------------- /Realtime_FacialRecognition/Extras/face_recognition_rnc.py: -------------------------------------------------------------------------------- 1 | # Train multiple images per person 2 | # Find and recognize faces in an image using a RNC with scikit-learn 3 | 4 | """ 5 | Structure: 6 | .jpg 7 | / 8 | / 9 | .jpg 10 | .jpg 11 | . 12 | . 13 | .jpg 14 | / 15 | .jpg 16 | .jpg 17 | . 18 | . 19 | .jpg 20 | . 21 | . 22 | / 23 | .jpg 24 | .jpg 25 | . 26 | . 27 | .jpg 28 | """ 29 | 30 | import face_recognition 31 | from sklearn.neighbors import RadiusNeighborsClassifier 32 | import os 33 | 34 | # Training the SVC classifier 35 | 36 | # The training data would be all the face encodings from all the known images and the labels are their names 37 | encodings = [] 38 | names = [] 39 | 40 | # Training directory 41 | train_dir = os.listdir('/train_dir/') 42 | 43 | # Loop through each person in the training directory 44 | for person in train_dir: 45 | pix = os.listdir("/train_dir/" + person) 46 | 47 | # Loop through each training image for the current person 48 | for person_img in pix: 49 | # Get the face encodings for the face in each image file 50 | face = face_recognition.load_image_file("/train_dir/" + person + "/" + person_img) 51 | face_bounding_boxes = face_recognition.face_locations(face) 52 | 53 | #If training image contains exactly one face 54 | if len(face_bounding_boxes) == 1: 55 | face_enc = face_recognition.face_encodings(face)[0] 56 | # Add face encoding for current image with corresponding label (name) to the training data 57 | encodings.append(face_enc) 58 | names.append(person) 59 | else: 60 | print(person + "/" + person_img + " was skipped and can't be used for training") 61 | 62 | # Create and train the Radius Neighbors Classifier 63 | clf = RadiusNeighborsClassifier(radius=0.5, weights='distance', algorithm='auto', 64 | leaf_size=30, p=2, metric='minkowski', outlier_label=None, 65 | metric_params=None, n_jobs=None) 66 | clf.fit(encodings, names) 67 | 68 | # Load the test image with unknown faces into a numpy array 69 | test_image = face_recognition.load_image_file('test_image.jpg') 70 | 71 | # Find all the faces in the test image using the default HOG-based model 72 | face_locations = face_recognition.face_locations(test_image) 73 | no = len(face_locations) 74 | print("Number of faces detected: ", no) 75 | 76 | # Predict all the faces in the test image using the trained classifier 77 | print("Found:") 78 | for i in range(no): 79 | test_image_enc = face_recognition.face_encodings(test_image, known_face_locations=face_locations)[i] 80 | try: 81 | name = clf.predict(test_image_enc) 82 | print(*name) 83 | except ValueError: 84 | print('No matches Found') 85 | -------------------------------------------------------------------------------- /Realtime_FacialRecognition/facerec_ipcamera_knn.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is an example of using the k-nearest-neighbors (KNN) algorithm for face recognition. 3 | 4 | When should I use this example? 5 | This example is useful when you wish to recognize a large set of known people, 6 | and make a prediction for an unknown person in a feasible computation time. 7 | 8 | Algorithm Description: 9 | The knn classifier is first trained on a set of labeled (known) faces and can then predict the person 10 | in a live stream by finding the k most similar faces (images with closet face-features under eucledian distance) 11 | in its training set, and performing a majority vote (possibly weighted) on their label. 12 | 13 | For example, if k=3, and the three closest face images to the given image in the training set are one image of Biden 14 | and two images of Obama, The result would be 'Obama'. 15 | 16 | * This implementation uses a weighted vote, such that the votes of closer-neighbors are weighted more heavily. 17 | 18 | Usage: 19 | 20 | 1. Prepare a set of images of the known people you want to recognize. Organize the images in a single directory 21 | with a sub-directory for each known person. 22 | 23 | 2. Then, call the 'train' function with the appropriate parameters. Make sure to pass in the 'model_save_path' if you 24 | want to save the model to disk so you can re-use the model without having to re-train it. 25 | 26 | 3. Call 'predict' and pass in your trained model to recognize the people in a live video stream. 27 | 28 | NOTE: This example requires scikit-learn, opencv and numpy to be installed! You can install it with pip: 29 | 30 | $ pip3 install scikit-learn 31 | $ pip3 install numpy 32 | $ pip3 install opencv-contrib-python 33 | 34 | """ 35 | 36 | import cv2 37 | import math 38 | from sklearn import neighbors 39 | import os 40 | import os.path 41 | import pickle 42 | from PIL import Image, ImageDraw 43 | import face_recognition 44 | from face_recognition.face_recognition_cli import image_files_in_folder 45 | import numpy as np 46 | 47 | 48 | ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'JPG'} 49 | 50 | 51 | def train(train_dir, model_save_path=None, n_neighbors=None, knn_algo='ball_tree', verbose=False): 52 | """ 53 | Trains a k-nearest neighbors classifier for face recognition. 54 | 55 | :param train_dir: directory that contains a sub-directory for each known person, with its name. 56 | 57 | (View in source code to see train_dir example tree structure) 58 | 59 | Structure: 60 | / 61 | ├── / 62 | │ ├── .jpeg 63 | │ ├── .jpeg 64 | │ ├── ... 65 | ├── / 66 | │ ├── .jpeg 67 | │ └── .jpeg 68 | └── ... 69 | 70 | :param model_save_path: (optional) path to save model on disk 71 | :param n_neighbors: (optional) number of neighbors to weigh in classification. Chosen automatically if not specified 72 | :param knn_algo: (optional) underlying data structure to support knn.default is ball_tree 73 | :param verbose: verbosity of training 74 | :return: returns knn classifier that was trained on the given data. 75 | """ 76 | X = [] 77 | y = [] 78 | 79 | # Loop through each person in the training set 80 | for class_dir in os.listdir(train_dir): 81 | if not os.path.isdir(os.path.join(train_dir, class_dir)): 82 | continue 83 | 84 | # Loop through each training image for the current person 85 | for img_path in image_files_in_folder(os.path.join(train_dir, class_dir)): 86 | image = face_recognition.load_image_file(img_path) 87 | face_bounding_boxes = face_recognition.face_locations(image) 88 | 89 | if len(face_bounding_boxes) != 1: 90 | # If there are no people (or too many people) in a training image, skip the image. 91 | if verbose: 92 | 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")) 93 | else: 94 | # Add face encoding for current image to the training set 95 | X.append(face_recognition.face_encodings(image, known_face_locations=face_bounding_boxes)[0]) 96 | y.append(class_dir) 97 | 98 | # Determine how many neighbors to use for weighting in the KNN classifier 99 | if n_neighbors is None: 100 | n_neighbors = int(round(math.sqrt(len(X)))) 101 | if verbose: 102 | print("Chose n_neighbors automatically:", n_neighbors) 103 | 104 | # Create and train the KNN classifier 105 | knn_clf = neighbors.KNeighborsClassifier(n_neighbors=n_neighbors, algorithm=knn_algo, weights='distance') 106 | knn_clf.fit(X, y) 107 | 108 | # Save the trained KNN classifier 109 | if model_save_path is not None: 110 | with open(model_save_path, 'wb') as f: 111 | pickle.dump(knn_clf, f) 112 | 113 | return knn_clf 114 | 115 | 116 | def predict(X_frame, knn_clf=None, model_path=None, distance_threshold=0.5): 117 | """ 118 | Recognizes faces in given image using a trained KNN classifier 119 | 120 | :param X_frame: frame to do the prediction on. 121 | :param knn_clf: (optional) a knn classifier object. if not specified, model_save_path must be specified. 122 | :param model_path: (optional) path to a pickled knn classifier. if not specified, model_save_path must be knn_clf. 123 | :param distance_threshold: (optional) distance threshold for face classification. the larger it is, the more chance 124 | of mis-classifying an unknown person as a known one. 125 | :return: a list of names and face locations for the recognized faces in the image: [(name, bounding box), ...]. 126 | For faces of unrecognized persons, the name 'unknown' will be returned. 127 | """ 128 | if knn_clf is None and model_path is None: 129 | raise Exception("Must supply knn classifier either thourgh knn_clf or model_path") 130 | 131 | # Load a trained KNN model (if one was passed in) 132 | if knn_clf is None: 133 | with open(model_path, 'rb') as f: 134 | knn_clf = pickle.load(f) 135 | 136 | X_face_locations = face_recognition.face_locations(X_frame) 137 | 138 | # If no faces are found in the image, return an empty result. 139 | if len(X_face_locations) == 0: 140 | return [] 141 | 142 | # Find encodings for faces in the test image 143 | faces_encodings = face_recognition.face_encodings(X_frame, known_face_locations=X_face_locations) 144 | 145 | # Use the KNN model to find the best matches for the test face 146 | closest_distances = knn_clf.kneighbors(faces_encodings, n_neighbors=1) 147 | are_matches = [closest_distances[0][i][0] <= distance_threshold for i in range(len(X_face_locations))] 148 | 149 | # Predict classes and remove classifications that aren't within the threshold 150 | return [(pred, loc) if rec else ("unknown", loc) for pred, loc, rec in zip(knn_clf.predict(faces_encodings), X_face_locations, are_matches)] 151 | 152 | 153 | def show_prediction_labels_on_image(frame, predictions): 154 | """ 155 | Shows the face recognition results visually. 156 | 157 | :param frame: frame to show the predictions on 158 | :param predictions: results of the predict function 159 | :return opencv suited image to be fitting with cv2.imshow fucntion: 160 | """ 161 | pil_image = Image.fromarray(frame) 162 | draw = ImageDraw.Draw(pil_image) 163 | 164 | for name, (top, right, bottom, left) in predictions: 165 | # enlarge the predictions for the full sized image. 166 | top *= 2 167 | right *= 2 168 | bottom *= 2 169 | left *= 2 170 | # Draw a box around the face using the Pillow module 171 | draw.rectangle(((left, top), (right, bottom)), outline=(0, 0, 255)) 172 | 173 | # There's a bug in Pillow where it blows up with non-UTF-8 text 174 | # when using the default bitmap font 175 | name = name.encode("UTF-8") 176 | 177 | # Draw a label with a name below the face 178 | text_width, text_height = draw.textsize(name) 179 | draw.rectangle(((left, bottom - text_height - 10), (right, bottom)), fill=(0, 0, 255), outline=(0, 0, 255)) 180 | draw.text((left + 6, bottom - text_height - 5), name, fill=(255, 255, 255, 255)) 181 | 182 | # Remove the drawing library from memory as per the Pillow docs. 183 | del draw 184 | # Save image in open-cv format to be able to show it. 185 | 186 | opencvimage = np.array(pil_image) 187 | return opencvimage 188 | 189 | 190 | if __name__ == "__main__": 191 | print("Training KNN classifier...") 192 | classifier = train("knn_examples/train", model_save_path="trained_knn_model.clf", n_neighbors=2) 193 | print("Training complete!") 194 | # process one frame in every 30 frames for speed 195 | process_this_frame = 29 196 | print('Setting cameras up...') 197 | # multiple cameras can be used with the format url = 'http://username:password@camera_ip:port' 198 | url = 'http://admin:admin@192.168.0.106:8081/' 199 | cap = cv2.VideoCapture(url) 200 | while 1 > 0: 201 | ret, frame = cap.read() 202 | if ret: 203 | # Different resizing options can be chosen based on desired program runtime. 204 | # Image resizing for more stable streaming 205 | img = cv2.resize(frame, (0, 0), fx=0.5, fy=0.5) 206 | process_this_frame = process_this_frame + 1 207 | if process_this_frame % 30 == 0: 208 | # hint: this is temporary image, and the latest prediction is shown on frames until another processing is done. 209 | predictions1 = predict(img, model_path="trained_knn_model.clf") 210 | 211 | frame = show_prediction_labels_on_image(frame, predictions1) 212 | cv2.imshow('camera', frame) 213 | if ord('q') == cv2.waitKey(10): 214 | cap.release() 215 | cv2.destroyAllWindows() 216 | exit(0) 217 | -------------------------------------------------------------------------------- /Realtime_FacialRecognition/threaded_facerec_ipcamera_knn.py: -------------------------------------------------------------------------------- 1 | """ 2 | This is an example of using the k-nearest-neighbors (KNN) algorithm for face recognition. 3 | 4 | When should I use this example? 5 | This example is useful when you wish to recognize a large set of known people, 6 | and make a prediction for an unknown person in a feasible computation time. 7 | 8 | Algorithm Description: 9 | The knn classifier is first trained on a set of labeled (known) faces and can then predict the person 10 | in a live stream by finding the k most similar faces (images with closet face-features under eucledian distance) 11 | in its training set, and performing a majority vote (possibly weighted) on their label. 12 | 13 | For example, if k=3, and the three closest face images to the given image in the training set are one image of Biden 14 | and two images of Obama, The result would be 'Obama'. 15 | 16 | * This implementation uses a weighted vote, such that the votes of closer-neighbors are weighted more heavily. 17 | 18 | Usage: 19 | 20 | 1. Prepare a set of images of the known people you want to recognize. Organize the images in a single directory 21 | with a sub-directory for each known person. 22 | 23 | 2. Then, call the 'train' function with the appropriate parameters. Make sure to pass in the 'model_save_path' if you 24 | want to save the model to disk so you can re-use the model without having to re-train it. 25 | 26 | 3. Call 'predict' and pass in your trained model to recognize the people in a live video stream. 27 | 28 | NOTE: This example requires scikit-learn, opencv and numpy to be installed! You can install it with pip: 29 | 30 | $ pip3 install scikit-learn 31 | $ pip3 install numpy 32 | $ pip3 install opencv-contrib-python 33 | 34 | """ 35 | 36 | import cv2 37 | import math 38 | from sklearn import neighbors 39 | import os 40 | import os.path 41 | import pickle 42 | from PIL import Image, ImageDraw 43 | import face_recognition 44 | from face_recognition.face_recognition_cli import image_files_in_folder 45 | import numpy as np 46 | from threading import Thread 47 | 48 | 49 | 50 | ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'JPG'} 51 | 52 | 53 | def train(train_dir, model_save_path=None, n_neighbors=None, knn_algo='ball_tree', verbose=False): 54 | """ 55 | Trains a k-nearest neighbors classifier for face recognition. 56 | 57 | :param train_dir: directory that contains a sub-directory for each known person, with its name. 58 | 59 | (View in source code to see train_dir example tree structure) 60 | 61 | Structure: 62 | / 63 | ├── / 64 | │ ├── .jpeg 65 | │ ├── .jpeg 66 | │ ├── ... 67 | ├── / 68 | │ ├── .jpeg 69 | │ └── .jpeg 70 | └── ... 71 | 72 | :param model_save_path: (optional) path to save model on disk 73 | :param n_neighbors: (optional) number of neighbors to weigh in classification. Chosen automatically if not specified 74 | :param knn_algo: (optional) underlying data structure to support knn.default is ball_tree 75 | :param verbose: verbosity of training 76 | :return: returns knn classifier that was trained on the given data. 77 | """ 78 | X = [] 79 | y = [] 80 | 81 | # Loop through each person in the training set 82 | for class_dir in os.listdir(train_dir): 83 | if not os.path.isdir(os.path.join(train_dir, class_dir)): 84 | continue 85 | 86 | # Loop through each training image for the current person 87 | for img_path in image_files_in_folder(os.path.join(train_dir, class_dir)): 88 | image = face_recognition.load_image_file(img_path) 89 | face_bounding_boxes = face_recognition.face_locations(image) 90 | 91 | if len(face_bounding_boxes) != 1: 92 | # If there are no people (or too many people) in a training image, skip the image. 93 | if verbose: 94 | 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")) 95 | else: 96 | # Add face encoding for current image to the training set 97 | X.append(face_recognition.face_encodings(image, known_face_locations=face_bounding_boxes)[0]) 98 | y.append(class_dir) 99 | 100 | # Determine how many neighbors to use for weighting in the KNN classifier 101 | if n_neighbors is None: 102 | n_neighbors = int(round(math.sqrt(len(X)))) 103 | if verbose: 104 | print("Chose n_neighbors automatically:", n_neighbors) 105 | 106 | # Create and train the KNN classifier 107 | knn_clf = neighbors.KNeighborsClassifier(n_neighbors=n_neighbors, algorithm=knn_algo, weights='distance') 108 | knn_clf.fit(X, y) 109 | 110 | # Save the trained KNN classifier 111 | if model_save_path is not None: 112 | with open(model_save_path, 'wb') as f: 113 | pickle.dump(knn_clf, f) 114 | 115 | return knn_clf 116 | 117 | 118 | def predict(X_frame, knn_clf=None, model_path=None, distance_threshold=0.5): 119 | """ 120 | Recognizes faces in given image using a trained KNN classifier 121 | 122 | :param X_frame: frame to do the prediction on. 123 | :param knn_clf: (optional) a knn classifier object. if not specified, model_save_path must be specified. 124 | :param model_path: (optional) path to a pickled knn classifier. if not specified, model_save_path must be knn_clf. 125 | :param distance_threshold: (optional) distance threshold for face classification. the larger it is, the more chance 126 | of mis-classifying an unknown person as a known one. 127 | :return: a list of names and face locations for the recognized faces in the image: [(name, bounding box), ...]. 128 | For faces of unrecognized persons, the name 'unknown' will be returned. 129 | """ 130 | if knn_clf is None and model_path is None: 131 | raise Exception("Must supply knn classifier either thourgh knn_clf or model_path") 132 | 133 | # Load a trained KNN model (if one was passed in) 134 | if knn_clf is None: 135 | with open(model_path, 'rb') as f: 136 | knn_clf = pickle.load(f) 137 | 138 | X_face_locations = face_recognition.face_locations(X_frame) 139 | 140 | # If no faces are found in the image, return an empty result. 141 | if len(X_face_locations) == 0: 142 | return [] 143 | 144 | # Find encodings for faces in the test image 145 | faces_encodings = face_recognition.face_encodings(X_frame, known_face_locations=X_face_locations) 146 | 147 | # Use the KNN model to find the best matches for the test face 148 | closest_distances = knn_clf.kneighbors(faces_encodings, n_neighbors=1) 149 | are_matches = [closest_distances[0][i][0] <= distance_threshold for i in range(len(X_face_locations))] 150 | 151 | # Predict classes and remove classifications that aren't within the threshold 152 | return [(pred, loc) if rec else ("unknown", loc) for pred, loc, rec in zip(knn_clf.predict(faces_encodings), X_face_locations, are_matches)] 153 | 154 | 155 | def show_prediction_labels_on_image(frame, predictions): 156 | """ 157 | Shows the face recognition results visually. 158 | 159 | :param frame: frame to show the predictions on 160 | :param predictions: results of the predict function 161 | :return opencv suited image to be fitting with cv2.imshow fucntion: 162 | """ 163 | pil_image = Image.fromarray(frame) 164 | draw = ImageDraw.Draw(pil_image) 165 | 166 | for name, (top, right, bottom, left) in predictions: 167 | # enlarge the predictions for the full sized image. 168 | top *= 2 169 | right *= 2 170 | bottom *= 2 171 | left *= 2 172 | # Draw a box around the face using the Pillow module 173 | draw.rectangle(((left, top), (right, bottom)), outline=(0, 0, 255)) 174 | 175 | # There's a bug in Pillow where it blows up with non-UTF-8 text 176 | # when using the default bitmap font 177 | name = name.encode("UTF-8") 178 | 179 | # Draw a label with a name below the face 180 | text_width, text_height = draw.textsize(name) 181 | draw.rectangle(((left, bottom - text_height - 10), (right, bottom)), fill=(0, 0, 255), outline=(0, 0, 255)) 182 | draw.text((left + 6, bottom - text_height - 5), name, fill=(255, 255, 255, 255)) 183 | 184 | # Remove the drawing library from memory as per the Pillow docs. 185 | del draw 186 | # Save image in open-cv format to be able to show it. 187 | 188 | opencvimage = np.array(pil_image) 189 | return opencvimage 190 | 191 | 192 | class WebcamVideoStream: 193 | def __init__(self, src=0, name="WebcamVideoStream"): 194 | # initialize the video camera stream and read the first frame 195 | # from the stream 196 | self.stream = cv2.VideoCapture(src) 197 | (self.grabbed, self.frame) = self.stream.read() 198 | 199 | # initialize the thread name 200 | self.name = name 201 | 202 | # initialize the variable used to indicate if the thread should 203 | # be stopped 204 | self.stopped = False 205 | 206 | def start(self): 207 | # start the thread to read frames from the video stream 208 | t = Thread(target=self.update, name=self.name, args=()) 209 | t.daemon = True 210 | t.start() 211 | return self 212 | 213 | def update(self): 214 | # keep looping infinitely until the thread is stopped 215 | while True: 216 | # if the thread indicator variable is set, stop the thread 217 | if self.stopped: 218 | return 219 | 220 | # otherwise, read the next frame from the stream 221 | (self.grabbed, self.frame) = self.stream.read() 222 | 223 | def read(self): 224 | # return the frame most recently read 225 | return self.frame 226 | 227 | def stop(self): 228 | # indicate that the thread should be stopped 229 | self.stopped = True 230 | 231 | 232 | if __name__ == "__main__": 233 | print("Training KNN classifier...") 234 | classifier = train("knn_examples/train", model_save_path="trained_knn_model.clf", n_neighbors=2) 235 | print("Training complete!") 236 | # process one frame in every 30 frames for speed 237 | process_this_frame = 29 238 | print('Setting cameras up...') 239 | # multiple cameras can be used with the format url = 'http://username:password@camera_ip:port' 240 | url = 'http://admin:admin@192.168.0.106:8081/' 241 | cap = WebcamVideoStream(src=url).start() 242 | time.sleep(1.0) 243 | while 1 > 0: 244 | frame = cap.read() 245 | # Different resizing options can be chosen based on desired program runtime. 246 | # Image resizing for more stable streaming 247 | img = cv2.resize(frame, (0, 0), fx=0.5, fy=0.5) 248 | process_this_frame = process_this_frame + 1 249 | if process_this_frame % 30 == 0: 250 | # hint: this is temporary image, and the latest prediction is shown on frames until another processing is done. 251 | predictions1 = predict(img, model_path="trained_knn_model.clf") 252 | 253 | frame = show_prediction_labels_on_image(frame, predictions1) 254 | cv2.imshow('camera', frame) 255 | if ord('q') == cv2.waitKey(10): 256 | cv2.destroyAllWindows() 257 | exit(0) 258 | --------------------------------------------------------------------------------