【更新/修复】首次提交及修复保存的数据命名导致的最终人脸识别过程中闪退的现象 #1

Merged
mabinhao merged 1 commits from DLib_Face_recognition_loong into master 2025-10-22 17:39:11 +08:00
30 changed files with 533 additions and 1155 deletions

5
.idea/.gitignore generated vendored Normal file
View File

@ -0,0 +1,5 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/

View File

@ -0,0 +1,10 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$">
<excludeFolder url="file://$MODULE_DIR$/.venv" />
</content>
<orderEntry type="jdk" jdkName="Python 3.10 (Dlib_face_recognition_from_camera) (2)" jdkType="Python SDK" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
</module>

View File

@ -0,0 +1,6 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

7
.idea/misc.xml generated Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="Black">
<option name="sdkName" value="Python 3.10 (Dlib_face_recognition_from_camera) (2)" />
</component>
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.10 (Dlib_face_recognition_from_camera) (2)" project-jdk-type="Python SDK" />
</project>

8
.idea/modules.xml generated Normal file
View File

@ -0,0 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/Dlib_face_recognition_from_camera.iml" filepath="$PROJECT_DIR$/.idea/Dlib_face_recognition_from_camera.iml" />
</modules>
</component>
</project>

7
.idea/vcs.xml generated Normal file
View File

@ -0,0 +1,7 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="" vcs="Git" />
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@ -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: ``<class 'dlib.dlib.rectangles'>`` / Dlib frontal face detector
.. code-block:: python
detector = dlib.get_frontal_face_detector()
faces = detector(img_gray, 0)
#. Dlib 人脸 landmark 特征点检测器, output: ``<class 'dlib.dlib.full_object_detection'>`` / 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.

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

1
data/features_all.csv Normal file
View File

@ -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
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

View File

@ -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()

View File

@ -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()

View File

@ -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()

View File

@ -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 <class 'str'>
# Output: face_descriptor <class 'dlib.vector'>
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 <class 'str'>
# Output: features_mean_personX <class 'numpy.ndarray'>
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()

232
get_faces.py Executable file
View File

@ -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()

View File

@ -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()

View File

@ -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()

Binary file not shown.

Before

Width:  |  Height:  |  Size: 206 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 216 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 358 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 345 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 184 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 332 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 267 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 74 KiB