autoCloseScreen/workspace_monitor.py

437 lines
17 KiB
Python
Raw Normal View History

2024-12-04 03:53:38 +00:00
import cv2
import time
import ctypes
import sys
import traceback
import logging
import os
from datetime import datetime
2024-12-04 07:53:07 +00:00
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
2024-12-04 03:53:38 +00:00
QHBoxLayout, QPushButton, QLabel, QSpinBox,
2024-12-04 07:53:07 +00:00
QStyle, QProgressBar, QSystemTrayIcon, QMenu, QMessageBox)
from PyQt5.QtCore import Qt, QTimer
from PyQt5.QtGui import QImage, QPixmap, QIcon, QFont
2024-12-04 03:53:38 +00:00
# 设置日志
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s',
handlers=[
logging.FileHandler('app.log'),
logging.StreamHandler()
]
)
logger = logging.getLogger(__name__)
def handle_exception(exc_type, exc_value, exc_traceback):
logger.error("Uncaught exception", exc_info=(exc_type, exc_value, exc_traceback))
sys.__excepthook__(exc_type, exc_value, exc_traceback)
sys.excepthook = handle_exception
try:
logger.info("Starting application...")
class WorkspaceMonitor(QMainWindow):
def __init__(self):
try:
super().__init__()
logger.info("Initializing WorkspaceMonitor...")
2024-12-04 07:40:25 +00:00
self.setWindowTitle("工位监控系统")
2024-12-04 03:53:38 +00:00
self.setMinimumSize(1000, 700)
# 系统托盘
self.tray_icon = QSystemTrayIcon(self)
2024-12-04 07:53:07 +00:00
self.tray_icon.setIcon(self.style().standardIcon(QStyle.SP_ComputerIcon))
2024-12-04 03:53:38 +00:00
self.create_tray_menu()
self.tray_icon.show()
# 初始化变量
self.running = False
self.timeout = 10
2024-12-04 07:40:25 +00:00
logger.info("Loading face detection model...")
# 使用OpenCV的人脸检测器
self.face_cascade = cv2.CascadeClassifier(cv2.data.haarcascades + 'haarcascade_frontalface_default.xml')
if self.face_cascade.empty():
raise Exception("无法加载人脸检测模型")
2024-12-04 03:53:38 +00:00
logger.info("Opening camera...")
self.cap = cv2.VideoCapture(0)
if not self.cap.isOpened():
logger.error("Failed to open camera!")
raise Exception("无法打开摄像头")
self.last_face_time = time.time()
self.no_face_duration = 0
self.setup_ui()
logger.info("Initialization complete.")
except Exception as e:
logger.error(f"Error in WorkspaceMonitor initialization: {str(e)}")
logger.error(traceback.format_exc())
raise
def setup_ui(self):
central_widget = QWidget()
self.setCentralWidget(central_widget)
main_layout = QVBoxLayout(central_widget)
# 标题
2024-12-04 07:40:25 +00:00
title_label = QLabel("工位监控系统")
2024-12-04 07:53:07 +00:00
title_label.setFont(QFont('Arial', 16, QFont.Bold))
title_label.setAlignment(Qt.AlignCenter)
2024-12-04 03:53:38 +00:00
main_layout.addWidget(title_label)
# 摄像头预览
preview_container = QWidget()
preview_container.setStyleSheet("background-color: #f0f0f0; border-radius: 10px;")
preview_layout = QVBoxLayout(preview_container)
self.camera_label = QLabel()
2024-12-04 07:53:07 +00:00
self.camera_label.setAlignment(Qt.AlignCenter)
2024-12-04 03:53:38 +00:00
self.camera_label.setMinimumHeight(480)
preview_layout.addWidget(self.camera_label)
main_layout.addWidget(preview_container)
# 控制面板
control_panel = QWidget()
control_panel.setStyleSheet("""
QWidget {
background-color: #ffffff;
border-radius: 10px;
padding: 10px;
}
QPushButton {
background-color: #4CAF50;
color: white;
border-radius: 5px;
padding: 8px;
min-width: 100px;
}
QPushButton:hover {
background-color: #45a049;
}
QLabel {
color: #333333;
}
""")
control_layout = QHBoxLayout(control_panel)
# 开始/停止按钮
self.start_stop_btn = QPushButton("开始监控")
self.start_stop_btn.clicked.connect(self.toggle_monitoring)
control_layout.addWidget(self.start_stop_btn)
# 超时设置
timeout_container = QWidget()
timeout_layout = QHBoxLayout(timeout_container)
timeout_label = QLabel("锁屏等待时间:")
self.timeout_spinbox = QSpinBox()
self.timeout_spinbox.setRange(5, 300)
self.timeout_spinbox.setValue(10)
self.timeout_spinbox.setSuffix("")
self.timeout_spinbox.valueChanged.connect(self.update_timeout)
timeout_layout.addWidget(timeout_label)
timeout_layout.addWidget(self.timeout_spinbox)
control_layout.addWidget(timeout_container)
# 状态显示
status_container = QWidget()
status_layout = QVBoxLayout(status_container)
self.status_label = QLabel("状态: 未开始监控")
self.status_label.setStyleSheet("""
QLabel {
font-weight: bold;
font-size: 14px;
color: #333333;
margin-bottom: 5px;
}
""")
self.confidence_label = QLabel("置信度: 0%")
self.confidence_label.setStyleSheet("""
QLabel {
color: #666666;
margin-bottom: 5px;
}
""")
# 进度条容器
progress_container = QWidget()
progress_container.setFixedHeight(45)
progress_container.setStyleSheet("""
QWidget {
background-color: transparent;
padding: 5px;
}
""")
progress_layout = QVBoxLayout(progress_container)
progress_layout.setContentsMargins(0, 0, 0, 0)
# 进度条
self.progress_bar = QProgressBar()
self.progress_bar.setRange(0, 100)
self.progress_bar.setValue(0)
self.progress_bar.setFormat("离开时间: 0s")
self.progress_bar.setMinimumWidth(250)
self.progress_bar.setFixedHeight(20)
self.set_progress_bar_style()
progress_layout.addWidget(self.progress_bar)
status_layout.addWidget(self.status_label)
status_layout.addWidget(self.confidence_label)
status_layout.addWidget(progress_container)
control_layout.addWidget(status_container)
main_layout.addWidget(control_panel)
self.timer = QTimer()
self.timer.timeout.connect(self.update_frame)
def create_tray_menu(self):
menu = QMenu()
show_action = menu.addAction("显示主窗口")
show_action.triggered.connect(self.show)
quit_action = menu.addAction("退出")
quit_action.triggered.connect(self.close)
self.tray_icon.setContextMenu(menu)
self.tray_icon.activated.connect(self.tray_icon_activated)
def tray_icon_activated(self, reason):
2024-12-04 07:53:07 +00:00
if reason == QSystemTrayIcon.DoubleClick:
2024-12-04 03:53:38 +00:00
self.show()
def update_frame(self):
# 检查摄像头是否连接
if not self.cap.isOpened():
self.handle_camera_disconnected()
return
ret, frame = self.cap.read()
if not ret:
self.handle_camera_disconnected()
return
2024-12-04 07:40:25 +00:00
# 转换为灰度图进行人脸检测
gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
faces = self.face_cascade.detectMultiScale(
gray,
scaleFactor=1.1,
minNeighbors=5,
minSize=(30, 30)
)
2024-12-04 03:53:38 +00:00
current_time = time.time()
2024-12-04 07:40:25 +00:00
max_confidence = 0
2024-12-04 03:53:38 +00:00
2024-12-04 07:40:25 +00:00
if len(faces) > 0:
# 简单地使用检测到的人脸数量作为置信度的基础
max_confidence = min(len(faces) * 0.5, 1.0) # 限制最大值为1.0
for (x, y, w, h) in faces:
# 绘制人脸框
cv2.rectangle(frame, (x, y), (x+w, y+h), (0, 255, 0), 2)
# 显示置信度
cv2.putText(frame, f"置信度: {max_confidence:.2f}",
2024-12-04 08:05:47 +00:00
(x, y-10), cv2.FONT_HERSHEY_SIMPLEX,
0.5, (0, 255, 0), 2)
2024-12-04 03:53:38 +00:00
self.last_face_time = current_time
self.no_face_duration = 0
self.status_label.setText("状态: 检测到人脸")
self.confidence_label.setText(f"置信度: {max_confidence*100:.1f}%")
self.progress_bar.setValue(0)
self.progress_bar.setFormat("离开时间: 0s")
self.set_progress_bar_style("#4CAF50")
else:
self.no_face_duration = current_time - self.last_face_time
self.status_label.setText(f"状态: 未检测到人脸 ({int(self.no_face_duration)}秒)")
self.confidence_label.setText("置信度: 0%")
# 计算进度并更新进度条
progress = min(int(self.no_face_duration / self.timeout * 100), 100)
self.progress_bar.setValue(progress)
self.progress_bar.setFormat(f"离开时间: {int(self.no_face_duration)}s")
# 根据进度设置颜色
if progress > 70:
self.set_progress_bar_style("#FF4444") # 红色
elif progress > 30:
self.set_progress_bar_style("#FFA726") # 橙色
else:
self.set_progress_bar_style("#4CAF50") # 绿色
if self.no_face_duration > self.timeout:
self.status_label.setText(f"状态: 锁定屏幕 - {datetime.now()}")
2024-12-04 07:53:07 +00:00
self.tray_icon.showMessage("工位监控", "系统即将锁定", QSystemTrayIcon.Warning)
2024-12-04 03:53:38 +00:00
self.lock_windows()
# 重置所有状态
self.last_face_time = time.time()
self.no_face_duration = 0
self.progress_bar.setValue(0)
self.progress_bar.setFormat("离开时间: 0s")
self.set_progress_bar_style("#4CAF50") # 重置为绿色
time.sleep(1)
2024-12-04 07:40:25 +00:00
# 显示图像
rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
h, w, ch = rgb_frame.shape
2024-12-04 03:53:38 +00:00
bytes_per_line = ch * w
2024-12-04 08:05:47 +00:00
qt_image = QImage(rgb_frame.data, w, h, bytes_per_line, QImage.Format_RGB888)
2024-12-04 03:53:38 +00:00
scaled_pixmap = QPixmap.fromImage(qt_image).scaled(
self.camera_label.size(),
2024-12-04 07:53:07 +00:00
Qt.KeepAspectRatio
2024-12-04 03:53:38 +00:00
)
self.camera_label.setPixmap(scaled_pixmap)
def toggle_monitoring(self):
if not self.running:
2024-12-04 05:06:20 +00:00
# 开始监控时重置所有计时相关变量
self.last_face_time = time.time()
self.no_face_duration = 0
self.progress_bar.setValue(0)
self.progress_bar.setFormat("离开时间: 0s")
self.set_progress_bar_style("#4CAF50")
2024-12-04 03:53:38 +00:00
self.running = True
self.start_stop_btn.setText("停止监控")
self.start_stop_btn.setStyleSheet("background-color: #ff4444;")
self.status_label.setText("状态: 正在监控")
self.timer.start(30)
2024-12-04 07:53:07 +00:00
self.tray_icon.showMessage("工位监控", "监控已开始", QSystemTrayIcon.Information)
2024-12-04 03:53:38 +00:00
else:
self.running = False
self.start_stop_btn.setText("开始监控")
self.start_stop_btn.setStyleSheet("background-color: #4CAF50;")
self.status_label.setText("状态: 已停止监控")
self.timer.stop()
2024-12-04 03:57:17 +00:00
# 重置计时相关的变量
self.last_face_time = time.time()
self.no_face_duration = 0
self.progress_bar.setValue(0)
self.progress_bar.setFormat("离开时间: 0s")
self.set_progress_bar_style("#4CAF50") # 重置进度条颜色为绿色
self.confidence_label.setText("置信度: 0%")
2024-12-04 08:05:47 +00:00
self.tray_icon.showMessage("工位监控", "监控已停止", QSystemTrayIcon.Information)
2024-12-04 03:53:38 +00:00
def update_timeout(self, value):
self.timeout = value
def lock_windows(self):
ctypes.windll.user32.LockWorkStation()
2024-12-04 07:40:25 +00:00
2024-12-04 03:53:38 +00:00
def closeEvent(self, event):
if self.running:
2024-12-04 07:40:25 +00:00
self.tray_icon.showMessage("工位监控", "程序已最小化到系统托盘",
2024-12-04 08:05:47 +00:00
QSystemTrayIcon.Information)
2024-12-04 03:53:38 +00:00
self.hide()
event.ignore()
else:
self.running = False
self.timer.stop()
self.cap.release()
self.tray_icon.hide()
event.accept()
def handle_camera_disconnected(self):
if self.running:
self.running = False
self.timer.stop()
self.start_stop_btn.setText("开始监控")
self.start_stop_btn.setStyleSheet("background-color: #4CAF50;")
self.status_label.setText("状态: 摄像头已断开")
self.confidence_label.setText("置信度: 0%")
self.progress_bar.setValue(0)
self.progress_bar.setFormat("摄像头未连接")
self.tray_icon.showMessage(
"工位监控",
"摄像头已断开,监控已停止",
2024-12-04 08:05:47 +00:00
QSystemTrayIcon.Warning
2024-12-04 03:53:38 +00:00
)
# 尝试重新打开摄像头
self.try_reconnect_camera()
def try_reconnect_camera(self):
if self.cap.isOpened():
self.cap.release()
# 创建定时器尝试重新连接
self.reconnect_timer = QTimer()
self.reconnect_timer.timeout.connect(self.attempt_camera_reconnect)
self.reconnect_timer.start(2000) # 每2秒尝试重连
def attempt_camera_reconnect(self):
self.cap = cv2.VideoCapture(0)
if self.cap.isOpened():
self.reconnect_timer.stop()
self.status_label.setText("状态: 摄像头已重新连接")
self.progress_bar.setFormat("离开时间: %vs")
self.tray_icon.showMessage(
"工位监控",
"摄像头已重新连接,请手动开启监控",
2024-12-04 08:05:47 +00:00
QSystemTrayIcon.Information
2024-12-04 03:53:38 +00:00
)
def set_progress_bar_style(self, color="#4CAF50"):
base_style = """
QProgressBar {
border: 1px solid #E0E0E0;
border-radius: 4px;
text-align: center;
background-color: #F5F5F5;
padding: 1px;
font-size: 12px;
}
QProgressBar::chunk {
background-color: %s;
border-radius: 3px;
margin: 0px;
}
"""
self.progress_bar.setStyleSheet(base_style % color)
def main():
try:
logger.info("Starting main function...")
app = QApplication(sys.argv)
app.setStyle('Fusion')
window = WorkspaceMonitor()
window.show()
logger.info("Application started successfully.")
2024-12-04 08:05:47 +00:00
sys.exit(app.exec_())
2024-12-04 03:53:38 +00:00
except Exception as e:
logger.error(f"Error in main function: {str(e)}")
logger.error(traceback.format_exc())
raise
if __name__ == "__main__":
try:
main()
except Exception as e:
logger.error(f"Fatal error: {str(e)}")
logger.error(traceback.format_exc())
# 显示错误消息框
if QApplication.instance() is None:
app = QApplication(sys.argv)
msg = QMessageBox()
2024-12-04 08:05:47 +00:00
msg.setIcon(QMessageBox.Critical)
2024-12-04 03:53:38 +00:00
msg.setText("程序发生错误")
msg.setInformativeText(str(e))
msg.setWindowTitle("错误")
msg.setDetailedText(traceback.format_exc())
2024-12-04 08:05:47 +00:00
msg.exec_()
2024-12-04 03:53:38 +00:00
sys.exit(1)
except Exception as e:
logger.error(f"Fatal error outside main: {str(e)}")
logger.error(traceback.format_exc())
sys.exit(1)