photo/functions.py

244 lines
7.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import piexif
from PIL import Image
import face_recognition
from datetime import datetime
from models import db, User, Photo
from werkzeug.utils import secure_filename
import os
import numpy as np
def process_face_encoding(photo_path):
"""提取人脸特征编码并裁剪出最大的面部区域"""
# 加载图片
image = face_recognition.load_image_file(photo_path)
# 获取所有人脸的位置
face_locations = face_recognition.face_locations(image)
if not face_locations:
return None # 没有检测到人脸
# 找到最大的人脸
largest_face = max(face_locations, key=lambda x: (x[2] - x[0]) * (x[3] - x[1])) # 按照面积选取最大的人脸
# 获取该人脸的特征编码
face_encodings = face_recognition.face_encodings(image, [largest_face])
if face_encodings:
# 裁剪出最大的人脸部分
top, right, bottom, left = largest_face
image_pil = Image.open(photo_path)
cropped_face = image_pil.crop((left, top, right, bottom))
# 保存裁剪后的图像(可选)
cropped_face_path = photo_path.replace(".jpg", "_cropped.jpg")
cropped_face.save(cropped_face_path)
return face_encodings[0], cropped_face_path # 返回面部编码和裁剪后的人脸图片路径
return None # 如果没有提取到人脸特征编码
def add_user(username, userphoto):
"""添加用户并存储人脸特征"""
if userphoto:
filename = secure_filename(userphoto.filename)
user_dir = os.path.join("static/uploads/users",username)
user_dir =user_dir.replace("\\","/")
os.makedirs(user_dir, exist_ok=True)
photo_path = os.path.join(user_dir,"photo.jpg")
photo_path = photo_path.replace("\\","/")
# 保存头像
userphoto.save(photo_path)
# 处理人脸特征
face_encoding = process_face_encoding(photo_path)
if face_encoding is None:
print("未检测到人脸,无法添加用户")
return False
# 存储到数据库
new_user = User(username=username, encoding=face_encoding, photo=photo_path)
db.session.add(new_user)
db.session.commit()
return True
return False
# 删除用户
def delete_user(user_id):
try:
user = User.query.get(user_id)
if user:
db.session.delete(user)
db.session.commit()
return True
return False
except Exception as e:
print(e)
return False
# 编辑用户
def edit_user(user_id, username, userphoto):
try:
user = User.query.get(user_id)
if user:
user.username = username
if userphoto:
photo_path = os.path.join('static', 'uploads', 'users', str(user.id))
os.makedirs(photo_path, exist_ok=True)
photo_file = os.path.join(photo_path, userphoto.filename)
userphoto.save(photo_file)
# 更新照片路径
photo = Photo.query.filter_by(user_id=user.id).first()
photo.photo_path = photo_file
db.session.commit()
return True
return False
except Exception as e:
print(e)
return False
# 获取用户
def get_user(user_id):
return User.query.get(user_id)
def save_temp_photo(photo):
"""保存临时照片"""
temp_dir = 'static/uploads/temp'
os.makedirs(temp_dir, exist_ok=True)
photo_path = os.path.join(temp_dir, photo.filename).replace("\\", "/")
photo.save(photo_path)
return photo_path
def get_largest_face(image_path):
"""检测并裁剪最大的人脸"""
image = face_recognition.load_image_file(image_path)
face_locations = face_recognition.face_locations(image)
if not face_locations:
return None # 没有检测到人脸
# 找到最大的人脸
largest_face = max(face_locations, key=lambda loc: (loc[2] - loc[0]) * (loc[3] - loc[1]))
top, right, bottom, left = largest_face
# 裁剪最大的人脸
with Image.open(image_path) as img:
face_img = img.crop((left, top, right, bottom))
face_crop_path = image_path.replace(".jpg", "_face.jpg") # 生成裁剪后的人脸图片路径
face_img.save(face_crop_path)
return face_crop_path
def match_face(face_path):
"""匹配人脸并返回匹配的用户"""
face_image = face_recognition.load_image_file(face_path)
face_encodings = face_recognition.face_encodings(face_image)
if not face_encodings:
return None # 未检测到人脸
face_encoding = face_encodings[0] # 取第一张脸
users = User.query.all()
for user in users:
if user.encoding:
user_encoding = np.array(user.encoding) # 从数据库中获取存储的编码
match = face_recognition.compare_faces([user_encoding], face_encoding, tolerance=0.35)
if match[0]:
return user # 匹配成功
return None # 未找到匹配
def get_exif_time(photo_path):
"""提取 EXIF 时间"""
try:
with Image.open(photo_path) as img:
exif_data = img._getexif()
if exif_data:
timestamp = exif_data.get(36867, None) # 36867 为 EXIF 拍摄时间
return timestamp if timestamp else datetime.now().strftime("%Y-%m-%d %H:%M:%S")
except Exception as e:
print(f"无法提取 EXIF 时间: {e}")
return datetime.now().strftime("%Y-%m-%d %H:%M:%S")
def save_classified_photo(photo, user, timestamp):
"""保存分类后的照片"""
user_dir = os.path.join('static/uploads/users', str(user.id), timestamp)
os.makedirs(user_dir, exist_ok=True)
new_photo_path = os.path.join(user_dir, photo.filename)
try:
with Image.open(photo) as img:
img.save(new_photo_path, quality=95)
except Exception as e:
print(f"保存图片时出错: {e}")
# 保存到数据库
photo_record = Photo(user_id=user.id, created_at=timestamp, classification=True,
classification_image_path=new_photo_path)
db.session.add(photo_record)
db.session.commit()
print(f"照片 {photo.filename} 已保存至 {new_photo_path}")
def classify_photos(photos):
"""处理上传的照片"""
for photo in photos:
temp_photo_path = save_temp_photo(photo)
cropped_face_path = get_largest_face(temp_photo_path)
if not cropped_face_path:
print(f"没有检测到人脸:{photo.filename}")
continue
matched_user = match_face(cropped_face_path)
timestamp = get_exif_time(temp_photo_path)
if matched_user:
save_classified_photo(photo, matched_user, timestamp)
else:
print(f"没有找到匹配的人脸:{photo.filename}")
# 根据姓名和时间查找照片
def search_photos(name, date):
user = User.query.filter_by(username=name).first()
if not user:
return []
photos = Photo.query.filter_by(user_id=user.id).all()
filtered_photos = []
for photo in photos:
# 过滤日期
exif_data = piexif.load(photo.photo_path)
date_taken = exif_data.get(piexif.ExifIFD.DateTimeOriginal, b"").decode("utf-8")
if date_taken and date in date_taken:
filtered_photos.append(photo)
return filtered_photos
def find_match(image_path, known_face_encodings):
# 加载图片
unknown_image = face_recognition.load_image_file(image_path)
# 获取图片中的人脸特征编码
unknown_face_encoding = face_recognition.face_encodings(unknown_image)
if unknown_face_encoding:
unknown_face_encoding = unknown_face_encoding[0]
# 设置一个匹配的阈值例如0.6,值越低匹配越宽松
matches = face_recognition.compare_faces(known_face_encodings, unknown_face_encoding, tolerance=0.6)
if True in matches:
match_index = matches.index(True)
return match_index
return None