2025.2.6

今天开始页面美化和调用摄像头等功能,并且按照我当初的想法,这个程序应该可以导入图片、视频并且开启摄像头实时检测,所以前端页面还需要进行改动,由于本来这个程序是要搭配机器人使用,而页面上显示的X、Y坐标应该依据机器人的环形滑轨的位置来决定,但目前为止很多东西还没有付诸实际,所以当前只能暂时采用图片的左下角为原点进行记录,具体页面如下:

 代码如下:

from PySide6 import QtWidgets, QtCore, QtGui
import cv2, os, time, random
from threading import Thread, Lock
from ultralytics import YOLO

os.environ['YOLO_VERBOSE'] = 'False'


class MainWindow(QtWidgets.QMainWindow):
    update_signal = QtCore.Signal(QtGui.QImage)

    def __init__(self):
        super().__init__()
        self.setup_ui()
        self.setup_video()

        self.analysis_results = []
        self.current_detections = []
        self.current_frame = None
        self.lock = Lock()
        self.video_paused = False
        self.is_video_file = False

    def setup_ui(self):
        self.setWindowTitle("智能分析系统")
        self.resize(1200, 800)
        self.setStyleSheet("background-color: #F0F0F0;")

        central_widget = QtWidgets.QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QtWidgets.QVBoxLayout(central_widget)
        main_layout.setContentsMargins(10, 10, 10, 10)
        main_layout.setSpacing(10)

        # 顶部切换按钮
        btn_style = """
        QPushButton {
            background-color: #87CEFA;
            color: black;
            border: none;
            padding: 8px 16px;
            border-radius: 4px;
            min-width: 120px;
            min-height: 35px;
            font-size: 14px;
        }
        QPushButton:disabled {
            background-color: #D3D3D3;
            color: gray;
        }
        """

        self.analysis_btn = QtWidgets.QPushButton("数据分析")
        self.status_btn = QtWidgets.QPushButton("今日情况")
        self.analysis_btn.setStyleSheet(btn_style)
        self.status_btn.setStyleSheet(btn_style)

        top_layout = QtWidgets.QHBoxLayout()
        top_layout.addWidget(self.analysis_btn)
        top_layout.addWidget(self.status_btn)
        top_layout.setSpacing(10)
        main_layout.addLayout(top_layout)

        # 页面堆栈
        self.stacked_pages = QtWidgets.QStackedWidget()
        main_layout.addWidget(self.stacked_pages)

        self.setup_analysis_page()
        self.setup_status_page()

        self.analysis_btn.clicked.connect(self.switch_to_analysis)
        self.status_btn.clicked.connect(self.switch_to_status)
        self.switch_to_analysis()

    def switch_to_analysis(self):
        self.stacked_pages.setCurrentIndex(0)
        self.analysis_btn.setDisabled(True)
        self.status_btn.setDisabled(False)
        self.analysis_btn.setStyleSheet("background-color: #87CEFA; color: black;")
        self.status_btn.setStyleSheet("background-color: #D3D3D3; color: gray;")

    def switch_to_status(self):
        self.stacked_pages.setCurrentIndex(1)
        self.status_btn.setDisabled(True)
        self.analysis_btn.setDisabled(False)
        self.status_btn.setStyleSheet("background-color: #87CEFA; color: black;")
        self.analysis_btn.setStyleSheet("background-color: #D3D3D3; color: gray;")

    def setup_analysis_page(self):
        page = QtWidgets.QWidget()
        layout = QtWidgets.QHBoxLayout(page)
        layout.setContentsMargins(5, 5, 5, 5)
        layout.setSpacing(15)

        # 左侧视频区域
        left_panel = QtWidgets.QWidget()
        left_layout = QtWidgets.QVBoxLayout(left_panel)
        left_layout.setSpacing(10)

        self.video_label = QtWidgets.QLabel()
        self.video_label.setMinimumSize(640, 480)
        self.video_label.setStyleSheet("""
            border: 2px solid #666;
            background-color: #000000;
            border-radius: 5px;
        """)

        self.cam_btn = QtWidgets.QPushButton("打开摄像头")
        left_layout.addWidget(self.video_label)
        left_layout.addWidget(self.cam_btn)

        # 右侧信息面板
        right_panel = QtWidgets.QWidget()
        right_layout = QtWidgets.QVBoxLayout(right_panel)
        right_layout.setSpacing(15)

        # 按钮样式
        btn_style = """
        QPushButton {
            background-color: #4CAF50;
            color: white;
            border: none;
            padding: 8px 16px;
            border-radius: 4px;
            min-width: 150px;
            min-height: 35px;
            font-size: 14px;
        }
        QPushButton:hover { background-color: #45a049; }
        QPushButton:pressed { background-color: #3d8b40; }
        """

        # 新增导入按钮
        self.import_image_btn = QtWidgets.QPushButton("导入图片文件")
        self.import_image_btn.setStyleSheet(btn_style)
        self.import_btn = QtWidgets.QPushButton("导入视频文件")
        self.import_btn.setStyleSheet(btn_style)
        right_layout.addWidget(self.import_image_btn)
        right_layout.addWidget(self.import_btn)

        # 检测信息组
        info_group = QtWidgets.QGroupBox("检测信息")
        info_group.setStyleSheet("""
            QGroupBox {
                font-size: 14px;
                border: 1px solid #666;
                border-radius: 5px;
                margin-top: 10px;
            }
            QGroupBox::title {
                subcontrol-origin: margin;
                left: 10px;
                padding: 0 3px;
            }
        """)
        info_layout = QtWidgets.QFormLayout(info_group)
        info_layout.setVerticalSpacing(10)
        info_layout.setHorizontalSpacing(15)

        self.confidence_label = QtWidgets.QLabel("0%")
        self.target_count_label = QtWidgets.QLabel("0")
        self.x_label = QtWidgets.QLabel("0")
        self.y_label = QtWidgets.QLabel("0")
        self.target_select = QtWidgets.QComboBox()

        # 统一标签样式
        label_style = "font-size: 14px; min-width: 80px;"
        for label in [self.confidence_label, self.target_count_label, self.x_label, self.y_label]:
            label.setStyleSheet(label_style)

        info_layout.addRow("置信度:", self.confidence_label)
        info_layout.addRow("目标数量:", self.target_count_label)
        info_layout.addRow("X坐标:", self.x_label)
        info_layout.addRow("Y坐标:", self.y_label)
        info_layout.addRow("目标选择:", self.target_select)

        self.save_btn = QtWidgets.QPushButton("保存结果")
        self.save_btn.setStyleSheet(btn_style)
        right_layout.addWidget(info_group)
        right_layout.addWidget(self.save_btn)
        right_layout.addStretch()

        layout.addWidget(left_panel)
        layout.addWidget(right_panel)
        self.stacked_pages.addWidget(page)

    def setup_status_page(self):
        page = QtWidgets.QWidget()
        layout = QtWidgets.QVBoxLayout(page)

        # 成熟度展示
        maturity_group = QtWidgets.QGroupBox("今日成熟度分布")
        grid = QtWidgets.QGridLayout(maturity_group)

        maturities = ["60%", "55%", "65%", "57%"]
        for i, mat in enumerate(maturities):
            label = QtWidgets.QLabel(f"成熟度:{mat}")
            grid.addWidget(label, i // 2, i % 2)

        layout.addWidget(maturity_group)
        self.stacked_pages.addWidget(page)

    def setup_video(self):
        self.model = YOLO('yolov8n.pt')
        self.frame_queue = []
        self.cap = None
        self.video_timer = QtCore.QTimer()
        self.video_timer.timeout.connect(self.update_frame)
        self.update_signal.connect(self.update_image)

        self.cam_btn.setStyleSheet("""
            QPushButton {
                background-color: #4CAF50;
                color: white;
                min-width: 150px;
                min-height: 35px;
            }
        """)
        self.cam_btn.clicked.connect(self.toggle_camera)
        self.save_btn.clicked.connect(self.save_results)
        self.import_btn.clicked.connect(self.import_video)
        self.import_image_btn.clicked.connect(self.import_image)
        self.target_select.currentTextChanged.connect(self.update_selection)

        Thread(target=self.process_frames, daemon=True).start()

    def import_image(self):
        path, _ = QtWidgets.QFileDialog.getOpenFileName(
            self, "选择图片文件", "", "图片文件 (*.jpg *.png *.bmp)"
        )
        if path:
            self.video_paused = True
            if self.video_timer.isActive():
                self.video_timer.stop()
                self.cam_btn.setText("继续")

            image = cv2.imread(path)
            frame = cv2.cvtColor(image, cv2.COLOR_BGR2RGB)
            self.current_frame = frame.copy()

            results = self.model(frame)[0]
            self.current_detections = results

            # 更新检测信息
            if len(results) > 0:
                confidences = results.boxes.conf.cpu().numpy()
                avg_conf = confidences.mean() if len(confidences) > 0 else 0
                self.confidence_label.setText(f"{avg_conf:.1%}")
            self.target_count_label.setText(str(len(results)))
            self.x_label.setText(str(random.randint(0, 10)))
            self.y_label.setText(str(random.randint(0, 10)))

            # 更新下拉框
            self.target_select.clear()
            self.target_select.addItem("全部")
            for i in range(1, len(results) + 1):
                self.target_select.addItem(str(i))

            # 显示检测结果
            annotated = results.plot()
            annotated = cv2.cvtColor(annotated, cv2.COLOR_BGR2RGB)
            h, w, ch = annotated.shape
            q_img = QtGui.QImage(annotated.data, w, h, ch * w, QtGui.QImage.Format_RGB888)
            self.video_label.setPixmap(QtGui.QPixmap.fromImage(q_img))


    def import_video(self):
        path, _ = QtWidgets.QFileDialog.getOpenFileName(
            self, "选择视频文件", "", "视频文件 (*.mp4 *.avi)"
        )
        if path:
            if self.cap:
                self.cap.release()
            self.cap = cv2.VideoCapture(path)
            if self.cap.isOpened():
                self.video_timer.start(30)
                self.cam_btn.setText("暂停")

    def toggle_camera(self):
        if self.cam_btn.text() == "打开摄像头" or self.cam_btn.text() == "继续":
            if self.is_video_file and self.cap is not None:
                self.video_timer.start(30)
                self.cam_btn.setText("暂停")
                self.video_paused = False
            else:
                self.cap = cv2.VideoCapture(0, cv2.CAP_DSHOW)
                if self.cap.isOpened():
                    self.video_timer.start(30)
                    self.cam_btn.setText("暂停")
                    self.video_paused = False
        else:
            self.video_timer.stop()
            self.cam_btn.setText("继续")
            self.video_paused = True

    def update_frame(self):
        if self.cap and self.cap.isOpened():
            ret, frame = self.cap.read()
            if ret:
                with self.lock:
                    self.frame_queue.append(frame)
                    self.current_frame = frame.copy()

    def process_frames(self):
        while True:
            if self.frame_queue:
                with self.lock:
                    frame = self.frame_queue.pop(0)

                results = self.model(frame)[0]
                self.current_detections = results

                # 更新置信度显示
                if len(results) > 0:
                    confidences = results.boxes.conf.cpu().numpy()
                    avg_conf = confidences.mean() if len(confidences) > 0 else 0
                    self.confidence_label.setText(f"{avg_conf:.1%}")
                else:
                    self.confidence_label.setText("0%")

                # 更新其他信息
                self.target_count_label.setText(str(len(results)))
                self.x_label.setText(str(random.randint(0, 10)))
                self.y_label.setText(str(random.randint(0, 10)))

                # 更新下拉框
                self.target_select.clear()
                self.target_select.addItem("全部")
                for i in range(1, len(results) + 1):
                    self.target_select.addItem(str(i))

                # 绘制检测框
                annotated = results.plot()
                annotated = cv2.cvtColor(annotated, cv2.COLOR_BGR2RGB)
                h, w, ch = annotated.shape
                q_img = QtGui.QImage(annotated.data, w, h, ch * w, QtGui.QImage.Format_RGB888)
                self.update_signal.emit(q_img)

    def update_image(self, q_img):
        self.video_label.setPixmap(QtGui.QPixmap.fromImage(q_img))

    def update_selection(self):
        if self.video_paused and self.current_frame is not None:
            selected = self.target_select.currentText()
            frame = self.current_frame.copy()

            if selected != "全部" and self.current_detections:
                idx = int(selected) - 1
                if 0 <= idx < len(self.current_detections):
                    box = self.current_detections[idx].boxes.xyxy[0].cpu().numpy().astype(int)
                    cv2.rectangle(frame, (box[0], box[1]), (box[2], box[3]), (0, 255, 0), 2)

            frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
            h, w, ch = frame.shape
            q_img = QtGui.QImage(frame.data, w, h, ch * w, QtGui.QImage.Format_RGB888)
            self.video_label.setPixmap(QtGui.QPixmap.fromImage(q_img))

    def save_results(self):
        if self.video_label.pixmap():
            save_dir = os.path.join("result", time.strftime("%Y%m%d_%H%M%S"))
            os.makedirs(save_dir, exist_ok=True)

            # 保存图片
            image_path = os.path.join(save_dir, "capture.jpg")
            self.video_label.pixmap().save(image_path)

            # 保存信息
            info_path = os.path.join(save_dir, "info.txt")
            with open(info_path, "w") as f:
                f.write(f"置信度: {self.confidence_label.text()}\n")
                f.write(f"目标数量: {self.target_count_label.text()}\n")
                f.write(f"X坐标: {self.x_label.text()}\n")
                f.write(f"Y坐标: {self.y_label.text()}\n")

            QtWidgets.QMessageBox.information(self, "保存成功", f"数据已保存至: {save_dir}")


if __name__ == "__main__":
    app = QtWidgets.QApplication()
    window = MainWindow()
    window.show()
    app.exec()

 

posted @ 2025-02-05 14:02  贾贾鱼  阅读(19)  评论(0)    收藏  举报