当前位置:   article > 正文

关于OpenCV for Python入门-face_recognition实现人脸识别_opencv face recognition

opencv face recognition

face_recognition是世界上最简洁的人脸识别库,你可以使用Python和命令行工具提取、识别、操作人脸。

face_recognition的人脸识别是基于业内领先的C++开源库 dlib中的深度学习模型,用Labeled Faces in the Wild人脸数据集进行测试,有高达99.38%的准确率。但对小孩和亚洲人脸的识别准确率尚待提升。

face_recognition可以产生很多有趣的应用。

官方原文代码见:https://github.com/ageitgey/face_recognition/blob/master/examples/face_recognition_knn.py

face_recognition包括三个部分的代码

1、训练数据集

2、预测数据集

3、输出标签

训练数据集要遵循一定的数据格式,可以是以文件夹名称为标识的一个个图片,也可以是以文件名为标识的单个图片,当然前者每个人的图片越多,训练越充分。

训练数据集首先要检测出人脸,多个或零个均非合法的人脸

然后将图片二进制传入X,图片标识传入y,进行训练

训练图片是使用sklearn的KNN近邻分类器(KNeighborsClassifier)进行训练的,这个近邻的个数可以调节。

训练完成后写入模型文件,写入模型文件的好处是一次训练,后续可以直接使用,毕竟训练的时间过长,而用户可以实时添加人脸,难点在于如何增量进行训练?还没想到好办法。

预测过程中最大的困惑是neighbors的返回值,以及对返回值的处理,尤其是distance,这个distance关系到预测的准确与否,无论如何knn都会返回最近的距离和标签,但这个标签正确与否就不知道了,所以阈值设置很重要,我这边设置的是0.5。

最后是在图片上标注出人脸矩形和识别出的人物标签。

