更改部分bug加入人脸识别锁机制

This commit is contained in:
冯佳
2025-09-15 11:37:37 +08:00
parent f12a289c57
commit babab70845
6 changed files with 183 additions and 51 deletions

View File

@ -1,7 +1,7 @@
# This Python file uses the following encoding: utf-8
import sys
import time
from PyQt5.QtWidgets import QFileDialog
from PyQt5.QtWidgets import QFileDialog,QHeaderView
from PyQt5.QtWidgets import QApplication, QMainWindow, QStackedWidget, QWidget, QLayout, QLabel, QLineEdit, QPushButton, QMessageBox, QShortcut, QDialog,QTextEdit
from PyQt5 import uic
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QObject, QRunnable, QMutex, QTimer, QEvent
@ -455,8 +455,18 @@ class QFaceCameraViewPage(PageTemplate):
self.face_verify_result = None # 用于存储人脸验证结果
self.auto_connect_serial()
# 串口管理
self.refresh()
header = self.table.horizontalHeader()
# 用户ID列固定宽度
self.table.setColumnWidth(0, 100)
# 用户名列自适应内容
header.setSectionResizeMode(1, QHeaderView.ResizeToContents)
# 注册时间列填充剩余空间
header.setSectionResizeMode(2, QHeaderView.Stretch)
# 串口管理
def auto_connect_serial(self):
ports = [p.device for p in serial.tools.list_ports.comports()]
if not ports:
@ -540,15 +550,15 @@ class QFaceCameraViewPage(PageTemplate):
if msg_id == MID_REPLY:
info = parse_reply(data)
self.log(f"[REPLY] {info}")
if info.get("mid") in (CMD_ENROLL, CMD_ENROLL_ITG) and info.get("result") == 0x00:
if info.get("mid") == CMD_ENROLL_ITG:
if info.get("result") == 0x00:
user_id = info.get("user_id")
# 如果用户名为空使用用户ID作为用户名
user_name = self.last_enroll_name if self.last_enroll_name else str(user_id)
if user_id: # 只需检查user_id存在即可因为user_name已确保有值
if save_user(user_id, user_name):
self.log(f"[INFO] 用户 {user_name}(ID={user_id}) 已保存")
if user_id:
if save_user(user_id):
self.log(f"[INFO] 用户ID={user_id} 已保存")
else:
QMessageBox.warning(self, "提示", f"用户ID {user_id} 已存在!")
inform_box : DialogInform = DialogInform()
inform_box.information("提示", f"用户ID {user_id} 已存在!")
elif info.get("mid") == CMD_VERIFY :
if info.get("result") == 0x00:
@ -762,6 +772,8 @@ class APPWindow(QMainWindow):
# self.setGeometry(0, 0, 1024, 768)
# self.stack.setGeometry(0, 0, 1024, 768)
QFaceCameraViewPage.video_worker = None
QFaceCameraViewPage.ser = None
self.showFullScreen()
@ -875,10 +887,10 @@ class APPWindow(QMainWindow):
for camera_thread in self.camera_thread_list:
thread_to_stop : CameraThread = camera_thread
if self.video_worker and self.video_worker.isRunning():
self.video_worker.stop()
self.video_worker.wait(300)
if self.ser and getattr(self.ser,"is_open",False):
if QFaceCameraViewPage.video_worker and QFaceCameraViewPage.video_worker.isRunning():
QFaceCameraViewPage.video_worker.stop()
QFaceCameraViewPage.video_worker.wait(300)
if QFaceCameraViewPage.ser and getattr(QFaceCameraViewPage.ser,"is_open",False):
self.close_serial()
if thread_to_stop != None :
thread_to_stop.close()

View File

