Signed-off-by: sairate <sairate@sina.cn>
|
@ -5,6 +5,8 @@
|
||||||
</component>
|
</component>
|
||||||
<component name="ChangeListManager">
|
<component name="ChangeListManager">
|
||||||
<list default="true" id="c512d54a-7f5f-4cfb-af24-29d5821a33bf" name="更改" comment="Signed-off-by: sairate <sairate@sina.cn>">
|
<list default="true" id="c512d54a-7f5f-4cfb-af24-29d5821a33bf" name="更改" comment="Signed-off-by: sairate <sairate@sina.cn>">
|
||||||
|
<change afterPath="$PROJECT_DIR$/app.py" afterDir="false" />
|
||||||
|
<change afterPath="$PROJECT_DIR$/templates/index.html" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/.idea/workspace.xml" beforeDir="false" afterPath="$PROJECT_DIR$/.idea/workspace.xml" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/captured_faces/face_1.jpg" beforeDir="false" afterPath="$PROJECT_DIR$/captured_faces/face_1.jpg" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/captured_faces/face_1.jpg" beforeDir="false" afterPath="$PROJECT_DIR$/captured_faces/face_1.jpg" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/captured_faces/face_10.jpg" beforeDir="false" afterPath="$PROJECT_DIR$/captured_faces/face_10.jpg" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/captured_faces/face_10.jpg" beforeDir="false" afterPath="$PROJECT_DIR$/captured_faces/face_10.jpg" afterDir="false" />
|
||||||
|
@ -16,7 +18,7 @@
|
||||||
<change beforePath="$PROJECT_DIR$/captured_faces/face_7.jpg" beforeDir="false" afterPath="$PROJECT_DIR$/captured_faces/face_7.jpg" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/captured_faces/face_7.jpg" beforeDir="false" afterPath="$PROJECT_DIR$/captured_faces/face_7.jpg" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/captured_faces/face_8.jpg" beforeDir="false" afterPath="$PROJECT_DIR$/captured_faces/face_8.jpg" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/captured_faces/face_8.jpg" beforeDir="false" afterPath="$PROJECT_DIR$/captured_faces/face_8.jpg" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/captured_faces/face_9.jpg" beforeDir="false" afterPath="$PROJECT_DIR$/captured_faces/face_9.jpg" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/captured_faces/face_9.jpg" beforeDir="false" afterPath="$PROJECT_DIR$/captured_faces/face_9.jpg" afterDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/face_database.db" beforeDir="false" afterPath="$PROJECT_DIR$/face_database.db" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/face_database.db" beforeDir="false" />
|
||||||
<change beforePath="$PROJECT_DIR$/scanf_face.py" beforeDir="false" afterPath="$PROJECT_DIR$/scanf_face.py" afterDir="false" />
|
<change beforePath="$PROJECT_DIR$/scanf_face.py" beforeDir="false" afterPath="$PROJECT_DIR$/scanf_face.py" afterDir="false" />
|
||||||
</list>
|
</list>
|
||||||
<option name="SHOW_DIALOG" value="false" />
|
<option name="SHOW_DIALOG" value="false" />
|
||||||
|
@ -28,6 +30,7 @@
|
||||||
<option name="RECENT_TEMPLATES">
|
<option name="RECENT_TEMPLATES">
|
||||||
<list>
|
<list>
|
||||||
<option value="Python Script" />
|
<option value="Python Script" />
|
||||||
|
<option value="HTML File" />
|
||||||
</list>
|
</list>
|
||||||
</option>
|
</option>
|
||||||
</component>
|
</component>
|
||||||
|
@ -57,26 +60,28 @@
|
||||||
<option name="hideEmptyMiddlePackages" value="true" />
|
<option name="hideEmptyMiddlePackages" value="true" />
|
||||||
<option name="showLibraryContents" value="true" />
|
<option name="showLibraryContents" value="true" />
|
||||||
</component>
|
</component>
|
||||||
<component name="PropertiesComponent">{
|
<component name="PropertiesComponent"><![CDATA[{
|
||||||
"keyToString": {
|
"keyToString": {
|
||||||
"ASKED_ADD_EXTERNAL_FILES": "true",
|
"ASKED_ADD_EXTERNAL_FILES": "true",
|
||||||
"Python.add_face.executor": "Run",
|
"DefaultHtmlFileTemplate": "HTML File",
|
||||||
"Python.match_face.executor": "Run",
|
"Python.add_face.executor": "Run",
|
||||||
"Python.scanf_face.executor": "Run",
|
"Python.app.executor": "Run",
|
||||||
"Python.sqlite.executor": "Run",
|
"Python.match_face.executor": "Run",
|
||||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
"Python.scanf_face.executor": "Run",
|
||||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
"Python.sqlite.executor": "Run",
|
||||||
"SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||||
"git-widget-placeholder": "master",
|
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||||
"node.js.detected.package.eslint": "true",
|
"SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
||||||
"node.js.detected.package.tslint": "true",
|
"git-widget-placeholder": "master",
|
||||||
"node.js.selected.package.eslint": "(autodetect)",
|
"node.js.detected.package.eslint": "true",
|
||||||
"node.js.selected.package.tslint": "(autodetect)",
|
"node.js.detected.package.tslint": "true",
|
||||||
"nodejs_package_manager_path": "npm",
|
"node.js.selected.package.eslint": "(autodetect)",
|
||||||
"settings.editor.selected.configurable": "com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable",
|
"node.js.selected.package.tslint": "(autodetect)",
|
||||||
"vue.rearranger.settings.migration": "true"
|
"nodejs_package_manager_path": "npm",
|
||||||
|
"settings.editor.selected.configurable": "com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable",
|
||||||
|
"vue.rearranger.settings.migration": "true"
|
||||||
}
|
}
|
||||||
}</component>
|
}]]></component>
|
||||||
<component name="RunManager" selected="Python.scanf_face">
|
<component name="RunManager" selected="Python.scanf_face">
|
||||||
<configuration name="add_face" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
<configuration name="add_face" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||||
<module name="face" />
|
<module name="face" />
|
||||||
|
@ -101,6 +106,29 @@
|
||||||
<option name="INPUT_FILE" value="" />
|
<option name="INPUT_FILE" value="" />
|
||||||
<method v="2" />
|
<method v="2" />
|
||||||
</configuration>
|
</configuration>
|
||||||
|
<configuration name="app" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||||
|
<module name="face" />
|
||||||
|
<option name="ENV_FILES" value="" />
|
||||||
|
<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" />
|
||||||
|
<EXTENSION ID="PythonCoverageRunConfigurationExtension" runner="coverage.py" />
|
||||||
|
<option name="SCRIPT_NAME" value="$PROJECT_DIR$/app.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="match_face" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
<configuration name="match_face" type="PythonConfigurationType" factoryName="Python" temporary="true" nameIsGenerated="true">
|
||||||
<module name="face" />
|
<module name="face" />
|
||||||
<option name="ENV_FILES" value="" />
|
<option name="ENV_FILES" value="" />
|
||||||
|
@ -173,6 +201,7 @@
|
||||||
<recent_temporary>
|
<recent_temporary>
|
||||||
<list>
|
<list>
|
||||||
<item itemvalue="Python.scanf_face" />
|
<item itemvalue="Python.scanf_face" />
|
||||||
|
<item itemvalue="Python.app" />
|
||||||
<item itemvalue="Python.match_face" />
|
<item itemvalue="Python.match_face" />
|
||||||
<item itemvalue="Python.add_face" />
|
<item itemvalue="Python.add_face" />
|
||||||
<item itemvalue="Python.sqlite" />
|
<item itemvalue="Python.sqlite" />
|
||||||
|
@ -206,6 +235,11 @@
|
||||||
<workItem from="1724382932780" duration="803000" />
|
<workItem from="1724382932780" duration="803000" />
|
||||||
<workItem from="1724385627303" duration="110000" />
|
<workItem from="1724385627303" duration="110000" />
|
||||||
<workItem from="1724388047550" duration="281000" />
|
<workItem from="1724388047550" duration="281000" />
|
||||||
|
<workItem from="1724392582289" duration="224000" />
|
||||||
|
<workItem from="1724402091135" duration="241000" />
|
||||||
|
<workItem from="1724487223382" duration="3000" />
|
||||||
|
<workItem from="1724487238846" duration="322000" />
|
||||||
|
<workItem from="1724546711749" duration="3708000" />
|
||||||
</task>
|
</task>
|
||||||
<task id="LOCAL-00001" summary="sairate">
|
<task id="LOCAL-00001" summary="sairate">
|
||||||
<option name="closed" value="true" />
|
<option name="closed" value="true" />
|
||||||
|
@ -262,7 +296,8 @@
|
||||||
<component name="com.intellij.coverage.CoverageDataManagerImpl">
|
<component name="com.intellij.coverage.CoverageDataManagerImpl">
|
||||||
<SUITE FILE_PATH="coverage/face$sqlite.coverage" NAME="sqlite 覆盖结果" MODIFIED="1724310603865" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
<SUITE FILE_PATH="coverage/face$sqlite.coverage" NAME="sqlite 覆盖结果" MODIFIED="1724310603865" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||||
<SUITE FILE_PATH="coverage/face$match_face.coverage" NAME="match_face 覆盖结果" MODIFIED="1724314395402" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
<SUITE FILE_PATH="coverage/face$match_face.coverage" NAME="match_face 覆盖结果" MODIFIED="1724314395402" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||||
<SUITE FILE_PATH="coverage/face$scanf_face.coverage" NAME="scanf_face 覆盖结果" MODIFIED="1724388311934" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
<SUITE FILE_PATH="coverage/face$app.coverage" NAME="app 覆盖结果" MODIFIED="1724556824546" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||||
|
<SUITE FILE_PATH="coverage/face$scanf_face.coverage" NAME="scanf_face 覆盖结果" MODIFIED="1724556840774" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||||
<SUITE FILE_PATH="coverage/face$add_face.coverage" NAME="add_face 覆盖结果" MODIFIED="1724311005030" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
<SUITE FILE_PATH="coverage/face$add_face.coverage" NAME="add_face 覆盖结果" MODIFIED="1724311005030" SOURCE_PROVIDER="com.intellij.coverage.DefaultCoverageFileProvider" RUNNER="coverage.py" COVERAGE_BY_TEST_ENABLED="true" COVERAGE_TRACING_ENABLED="false" WORKING_DIRECTORY="$PROJECT_DIR$" />
|
||||||
</component>
|
</component>
|
||||||
</project>
|
</project>
|
|
@ -0,0 +1,26 @@
|
||||||
|
from flask import Flask, render_template
|
||||||
|
import sqlite3
|
||||||
|
import subprocess
|
||||||
|
|
||||||
|
#subprocess.Popen(["python", "scanf_face.py"])
|
||||||
|
|
||||||
|
|
||||||
|
app = Flask(__name__)
|
||||||
|
|
||||||
|
# 从数据库中获取匹配日志记录
|
||||||
|
def get_match_logs(db_name="face_database.db"):
|
||||||
|
conn = sqlite3.connect(db_name)
|
||||||
|
c = conn.cursor()
|
||||||
|
c.execute("SELECT name, identity, image_path, match_time FROM match_logs")
|
||||||
|
logs = c.fetchall()
|
||||||
|
conn.close()
|
||||||
|
return logs
|
||||||
|
|
||||||
|
# 首页,展示匹配记录
|
||||||
|
@app.route('/')
|
||||||
|
def index():
|
||||||
|
logs = get_match_logs()
|
||||||
|
return render_template('index.html', logs=logs)
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
app.run(debug=True)
|
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 20 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 11 KiB After Width: | Height: | Size: 14 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 15 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 22 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 16 KiB |
BIN
face_database.db
192
scanf_face.py
|
@ -3,18 +3,114 @@ import face_recognition
|
||||||
import os
|
import os
|
||||||
import sqlite3
|
import sqlite3
|
||||||
import numpy as np
|
import numpy as np
|
||||||
|
from datetime import datetime
|
||||||
|
import time
|
||||||
|
|
||||||
# 初始化摄像头
|
# 初始化摄像头
|
||||||
cap = cv2.VideoCapture(0)
|
cap = cv2.VideoCapture(0)
|
||||||
photo_count = 0
|
|
||||||
max_photos = 10
|
max_photos = 10
|
||||||
captured_images = []
|
|
||||||
|
|
||||||
# 创建目录以保存照片
|
# 创建目录以保存照片
|
||||||
save_path = "./captured_faces"
|
save_path = "./captured_faces"
|
||||||
os.makedirs(save_path, exist_ok=True)
|
os.makedirs(save_path, exist_ok=True)
|
||||||
|
|
||||||
while photo_count < max_photos:
|
|
||||||
|
def create_face_database(db_name="face_database.db"):
|
||||||
|
conn = sqlite3.connect(db_name)
|
||||||
|
c = conn.cursor()
|
||||||
|
c.execute('''CREATE TABLE IF NOT EXISTS faces
|
||||||
|
(id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
identity TEXT NOT NULL,
|
||||||
|
encoding BLOB NOT NULL)''')
|
||||||
|
|
||||||
|
# 创建匹配日志表
|
||||||
|
c.execute('''CREATE TABLE IF NOT EXISTS match_logs
|
||||||
|
(id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||||
|
name TEXT NOT NULL,
|
||||||
|
identity TEXT NOT NULL,
|
||||||
|
image_path TEXT NOT NULL,
|
||||||
|
match_time TEXT NOT NULL)''')
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
def add_face_to_database(name, identity, image_path, db_name="face_database.db"):
|
||||||
|
conn = sqlite3.connect(db_name)
|
||||||
|
c = conn.cursor()
|
||||||
|
|
||||||
|
# 加载图片并生成编码
|
||||||
|
image = face_recognition.load_image_file(image_path)
|
||||||
|
face_encodings = face_recognition.face_encodings(image)
|
||||||
|
|
||||||
|
if face_encodings:
|
||||||
|
face_encoding = face_encodings[0]
|
||||||
|
# 将编码转换为可以存储的格式
|
||||||
|
encoding_blob = np.array(face_encoding).tobytes()
|
||||||
|
c.execute("INSERT INTO faces (name, identity, encoding) VALUES (?, ?, ?)",
|
||||||
|
(name, identity, encoding_blob))
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
|
||||||
|
def log_match(name, identity, image_path, db_name="face_database.db", log_file="match_log.txt"):
|
||||||
|
conn = sqlite3.connect(db_name)
|
||||||
|
c = conn.cursor()
|
||||||
|
|
||||||
|
# 获取当前时间
|
||||||
|
match_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S")
|
||||||
|
|
||||||
|
# 将匹配信息插入到匹配日志表中
|
||||||
|
c.execute("INSERT INTO match_logs (name, identity, image_path, match_time) VALUES (?, ?, ?, ?)",
|
||||||
|
(name, identity, image_path, match_time))
|
||||||
|
conn.commit()
|
||||||
|
conn.close()
|
||||||
|
|
||||||
|
# 将匹配信息写入文本文件
|
||||||
|
with open(log_file, "a") as f:
|
||||||
|
f.write(f"匹配成功: {name} ({identity}) 在 {image_path} 时间: {match_time}\n")
|
||||||
|
|
||||||
|
|
||||||
|
def match_faces(captured_images, db_name="face_database.db", tolerance=0.4, log_file="match_log.txt"):
|
||||||
|
conn = sqlite3.connect(db_name)
|
||||||
|
c = conn.cursor()
|
||||||
|
|
||||||
|
# 获取数据库中所有存储的人脸编码
|
||||||
|
c.execute("SELECT name, identity, encoding FROM faces")
|
||||||
|
known_faces = c.fetchall()
|
||||||
|
|
||||||
|
for image_path in captured_images:
|
||||||
|
# 加载待匹配图片并生成编码
|
||||||
|
unknown_image = face_recognition.load_image_file(image_path)
|
||||||
|
face_encodings = face_recognition.face_encodings(unknown_image)
|
||||||
|
|
||||||
|
if len(face_encodings) == 0:
|
||||||
|
print(f"没有人脸 {image_path}")
|
||||||
|
continue # 如果没有检测到人脸,跳过该图片
|
||||||
|
|
||||||
|
unknown_encoding = face_encodings[0]
|
||||||
|
|
||||||
|
for name, identity, encoding_blob in known_faces:
|
||||||
|
known_encoding = np.frombuffer(encoding_blob, dtype=np.float64)
|
||||||
|
match = face_recognition.compare_faces([known_encoding], unknown_encoding, tolerance=tolerance)
|
||||||
|
|
||||||
|
if match[0]: # 如果匹配成功
|
||||||
|
print(f"发现匹配: {name} ({identity}) 在 {image_path}")
|
||||||
|
log_match(name, identity, image_path, db_name, log_file) # 记录匹配信息和时间到数据库和TXT文件
|
||||||
|
conn.close()
|
||||||
|
return True # 一旦找到匹配,返回成功
|
||||||
|
print(f"没发现匹配: 在 {image_path}")
|
||||||
|
conn.close()
|
||||||
|
return False # 如果所有比较都没有匹配,返回失败
|
||||||
|
|
||||||
|
# 创建人脸数据库
|
||||||
|
create_face_database()
|
||||||
|
|
||||||
|
# 向数据库中添加人脸
|
||||||
|
add_face_to_database("屈礼", "居民", "./db_image/test.jpg")
|
||||||
|
|
||||||
|
# 主程序循环
|
||||||
|
while True:
|
||||||
ret, frame = cap.read()
|
ret, frame = cap.read()
|
||||||
if not ret:
|
if not ret:
|
||||||
break
|
break
|
||||||
|
@ -25,6 +121,20 @@ while photo_count < max_photos:
|
||||||
# 检测人脸
|
# 检测人脸
|
||||||
face_locations = face_recognition.face_locations(rgb_frame)
|
face_locations = face_recognition.face_locations(rgb_frame)
|
||||||
|
|
||||||
|
if face_locations:
|
||||||
|
print("检测到人脸,开始抓拍...")
|
||||||
|
|
||||||
|
captured_images = []
|
||||||
|
photo_count = 0
|
||||||
|
|
||||||
|
while photo_count < max_photos:
|
||||||
|
ret, frame = cap.read()
|
||||||
|
if not ret:
|
||||||
|
break
|
||||||
|
|
||||||
|
rgb_frame = frame[:, :, ::-1]
|
||||||
|
face_locations = face_recognition.face_locations(rgb_frame)
|
||||||
|
|
||||||
for face_location in face_locations:
|
for face_location in face_locations:
|
||||||
top, right, bottom, left = face_location
|
top, right, bottom, left = face_location
|
||||||
|
|
||||||
|
@ -48,78 +158,16 @@ while photo_count < max_photos:
|
||||||
if cv2.waitKey(1) & 0xFF == ord('q'):
|
if cv2.waitKey(1) & 0xFF == ord('q'):
|
||||||
break
|
break
|
||||||
|
|
||||||
cap.release()
|
# 关闭窗口
|
||||||
cv2.destroyAllWindows()
|
cv2.destroyAllWindows()
|
||||||
|
|
||||||
print(f"Captured {photo_count} images.")
|
|
||||||
|
|
||||||
def create_face_database(db_name="face_database.db"):
|
|
||||||
conn = sqlite3.connect(db_name)
|
|
||||||
c = conn.cursor()
|
|
||||||
c.execute('''CREATE TABLE IF NOT EXISTS faces
|
|
||||||
(id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
||||||
name TEXT NOT NULL,
|
|
||||||
encoding BLOB NOT NULL)''')
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
def add_face_to_database(name, image_path, db_name="face_database.db"):
|
|
||||||
conn = sqlite3.connect(db_name)
|
|
||||||
c = conn.cursor()
|
|
||||||
|
|
||||||
# 加载图片并生成编码
|
|
||||||
image = face_recognition.load_image_file(image_path)
|
|
||||||
face_encodings = face_recognition.face_encodings(image)
|
|
||||||
|
|
||||||
if face_encodings:
|
|
||||||
face_encoding = face_encodings[0]
|
|
||||||
# 将编码转换为可以存储的格式
|
|
||||||
encoding_blob = np.array(face_encoding).tobytes()
|
|
||||||
c.execute("INSERT INTO faces (name, encoding) VALUES (?, ?)",
|
|
||||||
(name, encoding_blob))
|
|
||||||
conn.commit()
|
|
||||||
conn.close()
|
|
||||||
|
|
||||||
def match_faces(captured_images, db_name="face_database.db", tolerance=0.4):
|
|
||||||
conn = sqlite3.connect(db_name)
|
|
||||||
c = conn.cursor()
|
|
||||||
|
|
||||||
# 获取数据库中所有存储的人脸编码
|
|
||||||
c.execute("SELECT name, encoding FROM faces")
|
|
||||||
known_faces = c.fetchall()
|
|
||||||
|
|
||||||
for image_path in captured_images:
|
|
||||||
# 加载待匹配图片并生成编码
|
|
||||||
unknown_image = face_recognition.load_image_file(image_path)
|
|
||||||
face_encodings = face_recognition.face_encodings(unknown_image)
|
|
||||||
|
|
||||||
if len(face_encodings) == 0:
|
|
||||||
print(f"没有人脸 {image_path}")
|
|
||||||
continue # 如果没有检测到人脸,跳过该图片
|
|
||||||
|
|
||||||
unknown_encoding = face_encodings[0]
|
|
||||||
|
|
||||||
for name, encoding_blob in known_faces:
|
|
||||||
known_encoding = np.frombuffer(encoding_blob, dtype=np.float64)
|
|
||||||
match = face_recognition.compare_faces([known_encoding], unknown_encoding, tolerance=tolerance)
|
|
||||||
|
|
||||||
if match[0]: # 如果匹配成功
|
|
||||||
print(f"发现匹配: {name} 在 {image_path}")
|
|
||||||
conn.close()
|
|
||||||
return True # 一旦找到匹配,返回成功
|
|
||||||
else:
|
|
||||||
print(f"没发现匹配: 在 {image_path}")
|
|
||||||
conn.close()
|
|
||||||
return False # 如果所有比较都没有匹配,返回失败
|
|
||||||
|
|
||||||
# 创建人脸数据库
|
|
||||||
create_face_database()
|
|
||||||
|
|
||||||
# 向数据库中添加人脸
|
|
||||||
add_face_to_database("屈礼", "./db_image/test.jpg")
|
|
||||||
|
|
||||||
# 逐张匹配抓拍的照片
|
|
||||||
if match_faces(captured_images):
|
if match_faces(captured_images):
|
||||||
print("至少一张匹配")
|
print("至少一张匹配")
|
||||||
else:
|
else:
|
||||||
print("没有匹配")
|
print("没有匹配")
|
||||||
|
|
||||||
|
# 等待60秒后继续循环检测
|
||||||
|
print("等待30秒后继续...")
|
||||||
|
time.sleep(30)
|
||||||
|
|
||||||
|
cap.release()
|
||||||
|
|
|
@ -0,0 +1,60 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html lang="en">
|
||||||
|
<head>
|
||||||
|
<meta charset="UTF-8">
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||||
|
<title>匹配记录</title>
|
||||||
|
<style>
|
||||||
|
body {
|
||||||
|
font-family: Arial, sans-serif;
|
||||||
|
background-color: #f4f4f4;
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
.container {
|
||||||
|
width: 80%;
|
||||||
|
margin: 20px auto;
|
||||||
|
background: #fff;
|
||||||
|
padding: 20px;
|
||||||
|
box-shadow: 0 0 10px rgba(0, 0, 0, 0.1);
|
||||||
|
}
|
||||||
|
table {
|
||||||
|
width: 100%;
|
||||||
|
border-collapse: collapse;
|
||||||
|
margin: 20px 0;
|
||||||
|
}
|
||||||
|
table, th, td {
|
||||||
|
border: 1px solid #ddd;
|
||||||
|
}
|
||||||
|
th, td {
|
||||||
|
padding: 10px;
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
th {
|
||||||
|
background-color: #4CAF50;
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<div class="container">
|
||||||
|
<h1>Face Match Logs</h1>
|
||||||
|
<table>
|
||||||
|
<tr>
|
||||||
|
<th>Name</th>
|
||||||
|
<th>Identity</th>
|
||||||
|
<th>Image Path</th>
|
||||||
|
<th>Match Time</th>
|
||||||
|
</tr>
|
||||||
|
{% for log in logs %}
|
||||||
|
<tr>
|
||||||
|
<td>{{ log[0] }}</td>
|
||||||
|
<td>{{ log[1] }}</td>
|
||||||
|
<td>{{ log[2] }}</td>
|
||||||
|
<td>{{ log[3] }}</td>
|
||||||
|
</tr>
|
||||||
|
{% endfor %}
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</body>
|
||||||
|
</html>
|