File size: 7,831 Bytes
22c0f65 1fa526d 22c0f65 1fa526d 22c0f65 1fa526d 22c0f65 1fa526d 22c0f65 | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 | from flask import Flask, request, jsonify
from flask_cors import CORS
import base64
import secrets
from deepface import DeepFace
import cv2
import numpy as np
from pymongo import MongoClient
app = Flask(__name__)
CORS(app)
# ========================
# KẾT NỐI MONGODB
# ========================
mongo_uri = "mongodb+srv://huyh01480_db_user:zxvAwzAhr8yk3lWe@cluster0.n8pboqq.mongodb.net/?retryWrites=true&w=majority&appName=Cluster0"
client = MongoClient(mongo_uri)
db = client["userdb"] # database
users_col = db["users"] # collection tương đương bảng user
# ========================
# REGISTER USER
# ========================
from deepface import DeepFace
import cv2
import numpy as np
import base64
@app.route('/api/register', methods=['POST'])
def register():
data = request.json
username = data.get('username')
password = data.get('password')
img_data = data.get('img')
fullName = data.get('fullName')
email = data.get('email')
phone = data.get('phone')
gender = data.get('gender')
# Kiểm tra dữ liệu bắt buộc
if not username or not password or not img_data:
return jsonify({'error': 'username, password và ảnh là bắt buộc'}), 400
img_str = img_data.split(",")[1] if "," in img_data else img_data
# Kiểm tra Base64 hợp lệ
try:
decoded = base64.b64decode(img_str)
except Exception:
return jsonify({'error': 'Ảnh không hợp lệ, phải là Base64'}), 400
# Chuyển base64 → ảnh OpenCV
try:
nparr = np.frombuffer(decoded, np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
if img is None:
return jsonify({'error': 'Ảnh không thể đọc được'}), 400
except Exception:
return jsonify({'error': 'Không thể xử lý ảnh'}), 400
# ===== KIỂM TRA ẢNH CÓ MẶT KHÔNG =====
try:
DeepFace.extract_faces(img, enforce_detection=True)
except Exception:
return jsonify({'error': 'Ảnh không có khuôn mặt hợp lệ'}), 400
try:
# Kiểm tra username trùng
existing_user = users_col.find_one({"userName": username})
if existing_user:
return jsonify({'error': 'Tên người dùng đã tồn tại'}), 409
# Dữ liệu người dùng chỉ gồm các trường yêu cầu
user_info = {
"userName": username,
"password": password,
"img": img_str,
"fullName": fullName,
"email": email,
"phone": phone,
"gender": gender,
}
# Lưu vào MongoDB
users_col.insert_one(user_info)
return jsonify({'message': 'Đăng ký thành công!', 'user': username}), 201
except Exception as e:
return jsonify({'error': str(e)}), 500
# LOGIN + KIỂM TRA KHUÔN MẶT
# ========================
@app.route('/api/login', methods=['POST'])
def login():
data = request.json
username = data.get('username')
password = data.get('password')
img_data = data.get('img')
if not username or not password or not img_data:
return jsonify({'error': 'username, password và ảnh là bắt buộc'}), 400
img_str = img_data.split(",")[1] if "," in img_data else img_data
try:
# Lấy user từ MongoDB
user = users_col.find_one({"userName": username, "password": password})
if not user:
return jsonify({'error': 'Username hoặc password sai'}), 401
# Base64 → ảnh
nparr_input = np.frombuffer(base64.b64decode(img_str), np.uint8)
img_input = cv2.imdecode(nparr_input, cv2.IMREAD_COLOR)
nparr_db = np.frombuffer(base64.b64decode(user['img']), np.uint8)
img_db = cv2.imdecode(nparr_db, cv2.IMREAD_COLOR)
# So sánh mặt
try:
result = DeepFace.verify(img_input, img_db, enforce_detection=True)
except Exception as e:
return jsonify({'error': f'Lỗi khi nhận diện khuôn mặt: {e}'}), 400
# Tính %
distance = result.get("distance", 1)
similarity = max(0, (1 - distance)) * 100
similarity = round(similarity, 2)
if result['verified']:
token = secrets.token_hex(16)
# Xóa _id vì không serializable
user_info = {
"userName": user.get("userName"),
"fullName": user.get("fullName"),
"email": user.get("email"),
"phone": user.get("phone"),
"gender": user.get("gender"),
"img": user.get("img")
}
return jsonify({
'message': 'Login thành công!',
'token': token,
'similarity': similarity,
'user': user_info
})
else:
return jsonify({
'error': 'Khuôn mặt không trùng khớp',
'similarity': similarity
}), 401
except Exception as e:
return jsonify({'error': str(e)}), 500
# ========================
# PHÂN TÍCH KHUÔN MẶT
# ========================
def convert_numpy(obj):
if isinstance(obj, dict):
return {k: convert_numpy(v) for k, v in obj.items()}
elif isinstance(obj, list):
return [convert_numpy(i) for i in obj]
elif isinstance(obj, (np.float32, np.float64)):
return float(obj)
elif isinstance(obj, (np.int32, np.int64)):
return int(obj)
else:
return obj
@app.route('/api/analyze', methods=['POST'])
def analyze_face():
data = request.json
img_data = data.get('img')
if not img_data:
return jsonify({'error': 'Ảnh là bắt buộc'}), 400
img_str = img_data.split(",")[1] if "," in img_data else img_data
try:
nparr = np.frombuffer(base64.b64decode(img_str), np.uint8)
img = cv2.imdecode(nparr, cv2.IMREAD_COLOR)
result = DeepFace.analyze(img, actions=['age','gender','emotion','race'], enforce_detection=True)
result = convert_numpy(result)
return jsonify({'result': result})
except Exception as e:
return jsonify({'error': f'Lỗi khi phân tích khuôn mặt: {e}'}), 400
@app.route('/api/compare', methods=['POST'])
def compare_faces():
data = request.json
img1_data = data.get("img1")
img2_data = data.get("img2")
if not img1_data or not img2_data:
return jsonify({'error': 'Cần 2 ảnh base64 để so sánh'}), 400
# Tách phần base64 (nếu có prefix data:image/png;base64,)
img1_str = img1_data.split(",")[1] if "," in img1_data else img1_data
img2_str = img2_data.split(",")[1] if "," in img2_data else img2_data
try:
# Base64 → OpenCV image
nparr1 = np.frombuffer(base64.b64decode(img1_str), np.uint8)
img1 = cv2.imdecode(nparr1, cv2.IMREAD_COLOR)
nparr2 = np.frombuffer(base64.b64decode(img2_str), np.uint8)
img2 = cv2.imdecode(nparr2, cv2.IMREAD_COLOR)
# So sánh khuôn mặt bằng DeepFace
try:
result = DeepFace.verify(img1, img2, enforce_detection=True)
except Exception as e:
return jsonify({'error': f'Lỗi nhận diện: {e}'}), 400
# Tính phần trăm giống nhau
distance = result.get("distance", 1)
similarity = max(0, (1 - distance)) * 100
similarity = round(similarity, 2)
return jsonify({
"verified": result.get("verified", False),
"distance": distance,
"similarity": similarity
})
except Exception as e:
return jsonify({'error': str(e)}), 500
# ========================
# RUN
# ========================
if __name__ == '__main__':
app.run(debug=True)
|