14 Commits

80 changed files with 453 additions and 393 deletions

View File

@ -1,12 +1,14 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/data" isTestSource="false" />
</content>
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
</component>
<component name="TestRunnerService">
<option name="projectConfiguration" value="py.test" />
<option name="projectConfiguration" value="pytest" />
<option name="PROJECT_TEST_RUNNER" value="py.test" />
</component>
</module>

View File

@ -8,5 +8,12 @@
</list>
</option>
</inspection_tool>
<inspection_tool class="PyPep8NamingInspection" enabled="true" level="WEAK WARNING" enabled_by_default="true">
<option name="ignoredErrors">
<list>
<option value="N806" />
</list>
</option>
</inspection_tool>
</profile>
</component>

261
.idea/workspace.xml generated
View File

@ -1,10 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ChangeListManager">
<list default="true" id="39c25e36-24e3-48b8-a41f-0d53e408e855" name="Default" comment="">
<list default="true" id="e58b655a-3a9b-4001-b4da-39e07ab46629" name="Default Changelist" comment="">
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
<change beforePath="$PROJECT_DIR$/README.rst" beforeDir="false" afterPath="$PROJECT_DIR$/README.rst" afterDir="false" />
<change beforePath="$PROJECT_DIR$/data/data_dlib/dlib_face_recognition_resnet_model_v1.dat" beforeDir="false" afterPath="$PROJECT_DIR$/data/data_dlib/dlib_face_recognition_resnet_model_v1.dat" afterDir="false" />
<change beforePath="$PROJECT_DIR$/data/data_dlib/shape_predictor_5_face_landmarks.dat" beforeDir="false" afterPath="$PROJECT_DIR$/data/data_dlib/shape_predictor_5_face_landmarks.dat" afterDir="false" />
<change beforePath="$PROJECT_DIR$/data/data_dlib/shape_predictor_68_face_landmarks.dat" beforeDir="false" afterPath="$PROJECT_DIR$/data/data_dlib/shape_predictor_68_face_landmarks.dat" afterDir="false" />
<change beforePath="$PROJECT_DIR$/face_reco_from_camera.py" beforeDir="false" afterPath="$PROJECT_DIR$/face_reco_from_camera.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/features_extraction_to_csv.py" beforeDir="false" afterPath="$PROJECT_DIR$/features_extraction_to_csv.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/get_faces_from_camera.py" beforeDir="false" afterPath="$PROJECT_DIR$/get_faces_from_camera.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/how_to_use_camera.py" beforeDir="false" afterPath="$PROJECT_DIR$/how_to_use_camera.py" afterDir="false" />
<change beforePath="$PROJECT_DIR$/introduction/Dlib_Face_recognition_by_coneypo.pptx" beforeDir="false" afterPath="$PROJECT_DIR$/introduction/Dlib_Face_recognition_by_coneypo.pptx" afterDir="false" />
<change beforePath="$PROJECT_DIR$/introduction/face_reco_single_person.png" beforeDir="false" afterPath="$PROJECT_DIR$/introduction/face_reco_single_person.png" afterDir="false" />
<change beforePath="$PROJECT_DIR$/introduction/face_reco_single_person_customize_name.png" beforeDir="false" afterPath="$PROJECT_DIR$/introduction/face_reco_single_person_customize_name.png" afterDir="false" />
<change beforePath="$PROJECT_DIR$/introduction/face_reco_two_people.png" beforeDir="false" afterPath="$PROJECT_DIR$/introduction/face_reco_two_people.png" afterDir="false" />
<change beforePath="$PROJECT_DIR$/introduction/face_reco_two_people_in_database.png" beforeDir="false" afterPath="$PROJECT_DIR$/introduction/face_reco_two_people_in_database.png" afterDir="false" />
<change beforePath="$PROJECT_DIR$/introduction/get_face_from_camera.png" beforeDir="false" afterPath="$PROJECT_DIR$/introduction/get_face_from_camera.png" afterDir="false" />
<change beforePath="$PROJECT_DIR$/introduction/get_face_from_camera_out_of_range.png" beforeDir="false" afterPath="$PROJECT_DIR$/introduction/get_face_from_camera_out_of_range.png" afterDir="false" />
<change beforePath="$PROJECT_DIR$/introduction/overview.png" beforeDir="false" afterPath="$PROJECT_DIR$/introduction/overview.png" afterDir="false" />
<change beforePath="$PROJECT_DIR$/requirements.txt" beforeDir="false" afterPath="$PROJECT_DIR$/requirements.txt" afterDir="false" />
</list>
<option name="EXCLUDED_CONVERTED_TO_IGNORED" value="true" />
<option name="SHOW_DIALOG" value="false" />
@ -14,54 +29,37 @@
</component>
<component name="FileEditorManager">
<leaf SIDE_TABS_SIZE_LIMIT_KEY="300">
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/get_faces_from_camera.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="176">
<caret line="172" selection-start-line="172" selection-end-line="172" />
<folding>
<element signature="e#277#310#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/get_features_into_CSV.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="270">
<caret line="56" column="24" selection-start-line="56" selection-start-column="24" selection-end-line="56" selection-end-column="24" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/data/features_all.csv">
<provider selected="true" editor-type-id="csv-text-editor" />
</entry>
</file>
<file pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/face_reco_from_camera.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="195">
<caret line="96" selection-start-line="96" selection-end-line="96" />
<folding>
<element signature="e#201#234#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/README.rst">
<provider selected="true" editor-type-id="restructured-text-editor" />
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/how_to_use_camera.py">
<entry file="file://$PROJECT_DIR$/get_faces_from_camera.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="15">
<caret line="27" column="13" selection-start-line="27" selection-start-column="13" selection-end-line="27" selection-end-column="13" />
<state relative-caret-position="309">
<caret line="69" selection-start-line="69" selection-end-line="69" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="false">
<entry file="file://$PROJECT_DIR$/features_extraction_to_csv.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="248">
<caret line="73" column="36" selection-start-line="73" selection-start-column="36" selection-end-line="73" selection-end-column="36" />
</state>
</provider>
</entry>
</file>
<file pinned="false" current-in-tab="true">
<entry file="file://$PROJECT_DIR$/face_reco_from_camera.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="489">
<caret line="160" column="23" lean-forward="true" selection-start-line="160" selection-start-column="23" selection-end-line="160" selection-end-column="23" />
<folding>
<element signature="e#230#264#0" expanded="true" />
</folding>
</state>
</provider>
</entry>
@ -77,40 +75,25 @@
</component>
<component name="FindInProjectRecents">
<findStrings>
<find>rects</find>
<find>i</find>
<find>dets</find>
<find>cnt_p</find>
<find>im_rd</find>
<find>predictor</find>
<find></find>
<find></find>
<find>pre_clear</find>
<find>np</find>
<find>path_make_dir</find>
<find>path_csvs_from_photos</find>
<find>path_faces_rd</find>
<find>path_csv</find>
<find>path_csv_from_photos_rd</find>
<find>feature_mean</find>
<find>dir_pics</find>
<find>current_face_dir</find>
<find>person_cnt</find>
<find>cnt_ss</find>
<find>path_photos_from_camera</find>
<find>path_csv_from_photos</find>
<find>facerec</find>
<find>img</find>
<find>feature_mean_list_personX</find>
<find>feature_list_personX</find>
<find>feature</find>
<find>features_list_personX</find>
<find>feature_mean_personX</find>
<find>data_csvs</find>
<find>features_known_arr</find>
<find>with</find>
</findStrings>
<replaceStrings>
<replace>feature_num</replace>
<replace>faces</replace>
<replace>cnt_ss</replace>
<replace>,</replace>
<replace>face_rec</replace>
<replace>img_rd</replace>
<replace>:</replace>
<replace>pre_work</replace>
<replace>path_csvs_from_photos</replace>
<replace>path_photos_from_camera</replace>
<replace>path_csv_from_photos</replace>
<replace>feature_mean_list</replace>
<replace>photos_list</replace>
<replace>descriptor_mean_list_personX</replace>
<replace>features_list_personX</replace>
<replace>features_mean_personX</replace>
</replaceStrings>
</component>
<component name="Git.Settings">
@ -119,21 +102,22 @@
<component name="IdeDocumentHistory">
<option name="CHANGED_PATHS">
<list>
<option value="$PROJECT_DIR$/use_camera.py" />
<option value="$PROJECT_DIR$/how_to_use_camera.py" />
<option value="$PROJECT_DIR$/requirements.txt" />
<option value="$PROJECT_DIR$/get_features_into_CSV.py" />
<option value="$PROJECT_DIR$/get_origin.py" />
<option value="$PROJECT_DIR$/test.py" />
<option value="$PROJECT_DIR$/features_extraction_to_csv.py" />
<option value="$PROJECT_DIR$/get_faces_from_camera.py" />
<option value="$PROJECT_DIR$/README.rst" />
<option value="$PROJECT_DIR$/face_reco_from_camera.py" />
</list>
</option>
</component>
<component name="ProjectFrameBounds">
<option name="x" value="438" />
<option name="y" value="28" />
<option name="width" value="1717" />
<option name="height" value="987" />
<component name="ProjectFrameBounds" extendedState="6">
<option name="x" value="-281" />
<option name="y" value="574" />
<option name="width" value="1910" />
<option name="height" value="741" />
</component>
<component name="ProjectLevelVcsManager" settingsEditedManually="true" />
<component name="ProjectView">
@ -161,15 +145,8 @@
</panes>
</component>
<component name="PropertiesComponent">
<property name="last_opened_file_path" value="$PROJECT_DIR$" />
<property name="settings.editor.selected.configurable" value="com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable" />
</component>
<component name="PyConsoleOptionsProvider">
<option name="myPythonConsoleState">
<console-settings is-module-sdk="true">
<option name="myUseModuleSdk" value="true" />
</console-settings>
</option>
<property name="SHARE_PROJECT_CONFIGURATION_FILES" value="true" />
<property name="last_opened_file_path" value="/media/con/Ubuntu 18.0/Face_Recognition" />
</component>
<component name="RunDashboard">
<option name="ruleStates">
@ -205,6 +182,27 @@
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="features_extraction_to_csv" type="PythonConfigurationType" factoryName="Python" temporary="true">
<module name="Dlib_face_recognition_from_camera" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/features_extraction_to_csv.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="get_faces_from_camera" type="PythonConfigurationType" factoryName="Python" temporary="true">
<module name="Dlib_face_recognition_from_camera" />
<option name="INTERPRETER_OPTIONS" value="" />
@ -226,7 +224,7 @@
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="get_features_into_CSV" type="PythonConfigurationType" factoryName="Python" temporary="true">
<configuration name="get_origin" type="PythonConfigurationType" factoryName="Python" temporary="true">
<module name="Dlib_face_recognition_from_camera" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
@ -238,28 +236,7 @@
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/get_features_into_CSV.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
<option name="MODULE_MODE" value="false" />
<option name="REDIRECT_INPUT" value="false" />
<option name="INPUT_FILE" value="" />
<method v="2" />
</configuration>
<configuration name="how_to_use_camera" type="PythonConfigurationType" factoryName="Python" temporary="true">
<module name="Dlib_face_recognition_from_camera" />
<option name="INTERPRETER_OPTIONS" value="" />
<option name="PARENT_ENVS" value="true" />
<envs>
<env name="PYTHONUNBUFFERED" value="1" />
</envs>
<option name="SDK_HOME" value="" />
<option name="WORKING_DIRECTORY" value="$PROJECT_DIR$" />
<option name="IS_MODULE_SDK" value="true" />
<option name="ADD_CONTENT_ROOTS" value="true" />
<option name="ADD_SOURCE_ROOTS" value="true" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/how_to_use_camera.py" />
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/get_origin.py" />
<option name="PARAMETERS" value="" />
<option name="SHOW_COMMAND_LINE" value="false" />
<option name="EMULATE_TERMINAL" value="false" />
@ -291,18 +268,18 @@
</configuration>
<list>
<item itemvalue="Python.face_reco_from_camera" />
<item itemvalue="Python.features_extraction_to_csv" />
<item itemvalue="Python.get_faces_from_camera" />
<item itemvalue="Python.get_features_into_CSV" />
<item itemvalue="Python.how_to_use_camera" />
<item itemvalue="Python.get_origin" />
<item itemvalue="Python.test" />
</list>
<recent_temporary>
<list>
<item itemvalue="Python.face_reco_from_camera" />
<item itemvalue="Python.get_features_into_CSV" />
<item itemvalue="Python.features_extraction_to_csv" />
<item itemvalue="Python.get_faces_from_camera" />
<item itemvalue="Python.test" />
<item itemvalue="Python.how_to_use_camera" />
<item itemvalue="Python.get_origin" />
</list>
</recent_temporary>
</component>
@ -311,7 +288,7 @@
</component>
<component name="TaskManager">
<task active="true" id="Default" summary="Default task">
<changelist id="39c25e36-24e3-48b8-a41f-0d53e408e855" name="Default" comment="" />
<changelist id="e58b655a-3a9b-4001-b4da-39e07ab46629" name="Default Changelist" comment="" />
<created>1538622047029</created>
<option name="number" value="Default" />
<option name="presentableId" value="Default" />
@ -323,18 +300,18 @@
<frame x="0" y="27" width="1920" height="988" extended-state="6" />
<editor active="true" />
<layout>
<window_info content_ui="combo" id="Project" order="0" visible="true" weight="0.13502109" />
<window_info active="true" content_ui="combo" id="Project" order="0" visible="true" weight="0.2090813" />
<window_info id="Structure" order="1" weight="0.25" />
<window_info id="Favorites" order="2" side_tool="true" />
<window_info anchor="bottom" id="Message" order="0" />
<window_info anchor="bottom" id="Find" order="1" />
<window_info active="true" anchor="bottom" id="Run" order="2" visible="true" weight="0.035252646" />
<window_info anchor="bottom" id="Run" order="2" visible="true" weight="0.25686976" />
<window_info anchor="bottom" id="Debug" order="3" weight="0.39952996" />
<window_info anchor="bottom" id="Cvs" order="4" weight="0.25" />
<window_info anchor="bottom" id="Inspection" order="5" weight="0.4" />
<window_info anchor="bottom" id="TODO" order="6" />
<window_info anchor="bottom" id="Version Control" order="7" />
<window_info anchor="bottom" id="Terminal" order="8" weight="0.4620462" />
<window_info anchor="bottom" id="Version Control" order="7" weight="0.32983682" />
<window_info anchor="bottom" id="Terminal" order="8" weight="0.28434888" />
<window_info anchor="bottom" id="Event Log" order="9" side_tool="true" />
<window_info anchor="bottom" id="Python Console" order="10" />
<window_info anchor="right" id="Commander" order="0" weight="0.4" />
@ -357,22 +334,26 @@
<entry file="file://$PROJECT_DIR$/use_camera.py" />
<entry file="file://$PROJECT_DIR$/patch" />
<entry file="file://$PROJECT_DIR$/README.md" />
<entry file="file://$PROJECT_DIR$/data/data_csvs_from_camera/person_1.csv" />
<entry file="file://$PROJECT_DIR$/data/data_csvs_from_camera/person_2.csv" />
<entry file="file://$PROJECT_DIR$/data/data_faces_from_camera/person_6/img_face_1.jpg" />
<entry file="file://$PROJECT_DIR$/test.py">
<entry file="file://$PROJECT_DIR$/introduction/face_reco_single_person_custmize_name.png" />
<entry file="file://$PROJECT_DIR$/data/data_csvs_from_camera/person_1.csv" />
<entry file="file://$PROJECT_DIR$/get_features_into_CSV.py" />
<entry file="file://$PROJECT_DIR$/get_origin.py" />
<entry file="file://$PROJECT_DIR$/test.py" />
<entry file="file://$PROJECT_DIR$/requirements.txt">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="30">
<caret line="2" column="28" selection-start-line="2" selection-start-column="6" selection-end-line="2" selection-end-column="28" />
<state relative-caret-position="36">
<caret line="2" column="16" selection-start-line="2" selection-start-column="16" selection-end-line="2" selection-end-column="16" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/README.rst">
<provider selected="true" editor-type-id="restructured-text-editor" />
<entry file="file://$PROJECT_DIR$/introduction/face_reco_two_people_in_database.png">
<provider selected="true" editor-type-id="images" />
</entry>
<entry file="file://$PROJECT_DIR$/how_to_use_camera.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="15">
<state relative-caret-position="486">
<caret line="27" column="13" selection-start-line="27" selection-start-column="13" selection-end-line="27" selection-end-column="13" />
</state>
</provider>
@ -380,29 +361,29 @@
<entry file="file://$PROJECT_DIR$/data/features_all.csv">
<provider selected="true" editor-type-id="csv-text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/get_features_into_CSV.py">
<entry file="file://$PROJECT_DIR$/get_faces_from_camera.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="270">
<caret line="56" column="24" selection-start-line="56" selection-start-column="24" selection-end-line="56" selection-end-column="24" />
<state relative-caret-position="309">
<caret line="69" selection-start-line="69" selection-end-line="69" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/get_faces_from_camera.py">
<entry file="file://$PROJECT_DIR$/features_extraction_to_csv.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="176">
<caret line="172" selection-start-line="172" selection-end-line="172" />
<folding>
<element signature="e#277#310#0" expanded="true" />
</folding>
<state relative-caret-position="248">
<caret line="73" column="36" selection-start-line="73" selection-start-column="36" selection-end-line="73" selection-end-column="36" />
</state>
</provider>
</entry>
<entry file="file://$PROJECT_DIR$/README.rst">
<provider selected="true" editor-type-id="restructured-text-editor" />
</entry>
<entry file="file://$PROJECT_DIR$/face_reco_from_camera.py">
<provider selected="true" editor-type-id="text-editor">
<state relative-caret-position="195">
<caret line="96" selection-start-line="96" selection-end-line="96" />
<state relative-caret-position="489">
<caret line="160" column="23" lean-forward="true" selection-start-line="160" selection-start-column="23" selection-end-line="160" selection-end-column="23" />
<folding>
<element signature="e#201#234#0" expanded="true" />
<element signature="e#230#264#0" expanded="true" />
</folding>
</state>
</provider>

