Compare commits
No commits in common. "a3ba05a4266e04164418475f6d5b6b1af53d6f8f" and "490abddd23c3796f228e8c76ca4aa9e27430ac4a" have entirely different histories.
a3ba05a426
...
490abddd23
|
@ -5,8 +5,6 @@
|
||||||
</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" />
|
||||||
|
@ -18,7 +16,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" />
|
<change beforePath="$PROJECT_DIR$/face_database.db" beforeDir="false" afterPath="$PROJECT_DIR$/face_database.db" afterDir="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" />
|
||||||
|
@ -30,7 +28,6 @@
|
||||||
<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>
|
||||||
|
@ -60,28 +57,26 @@
|
||||||
<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"><![CDATA[{
|
<component name="PropertiesComponent">{
|
||||||
"keyToString": {
|
"keyToString": {
|
||||||
"ASKED_ADD_EXTERNAL_FILES": "true",
|
"ASKED_ADD_EXTERNAL_FILES": "true",
|
||||||
"DefaultHtmlFileTemplate": "HTML File",
|
"Python.add_face.executor": "Run",
|
||||||
"Python.add_face.executor": "Run",
|
"Python.match_face.executor": "Run",
|
||||||
"Python.app.executor": "Run",
|
"Python.scanf_face.executor": "Run",
|
||||||
"Python.match_face.executor": "Run",
|
"Python.sqlite.executor": "Run",
|
||||||
"Python.scanf_face.executor": "Run",
|
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
||||||
"Python.sqlite.executor": "Run",
|
"RunOnceActivity.ShowReadmeOnStart": "true",
|
||||||
"RunOnceActivity.OpenProjectViewOnStart": "true",
|
"SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
||||||
"RunOnceActivity.ShowReadmeOnStart": "true",
|
"git-widget-placeholder": "master",
|
||||||
"SHARE_PROJECT_CONFIGURATION_FILES": "true",
|
"node.js.detected.package.eslint": "true",
|
||||||
"git-widget-placeholder": "master",
|
"node.js.detected.package.tslint": "true",
|
||||||
"node.js.detected.package.eslint": "true",
|
"node.js.selected.package.eslint": "(autodetect)",
|
||||||
"node.js.detected.package.tslint": "true",
|
"node.js.selected.package.tslint": "(autodetect)",
|
||||||
"node.js.selected.package.eslint": "(autodetect)",
|
"nodejs_package_manager_path": "npm",
|
||||||
"node.js.selected.package.tslint": "(autodetect)",
|
"settings.editor.selected.configurable": "com.jetbrains.python.configuration.PyActiveSdkModuleConfigurable",
|
||||||
"nodejs_package_manager_path": "npm",
|
"vue.rearranger.settings.migration": "true"
|
||||||
"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" />
|
||||||
|
@ -106,29 +101,6 @@
|
||||||
<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="" />
|
||||||
|
@ -201,7 +173,6 @@
|
||||||
<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" />
|
||||||
|
@ -235,11 +206,6 @@
|
||||||
<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" />
|
||||||
|
@ -296,8 +262,7 @@
|
||||||
<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$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="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$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>
|
26
app.py
|
@ -1,26 +0,0 @@
|
||||||
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: 20 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 14 KiB After Width: | Height: | Size: 11 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 15 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 22 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 16 KiB After Width: | Height: | Size: 12 KiB |
BIN
face_database.db
202
scanf_face.py
|
@ -3,114 +3,18 @@ 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
|
||||||
|
@ -121,20 +25,6 @@ while True:
|
||||||
# 检测人脸
|
# 检测人脸
|
||||||
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
|
||||||
|
|
||||||
|
@ -158,16 +48,78 @@ while True:
|
||||||
if cv2.waitKey(1) & 0xFF == ord('q'):
|
if cv2.waitKey(1) & 0xFF == ord('q'):
|
||||||
break
|
break
|
||||||
|
|
||||||
# 关闭窗口
|
|
||||||
cv2.destroyAllWindows()
|
|
||||||
|
|
||||||
if match_faces(captured_images):
|
|
||||||
print("至少一张匹配")
|
|
||||||
else:
|
|
||||||
print("没有匹配")
|
|
||||||
|
|
||||||
# 等待60秒后继续循环检测
|
|
||||||
print("等待30秒后继续...")
|
|
||||||
time.sleep(30)
|
|
||||||
|
|
||||||
cap.release()
|
cap.release()
|
||||||
|
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):
|
||||||
|
print("至少一张匹配")
|
||||||
|
else:
|
||||||
|
print("没有匹配")
|
||||||
|
|
|
@ -1,60 +0,0 @@
|
||||||
<!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>
|
|