[feat] 3-test.py

This commit is contained in:
He
2025-11-23 15:39:13 +08:00
parent f8fb6f8427
commit f4a4936b5c
2 changed files with 326 additions and 1 deletions

310
3-test.py Normal file
View File

@@ -0,0 +1,310 @@
import sys
import random
import cv2
from cvzone.FaceDetectionModule import FaceDetector
from PySide6.QtCore import QTimer, Qt
from PySide6.QtGui import QImage, QPixmap
from PySide6.QtWidgets import QApplication, QWidget, QLabel, QPushButton, QVBoxLayout, QProgressBar
class LoadingScreen(QWidget):
def __init__(self):
super().__init__()
self.setWindowTitle("加载中...")
self.setFixedSize(400, 250) # 增大窗口大小以容纳错误信息
self.setWindowFlags(Qt.WindowStaysOnTopHint) # 保留置顶但移除无边框,方便关闭
self.setStyleSheet("background-color: #1E90FF;") # 蓝色背景
# 创建布局
layout = QVBoxLayout()
layout.setAlignment(Qt.AlignCenter)
layout.setSpacing(15)
# 加载提示文字
self.loading_label = QLabel("人脸模型加载中")
self.loading_label.setAlignment(Qt.AlignCenter)
self.loading_label.setStyleSheet("color: white; font-size: 18px; font-weight: bold;")
layout.addWidget(self.loading_label)
# 错误信息标签
self.error_label = QLabel("")
self.error_label.setAlignment(Qt.AlignCenter)
self.error_label.setStyleSheet("color: #FFD700; font-size: 12px; font-weight: normal;")
self.error_label.setWordWrap(True)
self.error_label.setHidden(True) # 初始隐藏
layout.addWidget(self.error_label)
# 进度条 - 设置为不确定模式,显示加载动画
self.progress_bar = QProgressBar()
self.progress_bar.setRange(0, 0) # 设置为0,0表示不确定模式
self.progress_bar.setFixedHeight(10)
layout.addWidget(self.progress_bar)
# 关闭按钮 - 初始隐藏
self.close_button = QPushButton("关闭")
self.close_button.setFixedSize(100, 35)
self.close_button.setStyleSheet("""
QPushButton {
background-color: #FF6347;
color: white;
font-size: 14px;
border-radius: 5px;
}
QPushButton:hover {
background-color: #FF4500;
}
""")
self.close_button.clicked.connect(self.close)
self.close_button.setHidden(True) # 初始隐藏
layout.addWidget(self.close_button)
self.setLayout(layout)
def show_error(self, error_message):
"""显示错误信息并显示关闭按钮,隐藏进度条"""
self.loading_label.setText("人脸模型加载失败")
self.error_label.setText(f"错误详情: {error_message}")
self.error_label.setHidden(False)
self.progress_bar.setHidden(True)
self.close_button.setHidden(False)
self.setWindowTitle("加载失败")
# 调整窗口大小以适应错误信息
self.adjustSize()
QApplication.processEvents()
class FaceRandomApp(QWidget):
def __init__(self):
super().__init__()
# 先显示加载页面
self.loading_screen = LoadingScreen()
self.loading_screen.show()
# 强制立即处理GUI事件确保加载页面能立即显示
QApplication.processEvents()
# 延迟初始化主界面,让加载页面先显示
QTimer.singleShot(100, self.initialize_app)
def initialize_app(self):
# 状态normal → random
self.state = "normal"
self.selected_face_index = -1
self.static_frame = None # 保存随机状态下的静态画面
self.all_faces_snapshot = [] # 保存所有人脸信息快照
# 更新加载页面文字,提示正在进行人脸模型初始化
self.loading_screen.loading_label.setText("正在初始化人脸检测模型...")
QApplication.processEvents()
# 使用长距离模型和更低的人脸检测阈值以提高检测率
# 这里会加载模型,可能需要一些时间
try:
self.detector = FaceDetector(minDetectionCon=0.25, modelSelection=1)
self.loading_screen.loading_label.setText("人脸模型加载完成!")
# 只有在检测器初始化成功后才继续初始化
# 设置窗口标题
self.setWindowTitle("Face Random Selector")
# ---------------- 摄像头 ----------------
self.cap = cv2.VideoCapture(0)
# 设置摄像头分辨率
self.cap.set(3, 1280)
self.cap.set(4, 720)
# 设置窗口初始大小
self.resize(1280, 720)
# ---------------- 创建界面 ----------------
self.setup_ui()
self.faces = []
# 模拟加载完成
QTimer.singleShot(1500, self.finish_loading)
except Exception as e:
# 捕获并显示详细的错误信息(仅显示真实的错误内容)
error_type = type(e).__name__
error_message = str(e)
# 只显示真实的错误类型和错误消息
detailed_error = f"{error_type}: {error_message}"
print(f"初始化人脸检测器时出错: {detailed_error}")
# 显示错误信息并停止继续初始化
self.loading_screen.show_error(detailed_error)
# 不再继续初始化主界面
def finish_loading(self):
# 关闭加载页面
self.loading_screen.close()
# 显示主窗口
self.show()
# 启动定时器更新视频帧
self.timer = QTimer()
self.timer.timeout.connect(self.update_frame)
self.timer.start(30)
def setup_ui(self):
# 视频标签 - 填充整个窗口
self.video_label = QLabel(self)
self.video_label.setStyleSheet("background:#000;")
self.video_label.setGeometry(0, 0, self.width(), self.height())
# 按钮 - 叠加在视频上
self.btn = QPushButton("随机", self)
self.btn.setFixedSize(140, 55)
self.btn.setStyleSheet("""
QPushButton {
background-color: rgba(0, 0, 0, 120);
color: white;
font-size: 20px;
padding: 10px 20px;
border-radius: 8px;
}
QPushButton:hover {
background-color: rgba(30, 30, 30, 180);
}
""")
self.btn.clicked.connect(self.button_clicked)
# 初始按钮位置
self.update_button_position()
def resizeEvent(self, event):
"""窗口大小改变时自动调整视频和按钮位置"""
self.video_label.setGeometry(0, 0, self.width(), self.height())
self.update_button_position()
super().resizeEvent(event)
def update_button_position(self):
"""更新按钮位置"""
btn_w = 140
btn_h = 55
margin = 20
self.btn.setGeometry(
margin,
self.height() - btn_h - margin,
btn_w,
btn_h
)
# ---------------------------------------------------------
# 逻辑按钮:随机 ↔ 重置
# ---------------------------------------------------------
def button_clicked(self):
if self.state == "normal":
# 切换到随机状态
self.state = "random"
self.btn.setText("重置")
# 随机选择一个人脸
if len(self.faces) > 0:
self.selected_face_index = random.randint(0, len(self.faces) - 1)
# 保存当前帧作为静态画面
ret, img = self.cap.read()
if ret:
img = cv2.flip(img, 1)
# 调整图像大小以适应窗口
img = cv2.resize(img, (self.video_label.width(), self.video_label.height()))
self.static_frame = img.copy()
self.all_faces_snapshot = self.faces.copy()
else: # self.state == "random"
# 切换回初始状态
self.state = "normal"
self.selected_face_index = -1
self.static_frame = None
self.all_faces_snapshot = []
self.btn.setText("随机")
# ---------------------------------------------------------
# 刷视频帧
# ---------------------------------------------------------
def update_frame(self):
# ============================
# 状态normal检测所有人脸并显示绿框
# ============================
if self.state == "normal":
ret, img = self.cap.read()
if not ret:
return
img = cv2.flip(img, 1)
# 调整图像大小以适应窗口
img = cv2.resize(img, (self.video_label.width(), self.video_label.height()))
# 检测人脸
if self.detector is not None:
img, faces = self.detector.findFaces(img, draw=False)
self.faces = faces if faces else []
else:
self.faces = []
# 绘制所有人脸为绿色
for face in self.faces:
x, y, w, h = face["bbox"]
score = face["score"][0]
cv2.rectangle(img, (x, y), (x + w, y + h), (0, 255, 0), 3)
cv2.putText(img, f"{score:.2f}", (x, y - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 255, 0), 2)
# 显示图像
self.display_image(img)
# ============================
# 状态random显示静态画面选中的人脸为红色其他为绿色
# ============================
elif self.state == "random" and self.static_frame is not None:
img = self.static_frame.copy()
# 绘制所有人脸,选中的为红色,其他为绿色
for i, face in enumerate(self.all_faces_snapshot):
x, y, w, h = face["bbox"]
score = face["score"][0]
if i == self.selected_face_index:
color = (0, 0, 255) # 红色
else:
color = (0, 255, 0) # 绿色
cv2.rectangle(img, (x, y), (x + w, y + h), color, 3)
cv2.putText(img, f"{score:.2f}", (x, y - 10),
cv2.FONT_HERSHEY_SIMPLEX, 0.6, color, 2)
# 显示图像
self.display_image(img)
# ---------------------------------------------------------
# 显示图像到 QLabel
# ---------------------------------------------------------
def display_image(self, img):
rgb = cv2.cvtColor(img, cv2.COLOR_BGR2RGB)
h, w, ch = rgb.shape
bytes_per_line = ch * w
qimg = QImage(rgb.data, w, h, bytes_per_line, QImage.Format.Format_RGB888)
self.video_label.setPixmap(QPixmap.fromImage(qimg))
# ---------------------------------------------------------
def closeEvent(self, event):
if self.cap.isOpened():
self.cap.release()
event.accept()
def main():
app = QApplication(sys.argv)
# 直接创建主应用窗口,它内部会处理加载页面
window = FaceRandomApp()
sys.exit(app.exec())
if __name__ == "__main__":
main()

View File

@@ -1 +1,16 @@
nuitka --standalone --include-package=cv2 --enable-plugin=pyside6 --windows-console-mode=disable --windows-icon-from-ico=./icon.ico --include-data-dir=F:\python310\lib\site-packages\cv2\data=cv2\data --output-dir=dist32 --remove-output 3-2.py
# Face Random
## 1.软件说明
FaceRandomSelector 是一款人脸随机选择工具。软件采用opencv的人脸检测算法能够快速准确地识别摄像头中的人脸并提供高效的随机选择功能帮助教师轻松实现课堂互动。
## 2.打包指令
` nuitka --standalone --include-package=cv2 --enable-plugin=pyside6 --windows-console-mode=disable --windows-icon-from-ico=./icon.ico --include-data-dir=F:\python310\lib\site-packages\cv2\data=cv2\data --output-dir=dist32 --remove-output 3-2.py `
## 3.版本说明
1. 1.py 2.py非稳定版本
2. 3-1.py存在UI不美观 窗口大小 摄像头清晰度等问题
3. 3-2.py解决3-1.py的相关问题
4. 3-3.py添加加载进度条
5. 3-test.py由3-3.py改编 给出具体的[人脸识别模型无法获取]的相关报错
> 软件务必保存在纯英文路径中!