在pyqt界面上添加按钮,实现中英切换,import sys
import cv2
import numpy as np
import json
import os
import time
import datetime
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QLabel,
QVBoxLayout, QHBoxLayout, QPushButton, QMessageBox,
QLineEdit, QSizePolicy, QGroupBox, QFrame, QStackedLayout)
from PyQt5.QtCore import Qt, pyqtSignal, QThread, QMutex, QMutexLocker, QTimer
from PyQt5.QtGui import QImage, QPixmap, QIntValidator, QFont, QColor, QPalette
from ultralytics import YOLO
from PyQt5.QtNetwork import QTcpSocket, QAbstractSocket
# 配置参数
CAPTURE_INDEX = 0
OBJ_LIST = ['without-safetybelt', 'safetybelt'] # 修改为安全带类别
DETECTOR_PATH = 'C:/weights/safetybelt/best.pt'
# 双语文本字典
TEXT = {
"main_title": ["AI智能安全带检测系统", "AI Smart Safety Belt Detection System"],
"video_title": ["实时监控画面", "Live Monitoring"],
"network_settings": ["网络设置", "Network Settings"],
"server_ip": ["服务器IP:", "Server IP:"],
"port": ["端口号:", "Port:"],
"set_network": ["设置网络", "Set Network"],
"connection_status": ["连接状态", "Connection Status"],
"not_connected": ["未连接", "Not Connected"],
"connected": ["已连接", "Connected"],
"disconnected": ["断开连接", "Disconnected"],
"detection_status": ["检测状态", "Detection Status"],
"belt_status": ["安全带佩戴状态", "Safety Belt Status"],
"waiting_detection": ["-- 等待检测 --", "-- Waiting for Detection --"],
"safe_state": ["安全状态", "Safe State"],
"danger_state": ["危险状态!", "Danger State!"],
"no_person": ["未检测到人员", "No Person Detected"],
"status_explanation": ["状态说明:", "Status Explanation:"],
"safe_explanation": ["安全: 所有人员佩戴安全带", "Safe: All personnel wearing safety belts"],
"danger_explanation": ["危险: 检测到未佩戴安全带", "Danger: Detected personnel not wearing safety belts"],
"info_explanation": ["信息: 未检测到人员", "Info: No personnel detected"],
"loading_camera": ["正在加载摄像头...", "Loading camera..."],
"system_started": ["系统已启动,正在初始化...", "System started, initializing..."],
"sending_status": ["发送状态", "Sending Status"],
"not_sent": ["未发送", "Not Sent"],
"preparing_send": ["准备发送...", "Preparing to send..."],
"send_success": ["发送成功", "Send Successful"],
"send_failed": ["发送失败", "Send Failed"],
"error": ["错误", "Error"],
"invalid_ip": ["无效的IP地址格式", "Invalid IP address format"],
"invalid_port": ["端口号必须为1-65535之间的整数", "Port must be an integer between 1-65535"],
"settings_success": ["设置成功", "Settings Successful"],
"network_updated": ["已更新网络设置", "Network settings updated"],
"config_error": ["配置错误", "Configuration Error"],
"config_failed": ["配置文件格式错误,已使用默认配置", "Configuration file format error, using default settings"],
"connecting": ["正在连接", "Connecting to"],
"last_update": ["最后更新", "Last update"],
"connecting_status": ["正在连接...", "Connecting..."]
}
# 样式常量 - 现代深色主题
MAIN_BG_COLOR = "#1e1e2e" # 深蓝紫色背景
PANEL_BG_COLOR = "#252536" # 面板背景
BUTTON_COLOR = "#4169E1" # 皇家蓝按钮
BUTTON_HOVER_COLOR = "#5a7df1" # 浅蓝色悬停
BUTTON_PRESSED_COLOR = "#2a4fc0" # 深蓝色按下
STATUS_SAFE_COLOR = "#32CD32" # 安全绿色
STATUS_DANGER_COLOR = "#FF4500" # 危险橙色
STATUS_INFO_COLOR = "#1E90FF" # 信息蓝色
TEXT_COLOR = "#e0e0ff" # 浅紫色文本
BORDER_COLOR = "#4a4a6a" # 边框颜色
ACCENT_COLOR = "#9370DB" # 强调色(紫色)
# 语言设置 (0=中文, 1=英文)
LANGUAGE = 0 # 默认中文
def tr(key):
"""翻译函数,根据LANGUAGE设置返回对应语言的文本"""
return TEXT[key][LANGUAGE] if key in TEXT else key
# TCP客户端线程
class TCPClientThread(QThread):
connectionStateChanged = pyqtSignal(str)
def __init__(self, server_ip, server_port=7978):
super().__init__()
self.server_ip = server_ip
self.server_port = server_port
self.running = True
self.client_socket = None
def run(self):
while self.running:
self.client_socket = QTcpSocket()
self.client_socket.connectToHost(self.server_ip, self.server_port)
if self.client_socket.waitForConnected(1000):
self.connectionStateChanged.emit(tr("connected"))
while self.running and self.client_socket.state() == QAbstractSocket.ConnectedState:
self.msleep(100)
else:
self.connectionStateChanged.emit(tr("disconnected"))
time.sleep(5)
def send_data(self, message):
if not (self.client_socket and self.client_socket.state() == QAbstractSocket.ConnectedState):
return -1
try:
byte_written = self.client_socket.write(message.encode('utf-8'))
if byte_written > 0:
self.client_socket.waitForBytesWritten(1000)
return byte_written
return -1
except Exception as e:
print(f"发送异常: {str(e)}")
return -1
def stop(self):
self.running = False
if self.client_socket:
self.client_socket.abort()
self.wait()
# 视频处理线程
class VideoThread(QThread):
update_signal = pyqtSignal(np.ndarray, str)
def __init__(self):
super().__init__()
self._run_flag = True
self.cap = cv2.VideoCapture(0)
self.model_belt = YOLO(DETECTOR_PATH) # 修改变量名为安全带检测
self.data_lock = QMutex()
self.current_data = {'safety': 'without-safetybelt'} # 默认状态为未佩戴安全带
# FPS相关属性
self.frame_count = 0
self.start_time = time.time()
self.fps = 0
def run(self):
while self._run_flag:
ret, frame = self.cap.read()
if ret:
# 安全带检测
results_belt = self.model_belt(frame) # 修改变量名
annotated_frame = frame.copy()
# 初始化安全状态
has_belt = False
has_no_belt = False
# 安全带检测逻辑
if results_belt[0].boxes is not None: # 修改变量名
boxes_belt = results_belt[0].boxes # 修改变量名
valid_boxes_belt = [box for box in boxes_belt if box.conf.item() > 0.5] # 修改变量名
for box in valid_boxes_belt: # 修改变量名
cls_id = int(box.cls)
cls_name = self.model_belt.names[cls_id] # 修改变量名
if cls_name in OBJ_LIST:
x1, y1, x2, y2 = map(int, box.xyxy[0])
# 根据是否佩戴安全带设置不同颜色
if cls_name == 'safetybelt': # 佩戴安全带
color = (0, 255, 0) # 绿色
has_belt = True
else: # 未佩戴安全带
color = (0, 0, 255) # 红色
has_no_belt = True
# 绘制检测框
cv2.rectangle(annotated_frame, (x1, y1), (x2, y2),
color, 2)
cv2.putText(annotated_frame, cls_name,
(x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX,
0.5, color, 2)
# 确定整体安全状态
if has_no_belt:
safety_status = 'without-safetybelt' # 只要有一个人未佩戴安全带
elif has_belt:
safety_status = 'safetybelt' # 所有人都佩戴了安全带
else:
safety_status = '' # 未检测到人员
# 计算并显示FPS(在视频帧上绘制)
self.frame_count += 1
if (time.time() - self.start_time) > 1.0:
self.fps = self.frame_count / (time.time() - self.start_time)
self.frame_count = 0
self.start_time = time.time()
# 在视频帧上绘制FPS
fps_text = f"FPS: {self.fps:.1f}"
cv2.putText(annotated_frame, fps_text, (10, 30),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 1,
cv2.LINE_AA)
self.update_signal.emit(annotated_frame, safety_status)
self.update_data(safety_status)
def update_data(self, safety):
with QMutexLocker(self.data_lock):
self.current_data.update({
'safety': safety or 'without-safetybelt'
})
def stop(self):
self._run_flag = False
self.cap.release()
self.wait()
# 主窗口类
class MainWindow(QMainWindow):
def __init__(self, server_ip='127.0.0.1', server_port=7978):
super().__init__()
self.setWindowTitle(tr("main_title")) # 修改标题为安全带检测
self.setGeometry(100, 100, 1200, 750)
# 设置主窗口样式
self.setStyleSheet(f"""
background-color: {MAIN_BG_COLOR};
color: {TEXT_COLOR};
font-family: 'Segoe UI', Arial, sans-serif;
""")
# 初始化成员变量
self.video_thread = None
self.tcp_client = None
self.first_frame_received = False # 标记是否接收到第一帧
# 初始化界面
main_widget = QWidget()
main_layout = QHBoxLayout(main_widget)
main_layout.setContentsMargins(20, 20, 20, 20)
main_layout.setSpacing(20)
# 左侧视频显示区域
video_frame = QFrame()
video_frame.setFrameShape(QFrame.StyledPanel)
video_frame.setStyleSheet(f"""
background-color: {PANEL_BG_COLOR};
border-radius: 12px;
border: 1px solid {BORDER_COLOR};
""")
video_layout = QVBoxLayout(video_frame)
video_layout.setContentsMargins(15, 15, 15, 15)
video_layout.setSpacing(15)
# 视频标题
video_title = QLabel(tr("video_title"))
video_title.setAlignment(Qt.AlignCenter)
video_title.setStyleSheet("""
font-size: 20px;
font-weight: bold;
color: #b0b0ff;
padding: 8px;
border-bottom: 2px solid #4a4a6a;
""")
video_layout.addWidget(video_title)
# 视频显示标签
self.video_label = QLabel()
self.video_label.setAlignment(Qt.AlignCenter)
self.video_label.setMinimumSize(720, 540)
self.video_label.setStyleSheet("""
background-color: #000000;
border-radius: 8px;
border: 1px solid #4a4a6a;
""")
# 添加摄像头加载提示(直接覆盖在视频标签上)
self.camera_status_label = QLabel(tr("loading_camera"))
self.camera_status_label.setAlignment(Qt.AlignCenter)
self.camera_status_label.setStyleSheet("""
font-size: 24px;
font-weight: bold;
color: #9370DB;
background-color: rgba(30, 30, 46, 180);
border-radius: 8px;
padding: 20px;
""")
self.camera_status_label.setVisible(True) # 初始显示加载提示
# 使用布局将提示标签覆盖在视频标签上
video_container = QWidget()
video_container_layout = QStackedLayout(video_container)
video_container_layout.setStackingMode(QStackedLayout.StackAll)
video_container_layout.addWidget(self.video_label)
video_container_layout.addWidget(self.camera_status_label)
video_layout.addWidget(video_container, 1)
main_layout.addWidget(video_frame, 70)
# 右侧控制面板
control_frame = QFrame()
control_frame.setStyleSheet(f"""
background-color: {PANEL_BG_COLOR};
border-radius: 12px;
border: 1px solid {BORDER_COLOR};
""")
control_layout = QVBoxLayout(control_frame)
control_layout.setContentsMargins(20, 20, 20, 20)
control_layout.setSpacing(20)
# 系统标题
title_label = QLabel(tr("main_title")) # 修改为安全带检测
title_label.setAlignment(Qt.AlignCenter)
title_label.setStyleSheet("""
font-size: 24px;
font-weight: bold;
color: {ACCENT_COLOR};
padding: 10px 0;
border-bottom: 2px solid #4a4a6a;
""".format(ACCENT_COLOR=ACCENT_COLOR))
control_layout.addWidget(title_label)
# 网络设置组
network_group = QGroupBox(tr("network_settings"))
network_group.setStyleSheet(f"""
QGroupBox {{
font-size: 18px;
font-weight: bold;
color: {TEXT_COLOR};
border: none;
}}
QGroupBox::title {{
subcontrol-origin: margin;
left: 10px;
padding: 0 5px;
color: {ACCENT_COLOR};
}}
""")
network_layout = QVBoxLayout(network_group)
network_layout.setSpacing(15)
network_layout.setContentsMargins(15, 25, 15, 15)
# IP地址行
ip_row = QHBoxLayout()
ip_label = QLabel(tr("server_ip"))
ip_label.setStyleSheet("font-size: 16px;")
self.ip_line_edit = QLineEdit(server_ip)
self.ip_line_edit.setStyleSheet(f"""
QLineEdit {{
background-color: #1e1e2e;
color: {TEXT_COLOR};
border: 1px solid {BORDER_COLOR};
border-radius: 6px;
padding: 8px 12px;
font-size: 16px;
selection-background-color: {ACCENT_COLOR};
}}
QLineEdit:focus {{
border: 2px solid {ACCENT_COLOR};
}}
""")
ip_row.addWidget(ip_label)
ip_row.addWidget(self.ip_line_edit, 1)
network_layout.addLayout(ip_row)
# 端口行
port_row = QHBoxLayout()
port_label = QLabel(tr("port"))
port_label.setStyleSheet("font-size: 16px;")
self.port_line_edit = QLineEdit(str(server_port))
self.port_line_edit.setValidator(QIntValidator(1, 65535, self))
self.port_line_edit.setStyleSheet(f"""
QLineEdit {{
background-color: #1e1e2e;
color: {TEXT_COLOR};
border: 1px solid {BORDER_COLOR};
border-radius: 6px;
padding: 8px 12px;
font-size: 16px;
selection-background-color: {ACCENT_COLOR};
}}
QLineEdit:focus {{
border: 2px solid {ACCENT_COLOR};
}}
""")
port_row.addWidget(port_label)
port_row.addWidget(self.port_line_edit, 1)
network_layout.addLayout(port_row)
# 按钮行
button_row = QHBoxLayout()
button_row.setSpacing(15)
self.set_network_button = QPushButton(tr("set_network"))
self.set_network_button.setCursor(Qt.PointingHandCursor)
self.set_network_button.setStyleSheet(f"""
QPushButton {{
background-color: {BUTTON_COLOR};
color: white;
border: none;
border-radius: 8px;
padding: 12px 20px;
font-size: 16px;
font-weight: bold;
min-width: 120px;
}}
QPushButton:hover {{
background-color: {BUTTON_HOVER_COLOR};
}}
QPushButton:pressed {{
background-color: {BUTTON_PRESSED_COLOR};
}}
""")
# 连接状态显示
self.connect_label = QLabel(f"{tr('connection_status')}: {tr('not_connected')}")
self.connect_label.setStyleSheet("""
font-size: 16px;
font-weight: bold;
padding: 10px;
background-color: #1e1e2e;
border-radius: 8px;
border: 1px solid #4a4a6a;
""")
button_row.addWidget(self.set_network_button)
button_row.addWidget(self.connect_label, 1)
network_layout.addLayout(button_row)
control_layout.addWidget(network_group)
# 状态显示组
status_group = QGroupBox(tr("detection_status"))
status_group.setStyleSheet(f"""
QGroupBox {{
font-size: 18px;
font-weight: bold;
color: {TEXT_COLOR};
border: none;
}}
QGroupBox::title {{
subcontrol-origin: margin;
left: 10px;
padding: 0 5px;
color: {ACCENT_COLOR};
}}
""")
status_layout = QVBoxLayout(status_group)
status_layout.setSpacing(15)
status_layout.setContentsMargins(15, 25, 15, 15)
# 安全带状态显示
status_box = QFrame()
status_box.setStyleSheet(f"""
background-color: #1e1e2e;
border-radius: 12px;
border: 1px solid #4a4a6a;
""")
status_box_layout = QVBoxLayout(status_box)
status_box_layout.setContentsMargins(20, 20, 20, 20)
status_box_layout.setSpacing(15)
status_title = QLabel(tr("belt_status")) # 修改为安全带
status_title.setStyleSheet("""
font-size: 18px;
font-weight: bold;
color: #b0b0ff;
padding-bottom: 5px;
border-bottom: 1px solid #4a4a6a;
""")
status_title.setAlignment(Qt.AlignCenter)
status_box_layout.addWidget(status_title)
self.belt_display = QLabel(tr("waiting_detection")) # 修改变量名
self.belt_display.setAlignment(Qt.AlignCenter)
self.belt_display.setStyleSheet(f"""
font-size: 28px;
font-weight: bold;
padding: 25px 0;
border-radius: 8px;
background-color: #2a2a3a;
""")
status_box_layout.addWidget(self.belt_display)
# 状态说明
status_info = QLabel(tr("status_explanation"))
status_info.setStyleSheet("font-size: 16px; font-weight: bold;")
# 状态指示器
status_indicator = QWidget()
indicator_layout = QVBoxLayout(status_indicator)
indicator_layout.setSpacing(5)
# 安全状态
safe_indicator = QHBoxLayout()
safe_label = QLabel(tr("safe_explanation")) # 修改为安全带
safe_label.setStyleSheet("font-size: 14px;")
safe_dot = QLabel("●")
safe_dot.setStyleSheet(f"color: {STATUS_SAFE_COLOR}; font-size: 20px;")
safe_indicator.addWidget(safe_dot)
safe_indicator.addWidget(safe_label)
safe_indicator.addStretch()
indicator_layout.addLayout(safe_indicator)
# 危险状态
danger_indicator = QHBoxLayout()
danger_label = QLabel(tr("danger_explanation")) # 修改为安全带
danger_label.setStyleSheet("font-size: 14px;")
danger_dot = QLabel("●")
danger_dot.setStyleSheet(f"color: {STATUS_DANGER_COLOR}; font-size: 20px;")
danger_indicator.addWidget(danger_dot)
danger_indicator.addWidget(danger_label)
danger_indicator.addStretch()
indicator_layout.addLayout(danger_indicator)
# 信息状态
info_indicator = QHBoxLayout()
info_label = QLabel(tr("info_explanation"))
info_label.setStyleSheet("font-size: 14px;")
info_dot = QLabel("●")
info_dot.setStyleSheet(f"color: {STATUS_INFO_COLOR}; font-size: 20px;")
info_indicator.addWidget(info_dot)
info_indicator.addWidget(info_label)
info_indicator.addStretch()
indicator_layout.addLayout(info_indicator)
status_box_layout.addWidget(status_info)
status_box_layout.addWidget(status_indicator)
status_layout.addWidget(status_box)
control_layout.addWidget(status_group)
# 添加控制面板到主布局
main_layout.addWidget(control_frame, 30)
self.setCentralWidget(main_widget)
# 连接设置网络按钮的信号
self.set_network_button.clicked.connect(self.update_network)
self.load_config() # 加载配置文件
self.setup_tcp() # 建立TCP连接
# 初始化视频线程
self.video_thread = VideoThread()
self.video_thread.update_signal.connect(self.update_frame)
self.video_thread.start()
# 状态栏初始化
self.statusBar().setStyleSheet(f"""
background-color: {PANEL_BG_COLOR};
color: {TEXT_COLOR};
border-top: 1px solid {BORDER_COLOR};
font-size: 12px;
padding: 4px;
""")
self.statusBar().showMessage(tr("system_started"))
self.send_status_label = QLabel(f"{tr('sending_status')}: {tr('not_sent')}")
self.statusBar().addPermanentWidget(self.send_status_label)
self.setup_timers() # 初始化定时器
def update_send_status(self, message, color="white"):
"""更新发送状态显示"""
color_map = {
"green": STATUS_SAFE_COLOR,
"red": STATUS_DANGER_COLOR,
"blue": STATUS_INFO_COLOR,
"orange": "#ff8c00",
"white": TEXT_COLOR
}
hex_color = color_map.get(color.lower(), TEXT_COLOR)
self.send_status_label.setStyleSheet(f"color: {hex_color}; font-size: 12px; font-weight: bold;")
self.send_status_label.setText(f"{tr('sending_status')}: {message}")
# 状态栏更新
current_time = datetime.datetime.now().strftime('%H:%M:%S')
self.statusBar().showMessage(f"{tr('last_update')}: {current_time} - {message}", 3000)
def send_class_data(self):
"""发送检测数据"""
self.update_send_status(tr("preparing_send"), "blue")
sent_bytes = -1
try:
# 基础校验
if not hasattr(self, 'tcp_client') or not self.tcp_client.client_socket:
self.update_send_status(tr("not_connected"), "red")
return
if self.tcp_client.client_socket.state() != QAbstractSocket.ConnectedState:
self.update_send_status(tr("not_connected"), "red")
return
# 获取数据
with QMutexLocker(self.video_thread.data_lock):
data = self.video_thread.current_data.copy()
# 生成报告
xml_data = self.generate_report(data)
# 执行发送
sent_bytes = self.tcp_client.send_data(xml_data)
expected_bytes = len(xml_data.encode('utf-8'))
# 结果处理
if sent_bytes == expected_bytes:
status_msg = tr("send_success")
else:
status_msg = f"{tr('send_failed')} ({sent_bytes}/{expected_bytes} {tr('bytes') if LANGUAGE == 0 else 'bytes'})"
color = "green" if sent_bytes == expected_bytes else "orange"
self.update_send_status(status_msg, color)
except Exception as e:
error_msg = f"{tr('send_failed')}: {str(e)} | {tr('sent_bytes') if LANGUAGE == 0 else 'Sent'}: {sent_bytes}{tr('bytes') if LANGUAGE == 0 else 'bytes'}"
print(error_msg)
self.update_send_status(error_msg[:40], "red")
# 异常时强制重置连接
if hasattr(self, 'tcp_client'):
self.tcp_client.stop()
def generate_report(self, data):
"""生成报告字符串"""
# 判断安全模式(safetybelt=1,其他=0)
mode = 1 if data.get('safety') == 'safetybelt' else 0 # 修改为安全带检测
# 构建字符串
report_str = (
"{json;report;"
f"mode:{mode};}}"
)
return report_str
def update_network(self):
"""更新网络设置"""
new_ip = self.ip_line_edit.text()
new_port = self.port_line_edit.text()
# 输入验证
if not self.validate_ip(new_ip):
QMessageBox.critical(self, tr("error"), tr("invalid_ip"))
return
try:
port = int(new_port)
if not (1 <= port <= 65535):
raise ValueError
except ValueError:
QMessageBox.critical(self, tr("error"), tr("invalid_port"))
return
# 更新界面显示
self.ip_line_edit.setText(new_ip)
self.port_line_edit.setText(str(port))
# 重启TCP连接
self.setup_tcp()
# 保存配置
self.save_config()
# 显示成功消息
QMessageBox.information(self, tr("settings_success"),
f"{tr('network_updated')}:\nIP: {new_ip}\n{tr('port')}: {port}",
QMessageBox.Ok)
def save_config(self):
"""保存配置到文件"""
config_folder = 'C:/config'
if not os.path.exists(config_folder):
os.makedirs(config_folder)
config_path = os.path.join(config_folder, 'config.txt')
with open(config_path, 'w') as f:
f.write("\n".join([
self.ip_line_edit.text(),
self.port_line_edit.text()
]))
def validate_ip(self, ip):
"""IP地址验证方法"""
try:
parts = ip.split('.')
if len(parts) != 4:
return False
return all(0 <= int(part) < 256 for part in parts)
except:
return False
def setup_timers(self):
"""设置定时器"""
self.class_timer = QTimer()
self.class_timer.setInterval(1000) # 每秒发送一次数据
self.class_timer.timeout.connect(self.send_class_data)
self.class_timer.start()
def setup_tcp(self):
"""创建TCP连接"""
# 获取当前IP
current_ip = self.ip_line_edit.text()
try:
current_port = int(self.port_line_edit.text())
except ValueError:
current_port = 7978
# 如果已有连接,先停止
if hasattr(self, 'tcp_client') and self.tcp_client:
self.tcp_client.stop()
self.tcp_client.wait()
# 创建新连接
self.tcp_client = TCPClientThread(current_ip, current_port)
self.tcp_client.connectionStateChanged.connect(self.update_connection_status)
self.tcp_client.start()
self.statusBar().showMessage(f"{tr('connecting')} {current_ip}...", 3000)
def load_config(self):
"""加载配置文件"""
config_folder = 'C:/config'
config_path = os.path.join(config_folder, 'config.txt')
try:
if os.path.exists(config_path):
with open(config_path, 'r') as f:
lines = [line.strip() for line in f.readlines()]
# 读取IP地址(第1行)和端口(第2行)
if len(lines) >= 1:
self.ip_line_edit.setText(lines[0])
if len(lines) >= 2:
self.port_line_edit.setText(lines[1])
print(f"配置加载成功:IP={lines[0]}")
except Exception as e:
print(f"配置加载失败: {str(e)}")
QMessageBox.warning(self, tr("config_error"),
f"{tr('config_failed')}\n{tr('error')}:{str(e)}")
def update_frame(self, frame, safety_status):
# 如果是第一帧,隐藏提示
if not self.first_frame_received:
self.camera_status_label.setVisible(False)
self.first_frame_received = True
# 更新安全带状态显示
if safety_status == 'safetybelt': # 佩戴安全带
self.belt_display.setText(tr("safe_state")) # 修改为安全带状态
self.belt_display.setStyleSheet(f"""
font-size: 28px;
font-weight: bold;
color: {STATUS_SAFE_COLOR};
padding: 25px 0;
border-radius: 8px;
background-color: #2a2a3a;
border: 2px solid {STATUS_SAFE_COLOR};
""")
elif safety_status == 'without-safetybelt': # 未佩戴安全带
self.belt_display.setText(tr("danger_state"))
self.belt_display.setStyleSheet(f"""
font-size: 28px;
font-weight: bold;
color: {STATUS_DANGER_COLOR};
padding: 25px 0;
border-radius: 8px;
background-color: #2a2a3a;
border: 2px solid {STATUS_DANGER_COLOR};
""")
else: # 未检测到人员
self.belt_display.setText(tr("no_person"))
self.belt_display.setStyleSheet(f"""
font-size: 28px;
font-weight: bold;
color: {STATUS_INFO_COLOR};
padding: 25px 0;
border-radius: 8px;
background-color: #2a2a3a;
border: 2px solid {STATUS_INFO_COLOR};
""")
# 显示视频帧(包含FPS信息)
rgb_image = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
h, w, ch = rgb_image.shape
qt_image = QImage(rgb_image.data, w, h, ch * w, QImage.Format_RGB888)
pixmap = QPixmap.fromImage(qt_image)
self.video_label.setPixmap(pixmap.scaled(
self.video_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))
def update_connection_status(self, status):
"""更新连接状态显示"""
self.connect_label.setText(f"{tr('connection_status')}: {status}")
if status == tr("connected"):
self.connect_label.setStyleSheet(f"""
font-size: 16px;
font-weight: bold;
color: {STATUS_SAFE_COLOR};
padding: 10px;
background-color: #1e1e2e;
border-radius: 8px;
border: 2px solid {STATUS_SAFE_COLOR};
""")
else:
self.connect_label.setStyleSheet(f"""
font-size: 16px;
font-weight: bold;
color: {STATUS_DANGER_COLOR};
padding: 10px;
background-color: #1e1e2e;
border-radius: 8px;
border: 2px solid {STATUS_DANGER_COLOR};
""")
def closeEvent(self, event):
"""关闭事件处理"""
self.video_thread.stop()
if hasattr(self, 'tcp_client'):
self.tcp_client.stop()
if hasattr(self, 'class_timer') and self.class_timer.isActive():
self.class_timer.stop()
event.accept()
if __name__ == "__main__":
app = QApplication(sys.argv)
# 设置应用字体
font = QFont("Segoe UI", 10)
app.setFont(font)
# 从配置文件加载初始端口
config_folder = 'C:/config'
config_path = os.path.join(config_folder, 'config.txt')
default_port = 7978
# 如果配置文件不存在,创建配置目录
if not os.path.exists(config_folder):
os.makedirs(config_folder)
# 尝试加载配置
if os.path.exists(config_path):
try:
with open(config_path, 'r') as f:
lines = f.readlines()
if len(lines) >= 2:
default_port = int(lines[1].strip())
except:
pass
window = MainWindow(server_port=default_port)
window.show()
sys.exit(app.exec_())