@ -93,7 +93,7 @@ color: rgb(207, 0, 13);</string>
</rect>
</property>
<property name="statusTip">
<string>SwitchOn,Index=2,Action=CmdExecute, SelectImag=SR_001.png, groupstart=6</string>
<string>SwitchOn,Index=2,Action=CmdExecute, SelectImag=SR_001.png, password,groupstart=6</string>
</property>
<property name="text">
<string/>
@ -115,7 +115,7 @@ color: rgb(207, 0, 13);</string>
</rect>
</property>
<property name="statusTip">
<string>SwitchOff,Index=3,Action=CmdExecute, SelectImag=SR_001.png</string>
<string>SwitchOff,Index=3,Action=CmdExecute, password,SelectImag=SR_001.png</string>
</property>
<property name="text">
<string/>
@ -218,7 +218,7 @@ color: rgb(207, 0, 13);</string>
</rect>
</property>
<property name="statusTip">
<string>SwitchOff,Index=4,Action=CmdExecute, SelectImag=SR_001.png</string>
<string>SwitchOff,Index=4,Action=CmdExecute, password,SelectImag=SR_001.png</string>
</property>
<property name="text">
<string/>

View File

@ -334,6 +334,22 @@ color: rgb(177, 229, 252);</string>
<string>人脸框</string>
</property>
</widget>
<widget class="QPushButton" name="btn_delete_user_id">
<property name="geometry">
<rect>
<x>10</x>
<y>240</y>
<width>80</width>
<height>23</height>
</rect>
</property>
<property name="statusTip">
<string>Index=0, Action=DeleteUser,SelectImag=IMxx_00F.png</string>
</property>
<property name="text">
<string>删除用户</string>
</property>
</widget>
</widget>
<widget class="QLabel" name="P05_01BG">
<property name="geometry">
@ -351,11 +367,40 @@ color: rgb(177, 229, 252);</string>
<pixmap>../image/FaceCameraView.png</pixmap>
</property>
</widget>
<widget class="QTableWidget" name="table">
<property name="geometry">
<rect>
<x>1080</x>
<y>520</y>
<width>821</width>
<height>371</height>
</rect>
</property>
<property name="styleSheet">
<string notr="true">background-color: rgb(255, 255, 255);</string>
</property>
<column>
<property name="text">
<string>用户ID</string>
</property>
</column>
<column>
<property name="text">
<string>用户名</string>
</property>
</column>
<column>
<property name="text">
<string>注册时间</string>
</property>
</column>
</widget>
<zorder>P05_01BG</zorder>
<zorder>groupBox_sys</zorder>
<zorder>group_log</zorder>
<zorder>group_video</zorder>
<zorder>group_cmd</zorder>
<zorder>table</zorder>
</widget>
</widget>
<resources/>

View File

