diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..10b731c
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,5 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
diff --git a/.idea/Dlib_face_recognition_from_camera.iml b/.idea/Dlib_face_recognition_from_camera.iml
new file mode 100644
index 0000000..a7bda17
--- /dev/null
+++ b/.idea/Dlib_face_recognition_from_camera.iml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..dc07e76
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..4490d0e
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..8306744
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/test_tkinter.py b/README.md
similarity index 100%
rename from test_tkinter.py
rename to README.md
diff --git a/README.rst b/README.rst
deleted file mode 100755
index ce36a39..0000000
--- a/README.rst
+++ /dev/null
@@ -1,269 +0,0 @@
-Face recognition from camera with Dlib
-######################################
-
-Introduction
-************
-
-调用摄像头进行人脸识别, 支持多张人脸同时识别 / Detect and recognize single or multi faces from camera;
-
-#. Tkinter 人脸录入界面, 支持录入时设置 (中文) 姓名 / Face register GUI with Tkinter, support setting (chinese) name when registering
-
- .. image:: introduction/face_register_tkinter_GUI.png
- :width: 1000
- :align: center
-
-#. 简单的 OpenCV 摄像头人脸录入界面 / Simple face register GUI with OpenCV, tkinter not needed and cannot set name
-
- .. image:: introduction/face_register.png
- :width: 1000
- :align: center
-
- 离摄像头过近, 人脸超出摄像头范围时, 会有 "OUT OF RANGE" 提醒 /
- Too close to the camera, or face ROI out of camera area, will have "OUT OF RANGE" warning;
-
- .. image:: introduction/face_register_warning.png
- :width: 1000
- :align: center
-
-#. 提取特征建立人脸数据库 / Generate face database from images captured
-#. 利用摄像头进行人脸识别 / Face recognizer
-
- face_reco_from_camera.py, 对于每一帧都做检测识别 / Do detection and recognition for every frame:
-
- .. image:: introduction/face_reco.png
- :width: 1000
- :align: center
-
- face_reco_from_camera_single_face.py, 对于人脸<=1, 只有新人脸出现才进行再识别来提高 FPS /
- Do re-reco only for new single face:
-
- .. image:: introduction/face_reco_single.png
- :width: 1000
- :align: center
-
- face_reco_from_camera_ot.py, 利用 OT 来实现再识别提高 FPS / Use OT to instead of re-reco for every frame to improve FPS:
-
- .. image:: introduction/face_reco_ot.png
- :width: 1000
- :align: center
-
- 定制显示名字, 可以写中文 / Show chinese name:
-
- .. image:: introduction/face_reco_chinese_name.png
- :width: 1000
- :align: center
-
-
-** 关于精度 / About accuracy:
-
-* When using a distance threshold of ``0.6``, the dlib model obtains an accuracy of ``99.38%`` on the standard LFW face recognition benchmark.
-
-** 关于算法 / About algorithm
-
-* 基于 Residual Neural Network / 残差网络的 CNN 模型;
-
-* This model is a ResNet network with 29 conv layers.
-It's essentially a version of the ResNet-34 network from the paper Deep Residual Learning for Image Recognition
-by He, Zhang, Ren, and Sun with a few layers removed and the number of filters per layer reduced by half.
-
-Overview
-********
-
-此项目中人脸识别的实现流程 (no OT, 每一帧都进行检测+识别) /
-Design of this repo, do detection and recognization for every frame:
-
-.. image:: introduction/overview.png
- :width: 1000
- :align: center
-
-实现流程 (with OT, 初始帧进行检测+识别, 后续帧检测+质心跟踪) / OT used:
-
-.. image:: introduction/overview_with_ot.png
- :width: 1000
- :align: center
-
-如果利用 OT 来跟踪, 可以大大提高 FPS, 因为做识别时候需要提取特征描述子的耗时很多 /
-Use OT can save the time for face descriptor computation to improve FPS;
-
-Steps
-*****
-
-#. 下载源码 / Git clone source code
-
- .. code-block:: bash
-
- git clone https://github.com/coneypo/Dlib_face_recognition_from_camera
-
-#. 安装依赖库 / Install some python packages needed
-
- .. code-block:: bash
-
- pip install -r requirements.txt
-
-#. 进行人脸信息采集录入, Tkinter GUI / Register faces with Tkinter GUI
-
- .. code-block:: bash
-
- # Install Tkinter
- sudo apt-get install python3-tk python3-pil python3-pil.imagetk
-
- python3 get_faces_from_camera_tkinter.py
-
-#. 进行人脸信息采集录入, OpenCV GUI / Register faces with OpenCV GUI, same with above step
-
- .. code-block:: bash
-
- python3 get_face_from_camera.py
-
-#. 提取所有录入人脸数据存入 ``features_all.csv`` / Features extraction and save into ``features_all.csv``
-
- .. code-block:: bash
-
- python3 features_extraction_to_csv.py
-
-#. 调用摄像头进行实时人脸识别 / Real-time face recognition
-
- .. code-block:: bash
-
- python3 face_reco_from_camera.py
-
-#. 对于人脸数<=1, 调用摄像头进行实时人脸识别 / Real-time face recognition (Better FPS compared with ``face_reco_from_camera.py``)
-
- .. code-block:: bash
-
- python3 face_reco_from_camera_single_face.py
-
-#. 利用 OT 算法, 调用摄像头进行实时人脸识别 / Real-time face recognition with OT (Better FPS)
-
- .. code-block:: bash
-
- python3 face_reco_from_camera_ot.py
-
-About Source Code
-*****************
-
-代码结构 / Code structure:
-
-::
-
- .
- ├── get_faces_from_camera.py # Step 1. Face register GUI with OpenCV
- ├── get_faces_from_camera_tkinter.py # Step 1. Face register GUI with Tkinter
- ├── features_extraction_to_csv.py # Step 2. Feature extraction
- ├── face_reco_from_camera.py # Step 3. Face recognizer
- ├── face_reco_from_camera_single_face.py # Step 3. Face recognizer for single person
- ├── face_reco_from_camera_ot.py # Step 3. Face recognizer with OT
- ├── face_descriptor_from_camera.py # Face descriptor computation
- ├── how_to_use_camera.py # Use the default camera by opencv
- ├── data
- │ ├── data_dlib # Dlib's model
- │ │ ├── dlib_face_recognition_resnet_model_v1.dat
- │ │ └── shape_predictor_68_face_landmarks.dat
- │ ├── data_faces_from_camera # Face images captured from camera (will generate after step 1)
- │ │ ├── person_1
- │ │ │ ├── img_face_1.jpg
- │ │ │ └── img_face_2.jpg
- │ │ └── person_2
- │ │ └── img_face_1.jpg
- │ │ └── img_face_2.jpg
- │ └── features_all.csv # CSV to save all the features of known faces (will generate after step 2)
- ├── README.rst
- └── requirements.txt # Some python packages needed
-
-用到的 Dlib 相关模型函数 / Dlib related functions used in this repo:
-
-#. Dlib 正向人脸检测器 (based on HOG), output: ```` / Dlib frontal face detector
-
-
- .. code-block:: python
-
- detector = dlib.get_frontal_face_detector()
- faces = detector(img_gray, 0)
-
-#. Dlib 人脸 landmark 特征点检测器, output: ```` / Dlib face landmark predictor, will use ``shape_predictor_68_face_landmarks.dat``
-
- .. code-block:: python
-
- # This is trained on the ibug 300-W dataset (https://ibug.doc.ic.ac.uk/resources/facial-point-annotations/)
- # Also note that this model file is designed for use with dlib's HOG face detector.
- # That is, it expects the bounding boxes from the face detector to be aligned a certain way,
- the way dlib's HOG face detector does it.
- # It won't work as well when used with a face detector that produces differently aligned boxes,
- # such as the CNN based mmod_human_face_detector.dat face detector.
-
- predictor = dlib.shape_predictor("data/data_dlib/shape_predictor_68_face_landmarks.dat")
- shape = predictor(img_rd, faces[i])
-
-
-#. Dlib 特征描述子 / Face recognition model, the object maps human faces into 128D vectors
-
-
- .. code-block:: python
-
- face_rec = dlib.face_recognition_model_v1("data/data_dlib/dlib_face_recognition_resnet_model_v1.dat")
-
-
-Python 源码介绍如下 / Source code:
-
-#. ``get_face_from_camera.py``:
-
- 人脸信息采集录入 / Face register with OpenCV GUI
-
- * 请注意存储人脸图片时, 矩形框不要超出摄像头范围, 要不然无法保存到本地;
- * 超出会有 "out of range" 的提醒;
-
-
-#. ``get_faces_from_camera_tkinter.py``:
-
- 进行人脸信息采集录入 Tkinter GUI / Face register with Tkinter GUI
-
-#. ``features_extraction_to_csv.py``:
-
- 从上一步存下来的图像文件中, 提取人脸数据存入 CSV / Extract features from face images saved in step 1;
-
- * 会生成一个存储所有特征人脸数据的 ``features_all.csv``
- * Size: ``n*129`` , n means n faces you registered and 129 means face name + 128D features of this face
-
-#. ``face_reco_from_camera.py``:
-
- 这一步将调用摄像头进行实时人脸识别; / This part will implement real-time face recognition;
-
- * 将捕获到的人脸数据和之前存的人脸数据进行对比计算欧式距离, 由此判断是否是同一个人;
-
- * Compare the faces captured from camera with the faces you have registered which are saved in ``features_all.csv``;
-
-#. ``face_reco_from_camera_single_face.py``:
-
- 针对于人脸数 <=1 的场景, 区别于 ``face_reco_from_camera.py`` (对每一帧都进行检测+识别), 只有人脸出现的时候进行识别;
-
-#. ``face_reco_from_camera_ot.py``:
-
- 只会对初始帧做检测+识别, 对后续帧做检测+质心跟踪;
-
-#. (optional) ``face_descriptor_from_camera.py``
-
- 调用摄像头进行实时特征描述子计算; / Real-time face descriptor computation;
-
-More
-****
-
-#. 如果希望详细了解 dlib 的用法, 请参考 Dlib 官方 Python api 的网站 / You can refer to this link for more information of how to use dlib: http://dlib.net/python/index.html
-
-#. Modify log level to ``logging.basicConfig(level=logging.DEBUG)`` to print info for every frame if needed (Default is ``logging.INFO``)
-
-#. 代码最好不要有中文路径 / No chinese characters in your code directory
-
-#. 人脸录入的时候先建文件夹再保存图片, 先 ``N`` 再 ``S`` / Press ``N`` before ``S``
-
-#. 关于 ``face_reco_from_camera.py`` 人脸识别卡顿 FPS 低问题, 原因是特征描述子提取很费时间; 光跑 ``face_descriptor_from_camera.py`` 中 ``face_reco_model.compute_face_descriptor`` 在我的机器上得到的平均 FPS 在 5 左右 (检测在 ``0.03s`` , 特征描述子提取在 ``0.158s`` , 和已知人脸进行遍历对比在 ``0.003s`` 左右); 所以主要提取特征时候耗资源, 可以用 OT 去做追踪 (使用 ``face_reco_from_camera_ot.py`` ), 而不是对每一帧都做检测+识别, 识别的性能从 20 FPS -> 200 FPS
-
-可以访问我的博客获取本项目的更详细介绍, 如有问题可以邮件联系我 /
-For more details, please visit my blog (in chinese) or send mail to coneypo@foxmail.com:
-
-* Blog: https://www.cnblogs.com/AdaminXie/p/9010298.html
-
-* 关于 OT 部分的更新在 Blog: https://www.cnblogs.com/AdaminXie/p/13566269.html
-
-* Feel free to create issue or contribute PR for it:)
-
-Thanks for your support.
diff --git a/data/data_faces/person_马斌昊/img_face_1.jpg b/data/data_faces/person_马斌昊/img_face_1.jpg
new file mode 100644
index 0000000..a99be71
Binary files /dev/null and b/data/data_faces/person_马斌昊/img_face_1.jpg differ
diff --git a/data/data_faces/person_马斌昊/img_face_2.jpg b/data/data_faces/person_马斌昊/img_face_2.jpg
new file mode 100644
index 0000000..896317c
Binary files /dev/null and b/data/data_faces/person_马斌昊/img_face_2.jpg differ
diff --git a/data/data_faces/person_马斌昊/img_face_3.jpg b/data/data_faces/person_马斌昊/img_face_3.jpg
new file mode 100644
index 0000000..80b257b
Binary files /dev/null and b/data/data_faces/person_马斌昊/img_face_3.jpg differ
diff --git a/data/features_all.csv b/data/features_all.csv
new file mode 100644
index 0000000..380d34a
--- /dev/null
+++ b/data/features_all.csv
@@ -0,0 +1 @@
+马斌昊,-0.0899050161242485,0.02384429331868887,0.10691650211811066,-0.026448555290699005,-0.12473130598664284,-0.026039691641926765,-0.10633478686213493,-0.10004803165793419,0.0756474919617176,-0.09969355911016464,0.2548818141222,-0.02838892675936222,-0.18727628886699677,-0.04292612988501787,-0.038223471492528915,0.14358164370059967,-0.13197344541549683,-0.08303523808717728,-0.04544464126229286,0.005225636065006256,0.05400150641798973,0.016614584252238274,0.04487479291856289,0.0208868607878685,-0.12604008615016937,-0.3497048169374466,-0.1073501706123352,-0.08952881768345833,-0.058808863162994385,-0.007420409703627229,-0.07389594614505768,0.027185998857021332,-0.14693009108304977,0.032583920285105705,0.002864556387066841,0.08570835366845131,-0.030903122387826443,-0.09934812411665916,0.13845199346542358,-0.052308812737464905,-0.2402488812804222,0.03694266080856323,0.07542015612125397,0.1459449827671051,0.2269286960363388,0.014682859182357788,0.05472549982368946,-0.11605571955442429,0.06804285570979118,-0.17394205182790756,0.028083041310310364,0.10427030548453331,0.05113978683948517,0.05636468715965748,0.0043844198808074,-0.14433760941028595,-0.00407144520431757,0.12244492024183273,-0.09491624310612679,-0.015221940353512764,0.024541491642594337,-0.07212522253394127,-0.001256248913705349,-0.08840961009263992,0.22439686954021454,0.11492674425244331,-0.15236739814281464,-0.1425611972808838,0.06785859912633896,-0.18730811774730682,-0.07806657627224922,0.07729200273752213,-0.1676863580942154,-0.21197973936796188,-0.32569898664951324,0.027618836611509323,0.39188095927238464,0.10446011275053024,-0.17949597537517548,0.014993381686508656,-0.06068217195570469,0.00010182708501815796,0.09084133803844452,0.1250796541571617,-0.021716125309467316,0.008610536344349384,-0.11595302447676659,-0.0045088487677276134,0.27449268102645874,-0.07868175581097603,-0.0018516536802053452,0.2252117618918419,-0.00012384727597236633,0.06658063270151615,0.010239068418741226,0.06843071430921555,-0.024587254971265793,0.015095856040716171,-0.10306384414434433,0.04500553756952286,-0.013208229094743729,-0.07549317926168442,-0.024796511977910995,0.06462816521525383,-0.1793217957019806,0.07073099911212921,-0.008851969614624977,-0.003468985203653574,0.019725533202290535,-0.03128764219582081,-0.11080201715230942,-0.05722355656325817,0.15097910165786743,-0.24694078415632248,0.1483754888176918,0.183498315513134,0.1129513792693615,0.17476002871990204,0.13292384147644043,0.095770925283432,-0.055514756590127945,-0.03940589725971222,-0.17228589206933975,0.006599367829039693,0.07312680780887604,-0.0077499039471149445,0.07860656827688217,0.03986034169793129
diff --git a/face_descriptor_from_camera.py b/face_descriptor_from_camera.py
deleted file mode 100644
index e64f408..0000000
--- a/face_descriptor_from_camera.py
+++ /dev/null
@@ -1,92 +0,0 @@
-# Copyright (C) 2018-2021 coneypo
-# SPDX-License-Identifier: MIT
-
-# 摄像头实时人脸特征描述子计算 / Real-time face descriptor computing
-
-import dlib # 人脸识别的库 Dlib
-import cv2 # 图像处理的库 OpenCV
-import time
-
-# 1. Dlib 正向人脸检测器
-detector = dlib.get_frontal_face_detector()
-
-# 2. Dlib 人脸 landmark 特征点检测器
-predictor = dlib.shape_predictor('data/data_dlib/shape_predictor_68_face_landmarks.dat')
-
-# 3. Dlib Resnet 人脸识别模型,提取 128D 的特征矢量
-face_reco_model = dlib.face_recognition_model_v1("data/data_dlib/dlib_face_recognition_resnet_model_v1.dat")
-
-
-class Face_Descriptor:
- def __init__(self):
- self.frame_time = 0
- self.frame_start_time = 0
- self.fps = 0
- self.frame_cnt = 0
-
- def update_fps(self):
- now = time.time()
- self.frame_time = now - self.frame_start_time
- self.fps = 1.0 / self.frame_time
- self.frame_start_time = now
-
- def run(self):
- cap = cv2.VideoCapture(0)
- cap.set(3, 480)
- self.process(cap)
- cap.release()
- cv2.destroyAllWindows()
-
- def process(self, stream):
- while stream.isOpened():
- flag, img_rd = stream.read()
- self.frame_cnt+=1
- k = cv2.waitKey(1)
-
- print('- Frame ', self.frame_cnt, " starts:")
-
- timestamp1 = time.time()
- faces = detector(img_rd, 0)
- timestamp2 = time.time()
- print("--- Time used to `detector`: %s seconds ---" % (timestamp2 - timestamp1))
-
- font = cv2.FONT_HERSHEY_SIMPLEX
-
- # 检测到人脸
- if len(faces) != 0:
- for face in faces:
- timestamp3 = time.time()
- face_shape = predictor(img_rd, face)
- timestamp4 = time.time()
- print("--- Time used to `predictor`: %s seconds ---" % (timestamp4 - timestamp3))
-
- timestamp5 = time.time()
- face_desc = face_reco_model.compute_face_descriptor(img_rd, face_shape)
- timestamp6 = time.time()
- print("--- Time used to `compute_face_descriptor:` %s seconds ---" % (timestamp6 - timestamp5))
-
- # 添加说明
- cv2.putText(img_rd, "Face descriptor", (20, 40), font, 1, (255, 255, 255), 1, cv2.LINE_AA)
- cv2.putText(img_rd, "FPS: " + str(self.fps.__round__(2)), (20, 100), font, 0.8, (0, 255, 0), 1, cv2.LINE_AA)
- cv2.putText(img_rd, "Faces: " + str(len(faces)), (20, 140), font, 0.8, (0, 255, 0), 1, cv2.LINE_AA)
- cv2.putText(img_rd, "S: Save current face", (20, 400), font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
- cv2.putText(img_rd, "Q: Quit", (20, 450), font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
-
- # 按下 'q' 键退出
- if k == ord('q'):
- break
-
- self.update_fps()
-
- cv2.namedWindow("camera", 1)
- cv2.imshow("camera", img_rd)
- print('\n')
-
-
-def main():
- Face_Descriptor_con = Face_Descriptor()
- Face_Descriptor_con.run()
-
-
-if __name__ == '__main__':
- main()
\ No newline at end of file
diff --git a/face_reco_from_camera.py b/face_reco_from_camera.py
index 60293b5..2437d1c 100755
--- a/face_reco_from_camera.py
+++ b/face_reco_from_camera.py
@@ -1,13 +1,6 @@
# Copyright (C) 2018-2021 coneypo
# SPDX-License-Identifier: MIT
-# Author: coneypo
-# Blog: http://www.cnblogs.com/AdaminXie
-# GitHub: https://github.com/coneypo/Dlib_face_recognition_from_camera
-# Mail: coneypo@foxmail.com
-
-# 摄像头实时人脸识别 / Real-time face detection and recognition
-
import dlib
import numpy as np
import cv2
@@ -17,44 +10,49 @@ import time
import logging
from PIL import Image, ImageDraw, ImageFont
-# Dlib 正向人脸检测器 / Use frontal face detector of Dlib
+# Dlib 正向人脸检测器
detector = dlib.get_frontal_face_detector()
-
-# Dlib 人脸 landmark 特征点检测器 / Get face landmarks
predictor = dlib.shape_predictor('data/data_dlib/shape_predictor_68_face_landmarks.dat')
-
-# Dlib Resnet 人脸识别模型,提取 128D 的特征矢量 / Use Dlib resnet50 model to get 128D face descriptor
face_reco_model = dlib.face_recognition_model_v1("data/data_dlib/dlib_face_recognition_resnet_model_v1.dat")
class Face_Recognizer:
def __init__(self):
- self.face_feature_known_list = [] # 用来存放所有录入人脸特征的数组 / Save the features of faces in database
- self.face_name_known_list = [] # 存储录入人脸名字 / Save the name of faces in database
+ self.face_feature_known_list = []
+ self.face_name_known_list = []
- self.current_frame_face_cnt = 0 # 存储当前摄像头中捕获到的人脸数 / Counter for faces in current frame
- self.current_frame_face_feature_list = [] # 存储当前摄像头中捕获到的人脸特征 / Features of faces in current frame
- self.current_frame_face_name_list = [] # 存储当前摄像头中捕获到的所有人脸的名字 / Names of faces in current frame
- self.current_frame_face_name_position_list = [] # 存储当前摄像头中捕获到的所有人脸的名字坐标 / Positions of faces in current frame
+ self.current_frame_face_cnt = 0
+ self.current_frame_face_feature_list = []
+ self.current_frame_face_name_list = []
+ self.current_frame_face_name_position_list = []
# Update FPS
- self.fps = 0 # FPS of current frame
- self.fps_show = 0 # FPS per second
+ self.fps = 0
+ self.fps_show = 0
self.frame_start_time = 0
self.frame_cnt = 0
self.start_time = time.time()
self.font = cv2.FONT_ITALIC
- self.font_chinese = ImageFont.truetype("simsun.ttc", 30)
+ # 安全加载中文字体
+ try:
+ self.font_chinese = ImageFont.truetype("simsun.ttc", 30)
+ except:
+ print("警告: 无法加载中文字体,使用默认字体")
+ self.font_chinese = ImageFont.load_default()
+
+ # 添加退出标志
+ self.exit_flag = False
- # 从 "features_all.csv" 读取录入人脸特征 / Read known faces from "features_all.csv"
def get_face_database(self):
if os.path.exists("data/features_all.csv"):
path_features_known_csv = "data/features_all.csv"
csv_rd = pd.read_csv(path_features_known_csv, header=None)
for i in range(csv_rd.shape[0]):
features_someone_arr = []
- self.face_name_known_list.append(csv_rd.iloc[i][0])
+ # 修复:确保姓名为字符串
+ name = str(csv_rd.iloc[i][0])
+ self.face_name_known_list.append(name)
for j in range(1, 129):
if csv_rd.iloc[i][j] == '':
features_someone_arr.append('0')
@@ -65,11 +63,8 @@ class Face_Recognizer:
return 1
else:
logging.warning("'features_all.csv' not found!")
- logging.warning("Please run 'get_faces_from_camera.py' "
- "and 'features_extraction_to_csv.py' before 'face_reco_from_camera.py'")
return 0
- # 计算两个128D向量间的欧式距离 / Compute the e-distance between two 128D features
@staticmethod
def return_euclidean_distance(feature_1, feature_2):
feature_1 = np.array(feature_1)
@@ -77,10 +72,8 @@ class Face_Recognizer:
dist = np.sqrt(np.sum(np.square(feature_1 - feature_2)))
return dist
- # 更新 FPS / Update FPS of Video stream
def update_fps(self):
now = time.time()
- # 每秒刷新 fps / Refresh fps per second
if str(self.start_time).split(".")[0] != str(now).split(".")[0]:
self.fps_show = self.fps
self.start_time = now
@@ -88,11 +81,9 @@ class Face_Recognizer:
self.fps = 1.0 / self.frame_time
self.frame_start_time = now
- # 生成的 cv2 window 上面添加说明文字 / PutText on cv2 window
def draw_note(self, img_rd):
cv2.putText(img_rd, "Face Recognizer", (20, 40), self.font, 1, (255, 255, 255), 1, cv2.LINE_AA)
- cv2.putText(img_rd, "Frame: " + str(self.frame_cnt), (20, 100), self.font, 0.8, (0, 255, 0), 1,
- cv2.LINE_AA)
+ cv2.putText(img_rd, "Frame: " + str(self.frame_cnt), (20, 100), self.font, 0.8, (0, 255, 0), 1, cv2.LINE_AA)
cv2.putText(img_rd, "FPS: " + str(self.fps_show.__round__(2)), (20, 130), self.font, 0.8, (0, 255, 0), 1,
cv2.LINE_AA)
cv2.putText(img_rd, "Faces: " + str(self.current_frame_face_cnt), (20, 160), self.font, 0.8, (0, 255, 0), 1,
@@ -100,126 +91,176 @@ class Face_Recognizer:
cv2.putText(img_rd, "Q: Quit", (20, 450), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
def draw_name(self, img_rd):
- # 在人脸框下面写人脸名字 / Write names under rectangle
+ # 在人脸框下面写人脸名字
img = Image.fromarray(cv2.cvtColor(img_rd, cv2.COLOR_BGR2RGB))
draw = ImageDraw.Draw(img)
for i in range(self.current_frame_face_cnt):
- # cv2.putText(img_rd, self.current_frame_face_name_list[i], self.current_frame_face_name_position_list[i], self.font, 0.8, (0, 255, 255), 1, cv2.LINE_AA)
- draw.text(xy=self.current_frame_face_name_position_list[i], text=self.current_frame_face_name_list[i], font=self.font_chinese,
- fill=(255, 255, 0))
- img_rd = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
+ try:
+ # 安全处理姓名
+ name = str(self.current_frame_face_name_list[i])
+ position = tuple(map(int, self.current_frame_face_name_position_list[i]))
+ draw.text(xy=position, text=name, font=self.font_chinese, fill=(255, 255, 0))
+ except Exception as e:
+ print(f"绘制姓名时出错: {e}")
+ continue
+ img_rd = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
return img_rd
- # 修改显示人名 / Show names in chinese
- def show_chinese_name(self):
- # Default known name: person_1, person_2, person_3
- if self.current_frame_face_cnt >= 1:
- # 修改录入的人脸姓名 / Modify names in face_name_known_list to chinese name
- self.face_name_known_list[0] = '张三'.encode('utf-8').decode()
- # self.face_name_known_list[1] = '张四'.encode('utf-8').decode()
+ def check_window_closed(self, window_name="camera"):
+ """检查窗口是否被关闭"""
+ try:
+ # 尝试获取窗口属性,如果窗口关闭会返回 -1
+ if cv2.getWindowProperty(window_name, cv2.WND_PROP_VISIBLE) < 1:
+ return True
+ return False
+ except:
+ # 如果窗口不存在,也会触发异常
+ return True
- # 处理获取的视频流,进行人脸识别 / Face detection and recognition from input video stream
def process(self, stream):
- # 1. 读取存放所有人脸特征的 csv / Read known faces from "features.all.csv"
- if self.get_face_database():
- while stream.isOpened():
- self.frame_cnt += 1
- logging.debug("Frame %d starts", self.frame_cnt)
- flag, img_rd = stream.read()
- faces = detector(img_rd, 0)
- kk = cv2.waitKey(1)
- # 按下 q 键退出 / Press 'q' to quit
- if kk == ord('q'):
- break
- else:
- self.draw_note(img_rd)
- self.current_frame_face_feature_list = []
- self.current_frame_face_cnt = 0
- self.current_frame_face_name_position_list = []
- self.current_frame_face_name_list = []
+ # 1. 读取存放所有人脸特征的 csv
+ if not self.get_face_database():
+ print("错误: 无法加载人脸数据库")
+ return
- # 2. 检测到人脸 / Face detected in current frame
- if len(faces) != 0:
- # 3. 获取当前捕获到的图像的所有人脸的特征 / Compute the face descriptors for faces in current frame
- for i in range(len(faces)):
- shape = predictor(img_rd, faces[i])
- self.current_frame_face_feature_list.append(face_reco_model.compute_face_descriptor(img_rd, shape))
- # 4. 遍历捕获到的图像中所有的人脸 / Traversal all the faces in the database
- for k in range(len(faces)):
- logging.debug("For face %d in camera:", k+1)
- # 先默认所有人不认识,是 unknown / Set the default names of faces with "unknown"
- self.current_frame_face_name_list.append("unknown")
+ print("人脸识别系统启动成功!")
+ print("按 'Q' 键退出程序")
+ print("或点击窗口关闭按钮退出")
- # 每个捕获人脸的名字坐标 / Positions of faces captured
- self.current_frame_face_name_position_list.append(tuple(
- [faces[k].left(), int(faces[k].bottom() + (faces[k].bottom() - faces[k].top()) / 4)]))
+ # 创建窗口并设置为正常模式
+ cv2.namedWindow("camera", cv2.WINDOW_NORMAL)
- # 5. 对于某张人脸,遍历所有存储的人脸特征
- # For every faces detected, compare the faces in the database
- current_frame_e_distance_list = []
- for i in range(len(self.face_feature_known_list)):
- # 如果 person_X 数据不为空
- if str(self.face_feature_known_list[i][0]) != '0.0':
- e_distance_tmp = self.return_euclidean_distance(self.current_frame_face_feature_list[k],
- self.face_feature_known_list[i])
- logging.debug(" With person %s, the e-distance is %f", str(i + 1), e_distance_tmp)
- current_frame_e_distance_list.append(e_distance_tmp)
- else:
- # 空数据 person_X
- current_frame_e_distance_list.append(999999999)
- # 6. 寻找出最小的欧式距离匹配 / Find the one with minimum e-distance
- similar_person_num = current_frame_e_distance_list.index(min(current_frame_e_distance_list))
- logging.debug("Minimum e-distance with %s: %f", self.face_name_known_list[similar_person_num], min(current_frame_e_distance_list))
+ while stream.isOpened() and not self.exit_flag:
+ # 检查窗口是否被关闭
+ if self.check_window_closed():
+ print("检测到窗口关闭,退出程序")
+ break
- if min(current_frame_e_distance_list) < 0.4:
- self.current_frame_face_name_list[k] = self.face_name_known_list[similar_person_num]
- logging.debug("Face recognition result: %s", self.face_name_known_list[similar_person_num])
- else:
- logging.debug("Face recognition result: Unknown person")
- logging.debug("\n")
+ self.frame_cnt += 1
+ flag, img_rd = stream.read()
- # 矩形框 / Draw rectangle
- for kk, d in enumerate(faces):
- # 绘制矩形框
- cv2.rectangle(img_rd, tuple([d.left(), d.top()]), tuple([d.right(), d.bottom()]),
- (255, 255, 255), 2)
+ if not flag:
+ print("无法读取视频帧")
+ break
- self.current_frame_face_cnt = len(faces)
+ # 检测按键和窗口关闭
+ kk = cv2.waitKey(1) & 0xFF
- # 7. 在这里更改显示的人名 / Modify name if needed
- # self.show_chinese_name()
+ # 按下 q 键退出
+ if kk == ord('q') or kk == ord('Q'):
+ print("接收到退出信号,退出程序")
+ break
- # 8. 写名字 / Draw name
- img_with_name = self.draw_name(img_rd)
+ # 检查窗口关闭
+ if cv2.getWindowProperty("camera", cv2.WND_PROP_VISIBLE) < 1:
+ print("窗口已关闭,退出程序")
+ break
- else:
- img_with_name = img_rd
+ self.draw_note(img_rd)
+ self.current_frame_face_feature_list = []
+ self.current_frame_face_cnt = 0
+ self.current_frame_face_name_position_list = []
+ self.current_frame_face_name_list = []
- logging.debug("Faces in camera now: %s", self.current_frame_face_name_list)
+ # 2. 检测到人脸
+ faces = detector(img_rd, 0)
+ if len(faces) != 0:
+ # 3. 获取当前捕获到的图像的所有人脸的特征
+ for i in range(len(faces)):
+ shape = predictor(img_rd, faces[i])
+ self.current_frame_face_feature_list.append(face_reco_model.compute_face_descriptor(img_rd, shape))
- cv2.imshow("camera", img_with_name)
+ # 4. 遍历捕获到的图像中所有的人脸
+ for k in range(len(faces)):
+ # 先默认所有人不认识
+ self.current_frame_face_name_list.append("unknown")
- # 9. 更新 FPS / Update stream FPS
- self.update_fps()
- logging.debug("Frame ends\n\n")
+ # 每个捕获人脸的名字坐标
+ self.current_frame_face_name_position_list.append(tuple(
+ [faces[k].left(), int(faces[k].bottom() + (faces[k].bottom() - faces[k].top()) / 4)]))
- # OpenCV 调用摄像头并进行 process
- def run(self):
- # cap = cv2.VideoCapture("video.mp4") # Get video stream from video file
- cap = cv2.VideoCapture(0) # Get video stream from camera
- cap.set(3, 480) # 640x480
- self.process(cap)
+ # 5. 对于某张人脸,遍历所有存储的人脸特征
+ current_frame_e_distance_list = []
+ for i in range(len(self.face_feature_known_list)):
+ if str(self.face_feature_known_list[i][0]) != '0.0':
+ e_distance_tmp = self.return_euclidean_distance(
+ self.current_frame_face_feature_list[k],
+ self.face_feature_known_list[i]
+ )
+ current_frame_e_distance_list.append(e_distance_tmp)
+ else:
+ current_frame_e_distance_list.append(999999999)
- cap.release()
+ # 6. 寻找出最小的欧式距离匹配
+ if current_frame_e_distance_list:
+ similar_person_num = current_frame_e_distance_list.index(min(current_frame_e_distance_list))
+ min_distance = min(current_frame_e_distance_list)
+
+ if min_distance < 0.4:
+ self.current_frame_face_name_list[k] = self.face_name_known_list[similar_person_num]
+
+ # 绘制矩形框
+ cv2.rectangle(img_rd,
+ (faces[k].left(), faces[k].top()),
+ (faces[k].right(), faces[k].bottom()),
+ (255, 255, 255), 2)
+
+ self.current_frame_face_cnt = len(faces)
+
+ # 8. 写名字
+ img_rd = self.draw_name(img_rd)
+
+ # 显示图像
+ cv2.imshow("camera", img_rd)
+
+ # 9. 更新 FPS
+ self.update_fps()
+
+ # 清理资源
cv2.destroyAllWindows()
+ print("程序正常退出")
+
+ def run(self):
+ cap = cv2.VideoCapture(0)
+ if not cap.isOpened():
+ print("错误: 无法打开摄像头")
+ return
+
+ # 设置摄像头参数
+ cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
+ cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
+
+ try:
+ self.process(cap)
+ except KeyboardInterrupt:
+ print("\n接收到 Ctrl+C,退出程序")
+ except Exception as e:
+ print(f"程序异常: {e}")
+ finally:
+ # 确保资源被释放
+ cap.release()
+ cv2.destroyAllWindows()
def main():
- # logging.basicConfig(level=logging.DEBUG) # Set log level to 'logging.DEBUG' to print debug info of every frame
logging.basicConfig(level=logging.INFO)
+ print("=== 人脸识别系统启动 ===")
+
+ # 检查必要的文件
+ required_files = [
+ 'data/data_dlib/shape_predictor_68_face_landmarks.dat',
+ 'data/data_dlib/dlib_face_recognition_resnet_model_v1.dat',
+ 'data/features_all.csv'
+ ]
+
+ for file in required_files:
+ if not os.path.exists(file):
+ print(f"错误: 缺少必要文件 {file}")
+ return
+
Face_Recognizer_con = Face_Recognizer()
Face_Recognizer_con.run()
if __name__ == '__main__':
- main()
+ main()
\ No newline at end of file
diff --git a/face_reco_from_camera_single_face.py b/face_reco_from_camera_single_face.py
deleted file mode 100644
index 245844b..0000000
--- a/face_reco_from_camera_single_face.py
+++ /dev/null
@@ -1,329 +0,0 @@
-# Copyright (C) 2018-2021 coneypo
-# SPDX-License-Identifier: MIT
-
-# Author: coneypo
-# Blog: http://www.cnblogs.com/AdaminXie
-# GitHub: https://github.com/coneypo/Dlib_face_recognition_from_camera
-# Mail: coneypo@foxmail.com
-
-# 单张人脸实时识别 / Real-time face detection and recognition for single face
-# 检测 -> 识别人脸, 新人脸出现 -> 再识别, 不会对于每一帧都进行识别 / Do detection -> recognize face, new face -> do re-recognition
-# 其实对于单张人脸, 不需要 OT 进行跟踪, 对于新出现的人脸, 再识别一次就好了 / No OT here, OT will be used only for multi faces
-
-import dlib
-import numpy as np
-import cv2
-import os
-import pandas as pd
-import time
-from PIL import Image, ImageDraw, ImageFont
-import logging
-
-# Dlib 正向人脸检测器 / Use frontal face detector of Dlib
-detector = dlib.get_frontal_face_detector()
-
-# Dlib 人脸 landmark 特征点检测器 / Get face landmarks
-predictor = dlib.shape_predictor('data/data_dlib/shape_predictor_68_face_landmarks.dat')
-
-# Dlib Resnet 人脸识别模型, 提取 128D 的特征矢量 / Use Dlib resnet50 model to get 128D face descriptor
-face_reco_model = dlib.face_recognition_model_v1("data/data_dlib/dlib_face_recognition_resnet_model_v1.dat")
-
-
-class Face_Recognizer:
- def __init__(self):
- self.font = cv2.FONT_ITALIC
- self.font_chinese = ImageFont.truetype("simsun.ttc", 30)
-
- # 统计 FPS / For FPS
- self.frame_time = 0
- self.frame_start_time = 0
- self.fps = 0
- self.fps_show = 0
- self.start_time = time.time()
-
- # 统计帧数 / cnt for frame
- self.frame_cnt = 0
-
- # 用来存储所有录入人脸特征的数组 / Save the features of faces in the database
- self.features_known_list = []
- # 用来存储录入人脸名字 / Save the name of faces in the database
- self.face_name_known_list = []
-
- # 用来存储上一帧和当前帧 ROI 的质心坐标 / List to save centroid positions of ROI in frame N-1 and N
- self.last_frame_centroid_list = []
- self.current_frame_centroid_list = []
-
- # 用来存储当前帧检测出目标的名字 / List to save names of objects in current frame
- self.current_frame_name_list = []
-
- # 上一帧和当前帧中人脸数的计数器 / cnt for faces in frame N-1 and N
- self.last_frame_faces_cnt = 0
- self.current_frame_face_cnt = 0
-
- # 用来存放进行识别时候对比的欧氏距离 / Save the e-distance for faceX when recognizing
- self.current_frame_face_X_e_distance_list = []
-
- # 存储当前摄像头中捕获到的所有人脸的坐标名字 / Save the positions and names of current faces captured
- self.current_frame_face_position_list = []
- # 存储当前摄像头中捕获到的人脸特征 / Save the features of people in current frame
- self.current_frame_face_feature_list = []
-
- # 控制再识别的后续帧数 / Reclassify after 'reclassify_interval' frames
- # 如果识别出 "unknown" 的脸, 将在 reclassify_interval_cnt 计数到 reclassify_interval 后, 对于人脸进行重新识别
- self.reclassify_interval_cnt = 0
- self.reclassify_interval = 10
-
- # 从 "features_all.csv" 读取录入人脸特征 / Get known faces from "features_all.csv"
- def get_face_database(self):
- if os.path.exists("data/features_all.csv"):
- path_features_known_csv = "data/features_all.csv"
- csv_rd = pd.read_csv(path_features_known_csv, header=None)
- for i in range(csv_rd.shape[0]):
- features_someone_arr = []
- self.face_name_known_list.append(csv_rd.iloc[i][0])
- for j in range(1, 129):
- if csv_rd.iloc[i][j] == '':
- features_someone_arr.append('0')
- else:
- features_someone_arr.append(csv_rd.iloc[i][j])
- self.features_known_list.append(features_someone_arr)
- logging.info("Faces in Database: %d", len(self.features_known_list))
- return 1
- else:
- logging.warning("'features_all.csv' not found!")
- logging.warning("Please run 'get_faces_from_camera.py' "
- "and 'features_extraction_to_csv.py' before 'face_reco_from_camera.py'")
- return 0
-
- # 获取处理之后 stream 的帧数 / Update FPS of video stream
- def update_fps(self):
- now = time.time()
- # 每秒刷新 fps / Refresh fps per second
- if str(self.start_time).split(".")[0] != str(now).split(".")[0]:
- self.fps_show = self.fps
- self.start_time = now
- self.frame_time = now - self.frame_start_time
- self.fps = 1.0 / self.frame_time
- self.frame_start_time = now
-
- # 计算两个128D向量间的欧式距离 / Compute the e-distance between two 128D features
- @staticmethod
- def return_euclidean_distance(feature_1, feature_2):
- feature_1 = np.array(feature_1)
- feature_2 = np.array(feature_2)
- dist = np.sqrt(np.sum(np.square(feature_1 - feature_2)))
- return dist
-
- # 生成的 cv2 window 上面添加说明文字 / putText on cv2 window
- def draw_note(self, img_rd):
- # 添加说明 (Add some statements
- cv2.putText(img_rd, "Face Recognizer for single face", (20, 40), self.font, 1, (255, 255, 255), 1,
- cv2.LINE_AA)
- cv2.putText(img_rd, "Frame: " + str(self.frame_cnt), (20, 100), self.font, 0.8, (0, 255, 0), 1,
- cv2.LINE_AA)
- cv2.putText(img_rd, "FPS: " + str(self.fps_show.__round__(2)), (20, 130), self.font, 0.8, (0, 255, 0), 1,
- cv2.LINE_AA)
- cv2.putText(img_rd, "Faces: " + str(self.current_frame_face_cnt), (20, 160), self.font, 0.8, (0, 255, 0), 1,
- cv2.LINE_AA)
- cv2.putText(img_rd, "Q: Quit", (20, 450), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
-
- def draw_name(self, img_rd):
- # 在人脸框下面写人脸名字 / Write names under ROI
- logging.debug(self.current_frame_name_list)
- img = Image.fromarray(cv2.cvtColor(img_rd, cv2.COLOR_BGR2RGB))
- draw = ImageDraw.Draw(img)
- draw.text(xy=self.current_frame_face_position_list[0], text=self.current_frame_name_list[0], font=self.font_chinese,
- fill=(255, 255, 0))
- img_rd = cv2.cvtColor(np.array(img), cv2.COLOR_RGB2BGR)
- return img_rd
-
- def show_chinese_name(self):
- if self.current_frame_face_cnt >= 1:
- logging.debug(self.face_name_known_list)
- # 修改录入的人脸姓名 / Modify names in face_name_known_list to chinese name
- self.face_name_known_list[0] = '张三'.encode('utf-8').decode()
- # self.face_name_known_list[1] = '张四'.encode('utf-8').decode()
-
- # 处理获取的视频流, 进行人脸识别 / Face detection and recognition wit OT from input video stream
- def process(self, stream):
- # 1. 读取存放所有人脸特征的 csv / Get faces known from "features.all.csv"
- if self.get_face_database():
- while stream.isOpened():
- self.frame_cnt += 1
- logging.debug("Frame " + str(self.frame_cnt) + " starts")
- flag, img_rd = stream.read()
- kk = cv2.waitKey(1)
-
- # 2. 检测人脸 / Detect faces for frame X
- faces = detector(img_rd, 0)
-
- # 3. 更新帧中的人脸数 / Update cnt for faces in frames
- self.last_frame_faces_cnt = self.current_frame_face_cnt
- self.current_frame_face_cnt = len(faces)
-
- # 4.1 当前帧和上一帧相比没有发生人脸数变化 / If cnt not changes, 1->1 or 0->0
- if self.current_frame_face_cnt == self.last_frame_faces_cnt:
- logging.debug("scene 1: 当前帧和上一帧相比没有发生人脸数变化 / No face cnt changes in this frame!!!")
-
- if "unknown" in self.current_frame_name_list:
- logging.debug(" >>> 有未知人脸, 开始进行 reclassify_interval_cnt 计数")
- self.reclassify_interval_cnt += 1
-
- # 4.1.1 当前帧一张人脸 / One face in this frame
- if self.current_frame_face_cnt == 1:
- if self.reclassify_interval_cnt == self.reclassify_interval:
- logging.debug(" scene 1.1 需要对于当前帧重新进行人脸识别 / Re-classify for current frame")
-
- self.reclassify_interval_cnt = 0
- self.current_frame_face_feature_list = []
- self.current_frame_face_X_e_distance_list = []
- self.current_frame_name_list = []
-
- for i in range(len(faces)):
- shape = predictor(img_rd, faces[i])
- self.current_frame_face_feature_list.append(
- face_reco_model.compute_face_descriptor(img_rd, shape))
-
- # a. 遍历捕获到的图像中所有的人脸 / Traversal all the faces in the database
- for k in range(len(faces)):
- self.current_frame_name_list.append("unknown")
-
- # b. 每个捕获人脸的名字坐标 / Positions of faces captured
- self.current_frame_face_position_list.append(tuple(
- [faces[k].left(),
- int(faces[k].bottom() + (faces[k].bottom() - faces[k].top()) / 4)]))
-
- # c. 对于某张人脸, 遍历所有存储的人脸特征 / For every face detected, compare it with all the faces in the database
- for i in range(len(self.features_known_list)):
- # 如果 person_X 数据不为空 / If the data of person_X is not empty
- if str(self.features_known_list[i][0]) != '0.0':
- e_distance_tmp = self.return_euclidean_distance(
- self.current_frame_face_feature_list[k],
- self.features_known_list[i])
- logging.debug(" with person %d, the e-distance: %f", i + 1, e_distance_tmp)
- self.current_frame_face_X_e_distance_list.append(e_distance_tmp)
- else:
- # 空数据 person_X / For empty data
- self.current_frame_face_X_e_distance_list.append(999999999)
-
- # d. 寻找出最小的欧式距离匹配 / Find the one with minimum e distance
- similar_person_num = self.current_frame_face_X_e_distance_list.index(
- min(self.current_frame_face_X_e_distance_list))
-
- if min(self.current_frame_face_X_e_distance_list) < 0.4:
- # 在这里更改显示的人名 / Modify name if needed
- self.show_chinese_name()
- self.current_frame_name_list[k] = self.face_name_known_list[similar_person_num]
- logging.debug(" recognition result for face %d: %s", k + 1,
- self.face_name_known_list[similar_person_num])
- else:
- logging.debug(" recognition result for face %d: %s", k + 1, "unknown")
- else:
- logging.debug(
- " scene 1.2 不需要对于当前帧重新进行人脸识别 / No re-classification needed for current frame")
- # 获取特征框坐标 / Get ROI positions
- for k, d in enumerate(faces):
- cv2.rectangle(img_rd,
- tuple([d.left(), d.top()]),
- tuple([d.right(), d.bottom()]),
- (255, 255, 255), 2)
-
- self.current_frame_face_position_list[k] = tuple(
- [faces[k].left(),
- int(faces[k].bottom() + (faces[k].bottom() - faces[k].top()) / 4)])
-
- img_rd = self.draw_name(img_rd)
-
- # 4.2 当前帧和上一帧相比发生人脸数变化 / If face cnt changes, 1->0 or 0->1
- else:
- logging.debug("scene 2: 当前帧和上一帧相比人脸数发生变化 / Faces cnt changes in this frame")
- self.current_frame_face_position_list = []
- self.current_frame_face_X_e_distance_list = []
- self.current_frame_face_feature_list = []
-
- # 4.2.1 人脸数从 0->1 / Face cnt 0->1
- if self.current_frame_face_cnt == 1:
- logging.debug(" scene 2.1 出现人脸, 进行人脸识别 / Get faces in this frame and do face recognition")
- self.current_frame_name_list = []
-
- for i in range(len(faces)):
- shape = predictor(img_rd, faces[i])
- self.current_frame_face_feature_list.append(
- face_reco_model.compute_face_descriptor(img_rd, shape))
-
- # a. 遍历捕获到的图像中所有的人脸 / Traversal all the faces in the database
- for k in range(len(faces)):
- self.current_frame_name_list.append("unknown")
-
- # b. 每个捕获人脸的名字坐标 / Positions of faces captured
- self.current_frame_face_position_list.append(tuple(
- [faces[k].left(), int(faces[k].bottom() + (faces[k].bottom() - faces[k].top()) / 4)]))
-
- # c. 对于某张人脸, 遍历所有存储的人脸特征 / For every face detected, compare it with all the faces in database
- for i in range(len(self.features_known_list)):
- # 如果 person_X 数据不为空 / If data of person_X is not empty
- if str(self.features_known_list[i][0]) != '0.0':
- e_distance_tmp = self.return_euclidean_distance(
- self.current_frame_face_feature_list[k],
- self.features_known_list[i])
- logging.debug(" with person %d, the e-distance: %f", i + 1, e_distance_tmp)
- self.current_frame_face_X_e_distance_list.append(e_distance_tmp)
- else:
- # 空数据 person_X / Empty data for person_X
- self.current_frame_face_X_e_distance_list.append(999999999)
-
- # d. 寻找出最小的欧式距离匹配 / Find the one with minimum e distance
- similar_person_num = self.current_frame_face_X_e_distance_list.index(
- min(self.current_frame_face_X_e_distance_list))
-
- if min(self.current_frame_face_X_e_distance_list) < 0.4:
- # 在这里更改显示的人名 / Modify name if needed
- self.show_chinese_name()
- self.current_frame_name_list[k] = self.face_name_known_list[similar_person_num]
- logging.debug(" recognition result for face %d: %s", k + 1,
- self.face_name_known_list[similar_person_num])
- else:
- logging.debug(" recognition result for face %d: %s", k + 1, "unknown")
-
- if "unknown" in self.current_frame_name_list:
- self.reclassify_interval_cnt += 1
-
- # 4.2.1 人脸数从 1->0 / Face cnt 1->0
- elif self.current_frame_face_cnt == 0:
- logging.debug(" scene 2.2 人脸消失, 当前帧中没有人脸 / No face in this frame!!!")
-
- self.reclassify_interval_cnt = 0
- self.current_frame_name_list = []
- self.current_frame_face_feature_list = []
-
- # 5. 生成的窗口添加说明文字 / Add note on cv2 window
- self.draw_note(img_rd)
-
- if kk == ord('q'):
- break
-
- self.update_fps()
-
- cv2.namedWindow("camera", 1)
- cv2.imshow("camera", img_rd)
-
- logging.debug("Frame ends\n\n")
-
- def run(self):
- # cap = cv2.VideoCapture("video.mp4") # Get video stream from video file
- cap = cv2.VideoCapture(0) # Get video stream from camera
- self.process(cap)
-
- cap.release()
- cv2.destroyAllWindows()
-
-
-def main():
- # logging.basicConfig(level=logging.DEBUG) # Set log level to 'logging.DEBUG' to print debug info of every frame
- logging.basicConfig(level=logging.INFO)
- Face_Recognizer_con = Face_Recognizer()
- Face_Recognizer_con.run()
-
-
-if __name__ == '__main__':
- main()
diff --git a/features_extraction_to_csv.py b/features_extraction_to_csv.py
index c19051b..e1694ac 100755
--- a/features_extraction_to_csv.py
+++ b/features_extraction_to_csv.py
@@ -1,13 +1,6 @@
# Copyright (C) 2018-2021 coneypo
# SPDX-License-Identifier: MIT
-# Author: coneypo
-# Blog: http://www.cnblogs.com/AdaminXie
-# GitHub: https://github.com/coneypo/Dlib_face_recognition_from_camera
-# Mail: coneypo@foxmail.com
-
-# 从人脸图像文件中提取人脸特征存入 "features_all.csv" / Extract features from images and save into "features_all.csv"
-
import os
import dlib
import csv
@@ -16,88 +9,128 @@ import logging
import cv2
from PIL import Image
-# 要读取人脸图像文件的路径 / Path of cropped faces
-path_images_from_camera = "data/data_faces_from_camera/"
+# 要读取人脸图像文件的路径
+path_images_from_camera = "data/data_faces"
-# Dlib 正向人脸检测器 / Use frontal face detector of Dlib
+# Dlib 检测器
detector = dlib.get_frontal_face_detector()
-
-# Dlib 人脸 landmark 特征点检测器 / Get face landmarks
predictor = dlib.shape_predictor('data/data_dlib/shape_predictor_68_face_landmarks.dat')
-
-# Dlib Resnet 人脸识别模型,提取 128D 的特征矢量 / Use Dlib resnet50 model to get 128D face descriptor
face_reco_model = dlib.face_recognition_model_v1("data/data_dlib/dlib_face_recognition_resnet_model_v1.dat")
-# 返回单张图像的 128D 特征 / Return 128D features for single image
-# Input: path_img
-# Output: face_descriptor
def return_128d_features(path_img):
- img_pil = Image.open(path_img)
- img_np = np.array(img_pil)
- img_rd = cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR)
- faces = detector(img_rd, 1)
+ """返回单张图像的 128D 特征"""
+ try:
+ img_pil = Image.open(path_img)
+ img_np = np.array(img_pil)
+ img_rd = cv2.cvtColor(img_np, cv2.COLOR_RGB2BGR)
+ faces = detector(img_rd, 1)
- logging.info("%-40s %-20s", "检测到人脸的图像 / Image with faces detected:", path_img)
+ logging.info("%-40s %-20s", "检测到人脸的图像:", path_img)
- # 因为有可能截下来的人脸再去检测,检测不出来人脸了, 所以要确保是 检测到人脸的人脸图像拿去算特征
- # For photos of faces saved, we need to make sure that we can detect faces from the cropped images
- if len(faces) != 0:
- shape = predictor(img_rd, faces[0])
- face_descriptor = face_reco_model.compute_face_descriptor(img_rd, shape)
- else:
- face_descriptor = 0
- logging.warning("no face")
- return face_descriptor
+ if len(faces) != 0:
+ shape = predictor(img_rd, faces[0])
+ face_descriptor = face_reco_model.compute_face_descriptor(img_rd, shape)
+ return face_descriptor
+ else:
+ logging.warning("未检测到人脸: %s", path_img)
+ return None
+ except Exception as e:
+ logging.error("处理图像时出错 %s: %s", path_img, e)
+ return None
-# 返回 personX 的 128D 特征均值 / Return the mean value of 128D face descriptor for person X
-# Input: path_face_personX
-# Output: features_mean_personX
def return_features_mean_personX(path_face_personX):
+ """返回 personX 的 128D 特征均值"""
features_list_personX = []
photos_list = os.listdir(path_face_personX)
+
if photos_list:
- for i in range(len(photos_list)):
- # 调用 return_128d_features() 得到 128D 特征 / Get 128D features for single image of personX
- logging.info("%-40s %-20s", "正在读的人脸图像 / Reading image:", path_face_personX + "/" + photos_list[i])
- features_128d = return_128d_features(path_face_personX + "/" + photos_list[i])
- # 遇到没有检测出人脸的图片跳过 / Jump if no face detected from image
- if features_128d == 0:
- i += 1
- else:
+ for photo in photos_list:
+ photo_path = os.path.join(path_face_personX, photo)
+ logging.info("正在读取图像: %s", photo_path)
+
+ features_128d = return_128d_features(photo_path)
+ if features_128d is not None:
features_list_personX.append(features_128d)
else:
- logging.warning("文件夹内图像文件为空 / Warning: No images in%s/", path_face_personX)
+ logging.warning("文件夹为空: %s", path_face_personX)
- # 计算 128D 特征的均值 / Compute the mean
- # personX 的 N 张图像 x 128D -> 1 x 128D
+ # 计算 128D 特征的均值
if features_list_personX:
- features_mean_personX = np.array(features_list_personX, dtype=object).mean(axis=0)
+ features_mean_personX = np.array(features_list_personX).mean(axis=0)
else:
- features_mean_personX = np.zeros(128, dtype=object, order='C')
+ features_mean_personX = np.zeros(128, dtype=np.float64)
+
return features_mean_personX
+def get_person_name_from_folder(folder_name):
+ """从文件夹名称获取有意义的姓名"""
+ # 常见的文件夹前缀
+ prefixes = ['person_', 'face_', 'user_']
+
+ for prefix in prefixes:
+ if folder_name.startswith(prefix):
+ name_part = folder_name[len(prefix):]
+ # 如果剩下的部分是纯数字,使用完整文件夹名
+ if name_part.isdigit():
+ return folder_name
+ else:
+ return name_part
+
+ return folder_name
+
+
def main():
logging.basicConfig(level=logging.INFO)
- # 获取已录入的最后一个人脸序号 / Get the order of latest person
- person_list = os.listdir("data/data_faces_from_camera/")
+
+ # 检查源文件夹是否存在
+ if not os.path.exists(path_images_from_camera):
+ logging.error("人脸图像文件夹不存在: %s", path_images_from_camera)
+ return
+
+ # 获取人脸文件夹列表
+ person_list = os.listdir(path_images_from_camera)
person_list.sort()
+ if not person_list:
+ logging.error("没有人脸文件夹可处理")
+ return
+
+ logging.info("找到 %d 个人脸文件夹: %s", len(person_list), person_list)
+
+ # 创建CSV文件
with open("data/features_all.csv", "w", newline="", encoding="utf-8") as csvfile:
writer = csv.writer(csvfile)
- for person in person_list:
- # Get the mean/average features of face/personX, it will be a list with a length of 128D
- logging.info("%sperson_%s", path_images_from_camera, person)
- features_mean_personX = return_features_mean_personX(path_images_from_camera + person)
- person_name = person.split('_', 2)[-1]
- features_mean_personX = np.insert(features_mean_personX, 0, person_name, axis=0)
- # features_mean_personX will be 129D, person name + 128 features
- writer.writerow(features_mean_personX)
- logging.info('\n')
- logging.info("所有录入人脸数据存入 / Save all the features of faces registered into: data/features_all.csv")
+
+ successful_count = 0
+ for person_folder in person_list:
+ folder_path = os.path.join(path_images_from_camera, person_folder)
+
+ if not os.path.isdir(folder_path):
+ continue
+
+ logging.info("处理文件夹: %s", person_folder)
+
+ # 提取特征
+ features_mean = return_features_mean_personX(folder_path)
+
+ # 获取有意义的姓名
+ person_name = get_person_name_from_folder(person_folder)
+ logging.info("使用姓名: %s", person_name)
+
+ # 构建行数据:姓名 + 128维特征
+ row_data = [person_name] + features_mean.tolist()
+ writer.writerow(row_data)
+
+ successful_count += 1
+ logging.info("完成: %s", person_name)
+ logging.info("-" * 50)
+
+ logging.info("成功处理 %d/%d 个人脸文件夹", successful_count, len(person_list))
+ logging.info("特征数据已保存到: data/features_all.csv")
if __name__ == '__main__':
- main()
+ main()
\ No newline at end of file
diff --git a/get_faces.py b/get_faces.py
new file mode 100755
index 0000000..ca8a62c
--- /dev/null
+++ b/get_faces.py
@@ -0,0 +1,232 @@
+# Copyright (C) 2018-2021 coneypo
+# SPDX-License-Identifier: MIT
+
+import dlib
+import numpy as np
+import cv2
+import os
+import shutil
+import time
+import logging
+
+# Dlib 正向人脸检测器
+detector = dlib.get_frontal_face_detector()
+
+
+class Face_Register:
+ def __init__(self):
+ self.path_photos_from_camera = "data/data_faces/"
+ self.font = cv2.FONT_ITALIC
+
+ self.existing_faces_cnt = 0
+ self.ss_cnt = 0
+ self.current_frame_faces_cnt = 0
+
+ self.save_flag = 1
+ self.press_n_flag = 0
+ self.current_person_name = "" # 新增:当前录入人姓名
+
+ # FPS
+ self.frame_time = 0
+ self.frame_start_time = 0
+ self.fps = 0
+ self.fps_show = 0
+ self.start_time = time.time()
+
+ def pre_work_mkdir(self):
+ if os.path.isdir(self.path_photos_from_camera):
+ pass
+ else:
+ os.makedirs(self.path_photos_from_camera, exist_ok=True)
+
+ def pre_work_del_old_face_folders(self):
+ folders_rd = os.listdir(self.path_photos_from_camera)
+ for folder in folders_rd:
+ shutil.rmtree(os.path.join(self.path_photos_from_camera, folder))
+ if os.path.isfile("data/features_all.csv"):
+ os.remove("data/features_all.csv")
+
+ def check_existing_faces_cnt(self):
+ if os.listdir(self.path_photos_from_camera):
+ person_list = os.listdir(self.path_photos_from_camera)
+ # 修改:不再提取数字序号,而是统计数量
+ self.existing_faces_cnt = len(person_list)
+ else:
+ self.existing_faces_cnt = 0
+
+ def update_fps(self):
+ now = time.time()
+ if str(self.start_time).split(".")[0] != str(now).split(".")[0]:
+ self.fps_show = self.fps
+ self.start_time = now
+ self.frame_time = now - self.frame_start_time
+ self.fps = 1.0 / self.frame_time
+ self.frame_start_time = now
+
+ def draw_note(self, img_rd):
+ # 添加说明
+ cv2.putText(img_rd, "Face Register", (20, 40), self.font, 1, (255, 255, 255), 1, cv2.LINE_AA)
+ cv2.putText(img_rd, "FPS: " + str(self.fps_show.__round__(2)), (20, 100), self.font, 0.8, (0, 255, 0), 1,
+ cv2.LINE_AA)
+ cv2.putText(img_rd, "Faces: " + str(self.current_frame_faces_cnt), (20, 140), self.font, 0.8, (0, 255, 0), 1,
+ cv2.LINE_AA)
+
+ # 修改:显示当前录入人姓名
+ if self.current_person_name:
+ cv2.putText(img_rd, f"Name: {self.current_person_name}", (20, 180), self.font, 0.8, (255, 255, 0), 1,
+ cv2.LINE_AA)
+
+ cv2.putText(img_rd, "N: Input Name & Create folder", (20, 320), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
+ cv2.putText(img_rd, "S: Save current face", (20, 350), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
+ cv2.putText(img_rd, "Q: Quit", (20, 380), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
+ cv2.putText(img_rd, "D: Delete all data", (20, 410), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
+
+ def get_person_name_from_input(self):
+ """从用户输入获取姓名"""
+ print("\n请输入姓名(中文或英文):")
+ name = input().strip()
+ return name if name else f"person_{self.existing_faces_cnt + 1}"
+
+ def create_person_folder(self, person_name):
+ """创建人员文件夹"""
+ # 清理文件名中的非法字符
+ safe_name = "".join(c for c in person_name if c.isalnum() or c in (' ', '-', '_')).rstrip()
+ if not safe_name:
+ safe_name = f"person_{self.existing_faces_cnt + 1}"
+
+ # 创建文件夹路径
+ folder_name = f"person_{safe_name}"
+ current_face_dir = os.path.join(self.path_photos_from_camera, folder_name)
+
+ os.makedirs(current_face_dir, exist_ok=True)
+ logging.info("新建人脸文件夹: %s", current_face_dir)
+
+ return current_face_dir, safe_name
+
+ def process(self, stream):
+ # 1. 新建储存人脸图像文件目录
+ self.pre_work_mkdir()
+
+ # 2. 检查已有人脸文件
+ self.check_existing_faces_cnt()
+
+ current_face_dir = ""
+ print("人脸录入说明:")
+ print("- 按 'N': 输入姓名并创建新人员文件夹")
+ print("- 按 'S': 保存当前检测到的人脸")
+ print("- 按 'D': 删除所有已录入数据")
+ print("- 按 'Q': 退出程序")
+
+ while stream.isOpened():
+ flag, img_rd = stream.read()
+ if not flag:
+ break
+
+ kk = cv2.waitKey(1)
+ faces = detector(img_rd, 0)
+
+ # 4. 按下 'n' 输入姓名并新建文件夹
+ if kk == ord('n'):
+ person_name = self.get_person_name_from_input()
+ current_face_dir, self.current_person_name = self.create_person_folder(person_name)
+ self.ss_cnt = 0
+ self.press_n_flag = 1
+ print(f"已创建文件夹: {current_face_dir}")
+ print("请调整位置并按 'S' 保存人脸")
+
+ # 5. 按下 'd' 删除所有数据
+ elif kk == ord('d'):
+ confirm = input("确定要删除所有数据吗?(y/n): ")
+ if confirm.lower() == 'y':
+ self.pre_work_del_old_face_folders()
+ self.existing_faces_cnt = 0
+ self.current_person_name = ""
+ self.press_n_flag = 0
+ print("所有数据已删除")
+ continue
+
+ # 6. 检测到人脸
+ if len(faces) != 0:
+ for k, d in enumerate(faces):
+ # 计算矩形框大小
+ height = d.bottom() - d.top()
+ width = d.right() - d.left()
+ hh = int(height / 2)
+ ww = int(width / 2)
+
+ # 判断人脸是否在范围内
+ if (d.right() + ww > 640 or d.bottom() + hh > 480 or
+ d.left() - ww < 0 or d.top() - hh < 0):
+ cv2.putText(img_rd, "OUT OF RANGE", (20, 300), self.font, 0.8, (0, 0, 255), 1, cv2.LINE_AA)
+ color_rectangle = (0, 0, 255)
+ save_flag = 0
+ else:
+ color_rectangle = (255, 255, 255)
+ save_flag = 1
+
+ # 绘制人脸框
+ cv2.rectangle(img_rd,
+ (d.left() - ww, d.top() - hh),
+ (d.right() + ww, d.bottom() + hh),
+ color_rectangle, 2)
+
+ # 创建空白图像用于保存人脸
+ img_blank = np.zeros((height * 2, width * 2, 3), np.uint8)
+
+ if save_flag and kk == ord('s'):
+ # 检查是否已创建文件夹
+ if self.press_n_flag:
+ self.ss_cnt += 1
+ # 提取人脸区域
+ for ii in range(height * 2):
+ for jj in range(width * 2):
+ img_blank[ii][jj] = img_rd[d.top() - hh + ii][d.left() - ww + jj]
+
+ # 保存人脸图像
+ filename = f"img_face_{self.ss_cnt}.jpg"
+ filepath = os.path.join(current_face_dir, filename)
+ cv2.imwrite(filepath, img_blank)
+
+ logging.info("保存人脸: %s", filepath)
+ print(f"已保存第 {self.ss_cnt} 张人脸图片")
+ else:
+ logging.warning("请先按 'N' 输入姓名创建文件夹")
+
+ self.current_frame_faces_cnt = len(faces)
+
+ # 绘制说明文字
+ self.draw_note(img_rd)
+
+ # 按下 'q' 退出
+ if kk == ord('q'):
+ break
+
+ # 更新 FPS
+ self.update_fps()
+
+ cv2.imshow("Face Register", img_rd)
+
+ def run(self):
+ cap = cv2.VideoCapture(0)
+ if not cap.isOpened():
+ print("错误: 无法打开摄像头")
+ return
+
+ # 设置摄像头参数
+ cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
+ cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
+
+ self.process(cap)
+ cap.release()
+ cv2.destroyAllWindows()
+ print("程序结束")
+
+
+def main():
+ logging.basicConfig(level=logging.INFO)
+ Face_Register_con = Face_Register()
+ Face_Register_con.run()
+
+
+if __name__ == '__main__':
+ main()
\ No newline at end of file
diff --git a/get_faces_from_camera_tkinter.py b/get_faces_UI.py
similarity index 100%
rename from get_faces_from_camera_tkinter.py
rename to get_faces_UI.py
diff --git a/get_faces_from_camera.py b/get_faces_from_camera.py
deleted file mode 100755
index 0763d79..0000000
--- a/get_faces_from_camera.py
+++ /dev/null
@@ -1,198 +0,0 @@
-# Copyright (C) 2018-2021 coneypo
-# SPDX-License-Identifier: MIT
-
-# Author: coneypo
-# Blog: http://www.cnblogs.com/AdaminXie
-# GitHub: https://github.com/coneypo/Dlib_face_recognition_from_camera
-# Mail: coneypo@foxmail.com
-
-# 进行人脸录入 / Face register
-
-import dlib
-import numpy as np
-import cv2
-import os
-import shutil
-import time
-import logging
-
-# Dlib 正向人脸检测器 / Use frontal face detector of Dlib
-detector = dlib.get_frontal_face_detector()
-
-
-class Face_Register:
- def __init__(self):
- self.path_photos_from_camera = "data/data_faces_from_camera/"
- self.font = cv2.FONT_ITALIC
-
- self.existing_faces_cnt = 0 # 已录入的人脸计数器 / cnt for counting saved faces
- self.ss_cnt = 0 # 录入 personX 人脸时图片计数器 / cnt for screen shots
- self.current_frame_faces_cnt = 0 # 录入人脸计数器 / cnt for counting faces in current frame
-
- self.save_flag = 1 # 之后用来控制是否保存图像的 flag / The flag to control if save
- self.press_n_flag = 0 # 之后用来检查是否先按 'n' 再按 's' / The flag to check if press 'n' before 's'
-
- # FPS
- self.frame_time = 0
- self.frame_start_time = 0
- self.fps = 0
- self.fps_show = 0
- self.start_time = time.time()
-
- # 新建保存人脸图像文件和数据 CSV 文件夹 / Mkdir for saving photos and csv
- def pre_work_mkdir(self):
- # 新建文件夹 / Create folders to save face images and csv
- if os.path.isdir(self.path_photos_from_camera):
- pass
- else:
- os.mkdir(self.path_photos_from_camera)
-
- # 删除之前存的人脸数据文件夹 / Delete old face folders
- def pre_work_del_old_face_folders(self):
- # 删除之前存的人脸数据文件夹, 删除 "/data_faces_from_camera/person_x/"...
- folders_rd = os.listdir(self.path_photos_from_camera)
- for i in range(len(folders_rd)):
- shutil.rmtree(self.path_photos_from_camera+folders_rd[i])
- if os.path.isfile("data/features_all.csv"):
- os.remove("data/features_all.csv")
-
- # 如果有之前录入的人脸, 在之前 person_x 的序号按照 person_x+1 开始录入 / Start from person_x+1
- def check_existing_faces_cnt(self):
- if os.listdir("data/data_faces_from_camera/"):
- # 获取已录入的最后一个人脸序号 / Get the order of latest person
- person_list = os.listdir("data/data_faces_from_camera/")
- person_num_list = []
- for person in person_list:
- person_num_list.append(int(person.split('_')[-1]))
- self.existing_faces_cnt = max(person_num_list)
-
- # 如果第一次存储或者没有之前录入的人脸, 按照 person_1 开始录入 / Start from person_1
- else:
- self.existing_faces_cnt = 0
-
- # 更新 FPS / Update FPS of Video stream
- def update_fps(self):
- now = time.time()
- # 每秒刷新 fps / Refresh fps per second
- if str(self.start_time).split(".")[0] != str(now).split(".")[0]:
- self.fps_show = self.fps
- self.start_time = now
- self.frame_time = now - self.frame_start_time
- self.fps = 1.0 / self.frame_time
- self.frame_start_time = now
-
- # 生成的 cv2 window 上面添加说明文字 / PutText on cv2 window
- def draw_note(self, img_rd):
- # 添加说明 / Add some notes
- cv2.putText(img_rd, "Face Register", (20, 40), self.font, 1, (255, 255, 255), 1, cv2.LINE_AA)
- cv2.putText(img_rd, "FPS: " + str(self.fps_show.__round__(2)), (20, 100), self.font, 0.8, (0, 255, 0), 1,
- cv2.LINE_AA)
- cv2.putText(img_rd, "Faces: " + str(self.current_frame_faces_cnt), (20, 140), self.font, 0.8, (0, 255, 0), 1, cv2.LINE_AA)
- cv2.putText(img_rd, "N: Create face folder", (20, 350), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
- cv2.putText(img_rd, "S: Save current face", (20, 400), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
- cv2.putText(img_rd, "Q: Quit", (20, 450), self.font, 0.8, (255, 255, 255), 1, cv2.LINE_AA)
-
- # 获取人脸 / Main process of face detection and saving
- def process(self, stream):
- # 1. 新建储存人脸图像文件目录 / Create folders to save photos
- self.pre_work_mkdir()
-
- # 2. 删除 "/data/data_faces_from_camera" 中已有人脸图像文件
- # / Uncomment if want to delete the saved faces and start from person_1
- # if os.path.isdir(self.path_photos_from_camera):
- # self.pre_work_del_old_face_folders()
-
- # 3. 检查 "/data/data_faces_from_camera" 中已有人脸文件
- self.check_existing_faces_cnt()
-
- while stream.isOpened():
- flag, img_rd = stream.read() # Get camera video stream
- kk = cv2.waitKey(1)
- faces = detector(img_rd, 0) # Use Dlib face detector
-
- # 4. 按下 'n' 新建存储人脸的文件夹 / Press 'n' to create the folders for saving faces
- if kk == ord('n'):
- self.existing_faces_cnt += 1
- current_face_dir = self.path_photos_from_camera + "person_" + str(self.existing_faces_cnt)
- os.makedirs(current_face_dir)
- logging.info("\n%-40s %s", "新建的人脸文件夹 / Create folders:", current_face_dir)
-
- self.ss_cnt = 0 # 将人脸计数器清零 / Clear the cnt of screen shots
- self.press_n_flag = 1 # 已经按下 'n' / Pressed 'n' already
-
- # 5. 检测到人脸 / Face detected
- if len(faces) != 0:
- # 矩形框 / Show the ROI of faces
- for k, d in enumerate(faces):
- # 计算矩形框大小 / Compute the size of rectangle box
- height = (d.bottom() - d.top())
- width = (d.right() - d.left())
- hh = int(height/2)
- ww = int(width/2)
-
- # 6. 判断人脸矩形框是否超出 480x640 / If the size of ROI > 480x640
- if (d.right()+ww) > 640 or (d.bottom()+hh > 480) or (d.left()-ww < 0) or (d.top()-hh < 0):
- cv2.putText(img_rd, "OUT OF RANGE", (20, 300), self.font, 0.8, (0, 0, 255), 1, cv2.LINE_AA)
- color_rectangle = (0, 0, 255)
- save_flag = 0
- if kk == ord('s'):
- logging.warning("请调整位置 / Please adjust your position")
- else:
- color_rectangle = (255, 255, 255)
- save_flag = 1
-
- cv2.rectangle(img_rd,
- tuple([d.left() - ww, d.top() - hh]),
- tuple([d.right() + ww, d.bottom() + hh]),
- color_rectangle, 2)
-
- # 7. 根据人脸大小生成空的图像 / Create blank image according to the size of face detected
- img_blank = np.zeros((int(height*2), width*2, 3), np.uint8)
-
- if save_flag:
- # 8. 按下 's' 保存摄像头中的人脸到本地 / Press 's' to save faces into local images
- if kk == ord('s'):
- # 检查有没有先按'n'新建文件夹 / Check if you have pressed 'n'
- if self.press_n_flag:
- self.ss_cnt += 1
- for ii in range(height*2):
- for jj in range(width*2):
- img_blank[ii][jj] = img_rd[d.top()-hh + ii][d.left()-ww + jj]
- cv2.imwrite(current_face_dir + "/img_face_" + str(self.ss_cnt) + ".jpg", img_blank)
- logging.info("%-40s %s/img_face_%s.jpg", "写入本地 / Save into:",
- str(current_face_dir), str(self.ss_cnt))
- else:
- logging.warning("请先按 'N' 来建文件夹, 按 'S' / Please press 'N' and press 'S'")
-
- self.current_frame_faces_cnt = len(faces)
-
- # 9. 生成的窗口添加说明文字 / Add note on cv2 window
- self.draw_note(img_rd)
-
- # 10. 按下 'q' 键退出 / Press 'q' to exit
- if kk == ord('q'):
- break
-
- # 11. Update FPS
- self.update_fps()
-
- cv2.namedWindow("camera", 1)
- cv2.imshow("camera", img_rd)
-
- def run(self):
- # cap = cv2.VideoCapture("video.mp4") # Get video stream from video file
- cap = cv2.VideoCapture(0) # Get video stream from camera
- self.process(cap)
-
- cap.release()
- cv2.destroyAllWindows()
-
-
-def main():
- logging.basicConfig(level=logging.INFO)
- Face_Register_con = Face_Register()
- Face_Register_con.run()
-
-
-if __name__ == '__main__':
- main()
\ No newline at end of file
diff --git a/how_to_use_camera.py b/how_to_use_camera.py
deleted file mode 100755
index c3af029..0000000
--- a/how_to_use_camera.py
+++ /dev/null
@@ -1,84 +0,0 @@
-# Author: coneypo
-# Blog: http://www.cnblogs.com/AdaminXie
-# GitHub: https://github.com/coneypo/Dlib_face_recognition_from_camera
-# Mail: coneypo@foxmail.com
-
-import cv2
-
-cap = cv2.VideoCapture(0)
-
-# cap.set(propId, value)
-# 设置视频参数: propId - 设置的视频参数, value - 设置的参数值
-"""
-0. cv2.CAP_PROP_POS_MSEC Current position of the video file in milliseconds.
-1. cv2.CAP_PROP_POS_FRAMES 0-based index of the frame to be decoded/captured next.
-2. cv2.CAP_PROP_POS_AVI_RATIO Relative position of the video file
-3. cv2.CAP_PROP_FRAME_WIDTH Width of the frames in the video stream.
-4. cv2.CAP_PROP_FRAME_HEIGHT Height of the frames in the video stream.
-5. cv2.CAP_PROP_FPS Frame rate.
-6. cv2.CAP_PROP_FOURCC 4-character code of codec.
-7. cv2.CAP_PROP_FRAME_COUNT Number of frames in the video file.
-8. cv2.CAP_PROP_FORMAT Format of the Mat objects returned by retrieve() .
-9. cv2.CAP_PROP_MODE Backend-specific value indicating the current capture mode.
-10. cv2.CAP_PROP_BRIGHTNESS Brightness of the image (only for cameras).
-11. cv2.CAP_PROP_CONTRAST Contrast of the image (only for cameras).
-12. cv2.CAP_PROP_SATURATION Saturation of the image (only for cameras).
-13. cv2.CAP_PROP_HUE Hue of the image (only for cameras).
-14. cv2.CAP_PROP_GAIN Gain of the image (only for cameras).
-15. cv2.CAP_PROP_EXPOSURE Exposure (only for cameras).
-16. cv2.CAP_PROP_CONVERT_RGB Boolean flags indicating whether images should be converted to RGB.
-17. cv2.CAP_PROP_WHITE_BALANCE Currently unsupported
-18. cv2.CAP_PROP_RECTIFICATION Rectification flag for stereo cameras (note: only supported by DC1394 v 2.x backend currently)
-"""
-
-# The default size of frame from camera will be 640x480 in Windows or Ubuntu
-# So we will not set "cap.set" here, it doesn't work
-# cap.set(propId=cv2.CAP_PROP_FRAME_WIDTH, value=cap.get(cv2.CAP_PROP_FRAME_WIDTH))
-
-# cap.isOpened() 返回 true/false, 检查摄像头初始化是否成功
-print(cap.isOpened())
-
-# cap.read()
-"""
-返回两个值
- 先返回一个布尔值, 如果视频读取正确, 则为 True, 如果错误, 则为 False;
- 也可用来判断是否到视频末尾;
-
- 再返回一个值, 为每一帧的图像, 该值是一个三维矩阵;
-
- 通用接收方法为:
- ret,frame = cap.read();
- ret: 布尔值;
- frame: 图像的三维矩阵;
- 这样 ret 存储布尔值, frame 存储图像;
-
- 若使用一个变量来接收两个值, 如:
- frame = cap.read()
- 则 frame 为一个元组, 原来使用 frame 处需更改为 frame[1]
-"""
-
-while cap.isOpened():
- ret_flag, img_camera = cap.read()
-
- print("height: ", img_camera.shape[0])
- print("width: ", img_camera.shape[1])
- print('\n')
-
- cv2.imshow("camera", img_camera)
-
- # 每帧数据延时 1ms, 延时为0, 读取的是静态帧
- k = cv2.waitKey(1)
-
- # 按下 's' 保存截图
- if k == ord('s'):
- cv2.imwrite("test.jpg", img_camera)
-
- # 按下 'q' 退出
- if k == ord('q'):
- break
-
-# 释放所有摄像头
-cap.release()
-
-# 删除建立的所有窗口
-cv2.destroyAllWindows()
diff --git a/introduction/Dlib_Face_recognition_by_coneypo.pptx b/introduction/Dlib_Face_recognition_by_coneypo.pptx
deleted file mode 100755
index 4df6ec6..0000000
Binary files a/introduction/Dlib_Face_recognition_by_coneypo.pptx and /dev/null differ
diff --git a/introduction/face_reco.png b/introduction/face_reco.png
deleted file mode 100644
index cf7e435..0000000
Binary files a/introduction/face_reco.png and /dev/null differ
diff --git a/introduction/face_reco_chinese_name.png b/introduction/face_reco_chinese_name.png
deleted file mode 100644
index 81b815c..0000000
Binary files a/introduction/face_reco_chinese_name.png and /dev/null differ
diff --git a/introduction/face_reco_ot.png b/introduction/face_reco_ot.png
deleted file mode 100644
index 475224b..0000000
Binary files a/introduction/face_reco_ot.png and /dev/null differ
diff --git a/introduction/face_reco_single.png b/introduction/face_reco_single.png
deleted file mode 100644
index 197f09a..0000000
Binary files a/introduction/face_reco_single.png and /dev/null differ
diff --git a/introduction/face_register.png b/introduction/face_register.png
deleted file mode 100644
index 2c71f7a..0000000
Binary files a/introduction/face_register.png and /dev/null differ
diff --git a/introduction/face_register_tkinter_GUI.png b/introduction/face_register_tkinter_GUI.png
deleted file mode 100644
index 726efec..0000000
Binary files a/introduction/face_register_tkinter_GUI.png and /dev/null differ
diff --git a/introduction/face_register_warning.png b/introduction/face_register_warning.png
deleted file mode 100644
index a39788b..0000000
Binary files a/introduction/face_register_warning.png and /dev/null differ
diff --git a/introduction/overview.png b/introduction/overview.png
deleted file mode 100755
index 1af5cb8..0000000
Binary files a/introduction/overview.png and /dev/null differ
diff --git a/introduction/overview_with_ot.png b/introduction/overview_with_ot.png
deleted file mode 100644
index acf2f59..0000000
Binary files a/introduction/overview_with_ot.png and /dev/null differ