Register
Login
Resources
Docs Blog Datasets Glossary Case Studies Tutorials & Webinars
Product
Data Engine LLMs Platform Enterprise
Pricing Explore
Connect to our Discord channel

facerec_ipcamera_knn.py 8.9 KB

You have to be logged in to leave a comment. Sign In
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
  1. """
  2. This is an example of using the k-nearest-neighbors (KNN) algorithm for face recognition.
  3. When should I use this example?
  4. This example is useful when you wish to recognize a large set of known people,
  5. and make a prediction for an unknown person in a feasible computation time.
  6. Algorithm Description:
  7. The knn classifier is first trained on a set of labeled (known) faces and can then predict the person
  8. in a live stream by finding the k most similar faces (images with closet face-features under eucledian distance)
  9. in its training set, and performing a majority vote (possibly weighted) on their label.
  10. For example, if k=3, and the three closest face images to the given image in the training set are one image of Biden
  11. and two images of Obama, The result would be 'Obama'.
  12. * This implementation uses a weighted vote, such that the votes of closer-neighbors are weighted more heavily.
  13. Usage:
  14. 1. Prepare a set of images of the known people you want to recognize. Organize the images in a single directory
  15. with a sub-directory for each known person.
  16. 2. Then, call the 'train' function with the appropriate parameters. Make sure to pass in the 'model_save_path' if you
  17. want to save the model to disk so you can re-use the model without having to re-train it.
  18. 3. Call 'predict' and pass in your trained model to recognize the people in a live video stream.
  19. NOTE: This example requires scikit-learn, opencv and numpy to be installed! You can install it with pip:
  20. $ pip3 install scikit-learn
  21. $ pip3 install numpy
  22. $ pip3 install opencv-contrib-python
  23. """
  24. import cv2
  25. import math
  26. from sklearn import neighbors
  27. import os
  28. import os.path
  29. import pickle
  30. from PIL import Image, ImageDraw
  31. import face_recognition
  32. from face_recognition.face_recognition_cli import image_files_in_folder
  33. import numpy as np
  34. ALLOWED_EXTENSIONS = {'png', 'jpg', 'jpeg', 'JPG'}
  35. def train(train_dir, model_save_path=None, n_neighbors=None, knn_algo='ball_tree', verbose=False):
  36. """
  37. Trains a k-nearest neighbors classifier for face recognition.
  38. :param train_dir: directory that contains a sub-directory for each known person, with its name.
  39. (View in source code to see train_dir example tree structure)
  40. Structure:
  41. <train_dir>/
  42. ├── <person1>/
  43. │ ├── <somename1>.jpeg
  44. │ ├── <somename2>.jpeg
  45. │ ├── ...
  46. ├── <person2>/
  47. │ ├── <somename1>.jpeg
  48. │ └── <somename2>.jpeg
  49. └── ...
  50. :param model_save_path: (optional) path to save model on disk
  51. :param n_neighbors: (optional) number of neighbors to weigh in classification. Chosen automatically if not specified
  52. :param knn_algo: (optional) underlying data structure to support knn.default is ball_tree
  53. :param verbose: verbosity of training
  54. :return: returns knn classifier that was trained on the given data.
  55. """
  56. X = []
  57. y = []
  58. # Loop through each person in the training set
  59. for class_dir in os.listdir(train_dir):
  60. if not os.path.isdir(os.path.join(train_dir, class_dir)):
  61. continue
  62. # Loop through each training image for the current person
  63. for img_path in image_files_in_folder(os.path.join(train_dir, class_dir)):
  64. image = face_recognition.load_image_file(img_path)
  65. face_bounding_boxes = face_recognition.face_locations(image)
  66. if len(face_bounding_boxes) != 1:
  67. # If there are no people (or too many people) in a training image, skip the image.
  68. if verbose:
  69. 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"))
  70. else:
  71. # Add face encoding for current image to the training set
  72. X.append(face_recognition.face_encodings(image, known_face_locations=face_bounding_boxes)[0])
  73. y.append(class_dir)
  74. # Determine how many neighbors to use for weighting in the KNN classifier
  75. if n_neighbors is None:
  76. n_neighbors = int(round(math.sqrt(len(X))))
  77. if verbose:
  78. print("Chose n_neighbors automatically:", n_neighbors)
  79. # Create and train the KNN classifier
  80. knn_clf = neighbors.KNeighborsClassifier(n_neighbors=n_neighbors, algorithm=knn_algo, weights='distance')
  81. knn_clf.fit(X, y)
  82. # Save the trained KNN classifier
  83. if model_save_path is not None:
  84. with open(model_save_path, 'wb') as f:
  85. pickle.dump(knn_clf, f)
  86. return knn_clf
  87. def predict(X_frame, knn_clf=None, model_path=None, distance_threshold=0.5):
  88. """
  89. Recognizes faces in given image using a trained KNN classifier
  90. :param X_frame: frame to do the prediction on.
  91. :param knn_clf: (optional) a knn classifier object. if not specified, model_save_path must be specified.
  92. :param model_path: (optional) path to a pickled knn classifier. if not specified, model_save_path must be knn_clf.
  93. :param distance_threshold: (optional) distance threshold for face classification. the larger it is, the more chance
  94. of mis-classifying an unknown person as a known one.
  95. :return: a list of names and face locations for the recognized faces in the image: [(name, bounding box), ...].
  96. For faces of unrecognized persons, the name 'unknown' will be returned.
  97. """
  98. if knn_clf is None and model_path is None:
  99. raise Exception("Must supply knn classifier either thourgh knn_clf or model_path")
  100. # Load a trained KNN model (if one was passed in)
  101. if knn_clf is None:
  102. with open(model_path, 'rb') as f:
  103. knn_clf = pickle.load(f)
  104. X_face_locations = face_recognition.face_locations(X_frame)
  105. # If no faces are found in the image, return an empty result.
  106. if len(X_face_locations) == 0:
  107. return []
  108. # Find encodings for faces in the test image
  109. faces_encodings = face_recognition.face_encodings(X_frame, known_face_locations=X_face_locations)
  110. # Use the KNN model to find the best matches for the test face
  111. closest_distances = knn_clf.kneighbors(faces_encodings, n_neighbors=1)
  112. are_matches = [closest_distances[0][i][0] <= distance_threshold for i in range(len(X_face_locations))]
  113. # Predict classes and remove classifications that aren't within the threshold
  114. return [(pred, loc) if rec else ("unknown", loc) for pred, loc, rec in zip(knn_clf.predict(faces_encodings), X_face_locations, are_matches)]
  115. def show_prediction_labels_on_image(frame, predictions):
  116. """
  117. Shows the face recognition results visually.
  118. :param frame: frame to show the predictions on
  119. :param predictions: results of the predict function
  120. :return opencv suited image to be fitting with cv2.imshow fucntion:
  121. """
  122. pil_image = Image.fromarray(frame)
  123. draw = ImageDraw.Draw(pil_image)
  124. for name, (top, right, bottom, left) in predictions:
  125. # enlarge the predictions for the full sized image.
  126. top *= 2
  127. right *= 2
  128. bottom *= 2
  129. left *= 2
  130. # Draw a box around the face using the Pillow module
  131. draw.rectangle(((left, top), (right, bottom)), outline=(0, 0, 255))
  132. # There's a bug in Pillow where it blows up with non-UTF-8 text
  133. # when using the default bitmap font
  134. name = name.encode("UTF-8")
  135. # Draw a label with a name below the face
  136. text_width, text_height = draw.textsize(name)
  137. draw.rectangle(((left, bottom - text_height - 10), (right, bottom)), fill=(0, 0, 255), outline=(0, 0, 255))
  138. draw.text((left + 6, bottom - text_height - 5), name, fill=(255, 255, 255, 255))
  139. # Remove the drawing library from memory as per the Pillow docs.
  140. del draw
  141. # Save image in open-cv format to be able to show it.
  142. opencvimage = np.array(pil_image)
  143. return opencvimage
  144. if __name__ == "__main__":
  145. print("Training KNN classifier...")
  146. classifier = train("knn_examples/train", model_save_path="trained_knn_model.clf", n_neighbors=2)
  147. print("Training complete!")
  148. # process one frame in every 30 frames for speed
  149. process_this_frame = 29
  150. print('Setting cameras up...')
  151. # multiple cameras can be used with the format url = 'http://username:password@camera_ip:port'
  152. url = 'http://admin:admin@192.168.0.106:8081/'
  153. cap = cv2.VideoCapture(url)
  154. while 1 > 0:
  155. ret, frame = cap.read()
  156. if ret:
  157. # Different resizing options can be chosen based on desired program runtime.
  158. # Image resizing for more stable streaming
  159. img = cv2.resize(frame, (0, 0), fx=0.5, fy=0.5)
  160. process_this_frame = process_this_frame + 1
  161. if process_this_frame % 30 == 0:
  162. predictions = predict(img, model_path="trained_knn_model.clf")
  163. frame = show_prediction_labels_on_image(frame, predictions)
  164. cv2.imshow('camera', frame)
  165. if ord('q') == cv2.waitKey(10):
  166. cap1.release()
  167. cv2.destroyAllWindows()
  168. exit(0)
Tip!

Press p or to see the previous file or, n or to see the next file

Comments

Loading...