@ -2,6 +2,7 @@
import sys
import os
import time
import csv
import inspect
import cv2
import json
@ -10,7 +11,7 @@ from PyQt5 import uic
from PyQt5.QtGui import QImage, QPixmap, QColor,QBrush, QKeySequence, QIcon, QPalette
from PyQt5.QtCore import Qt, QThread, pyqtSignal, QObject, QRunnable, QMutex, QTimer, QEvent, QSize, QDateTime
from PyQt5.QtWidgets import QApplication, QMainWindow, QVBoxLayout, QFrame, QWidget, QLayout, QLabel
from PyQt5.QtWidgets import QLineEdit, QPushButton, QMessageBox, QShortcut, QDialog
from PyQt5.QtWidgets import QLineEdit, QPushButton, QMessageBox, QShortcut, QDialog,QTableWidgetItem
sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
from Shared_CODE.CameraThread import CameraThread
import menu_utils as utils
@ -22,7 +23,7 @@ from Shared_CODE.DialogModifyText import DialogModifyText
from Shared_CODE.DialogInform import DialogInform
from QT5_Project.Shared_CODE.FaceRecognitionProtocol import parse_reply
from QT5_Project.Shared_CODE.DialogFaceEnrollItgSingle import EnrollItgSingleDialog
from QT5_Project.Shared_CODE.DialogFaceUserManage import UserManageDialog
from QT5_Project.Shared_CODE.DialogFaceUserManage import UserManageDialog, load_users, save_user, save_users_list, CSV_FILE
from Shared_CODE.get_tip_prop import *
from print_color import *
@ -801,6 +802,8 @@ class UIFrameWork(QMainWindow, class_comm_mqtt_interface):
print("密码认证成功")
elif choice == "face":
# 初始化锁标志
self._face_verify_locked = True # 开始验证时锁定
# 人脸认证异步处理
face_frame = self.parent_window.P05_01_FaceCameraView
face_frame.face_verify_result = None # 重置标志位
@ -809,6 +812,12 @@ class UIFrameWork(QMainWindow, class_comm_mqtt_interface):
timeout = system_parameter().get_verify_timeout()
start_time = time.time()
# 停止并删除旧定时器
if hasattr(self, "_face_verify_timer"):
if self._face_verify_timer.isActive():
self._face_verify_timer.stop()
self._face_verify_timer.deleteLater()
# 创建定时器轮询标志位
self._face_verify_timer = QTimer(self)
self._face_verify_timer.setInterval(50) # 每50ms检查一次
@ -817,6 +826,7 @@ class UIFrameWork(QMainWindow, class_comm_mqtt_interface):
nonlocal input
if face_frame.face_verify_result is not None:
self._face_verify_timer.stop()
self._face_verify_locked = False # 解锁
if face_frame.face_verify_result:
input = True
inform_box = DialogInform()
@ -828,10 +838,15 @@ class UIFrameWork(QMainWindow, class_comm_mqtt_interface):
inform_box.information("提示", "人脸认证失败")
elif time.time() - start_time > timeout:
self._face_verify_timer.stop()
self._face_verify_locked = False # 解锁
input = False
inform_box = DialogInform()
inform_box.information("提示", "人脸认证超时")
# 解绑旧槽,绑定新槽
try:
self._face_verify_timer.timeout.disconnect()
except Exception:
pass
self._face_verify_timer.timeout.connect(check_face_result)
self._face_verify_timer.start()
return # 异步处理,直接返回
@ -876,6 +891,11 @@ class UIFrameWork(QMainWindow, class_comm_mqtt_interface):
elif "FaceBox" in action_str:
self.toggle_face_box()
elif "DeleteUser" in action_str:
self.delete_user_by_id()
elif "UserCount" in action_str:
self.query_user_count()
self.virtual_widget_action_process(select_object, action_str)
@ -919,6 +939,12 @@ class UIFrameWork(QMainWindow, class_comm_mqtt_interface):
elif "FaceBox" in action_str:
self.toggle_face_box()
elif "DeleteUser" in action_str:
self.delete_user_by_id()
elif "UserCount" in action_str:
self.query_user_count()
self.virtual_widget_action_process(select_object, action_str)
def search_menu_match_object(self, object) :
@ -936,7 +962,8 @@ class UIFrameWork(QMainWindow, class_comm_mqtt_interface):
def do_verify(self):
pd_val = 0
timeout_val = system_parameter().get_verify_timeout()
self.send(build_verify(pd_val, timeout_val))
face_send = self.parent_window.P05_01_FaceCameraView
face_send.send(build_verify(pd_val, timeout_val))
def do_enroll_itg_single(self):
@ -1019,6 +1046,69 @@ class UIFrameWork(QMainWindow, class_comm_mqtt_interface):
else:
self.log("[WARN] 串口未连接,无法控制人脸框")
def delete_user_by_id(self, CSV_FILE = CSV_FILE):
users = load_users()
# 弹出对话框选择用户ID
dialog_modify_text = DialogModifyValue(self)
caption_str = "选择用户ID删除"
dialog_modify_text.update_modify_info("", 0, caption_str)
if dialog_modify_text.exec() != QDialog.Accepted:
return
# 获取用户输入的ID并转换为整数
try:
user_id = int(dialog_modify_text.value)
except ValueError:
DialogInform(self).information("提示", "请输入有效数字ID")
return
# 查找用户
user = next((u for u in users if u["user_id"] == user_id), None)
if not user:
DialogInform(self).information("提示", "用户不存在")
return
try:
# 1⃣ 下发删除命令
self.send(build_delete_user(user_id))
# 2⃣ 删除 CSV 文件对应行
if os.path.exists(CSV_FILE):
with open(CSV_FILE, "r", encoding="utf-8", newline="") as f:
reader = csv.DictReader(f)
fieldnames = reader.fieldnames
new_rows = [row for row in reader if str(row.get("user_id")) != str(user_id)]
with open(CSV_FILE, "w", encoding="utf-8", newline="") as f:
writer = csv.DictWriter(f, fieldnames=fieldnames)
writer.writeheader()
writer.writerows(new_rows)
except Exception as e:
DialogInform(self).information("提示", f"删除失败: {e}")
return
# 3⃣ 更新内存用户列表
users = [u for u in users if u["user_id"] != user_id]
save_users_list(users)
# 4⃣ 提示删除成功
DialogInform(self).information("提示", f"用户 {user.get('user_name', '')} (ID={user_id}) 已删除")
def query_user_count(self):
self.send(build_get_all_userid())
def refresh(self):
users = load_users()
self.table.setRowCount(len(users))
for r, u in enumerate(users):
self.table.setItem(r, 0, QTableWidgetItem(str(u.get("user_id", ""))))
self.table.setItem(r, 1, QTableWidgetItem(u.get("user_name", "")))
self.table.setItem(r, 2, QTableWidgetItem(u.get("created_at", "")))
################################################################################
#刷新屏幕上的系统信息, 例如时间日期之类