我这边是用的ORL数据集,以及从网上找到刘德华、成龙和我的照片。

  1. import math
  2. from sklearn import neighbors
  3. import os
  4. import os.path
  5. import pickle
  6. from PIL import Image, ImageDraw
  7. import face_recognition
  8. from face_recognition.face_recognition_cli import image_files_in_folder
  9. ALLOWED_EXTENSIONS = {'bmp','png', 'jpg', 'jpeg'}
  10. # 对指定的训练图片文件夹进行训练
  11. def train(train_dir, model_save_path=None, n_neighbors=None, knn_algo='ball_tree', verbose=False):
  12. """
  13. Trains a k-nearest neighbors classifier for face recognition.
  14. :param train_dir: directory that contains a sub-directory for each known person, with its name.
  15. (View in source code to see train_dir example tree structure)
  16. Structure:
  17. <train_dir>/
  18. ├── <person1>/
  19. │ ├── <somename1>.jpeg
  20. │ ├── <somename2>.jpeg
  21. │ ├── ...
  22. ├── <person2>/
  23. │ ├── <somename1>.jpeg
  24. │ └── <somename2>.jpeg
  25. └── ...
  26. :param model_save_path: (optional) path to save model on disk
  27. :param n_neighbors: (optional) number of neighbors to weigh in classification. Chosen automatically if not specified
  28. :param knn_algo: (optional) underlying data structure to support knn.default is ball_tree
  29. :param verbose: verbosity of training
  30. :return: returns knn classifier that was trained on the given data.
  31. """
  32. X = []
  33. y = []
  34. # 循环获取训练集图片
  35. for class_dir in os.listdir(train_dir):
  36. if not os.path.isdir(os.path.join(train_dir, class_dir)):
  37. continue
  38. # 遍历当前任务的每一张图片
  39. # image_files_in_folder,这个地方是获取文件夹下的所有图片文件,可以修改其中的图片类型
  40. # 默认是jpg|jpeg|png,后来追加了bmp
  41. print('training picture of {}'.format(class_dir))
  42. for img_path in image_files_in_folder(os.path.join(train_dir, class_dir)):
  43. # 加载图片文件,其实是numpy数组
  44. image = face_recognition.load_image_file(img_path)
  45. # 获取人脸检测框
  46. face_bounding_boxes = face_recognition.face_locations(image)
  47. # 多个人物或者0个人物不处理
  48. if len(face_bounding_boxes) != 1:
  49. # If there are no people (or too many people) in a training image, skip the image.
  50. if verbose:
  51. 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"))
  52. else:
  53. # Add face encoding for current image to the training set
  54. X.append(face_recognition.face_encodings(image, known_face_locations=face_bounding_boxes)[0])
  55. y.append(class_dir)
  56. # 设置KNN分类器的近邻数
  57. # Determine how many neighbors to use for weighting in the KNN classifier
  58. if n_neighbors is None:
  59. # n_neighbors = int(round(math.sqrt(len(X))))
  60. n_neighbors = 3
  61. if verbose:
  62. print("Chose n_neighbors automatically:", n_neighbors)
  63. # 创建KNN分类器,并进行训练
  64. knn_clf = neighbors.KNeighborsClassifier(n_neighbors=n_neighbors, algorithm=knn_algo, weights='distance')
  65. knn_clf.fit(X, y)
  66. # 保存KNN训练结果
  67. if model_save_path is not None:
  68. with open(model_save_path, 'wb') as f:
  69. pickle.dump(knn_clf, f)
  70. return knn_clf
  71. # 对指定的预测图片进行预测
  72. def predict(X_img_path, knn_clf=None, model_path=None, distance_threshold=0.5):
  73. """
  74. Recognizes faces in given image using a trained KNN classifier
  75. :param X_img_path: path to image to be recognized
  76. :param knn_clf: (optional) a knn classifier object. if not specified, model_save_path must be specified.
  77. :param model_path: (optional) path to a pickled knn classifier. if not specified, model_save_path must be knn_clf.
  78. :param distance_threshold: (optional) distance threshold for face classification. the larger it is, the more chance
  79. of mis-classifying an unknown person as a known one.
  80. :return: a list of names and face locations for the recognized faces in the image: [(name, bounding box), ...].
  81. For faces of unrecognized persons, the name 'unknown' will be returned.
  82. """
  83. # 校验当前文件类型
  84. if not os.path.isfile(X_img_path) or os.path.splitext(X_img_path)[1][1:] not in ALLOWED_EXTENSIONS:
  85. raise Exception("Invalid image path: {}".format(X_img_path))
  86. # 校验当前模型文件和knn模型,两个不能全空
  87. if knn_clf is None and model_path is None:
  88. raise Exception("Must supply knn classifier either thourgh knn_clf or model_path")
  89. # 加载训练好的KNN模型
  90. if knn_clf is None:
  91. with open(model_path, 'rb') as f:
  92. knn_clf = pickle.load(f)
  93. # 加载图片,获取人脸检测框
  94. X_img = face_recognition.load_image_file(X_img_path)
  95. X_face_locations = face_recognition.face_locations(X_img)
  96. # print('predict {}'.format(X_img_path))
  97. # 如果未找到人脸,返回[]
  98. if len(X_face_locations) == 0:
  99. return []
  100. # 对测试图片进行编码转换,转换为numpy数组
  101. faces_encodings = face_recognition.face_encodings(X_img, known_face_locations=X_face_locations)
  102. # 通过KNN模型找到最佳匹配的人脸
  103. closest_distances = knn_clf.kneighbors(faces_encodings, n_neighbors=3)
  104. # # 返回值indices:第0列元素为参考点的索引,后面是(n_neighbors - 1)个与之最近的点的索引
  105. # # 返回值distances:第0列元素为与自身的距离(为0),后面是(n_neighbors - 1)个与之最近的点与参考点的距离
  106. # closest_distances= [[0.34997745 0.3750366 0.37819395]]
  107. # closest_distances= [[ 5 12 11]]
  108. # for i in closest_distances:
  109. # print('closest_distances=',i)
  110. are_matches = []
  111. # are_matches = [closest_distances[0][i][0] <= distance_threshold for i in range(len(X_face_locations))]
  112. for i in range(len(X_face_locations)):
  113. are_matches.append( closest_distances[0][i][0] <= distance_threshold)
  114. #print('predict value=', closest_distances[0][i][0])
  115. # print('knn_clf.predict(faces_encodings)=',knn_clf.predict(faces_encodings))
  116. # 预测分类
  117. return [(pred, loc) if rec else ("unknown", loc) for pred, loc, rec in zip(knn_clf.predict(faces_encodings), X_face_locations, are_matches)]
  118. # 在图片上输出预测标签
  119. def show_prediction_labels_on_image(img_path, predictions):
  120. """
  121. Shows the face recognition results visually.
  122. :param img_path: path to image to be recognized
  123. :param predictions: results of the predict function
  124. :return:
  125. """
  126. # 打开图片,获取句柄
  127. pil_image = Image.open(img_path).convert("RGB")
  128. draw = ImageDraw.Draw(pil_image)
  129. # 对预测结果进行遍历
  130. for name, (top, right, bottom, left) in predictions:
  131. # 在人脸周边画矩形框
  132. draw.rectangle(((left, top), (right, bottom)), outline=(0, 0, 255))
  133. # There's a bug in Pillow where it blows up with non-UTF-8 text
  134. # when using the default bitmap font
  135. name = name.encode("UTF-8")
  136. # 在人脸地图输出标签
  137. text_width, text_height = draw.textsize(name)
  138. draw.rectangle(((left, bottom - text_height - 10), (right, bottom)), fill=(0, 0, 255), outline=(0, 0, 255))
  139. draw.text((left + 6, bottom - text_height - 5), name, fill=(255, 255, 255, 255))
  140. # Remove the drawing library from memory as per the Pillow docs
  141. del draw
  142. # Display the resulting image
  143. pil_image.show()
  144. if __name__ == "__main__":
  145. # 指定训练集路径和预测集路径
  146. train_dir=r'C:\Python\Pycharm\docxprocess\picture\ORL'
  147. test_dir=r'C:\Python\Pycharm\docxprocess\picture\predict'
  148. # 第一步,通过KNN分类器进行训练,并存储模型文件
  149. print("Training KNN classifier...")
  150. classifier = train(train_dir, model_save_path="trained_knn_model.clf", n_neighbors=3)
  151. print("Training complete!")
  152. # 第二步,使用训练分类器,对未知图片进行预测
  153. for image_file in os.listdir(test_dir):
  154. full_file_path = os.path.join(test_dir, image_file)
  155. print("Looking for faces in {}".format(image_file))
  156. # 使用训练模型进行预测
  157. predictions = predict(full_file_path, model_path="trained_knn_model.clf")
  158. # 输出结果
  159. for name, (top, right, bottom, left) in predictions:
  160. print("- Found {} at ({}, {})".format(name, left, top))
  161. # 图片上显示输出结果
  162. show_prediction_labels_on_image(os.path.join(test_dir, image_file), predictions)

人物1的识别,分类准确,距离为0

367e4ecc903683c5f2c91aff24c888b1.png

人物2的识别,分类准确,距离为0

51d37eec8106afebb10ca0e7ba30d9ff.png

合照的识别,里面包括周星驰、刘德华、李连杰、成龙,但周星驰和李连杰不在训练集内,周星驰未识别出来,刘德华和成龙识别正确,但李连杰识别出的最近距离甚至比刘德华本人还接近。

5757c1d3c034e873e9e2dfd8bce969c5.png

刘德华本人的识别,分类准确,距离为0.35左右

68ca3e3c2de2d036853c4e28e153c349.png

刘亦菲的识别,分类准确,距离为0.68左右

390080c8e582a77582a59c5267fe1498.png

本人的识别,分类准确,距离为0.42左右,我只有两张训练照片,一张是身份证,一张是正照。

0b3c41d475bb98908e831facb774ea16.png

最后,谢谢关注,谢谢支持!

4a9b15fce9f71a28e7a8e76abad83a07.png

本文内容由网友自发贡献,转载请注明出处:https://www.wpsshop.cn/w/Li_阴宅/article/detail/945843
推荐阅读
相关标签
  

闽ICP备14008679号