124
README.rst Normal file → Executable file
View File

@ -1,5 +1,5 @@
Face recognition from camera
############################
Face recognition from camera with Dlib
######################################
Introduction
************
@ -14,6 +14,12 @@ Detect and recognize single/multi-faces from camera;
.. image:: introduction/get_face_from_camera.png
:align: center
请不要离摄像头过近,人脸超出摄像头范围时会有 "OUT OF RANGE" 提醒 /
Please do not too close to the camera, or you can't save faces with "OUT OF RANGE" warning;
.. image:: introduction/get_face_from_camera_out_of_range.png
:align: center
#. 提取特征建立人脸数据库 / Generate database from images captured
#. 利用摄像头进行人脸识别 / Face recognizer
@ -23,33 +29,53 @@ Detect and recognize single/multi-faces from camera;
:align: center
当多张人脸 / When multi-faces:
一张已录入人脸 + 未录入 unknown 人脸 / 1x known face + 1x unknown face:
.. image:: introduction/face_reco_two_people.png
:align: center
同时识别多张已录入人脸 / multi-faces recognition at the same time:
.. image:: introduction/face_reco_two_people_in_database.png
: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.
Overview
********
此项目中人脸识别的实现流程 / The design of this repo:
.. image:: introduction/overview.png
:align: center
Steps
*****
#. 下载源码 / Download zip from website or via GitHub Desktop in windows, or git clone in Ubuntu
.. code-block:: bash
git clone https://github.com/coneypo/Dlib_face_recognition_from_camera
#. 进行 face register / 人脸信息采集录入
.. code-block:: python
.. code-block:: bash
python3 get_face_from_camera.py
#. 提取所有录入人脸数据存入 features_all.csv
#. 提取所有录入人脸数据存入 features_all.csv / Features extraction and save into features_all.csv
.. code-block:: python
.. code-block:: bash
python3 get_features_into_CSV.py
python3 features_extraction_to_csv.py
#. 调用摄像头进行实时人脸识别
#. 调用摄像头进行实时人脸识别 / Real-time face recognition
.. code-block:: python
.. code-block:: bash
python3 face_reco_from_camera.py
@ -57,6 +83,67 @@ Steps
About Source Code
*****************
Repo 的 tree / 树状图:
::
.
├── get_faces_from_camera.py # Step1. Faces register
├── features_extraction_to_csv.py # Step2. Features extraction
├── face_reco_from_camera.py # Step3. Faces recognition
├── 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_5_face_landmarks.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)
├── introduction # Some files for readme.rst
│   ├── Dlib_Face_recognition_by_coneypo.pptx
│   ├── face_reco_single_person_customize_name.png
│   ├── face_reco_single_person.png
│   ├── face_reco_two_people_in_database.png
│   ├── face_reco_two_people.png
│   ├── get_face_from_camera_out_of_range.png
│   ├── get_face_from_camera.png
│   └── overview.png
├── README.rst
└── requirements.txt # Some python packages needed
用到的 Dlib 相关模型函数:
#. Dlib 正向人脸检测器 (based on HOG), output: <class 'dlib.dlib.rectangles'>
.. code-block:: python
detector = dlib.get_frontal_face_detector()
faces = detector(img_gray, 0)
#. Dlib 人脸预测器, output: <class 'dlib.dlib.full_object_detection'>
.. code-block:: python
predictor = dlib.shape_predictor("data/data_dlib/shape_predictor_5_face_landmarks.dat")
shape = predictor(img_rd, faces[i])
#. 特征描述子 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 源码介绍如下:
#. get_face_from_camera.py:
@ -67,7 +154,7 @@ Python 源码介绍如下:
* 超出会有 "out of range" 的提醒;
#. get_features_into_CSV.py:
#. features_extraction_to_csv.py:
从上一步存下来的图像文件中,提取人脸数据存入CSV;
@ -82,28 +169,29 @@ Python 源码介绍如下:
* Compare the faces captured from camera with the faces you have registered which are saved in "features_all.csv"
* 将捕获到的人脸数据和之前存的人脸数据进行对比计算欧式距离, 由此判断是否是同一个人;
More
****
Tips:
1. Windows下建议不要把代码放到 ``C:\``, 可能会出现权限读取问题
#. 如果希望详细了解 dlib 的用法,请参考 Dlib 官方 Python api 的网站 / You can refer to this link for more information of how to use dlib: http://dlib.net/python/index.html
2. 代码最好不要有中文路径
#. Windows下建议不要把代码放到 ``C:\``, 可能会出现权限读取问题 / In windows, we will not recommend that running this repo in dir ``C:\``
3. 人脸录入的时候先建文件夹再保存图片, 先 ``N````S``
#. 代码最好不要有中文路径 / No chinese characters in your code directory
For more details, please refer to my blog (in chinese) or mail to me /
#. 人脸录入的时候先建文件夹再保存图片, 先 ``N````S`` / Press ``N`` before ``S``
可以访问我的博客获取本项目的更详细介绍,如有问题可以邮件联系我:
可以访问我的博客获取本项目的更详细介绍,如有问题可以邮件联系我 /
For more details, please refer to my blog (in chinese) or mail to me :
* Blog: https://www.cnblogs.com/AdaminXie/p/9010298.html
* Mail: coneypo@foxmail.com
* Mail: coneypo@foxmail.com ( Dlib 相关 repo 问题请联系 @foxmail 而不是 @intel )
仅限于交流学习, 商业合作勿扰;
Thanks for your support.
Thanks for your support.

