首页
智算服务
AI 生态大厅
算力商情政策资讯合作与生态场景方案关于我们

基于YOLOv11的图书馆占座检测系统 深度学习YOLO11模型如何训练图书馆占位检测数据集 YOLO数据集 目标检测算法

发布日期:2026-04-07 来源:知乎作者:知乎

图书馆占位检测数据集

  数据集包含2568张图像,提供YOLO和VOC两种标注方式,共2类。标注数量如下:

  • chair座位: 7434
  • person人: 3016
  • image num: 2568

模型代码

  模型训练使用yolov11n训练,30个epoch训练结果,mAP如描述图所示。

Qt界面

  运行界面采用Qt编写,本项目已经训练好模型,配置好环境后可直接使用,运行效果见描述图像。

图书馆占座检测系统信息表

类别 内容
系统名称 基于YOLOv11的图书馆占座检测系统
核心算法 YOLOv11n (Ultralytics)
检测任务 图书馆座位占用状态检测
检测类别 (共2类) chair (座位)
person (人)
数据集规模 总计 2568 张图像
标注数量 chair: 7434 个
person: 3016 个
标注格式 提供 YOLO (.txt) 和 VOC (.xml) 两种格式
模型性能 mAP@0.5: 0.983
chair AP: 0.976
person AP: 0.989
训练配置 Epochs: 30
模型: yolov11n.pt
用户界面 基于 PyQt5 开发的图形化界面
系统功能
  • 图片/视频文件导入检测
  • 实时摄像头检测
  • 检测结果显示(类别、置信度、坐标)
  • 检测结果统计与展示

构建系统代码

  以下是构建该系统的完整代码,分为两部分:模型训练代码和Qt界面代码。

1. 模型训练代码 (train.py)

  此代码用于训练YOLOv11n模型。请确保您的数据集已按以下结构组织,并创建了data.yaml文件。

  数据集结构示例:

library_dataset/
├── images/
│   ├── train/
│   └── val/
├── labels/
│   ├── train/
│   └── val/
└── data.yaml

  data.yaml 文件内容:

# data.yaml
path: ./library_dataset  # 数据集根目录
train: images/train      # 训练集图片路径
val: images/val          # 验证集图片路径

# 类别数量
nc: 2

# 类别名称
names:
  0: chair
  1: person

  train.py 代码:

from ultralytics import YOLO

def train_library_model():
    """
    使用 YOLOv11n 训练图书馆占座检测模型
    """
    # 1. 加载预训练模型
    model = YOLO('yolov11n.pt')  # 加载 YOLOv11n 预训练权重

    # 2. 开始训练
    results = model.train(
        data='library_dataset/data.yaml',  # 数据配置文件路径
        epochs=30,                         # 训练轮数
        imgsz=640,                         # 输入图像尺寸
        batch=16,                          # 批大小,根据显存调整
        name='library_occupancy_v11n',     # 训练任务名称
        project='runs/train',              # 项目保存目录
        exist_ok=True,                     # 允许覆盖已有实验
        patience=5,                        # 早停耐心值
        device=0                           # 使用GPU 0,若使用CPU则设为 'cpu'
    )

    print("训练完成!")
    print(f"最佳模型保存在: {results.save_dir}/weights/best.pt")

if __name__ == "__main__":
    train_library_model()

2. Qt 界面代码 (main_window.py)

  此代码使用PyQt5创建图形界面,实现图片/视频检测、摄像头实时检测及结果显示功能。请确保已安装PyQt5opencv-python

import sys
import os
import time
import cv2
import torch
from PyQt5.QtWidgets import (QApplication, QMainWindow, QWidget, QVBoxLayout,
                             QHBoxLayout, QLabel, QPushButton, QFileDialog,
                             QComboBox, QTableWidget, QTableWidgetItem, QMessageBox)
from PyQt5.QtGui import QPixmap, QImage, QFont
from PyQt5.QtCore import Qt, QTimer, QThread, pyqtSignal
from ultralytics import YOLO

