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()
 
                    
                     
                    
                 
                    
                
 
                
            
         
         浙公网安备 33010602011771号
浙公网安备 33010602011771号