View File

0
data/data_dlib/shape_predictor_5_face_landmarks.dat Normal file → Executable file
View File

0
data/data_dlib/shape_predictor_68_face_landmarks.dat Normal file → Executable file
View File

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.8 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 7.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 6.7 KiB

103
face_reco_from_camera.py Normal file → Executable file
View File

@ -1,11 +1,12 @@
# 摄像头实时人脸识别
# Real-time face recognition
# Author: coneypo
# Blog: http://www.cnblogs.com/AdaminXie
# GitHub: https://github.com/coneypo/Dlib_face_recognition_from_camera
# Created at 2018-05-11
# Updated at 2019-02-26
# Updated at 2019-04-09
import dlib # 人脸处理的库 Dlib
import numpy as np # 数据处理的库 numpy
@ -14,34 +15,29 @@ import pandas as pd # 数据处理的库 Pandas
# 人脸识别模型,提取128D的特征矢量
# face recognition model, the object maps human faces into 128D vectors
# Refer this tutorial: http://dlib.net/python/index.html#dlib.face_recognition_model_v1
facerec = dlib.face_recognition_model_v1("data/data_dlib/dlib_face_recognition_resnet_model_v1.dat")
# 计算两个128D向量间的欧式距离
# compute the e-distance between two 128D features
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)))
print("e_distance: ", dist)
if dist > 0.4:
return "diff"
else:
return "same"
return dist
# 处理存放所有人脸特征的 csv
path_features_known_csv = "data/features_all.csv"
csv_rd = pd.read_csv(path_features_known_csv, header=None)
# 存储的特征人脸个数
# print(csv_rd.shape[0])
# 用来存放所有录入人脸特征的数组
# the array to save the features of faces in the database
features_known_arr = []
# 读取已知人脸数据
# known faces
# print known faces
for i in range(csv_rd.shape[0]):
features_someone_arr = []
for j in range(0, len(csv_rd.ix[i, :])):
@ -50,31 +46,21 @@ for i in range(csv_rd.shape[0]):
print("Faces in Database:", len(features_known_arr))
# Dlib 检测器和预测器
# The detector and predictor will be used
detector = dlib.get_frontal_face_detector()
predictor = dlib.shape_predictor('data/data_dlib/shape_predictor_68_face_landmarks.dat')
# 创建 cv2 摄像头对象
# cv2.VideoCapture(0) to use the default camera of PC,
# and you can use local video name by use cv2.VideoCapture(filename)
cap = cv2.VideoCapture(0)
# cap.set(propId, value)
# 设置视频参数,propId 设置的视频参数,value 设置的参数值
cap.set(3, 480)
# 返回一张图像多张人脸的 128D 特征
def get_128d_features(img_gray):
faces = detector(img_gray, 1)
if len(faces) != 0:
face_des = []
for i in range(len(faces)):
shape = predictor(img_gray, faces[i])
face_des.append(facerec.compute_face_descriptor(img_gray, shape))
else:
face_des = []
return face_des
# cap.isOpened() 返回 true/false 检查初始化是否成功
# when the camera is open
while cap.isOpened():
flag, img_rd = cap.read()
@ -86,72 +72,95 @@ while cap.isOpened():
# 人脸数 faces
faces = detector(img_gray, 0)
# 待会要写的字体
# 待会要写的字体 font to write later
font = cv2.FONT_HERSHEY_COMPLEX
# 存储当前摄像头中捕获到的所有人脸的坐标/名字
# the list to save the positions and names of current faces captured
pos_namelist = []
name_namelist = []
# 按下 q 键退出
# press 'q' to exit
if kk == ord('q'):
break
else:
# 检测到人脸
# 检测到人脸 when face detected
if len(faces) != 0:
# 获取当前捕获到的图像的所有人脸的特征,存储到 features_cap_arr
# get the features captured and save into features_cap_arr
features_cap_arr = []
for i in range(len(faces)):
shape = predictor(img_rd, faces[i])
features_cap_arr.append(facerec.compute_face_descriptor(img_rd, shape))
# 遍历捕获到的图像中所有的人脸
# traversal all the faces in the database
for k in range(len(faces)):
print("##### camera person", k+1, "#####")
# 让人名跟随在矩形框的下方
# 确定人名的位置坐标
# 先默认所有人不认识,是 unknown
# set the default names of faces with "unknown"
name_namelist.append("unknown")
# 每个捕获人脸的名字坐标
# 每个捕获人脸的名字坐标 the positions of faces captured
pos_namelist.append(tuple([faces[k].left(), int(faces[k].bottom() + (faces[k].bottom() - faces[k].top())/4)]))
# 对于某张人脸,遍历所有存储的人脸特征
# for every faces detected, compare the faces in the database
e_distance_list = []
for i in range(len(features_known_arr)):
print("with person_", str(i+1), "the ", end='')
# 将某张人脸与存储的所有人脸数据进行比对
compare = return_euclidean_distance(features_cap_arr[k], features_known_arr[i])
if compare == "same": # 找到了相似脸
# 在这里修改 person_1, person_2 ... 的名字
# 这里只写了前三个
# 可以在这里改称 Jack, Tom and others
# Here you can modify the names shown on the camera
if i == 0:
name_namelist[k] = "Jack"
elif i == 1:
name_namelist[k] = "Tom"
elif i == 2:
name_namelist[k] = "Tony"
# 如果 person_X 数据不为空
if str(features_known_arr[i][0]) != '0.0':
print("with person", str(i + 1), "the e distance: ", end='')
e_distance_tmp = return_euclidean_distance(features_cap_arr[k], features_known_arr[i])
print(e_distance_tmp)
e_distance_list.append(e_distance_tmp)
else:
# 空数据 person_X
e_distance_list.append(999999999)
# Find the one with minimum e distance
similar_person_num = e_distance_list.index(min(e_distance_list))
print("Minimum e distance with person", int(similar_person_num)+1)
if min(e_distance_list) < 0.4:
# 在这里修改 person_1, person_2 ... 的名字
# 可以在这里改称 Jack, Tom and others
# Here you can modify the names shown on the camera
name_namelist[k] = str("Person "+str(int(similar_person_num)+1))\
.replace("Person 1", "Sherry")\
.replace("Person 2", "Jack")\
.replace("Person 3", "Ronnie")\
.replace("Person 4", "Terry")\
.replace("Person 5", "Wilson")
# print("May be person "+str(int(similar_person_num)+1))
else:
print("Unknown person")
# 矩形框
# draw rectangle
for kk, d in enumerate(faces):
# 绘制矩形框
cv2.rectangle(img_rd, tuple([d.left(), d.top()]), tuple([d.right(), d.bottom()]), (0, 255, 255), 2)
print('\n')
# 在人脸框下面写人脸名字
# write names under rectangle
for i in range(len(faces)):
cv2.putText(img_rd, name_namelist[i], pos_namelist[i], font, 0.8, (0, 255, 255), 1, cv2.LINE_AA)
print("Name list now:", name_namelist, "\n")
print("Faces in camera now:", name_namelist, "\n")
cv2.putText(img_rd, "Press 'q': Quit", (20, 450), font, 0.8, (84, 255, 159), 1, cv2.LINE_AA)
cv2.putText(img_rd, "Face Recognition", (20, 40), font, 1, (0, 0, 0), 1, cv2.LINE_AA)
cv2.putText(img_rd, "Faces: " + str(len(faces)), (20, 100), font, 1, (0, 0, 255), 1, cv2.LINE_AA)
# 窗口显示
# 窗口显示 show with opencv
cv2.imshow("camera", img_rd)
# 释放摄像头
# 释放摄像头 release camera
cap.release()
# 删除建立的窗口
# 删除建立的窗口 delete all the windows
cv2.destroyAllWindows()