# --- 检测线程 ---
class DetectionThread(QThread):
    # 信号用于更新UI
    frame_processed = pyqtSignal(QImage, list, float)
    finished = pyqtSignal()

    def __init__(self, model, source=0):
        super().__init__()
        self.model = model
        self.source = source  # 0 for webcam, or file path
        self.running = True

    def run(self):
        cap = cv2.VideoCapture(self.source)
        while self.running and cap.isOpened():
            ret, frame = cap.read()
            if not ret:
                break

            start_time = time.time()
            # 进行推理
            results = self.model(frame)
            infer_time = time.time() - start_time

            # 解析结果
            detections = []
            annotated_frame = results[0].plot()  # 获取带标注的帧
            for box in results[0].boxes:
                cls_id = int(box.cls[0])
                conf = float(box.conf[0])
                xyxy = box.xyxy[0].tolist()
                detections.append({
                    'class': self.model.names[cls_id],
                    'confidence': conf,
                    'coordinates': xyxy
                })

            # 转换颜色格式 (BGR -> RGB)
            rgb_image = cv2.cvtColor(annotated_frame, cv2.COLOR_BGR2RGB)
            h, w, ch = rgb_image.shape
            bytes_per_line = ch * w
            qt_image = QImage(rgb_image.data, w, h, bytes_per_line, QImage.Format_RGB888)

            # 发送信号
            self.frame_processed.emit(qt_image, detections, infer_time)

        cap.release()
        self.finished.emit()

    def stop(self):
        self.running = False
        self.wait()


