From cf5f4e9c22d8b1b664bcbed6dc1d66499e19683e Mon Sep 17 00:00:00 2001 From: Kegongteng Date: Sun, 16 Nov 2025 12:04:48 +0800 Subject: [PATCH] Create main.py --- main.py | 185 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 185 insertions(+) create mode 100644 main.py diff --git a/main.py b/main.py new file mode 100644 index 0000000..8c6f004 --- /dev/null +++ b/main.py @@ -0,0 +1,185 @@ +import sys +import random +import cv2 +from cvzone.FaceDetectionModule import FaceDetector +from PyQt6.QtCore import QTimer +from PyQt6.QtGui import QImage, QPixmap +from PyQt6.QtWidgets import QApplication, QWidget, QLabel, QPushButton + + +class FaceRandomApp(QWidget): + def __init__(self): + super().__init__() + + self.setWindowTitle("Face Random Selector") + self.resize(1280, 720) + + # 状态:normal → random + self.state = "normal" + self.selected_face_index = -1 + self.static_frame = None # 保存随机状态下的静态画面 + self.all_faces_snapshot = [] # 保存所有人脸信息快照 + + # ---------------- 摄像头 ---------------- + self.cap = cv2.VideoCapture(0) + self.cap.set(3, 1280) + self.cap.set(4, 720) + + # 使用长距离模型和更低的人脸检测阈值以提高检测率 + self.detector = FaceDetector(minDetectionCon=0.25, modelSelection=1) + + # ---------------- 视频区域 ---------------- + 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.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() + + # 定时刷新视频 + self.timer = QTimer() + self.timer.timeout.connect(self.update_frame) + self.timer.start(30) + + self.faces = [] + + # --------------------------------------------------------- + # 自动适配窗口大小时重新定位视频与按钮 + # --------------------------------------------------------- + def resizeEvent(self, event): + self.video_label.setGeometry(0, 0, self.width(), self.height()) + self.update_button_position() + + 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())) + + # 检测人脸 + img, faces = self.detector.findFaces(img, draw=False) + self.faces = faces if faces else [] + + # 绘制所有人脸为绿色 + 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 + qimg = QImage(rgb.data, w, h, ch * w, 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() + window.show() + sys.exit(app.exec()) + + +if __name__ == "__main__": + main() \ No newline at end of file