97
features_extraction_to_csv.py Executable file
View File

@ -0,0 +1,97 @@
# 从人脸图像文件中提取人脸特征存入 CSV
# Features extraction from images and save into features_all.csv
# Author: coneypo
# Blog: http://www.cnblogs.com/AdaminXie
# GitHub: https://github.com/coneypo/Dlib_face_recognition_from_camera
# Mail: coneypo@foxmail.com
# Created at 2018-05-11
# Updated at 2019-04-04
import cv2
import os
import dlib
from skimage import io
import csv
import numpy as np
# 要读取人脸图像文件的路径
path_images_from_camera = "data/data_faces_from_camera/"
# Dlib 正向人脸检测器
detector = dlib.get_frontal_face_detector()
# Dlib 人脸预测器
predictor = dlib.shape_predictor("data/data_dlib/shape_predictor_5_face_landmarks.dat")
# Dlib 人脸识别模型
# Face recognition model, the object maps human faces into 128D vectors
face_rec = dlib.face_recognition_model_v1("data/data_dlib/dlib_face_recognition_resnet_model_v1.dat")
# 返回单张图像的 128D 特征
def return_128d_features(path_img):
img_rd = io.imread(path_img)
img_gray = cv2.cvtColor(img_rd, cv2.COLOR_BGR2RGB)
faces = detector(img_gray, 1)
print("%-40s %-20s" % ("检测到人脸的图像 / image with faces detected:", path_img), '\n')
# 因为有可能截下来的人脸再去检测,检测不出来人脸了
# 所以要确保是 检测到人脸的人脸图像 拿去算特征
if len(faces) != 0:
shape = predictor(img_gray, faces[0])
face_descriptor = face_rec.compute_face_descriptor(img_gray, shape)
else:
face_descriptor = 0
print("no face")
return face_descriptor
# 将文件夹中照片特征提取出来, 写入 CSV
def return_features_mean_personX(path_faces_personX):
features_list_personX = []
photos_list = os.listdir(path_faces_personX)
if photos_list:
for i in range(len(photos_list)):
# 调用return_128d_features()得到128d特征
print("%-40s %-20s" % ("正在读的人脸图像 / image to read:", path_faces_personX + "/" + photos_list[i]))
features_128d = return_128d_features(path_faces_personX + "/" + photos_list[i])
# print(features_128d)
# 遇到没有检测出人脸的图片跳过
if features_128d == 0:
i += 1
else:
features_list_personX.append(features_128d)
else:
print("文件夹内图像文件为空 / Warning: No images in " + path_faces_personX + '/', '\n')
# 计算 128D 特征的均值
# personX 的 N 张图像 x 128D -> 1 x 128D
if features_list_personX:
features_mean_personX = np.array(features_list_personX).mean(axis=0)
else:
features_mean_personX = '0'
return features_mean_personX
# 获取已录入的最后一个人脸序号 / get the num 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]))
person_cnt = max(person_num_list)
with open("data/features_all.csv", "w", newline="") as csvfile:
writer = csv.writer(csvfile)
for person in range(person_cnt):
# Get the mean/average features of face/personX, it will be a list with a length of 128D
print(path_images_from_camera + "person_"+str(person+1))
features_mean_personX = return_features_mean_personX(path_images_from_camera + "person_"+str(person+1))
writer.writerow(features_mean_personX)
print("特征均值 / The mean of features:", list(features_mean_personX))
print('\n')
print("所有录入人脸数据存入 / Save all the features of faces registered into: data/features_all.csv")