# --- 主窗口 ---
class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("基于YOLOv11的图书馆占座检测")
        self.setGeometry(100, 100, 1200, 800)

        # 加载模型
        self.model = YOLO('runs/train/library_occupancy_v11n/weights/best.pt') # 请确保路径正确

        self.init_ui()
        self.detection_thread = None

    def init_ui(self):
        # --- 主布局 ---
        central_widget = QWidget()
        self.setCentralWidget(central_widget)
        main_layout = QHBoxLayout(central_widget)

        # --- 左侧:图像显示区域 ---
        left_layout = QVBoxLayout()
        self.image_label = QLabel("等待输入...")
        self.image_label.setAlignment(Qt.AlignCenter)
        self.image_label.setMinimumSize(640, 480)
        self.image_label.setStyleSheet("QLabel { background-color : lightgray; }")
        left_layout.addWidget(self.image_label)

        # --- 右侧:控制面板 ---
        right_layout = QVBoxLayout()

        # 文件导入
        file_group = QLabel("文件导入")
        file_group.setFont(QFont("Arial", 12, QFont.Bold))
        right_layout.addWidget(file_group)

        self.file_path_label = QLabel("d(DST1037)/qtUI/1.jpg")
        right_layout.addWidget(self.file_path_label)

        self.btn_select_video = QPushButton("请选择视频文件")
        self.btn_select_video.clicked.connect(self.select_video)
        right_layout.addWidget(self.btn_select_video)

        self.btn_webcam = QPushButton("摄像头未开启")
        self.btn_webcam.clicked.connect(self.toggle_webcam)
        right_layout.addWidget(self.btn_webcam)

        # 检测结果
        result_group = QLabel("检测结果")
        result_group.setFont(QFont("Arial", 12, QFont.Bold))
        right_layout.addWidget(result_group)

        self.time_label = QLabel("用时: 0.000s")
        self.count_label = QLabel("目标数目: 0")
        self.target_combo = QComboBox()
        self.target_combo.addItems(["全部", "chair", "person"])
        self.conf_label = QLabel("置信度: 0.00%")

        right_layout.addWidget(self.time_label)
        right_layout.addWidget(self.count_label)
        right_layout.addWidget(self.target_combo)
        right_layout.addWidget(self.conf_label)

        # 目标位置
        position_group = QLabel("目标位置")
        position_group.setFont(QFont("Arial", 12, QFont.Bold))
        right_layout.addWidget(position_group)

        self.xmin_label = QLabel("xmin: 0")
        self.ymin_label = QLabel("ymin: 0")
        self.xmax_label = QLabel("xmax: 0")
        self.ymax_label = QLabel("ymax: 0")

        right_layout.addWidget(self.xmin_label)
        right_layout.addWidget(self.ymin_label)
        right_layout.addWidget(self.xmax_label)
        right_layout.addWidget(self.ymax_label)

        # 操作按钮
        action_group = QLabel("操作")
        action_group.setFont(QFont("Arial", 12, QFont.Bold))
        right_layout.addWidget(action_group)

        self.btn_save = QPushButton("保存")
        self.btn_exit = QPushButton("退出")
        self.btn_exit.clicked.connect(self.close)

        btn_layout = QHBoxLayout()
        btn_layout.addWidget(self.btn_save)
        btn_layout.addWidget(self.btn_exit)
        right_layout.addLayout(btn_layout)

        # --- 底部:检测结果表格 ---
        self.table = QTableWidget()
        self.table.setColumnCount(5)
        self.table.setHorizontalHeaderLabels(["序号", "文件路径", "类别", "置信度", "坐标位置"])
        main_layout.addLayout(left_layout, 70)
        main_layout.addLayout(right_layout, 30)
        main_layout.addWidget(self.table)

    def select_video(self):
        file_path, _ = QFileDialog.getOpenFileName(self, "选择视频文件", "", "Video Files (*.mp4 *.avi *.mov)")
        if file_path:
            self.file_path_label.setText(file_path)
            self.start_detection(file_path)

    def toggle_webcam(self):
        if self.detection_thread and self.detection_thread.isRunning():
            self.detection_thread.stop()
            self.btn_webcam.setText("摄像头未开启")
        else:
            self.start_detection(0)
            self.btn_webcam.setText("摄像头已开启")

    def start_detection(self, source):
        if self.detection_thread and self.detection_thread.isRunning():
            self.detection_thread.stop()

        self.detection_thread = DetectionThread(self.model, source)
        self.detection_thread.frame_processed.connect(self.update_frame)
        self.detection_thread.finished.connect(self.on_detection_finished)
        self.detection_thread.start()

    def update_frame(self, qt_image, detections, infer_time):
        # 更新图像
        pixmap = QPixmap.fromImage(qt_image)
        self.image_label.setPixmap(pixmap.scaled(self.image_label.size(), Qt.KeepAspectRatio))

        # 更新检测结果
        self.time_label.setText(f"用时: {infer_time:.3f}s")
        self.count_label.setText(f"目标数目: {len(detections)}")

        # 更新置信度 (显示所有目标的平均置信度)
        if detections:
            avg_conf = sum(d['confidence'] for d in detections) / len(detections)
            self.conf_label.setText(f"置信度: {avg_conf:.2%}")
        else:
            self.conf_label.setText("置信度: 0.00%")

        # 更新表格
        self.table.setRowCount(len(detections))
        for i, det in enumerate(detections):
            self.table.setItem(i, 0, QTableWidgetItem(str(i + 1)))
            self.table.setItem(i, 1, QTableWidgetItem(self.file_path_label.text()))
            self.table.setItem(i, 2, QTableWidgetItem(det['class']))
            self.table.setItem(i, 3, QTableWidgetItem(f"{det['confidence']:.2%}"))
            coords = [int(x) for x in det['coordinates']]
            self.table.setItem(i, 4, QTableWidgetItem(str(coords)))

            # 如果有检测结果,更新位置信息(显示第一个检测到的目标)
            if i == 0:
                self.xmin_label.setText(f"xmin: {coords[0]}")
                self.ymin_label.setText(f"ymin: {coords[1]}")
                self.xmax_label.setText(f"xmax: {coords[2]}")
                self.ymax_label.setText(f"ymax: {coords[3]}")

    def on_detection_finished(self):
        self.btn_webcam.setText("摄像头未开启")
        QMessageBox.information(self, "提示", "视频播放完毕或摄像头已停止。")

    def closeEvent(self, event):
        if self.detection_thread and self.detection_thread.isRunning():
            self.detection_thread.stop()
        event.accept()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = MainWindow()
    window.show()
    sys.exit(app.exec_())

使用说明

  1. 准备环境: pip install ultralytics PyQt5 opencv-python torch
  2. 训练模型:
    • 将您的数据集按上述结构组织好。
    • 创建 data.yaml 文件。
    • 运行 train.py 脚本。
    • 训练完成后,模型权重将保存在 runs/train/library_occupancy_v11n/weights/best.pt
  3. 运行界面:
    • 确保 main_window.py 中的模型路径 self.model = YOLO('...') 指向您训练好的 best.pt 文件。
    • 运行 main_window.py 即可启动图形界面。
本文转载自知乎, 作者:知乎, 原文标题:《 基于YOLOv11的图书馆占座检测系统 深度学习YOLO11模型如何训练图书馆占位检测数据集 YOLO数据集 目标检测算法 》, 原文链接: https://zhuanlan.zhihu.com/p/2024739673570832835。 本平台仅做分享和推荐,不涉及任何商业用途。文章版权归原作者所有。如涉及作品内容、版权和其它问题,请与我们联系,我们将在第一时间删除内容!
本文相关推荐
暂无相关推荐