View File

@ -57,24 +57,23 @@ def save_users_list(users):
w.writerow([u.get("user_id", ""), u.get("user_name", ""), u.get("created_at", "")])
def save_user(user_id: int, user_name: str) -> bool:
def save_user(user_id: int) -> bool:
users = load_users()
for u in users:
if str(u["user_id"]) == str(user_id):
return False
created_at = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")
users.append({"user_id": str(user_id), "user_name": user_name, "created_at": created_at})
users.append({"user_id": str(user_id), "user_name": str(user_id), "created_at": created_at})
save_users_list(users)
return True
class UserManageDialog(QDialog):
def __init__(self, parent=None, send_func=None):
super().__init__(parent)
self.send_func = send_func
uic.loadUi(users_ui_file_path, self)
self.btn_delete.clicked.connect(self.delete_selected)
self.btn_refresh.clicked.connect(self.refresh)
self.btn_get.clicked.connect(self.get_from_device)
self.btn_del_all.clicked.connect(self.delete_all_users)
self.refresh()
@ -114,22 +113,6 @@ class UserManageDialog(QDialog):
self.table.setItem(r, 1, QTableWidgetItem(u.get("user_name", "")))
self.table.setItem(r, 2, QTableWidgetItem(u.get("created_at", "")))
def delete_selected(self):
row = self.table.currentRow()
if row < 0:
QMessageBox.warning(self, "提示", "删除选择用户")
return
uid = self.table.item(row, 0).text()
uname = self.table.item(row, 1).text()
try:
uid_int = int(uid)
self.send_func(build_delete_user(uid_int))
except:
pass
users = [u for u in load_users() if str(u["user_id"]) != uid]
save_users_list(users)
self.refresh()
QMessageBox.information(self, "提示", f"用户 {uname}(ID={uid}) 已删除")
def get_from_device(self):
self.send_func(build_get_all_userid())

View File

@ -1 +1,3 @@
1,1,2025-09-13 10:06:01
1,1,2025-09-15 10:48:28
2,2,2025-09-15 10:56:46
3,3,2025-09-15 11:00:04

1 1 1 2025-09-13 10:06:01 2025-09-15 10:48:28
2 2 2 2025-09-15 10:56:46
3 3 3 2025-09-15 11:00:04