108
get_faces_from_camera.py Normal file → Executable file
View File

@ -7,7 +7,7 @@
# Mail: coneypo@foxmail.com
# Created at 2018-05-11
# Updated at 2019-02-21
# Updated at 2019-04-12
import dlib # 人脸处理的库 Dlib
import numpy as np # 数据处理的库 Numpy
@ -16,41 +16,37 @@ import cv2 # 图像处理的库 OpenCv
import os # 读写文件
import shutil # 读写文件
# Dlib 正向人脸检测器
# Dlib 正向人脸检测器 / frontal face detector
detector = dlib.get_frontal_face_detector()
# Dlib 68 点特征预测器
# Dlib 68 点特征预测器 / 68 points features predictor
predictor = dlib.shape_predictor('data/data_dlib/shape_predictor_68_face_landmarks.dat')
# OpenCv 调用摄像头
# OpenCv 调用摄像头 use camera
cap = cv2.VideoCapture(0)
# 设置视频参数
# 设置视频参数 set camera
cap.set(3, 480)
# 人脸截图的计数器
# 人脸截图的计数器 the counter for screen shoot
cnt_ss = 0
# 存储人脸的文件夹
current_face_dir = 0
# 存储人脸的文件夹 the folder to save faces
current_face_dir = ""
# 保存 photos/csv 的路径
# 保存 faces images 的路径 the directory to save images of faces
path_photos_from_camera = "data/data_faces_from_camera/"
path_csv_from_photos = "data/data_csvs_from_camera/"
# 新建保存人脸图像文件和数据CSV文件夹
# mkdir for saving photos and csv
def pre_work_mkdir():
# 新建文件夹
# 新建文件夹 / make folders to save faces images and csv
if os.path.isdir(path_photos_from_camera):
pass
else:
os.mkdir(path_photos_from_camera)
if os.path.isdir(path_csv_from_photos):
pass
else:
os.mkdir(path_csv_from_photos)
pre_work_mkdir()
@ -58,42 +54,50 @@ pre_work_mkdir()
##### optional/可选, 默认关闭 #####
# 删除之前存的人脸数据文件夹
def pre_work_deldir():
# delete the old data of faces
def pre_work_del_old_face_folders():
# 删除之前存的人脸数据文件夹
# 删除 "/data_faces_from_camera/person_x/"...
folders_rd = os.listdir(path_photos_from_camera)
for i in range(len(folders_rd)):
shutil.rmtree(path_photos_from_camera+folders_rd[i])
csv_rd = os.listdir(path_csv_from_photos)
for i in range(len(csv_rd)):
os.remove(path_csv_from_photos+csv_rd[i])
if os.path.isfile("data/features_all.csv"):
os.remove("data/features_all.csv")
# 这里在每次程序录入之前, 删掉之前存的人脸数据
# 如果这里打开,每次进行人脸录入的时候都会删掉之前的人脸图像文件夹
# pre_work_deldir()
# 如果这里打开,每次进行人脸录入的时候都会删掉之前的人脸图像文件夹 person_1/,person_2/,person_3/...
# If enable this function, it will delete all the old data in dir person_1/,person_2/,/person_3/...
# pre_work_del_old_face_folders()
##################################
# 如果有之前录入的人脸
# 在之前 person_x 的序号按照 person_x+1 开始录入
# 如果有之前录入的人脸 / if the old folders exists
# 在之前 person_x 的序号按照 person_x+1 开始录入 / start from person_x+1
if os.listdir("data/data_faces_from_camera/"):
# 获取已录入的最后一个人脸序号
# 获取已录入的最后一个人脸序号 / get the num of latest person
person_list = os.listdir("data/data_faces_from_camera/")
person_list.sort()
person_num_latest = int(str(person_list[-1]).split("_")[-1])
person_cnt = person_num_latest
person_num_list = []
for person in person_list:
person_num_list.append(int(person.split('_')[-1]))
person_cnt = max(person_num_list)
# 如果第一次存储或者没有之前录入的人脸, 按照 person_1 开始录入
# start from person_1
else:
person_cnt = 0
# 之后用来控制是否保存图像的 flag
# 之后用来控制是否保存图像的 flag / the flag to control if save
save_flag = 1
# 之后用来检查是否先按 'n' 再按 's' / the flag to check if press 'n' before 's'
press_n_flag = 0
while cap.isOpened():
# 480 height * 640 width
flag, img_rd = cap.read()
# print(img_rd.shape)
# It should be 480 height * 640 width
kk = cv2.waitKey(1)
img_gray = cv2.cvtColor(img_rd, cv2.COLOR_RGB2GRAY)
@ -101,42 +105,47 @@ while cap.isOpened():
# 人脸数 faces
faces = detector(img_gray, 0)
# 待会要写的字体
# 待会要写的字体 / font to write
font = cv2.FONT_HERSHEY_COMPLEX
# 按下 'n' 新建存储人脸的文件夹
# 按下 'n' 新建存储人脸的文件夹 / press 'n' to create the folders for saving faces
if kk == ord('n'):
person_cnt += 1
current_face_dir = path_photos_from_camera + "person_" + str(person_cnt)
os.makedirs(current_face_dir)
print('\n')
print("新建的人脸文件夹: ", current_face_dir)
print("新建的人脸文件夹 / Create folders: ", current_face_dir)
# 将人脸计数器清零
cnt_ss = 0
cnt_ss = 0 # 将人脸计数器清零 / clear the cnt of faces
press_n_flag = 1 # 已经按下 'n' / have pressed 'n'
# 检测到人脸
# 检测到人脸 / if face detected
if len(faces) != 0:
# 矩形框
# 矩形框 / show the rectangle box
for k, d in enumerate(faces):
# 计算矩形大小
# we need to compute the width and height of the box
# (x,y), (宽度width, 高度height)
pos_start = tuple([d.left(), d.top()])
pos_end = tuple([d.right(), d.bottom()])
# 计算矩形框大小
# 计算矩形框大小 / compute the size of rectangle box
height = (d.bottom() - d.top())
width = (d.right() - d.left())
hh = int(height/2)
ww = int(width/2)
# 设置颜色 / The color of rectangle of faces detected
# 设置颜色 / the color of rectangle of faces detected
color_rectangle = (255, 255, 255)
# 判断人脸矩形框是否超出 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), font, 0.8, (0, 0, 255), 1, cv2.LINE_AA)
color_rectangle = (0, 0, 255)
save_flag = 0
if kk == ord('s'):
print("请调整位置 / Please adjust your position")
else:
color_rectangle = (255, 255, 255)
save_flag = 1
@ -146,41 +155,42 @@ while cap.isOpened():
tuple([d.right() + ww, d.bottom() + hh]),
color_rectangle, 2)
# 根据人脸大小生成空的图像
# 根据人脸大小生成空的图像 / create blank image according to the size of face detected
im_blank = np.zeros((int(height*2), width*2, 3), np.uint8)
if save_flag:
# 按下 's' 保存摄像头中的人脸到本地
# 按下 's' 保存摄像头中的人脸到本地 / press 's' to save faces into local images
if kk == ord('s'):
if os.path.isdir(current_face_dir):
# 检查有没有先按'n'新建文件夹 / check if you have pressed 'n'
if press_n_flag:
cnt_ss += 1
for ii in range(height*2):
for jj in range(width*2):
im_blank[ii][jj] = img_rd[d.top()-hh + ii][d.left()-ww + jj]
cv2.imwrite(current_face_dir + "/img_face_" + str(cnt_ss) + ".jpg", im_blank)
print("写入本地:", str(current_face_dir) + "/img_face_" + str(cnt_ss) + ".jpg")
print("写入本地 / Save into", str(current_face_dir) + "/img_face_" + str(cnt_ss) + ".jpg")
else:
print("请在按 'S' 之前先按 'N' 来建文件夹 / Please press 'N' before 'S'")
# 显示人脸数
# 显示人脸数 / show the numbers of faces detected
cv2.putText(img_rd, "Faces: " + str(len(faces)), (20, 100), font, 0.8, (0, 255, 0), 1, cv2.LINE_AA)
# 添加说明
# 添加说明 / add some statements
cv2.putText(img_rd, "Face Register", (20, 40), font, 1, (0, 0, 0), 1, cv2.LINE_AA)
cv2.putText(img_rd, "N: New face folder", (20, 350), font, 0.8, (0, 0, 0), 1, cv2.LINE_AA)
cv2.putText(img_rd, "S: Save current face", (20, 400), font, 0.8, (0, 0, 0), 1, cv2.LINE_AA)
cv2.putText(img_rd, "Q: Quit", (20, 450), font, 0.8, (0, 0, 0), 1, cv2.LINE_AA)
# 按下 'q' 键退出
# 按下 'q' 键退出 / press 'q' to exit
if kk == ord('q'):
break
# 窗口显示
# cv2.namedWindow("camera", 0) # 如果需要摄像头窗口大小可调
# 如果需要摄像头窗口大小可调 / uncomment this line if you want the camera window is resizeable
# cv2.namedWindow("camera", 0)
cv2.imshow("camera", img_rd)
# 释放摄像头
# 释放摄像头 / release camera
cap.release()
# 删除建立的窗口
cv2.destroyAllWindows()

