2024-08-22 16:30:26 +08:00
|
|
|
|
import cv2
|
|
|
|
|
import face_recognition
|
|
|
|
|
import os
|
|
|
|
|
import sqlite3
|
|
|
|
|
import numpy as np
|
2024-08-25 11:36:23 +08:00
|
|
|
|
from datetime import datetime
|
|
|
|
|
import time
|
2024-08-22 16:30:26 +08:00
|
|
|
|
|
|
|
|
|
# 初始化摄像头
|
|
|
|
|
cap = cv2.VideoCapture(0)
|
|
|
|
|
max_photos = 10
|
|
|
|
|
|
|
|
|
|
# 创建目录以保存照片
|
2024-08-23 09:12:01 +08:00
|
|
|
|
save_path = "./captured_faces"
|
2024-08-22 16:30:26 +08:00
|
|
|
|
os.makedirs(save_path, exist_ok=True)
|
|
|
|
|
|
|
|
|
|
def create_face_database(db_name="face_database.db"):
|
2024-08-25 13:21:02 +08:00
|
|
|
|
"""创建人脸数据库和匹配日志表"""
|
2024-08-22 16:30:26 +08:00
|
|
|
|
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,
|
2024-08-25 11:36:23 +08:00
|
|
|
|
identity TEXT NOT NULL,
|
2024-08-25 13:21:02 +08:00
|
|
|
|
image_path TEXT NOT NULL,
|
2024-08-22 16:30:26 +08:00
|
|
|
|
encoding BLOB NOT NULL)''')
|
2024-08-25 11:36:23 +08:00
|
|
|
|
|
|
|
|
|
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)''')
|
2024-08-22 16:30:26 +08:00
|
|
|
|
conn.commit()
|
|
|
|
|
conn.close()
|
|
|
|
|
|
2024-08-25 11:36:23 +08:00
|
|
|
|
def add_face_to_database(name, identity, image_path, db_name="face_database.db"):
|
2024-08-25 13:21:02 +08:00
|
|
|
|
"""将人脸信息添加到数据库"""
|
2024-08-22 16:30:26 +08:00
|
|
|
|
conn = sqlite3.connect(db_name)
|
|
|
|
|
c = conn.cursor()
|
|
|
|
|
|
2024-08-28 09:34:15 +08:00
|
|
|
|
# 将图片路径转换为相对路径
|
|
|
|
|
relative_image_path = os.path.relpath(image_path, start='./static')
|
|
|
|
|
|
2024-08-22 16:30:26 +08:00
|
|
|
|
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()
|
2024-08-25 13:21:02 +08:00
|
|
|
|
c.execute("INSERT INTO faces (name, identity, image_path, encoding) VALUES (?, ?, ?, ?)",
|
2024-08-28 09:34:15 +08:00
|
|
|
|
(name, identity, relative_image_path, encoding_blob))
|
2024-08-22 16:30:26 +08:00
|
|
|
|
conn.commit()
|
|
|
|
|
conn.close()
|
|
|
|
|
|
2024-08-28 09:34:15 +08:00
|
|
|
|
|
|
|
|
|
|
2024-08-25 11:36:23 +08:00
|
|
|
|
def match_faces(captured_images, db_name="face_database.db", tolerance=0.4, log_file="match_log.txt"):
|
2024-08-25 13:21:02 +08:00
|
|
|
|
"""比对抓拍的图片与数据库中的已知人脸"""
|
2024-08-22 16:30:26 +08:00
|
|
|
|
conn = sqlite3.connect(db_name)
|
|
|
|
|
c = conn.cursor()
|
|
|
|
|
|
2024-08-28 09:34:15 +08:00
|
|
|
|
c.execute("SELECT name, identity, image_path, encoding FROM faces")
|
2024-08-23 09:12:01 +08:00
|
|
|
|
known_faces = c.fetchall()
|
2024-08-22 16:30:26 +08:00
|
|
|
|
|
2024-08-23 09:12:01 +08:00
|
|
|
|
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:
|
2024-08-25 13:21:02 +08:00
|
|
|
|
print(f"没有检测到人脸:{image_path}")
|
|
|
|
|
continue
|
2024-08-23 09:12:01 +08:00
|
|
|
|
|
|
|
|
|
unknown_encoding = face_encodings[0]
|
|
|
|
|
|
2024-08-28 09:34:15 +08:00
|
|
|
|
for name, identity, db_image_path, encoding_blob in known_faces:
|
2024-08-23 09:12:01 +08:00
|
|
|
|
known_encoding = np.frombuffer(encoding_blob, dtype=np.float64)
|
|
|
|
|
match = face_recognition.compare_faces([known_encoding], unknown_encoding, tolerance=tolerance)
|
2024-08-22 16:30:26 +08:00
|
|
|
|
|
2024-08-25 13:21:02 +08:00
|
|
|
|
if match[0]:
|
|
|
|
|
print(f"匹配成功: {name} ({identity}) 在 {image_path}")
|
2024-08-28 09:34:15 +08:00
|
|
|
|
log_match(name, identity, db_image_path, db_name, log_file) # 使用数据库中的 image_path
|
|
|
|
|
# 不更新数据库中的 image_path,因为我们只在匹配时使用它
|
2024-08-25 13:21:02 +08:00
|
|
|
|
conn.commit()
|
2024-08-23 09:12:01 +08:00
|
|
|
|
conn.close()
|
2024-08-25 13:21:02 +08:00
|
|
|
|
return True
|
|
|
|
|
|
|
|
|
|
print(f"未发现匹配: 在 {image_path} 中的任何已知人脸")
|
|
|
|
|
|
|
|
|
|
conn.close()
|
|
|
|
|
return False
|
|
|
|
|
|
|
|
|
|
|
2024-08-28 09:34:15 +08:00
|
|
|
|
|
|
|
|
|
def log_match(name, identity, db_image_path, db_name, log_file):
|
|
|
|
|
"""记录匹配结果,将数据库中的图片路径和匹配时间添加到匹配记录表单中"""
|
2024-08-25 13:21:02 +08:00
|
|
|
|
conn = sqlite3.connect(db_name)
|
|
|
|
|
c = conn.cursor()
|
2024-08-28 09:34:15 +08:00
|
|
|
|
|
|
|
|
|
# 记录到日志文件
|
|
|
|
|
with open(log_file, 'a') as log:
|
|
|
|
|
log.write(f"{name},{identity},{db_image_path}\n")
|
|
|
|
|
|
|
|
|
|
# 将匹配信息插入到匹配日志表
|
2024-08-25 13:21:02 +08:00
|
|
|
|
c.execute("INSERT INTO match_logs (name, identity, image_path, match_time) VALUES (?, ?, ?, ?)",
|
2024-08-28 09:34:15 +08:00
|
|
|
|
(name, identity, db_image_path, datetime.now().strftime("%Y-%m-%d %H:%M:%S")))
|
|
|
|
|
|
2024-08-25 13:21:02 +08:00
|
|
|
|
conn.commit()
|
2024-08-23 09:12:01 +08:00
|
|
|
|
conn.close()
|
2024-08-22 16:30:26 +08:00
|
|
|
|
|
2024-08-28 09:34:15 +08:00
|
|
|
|
|
2024-08-22 16:30:26 +08:00
|
|
|
|
# 创建人脸数据库
|
|
|
|
|
create_face_database()
|
|
|
|
|
|
|
|
|
|
# 向数据库中添加人脸
|
2024-08-28 09:34:15 +08:00
|
|
|
|
add_face_to_database("李四", "居民", "./static/db_image/test1.jpg")
|
|
|
|
|
add_face_to_database("张三", "居民", "./static/db_image/test2.jpg")
|
|
|
|
|
add_face_to_database("王五", "居民", "./static/db_image/test3.jpg")
|
2024-08-25 11:36:23 +08:00
|
|
|
|
|
|
|
|
|
# 主程序循环
|
|
|
|
|
while True:
|
|
|
|
|
ret, frame = cap.read()
|
|
|
|
|
if not ret:
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
rgb_frame = frame[:, :, ::-1]
|
|
|
|
|
face_locations = face_recognition.face_locations(rgb_frame)
|
2024-08-23 09:12:01 +08:00
|
|
|
|
|
2024-08-25 11:36:23 +08:00
|
|
|
|
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:
|
|
|
|
|
top, right, bottom, left = face_location
|
|
|
|
|
cv2.rectangle(frame, (left, top), (right, bottom), (0, 255, 0), 2)
|
|
|
|
|
|
|
|
|
|
face_image = frame[top:bottom, left:right]
|
|
|
|
|
image_path = os.path.join(save_path, f"face_{photo_count + 1}.jpg")
|
|
|
|
|
cv2.imwrite(image_path, face_image)
|
|
|
|
|
captured_images.append(image_path)
|
|
|
|
|
|
|
|
|
|
photo_count += 1
|
|
|
|
|
if photo_count >= max_photos:
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
cv2.imshow("Capturing Faces", frame)
|
|
|
|
|
if cv2.waitKey(1) & 0xFF == ord('q'):
|
|
|
|
|
break
|
|
|
|
|
|
|
|
|
|
cv2.destroyAllWindows()
|
|
|
|
|
|
|
|
|
|
if match_faces(captured_images):
|
2024-08-25 13:21:02 +08:00
|
|
|
|
print("匹配成功")
|
2024-08-25 11:36:23 +08:00
|
|
|
|
else:
|
|
|
|
|
print("没有匹配")
|
|
|
|
|
|
|
|
|
|
print("等待30秒后继续...")
|
|
|
|
|
time.sleep(30)
|
|
|
|
|
|
|
|
|
|
cap.release()
|