View File

@ -1,137 +0,0 @@
# 从人脸图像文件中提取人脸特征存入 CSV
# Get features from images and save into features_all.csv
# Author: coneypo
# Blog: http://www.cnblogs.com/AdaminXie
# GitHub: https://github.com/coneypo/Dlib_face_recognition_from_camera
# Mail: coneypo@foxmail.com
# Created at 2018-05-11
# Updated at 2019-02-25
# 增加录入多张人脸到 CSV 的功能
# return_128d_features() 获取某张图像的 128D 特征
# write_into_csv() 获取某个路径下所有图像的特征,并写入 CSV
# compute_the_mean() 从 CSV 中读取 128D 特征,并计算特征均值
import cv2
import os
import dlib
from skimage import io
import csv
import numpy as np
import pandas as pd
# 要读取人脸图像文件的路径
path_photos_from_camera = "data/data_faces_from_camera/"
# 储存人脸特征 csv 的路径
path_csv_from_photos = "data/data_csvs_from_camera/"
# Dlib 正向人脸检测器
detector = dlib.get_frontal_face_detector()
# Dlib 人脸预测器
predictor = dlib.shape_predictor("data/data_dlib/shape_predictor_5_face_landmarks.dat")
# Dlib 人脸识别模型
# Face recognition model, the object maps human faces into 128D vectors
facerec = dlib.face_recognition_model_v1("data/data_dlib/dlib_face_recognition_resnet_model_v1.dat")
# 返回单张图像的 128D 特征
def return_128d_features(path_img):
img = io.imread(path_img)
img_gray = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
faces = detector(img_gray, 1)
print("检测到人脸的图像:", path_img, "\n")
# 因为有可能截下来的人脸再去检测,检测不出来人脸了
# 所以要确保是 检测到人脸的人脸图像 拿去算特征
if len(faces) != 0:
shape = predictor(img_gray, faces[0])
face_descriptor = facerec.compute_face_descriptor(img_gray, shape)
else:
face_descriptor = 0
print("no face")
# print(face_descriptor)
return face_descriptor
# 将文件夹中照片特征提取出来, 写入 CSV
# path_faces_personX: 图像文件夹的路径
# path_csv_from_photos: 要生成的 CSV 路径
def write_into_csv(path_faces_personX, path_csv_from_photos):
photos_list = os.listdir(path_faces_personX)
with open(path_csv_from_photos, "w", newline="") as csvfile:
writer = csv.writer(csvfile)
if photos_list:
for i in range(len(photos_list)):
# 调用return_128d_features()得到128d特征
print("正在读的人脸图像:", path_faces_personX + "/" + photos_list[i])
features_128d = return_128d_features(path_faces_personX + "/" + photos_list[i])
# print(features_128d)
# 遇到没有检测出人脸的图片跳过
if features_128d == 0:
i += 1
else:
writer.writerow(features_128d)
else:
print("Warning: Empty photos in "+path_faces_personX+'/')
writer.writerow("")
# 读取某人所有的人脸图像的数据,写入 person_X.csv
faces = os.listdir(path_photos_from_camera)
faces.sort()
for person in faces:
print("##### " + person + " #####")
print(path_csv_from_photos + person + ".csv")
write_into_csv(path_photos_from_camera + person, path_csv_from_photos + person + ".csv")
print('\n')
# 从 CSV 中读取数据,计算 128D 特征的均值
def compute_the_mean(path_csv_from_photos):
column_names = []
# 128D 特征
for feature_num in range(128):
column_names.append("features_" + str(feature_num + 1))
# 利用 pandas 读取 csv
rd = pd.read_csv(path_csv_from_photos, names=column_names)
if rd.size != 0:
# 存放 128D 特征的均值
feature_mean_list = []
for feature_num in range(128):
tmp_arr = rd["features_" + str(feature_num + 1)]
tmp_arr = np.array(tmp_arr)
# 计算某一个特征的均值
tmp_mean = np.mean(tmp_arr)
feature_mean_list.append(tmp_mean)
else:
feature_mean_list = []
return feature_mean_list
# 存放所有特征均值的 CSV 的路径
path_csv_from_photos_feature_all = "data/features_all.csv"
# 存放人脸特征的 CSV 的路径
path_csv_from_photos = "data/data_csvs_from_camera/"
with open(path_csv_from_photos_feature_all, "w", newline="") as csvfile:
writer = csv.writer(csvfile)
csv_rd = os.listdir(path_csv_from_photos)
csv_rd.sort()
print("##### 得到的特征均值 / The generated average values of features stored in: #####")
for i in range(len(csv_rd)):
feature_mean_list = compute_the_mean(path_csv_from_photos + csv_rd[i])
print(path_csv_from_photos + csv_rd[i])
writer.writerow(feature_mean_list)

0
how_to_use_camera.py Normal file → Executable file
View File

BIN
introduction/Dlib_Face_recognition_by_coneypo.pptx Normal file → Executable file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 853 KiB

BIN
introduction/face_reco_single_person.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 357 KiB

After

Width:  |  Height:  |  Size: 428 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 457 KiB

BIN
introduction/face_reco_two_people.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 397 KiB

After

Width:  |  Height:  |  Size: 499 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 425 KiB

BIN
introduction/get_face_from_camera.png Normal file → Executable file

Binary file not shown.

Before

Width:  |  Height:  |  Size: 396 KiB

After

Width:  |  Height:  |  Size: 416 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 433 KiB

BIN
introduction/overview.png Executable file

Binary file not shown.

After

Width:  |  Height:  |  Size: 324 KiB

3
requirements.txt Executable file
View File

@ -0,0 +1,3 @@
dlib==19.17.0
numpy==1.15.1
scikit-image==0.14.0