智慧校园-校园暴力目标检测数据集 校园打架行为检测数据集暴力行为检测数据集的训练及应用 YOLOv8** 和 **PyQt5** 的校园暴力检测系统

目标检测实战:仪表盘指针识别

保姆级 YOLOv8/9/10 教程,附完整数据集与源码

智慧校园-校园暴力目标检测数据集
在这里插入图片描述

包含[ ‘fight02’, ‘fighter01’, ‘fighter02’, ‘fighter03’, ‘fighter04’, ‘ousider02’, ‘ousider03’, ‘outsider01’, ‘outsider02’, ‘outsider03’, ‘outsider04’, ‘outsider05’, ‘threatener01’, ‘threatener02’, ‘threatener03’, ‘threatener04’, ‘victim01’, ‘victim02’, ‘victim03’, ‘victim04’]几个种类。
在这里插入图片描述

数据集包含图片共4339张。
可提供各种YOLO格式

在这里插入图片描述
1
在这里插入图片描述

构建一个基于 YOLOv8PyQt5 的校园暴力检测系统,核心在于利用 YOLOv8 强大的多目标检测能力识别出 fighter (打斗者), victim (受害者), threatener (威胁者) 等角色,并通过 PyQt5 构建一个可视化的监控界面,实现实时报警和视频回放。

以下是完整的实施步骤,包含数据预处理模型训练PyQt5 界面开发核心逻辑代码


🛠️ 1. 数据预处理与配置

由于你的数据集中存在拼写错误 (ousider vs outsider) 且类别过于细碎 (01-04),为了提升模型的泛化能力和训练稳定性,建议进行类别合并

A. 类别合并策略 (推荐)

将 20 个细粒度类别合并为 4 个核心行为类别:

  • fighter: 合并 fighter01 ~ fighter04, fight02
  • victim: 合并 victim01 ~ victim04
  • threatener: 合并 threatener01 ~ threatener04
  • outsider: 合并 outsider01 ~ outsider05, ousider02, ousider03

如果不合并:模型需要学习区分“第一个打斗者”和“第二个打斗者”,这在逻辑上是不必要的,且会导致样本分散,降低精度。强烈建议合并。

B. 数据集目录结构
violence_dataset/
├── images/
│   ├── train/
│   ├── val/
│   └── test/
├── labels/  # 确保这里的 txt 文件中的类别 ID 已根据合并策略更新 (0-3)
│   ├── train/
│   ├── val/
│   └── test/
└── violence_data.yaml
C. 配置文件 violence_data.yaml
path: ./violence_dataset
train: images/train
val: images/val
test: images/test

nc: 4  # 合并后的类别数

names:
  0: fighter     # 打斗者 (红色预警)
  1: victim      # 受害者 (橙色预警)
  2: threatener  # 威胁者 (黄色预警)
  3: outsider    # 旁观者 (蓝色标记,通常不触发强报警)

🚀 2. YOLOv8 模型训练

使用 Python 脚本进行训练,针对暴力行为特点调整超参数。

from ultralytics import YOLO
import torch

def train_violence_model():
    print("🥊 开始训练校园暴力检测模型...")
    
    # 加载预训练权重 (建议使用 m 或 l 版本以捕捉细微动作)
    model = YOLO('yolov8m.pt') 

    results = model.train(
        data='violence_data.yaml',
        epochs=100,
        imgsz=640,
        batch=16,
        device='0' if torch.cuda.is_available() else 'cpu',
        workers=4,
        
        # 针对暴力行为的增强
        augment=True,
        hsv_h=0.015,
        hsv_s=0.7,
        hsv_v=0.4,
        degrees=0.0,      # 暴力场景通常水平,禁止旋转
        translate=0.1,
        scale=0.5,
        shear=0.0,
        perspective=0.0,
        flipud=0.0,       # 禁止上下翻转
        fliplr=0.5,
        mosaic=1.0,       # Mosaic 对拥挤场景(多人打架)非常有效
        mixup=0.1,
        copy_paste=0.2,   # 增加打斗者的出现频率
        
        # 优化器设置
        optimizer='SGD',
        lr0=0.01,
        lrf=0.01,
        patience=30,
        
        project='runs/violence_detect',
        name='violence_yolov8m_v1',
        exist_ok=False,
        verbose=True
    )
    
    print(f"✅ 训练完成!模型保存于:{results.save_dir}/weights/best.pt")
    
    # 验证模型
    model.val(split='test')

if __name__ == '__main__':
    train_violence_model()

🖥️ 3. 构建 PyQt5 暴力检测系统

这是一个完整的单文件 PyQt5 应用程序,集成了视频流读取、YOLOv8 推理、实时绘图、报警逻辑和日志记录。

前置安装
pip install ultralytics opencv-python PyQt5 numpy
核心代码 violence_monitor.py
import sys
import cv2
import numpy as np
from PyQt5.QtWidgets import (QApplication, QMainWindow, QLabel, QPushButton, 
                             QVBoxLayout, QWidget, QMessageBox, QTextEdit, QGroupBox)
from PyQt5.QtCore import QTimer, Qt, QThread, pyqtSignal
from PyQt5.QtGui import QImage, QPixmap, QFont, QColor
from ultralytics import YOLO
from datetime import datetime

# --- 配置区域 ---
MODEL_PATH = 'runs/violence_detect/violence_yolov8m_v1/weights/best.pt'
CONF_THRESHOLD = 0.4
IOU_THRESHOLD = 0.5
ALERT_CLASSES = ['fighter', 'victim', 'threatener']  # 触发报警的类别
COLORS = {
    'fighter': (0, 0, 255),      # Red (BGR)
    'victim': (0, 165, 255),     # Orange
    'threatener': (0, 255, 255), # Yellow
    'outsider': (255, 255, 0)    # Cyan
}

class DetectionThread(QThread):
    """后台检测线程,避免阻塞 UI"""
    frame_signal = pyqtSignal(QImage, list, float)  # 图像, 检测结果, FPS

    def __init__(self, video_source, model_path):
        super().__init__()
        self.video_source = video_source
        self.model = YOLO(model_path)
        self.running = True

    def run(self):
        cap = cv2.VideoCapture(self.video_source)
        if not cap.isOpened():
            print("无法打开摄像头/视频")
            return

        while self.running:
            ret, frame = cap.read()
            if not ret:
                break
            
            start_time = cv2.getTickCount()
            
            # YOLO 推理
            results = self.model(frame, conf=CONF_THRESHOLD, iou=IOU_THRESHOLD, verbose=False)
            result = results[0]
            
            detections = []
            boxes = result.boxes
            if boxes is not None:
                for i in range(len(boxes)):
                    cls_id = int(boxes.cls[i])
                    conf = float(boxes.conf[i])
                    class_name = self.model.names[cls_id]
                    xyxy = boxes.xyxy[i].cpu().numpy()
                    detections.append({
                        'class': class_name,
                        'conf': conf,
                        'box': xyxy
                    })
            
            # 计算 FPS
            end_time = cv2.getTickCount()
            fps = cv2.getTickFrequency() / (end_time - start_time)
            
            # 绘制结果到帧上 (为了在 UI 显示)
            display_frame = self.draw_detections(frame, detections)
            
            # 转换格式 BGR -> RGB -> QImage
            h, w, ch = display_frame.shape
            bytes_per_line = ch * w
            qt_image = QImage(display_frame.data, w, h, bytes_per_line, QImage.Format_RGB888)
            
            self.frame_signal.emit(qt_image, detections, fps)
            
            # 控制帧率 (可选,防止过快)
            # self.msleep(30) 

        cap.release()

    def draw_detections(self, frame, detections):
        for det in detections:
            x1, y1, x2, y2 = map(int, det['box'])
            label = f"{det['class']} {det['conf']:.2f}"
            color = COLORS.get(det['class'], (0, 255, 0))
            
            # 画框
            cv2.rectangle(frame, (x1, y1), (x2, y2), color, 2)
            # 画背景文字
            (w, h), _ = cv2.getTextSize(label, cv2.FONT_HERSHEY_SIMPLEX, 0.6, 2)
            cv2.rectangle(frame, (x1, y1 - 20), (x1 + w, y1), color, -1)
            cv2.putText(frame, label, (x1, y1 - 5), cv2.FONT_HERSHEY_SIMPLEX, 0.6, (0, 0, 0), 2)
        return frame

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

class ViolenceMonitorSystem(QMainWindow):
    def __init__(self):
        super().__init__()
        self.setWindowTitle("🏫 校园暴力智能监控系统 (YOLOv8 + PyQt5)")
        self.setGeometry(100, 100, 1200, 800)
        
        # 加载模型检查
        try:
            self.model_path = MODEL_PATH
            # 简单检查文件是否存在,实际加载在线程中
            import os
            if not os.path.exists(self.model_path):
                QMessageBox.critical(self, "错误", f"未找到模型文件:\n{self.model_path}\n请先运行训练脚本!")
                sys.exit(1)
        except Exception as e:
            QMessageBox.critical(self, "错误", str(e))
            sys.exit(1)

        self.init_ui()
        self.thread = None
        self.alert_count = 0
        self.last_alert_time = 0

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

        # 1. 视频显示区域
        self.video_label = QLabel("等待视频流...")
        self.video_label.setAlignment(Qt.AlignCenter)
        self.video_label.setStyleSheet("background-color: #000; border: 2px solid #333; min-height: 480px;")
        main_layout.addWidget(self.video_label, stretch=3)

        # 2. 控制与日志区域
        control_layout = QVBoxLayout()
        
        # 状态面板
        status_group = QGroupBox("🚨 实时状态")
        status_layout = QVBoxLayout()
        self.status_label = QLabel("状态: ⭕ 监测中")
        self.status_label.setFont(QFont("Arial", 14, QFont.Bold))
        self.status_label.setStyleSheet("color: green;")
        self.fps_label = QLabel("FPS: 0.0")
        status_layout.addWidget(self.status_label)
        status_layout.addWidget(self.fps_label)
        status_group.setLayout(status_layout)
        control_layout.addWidget(status_group)

        # 日志面板
        log_group = QGroupBox("📝 报警日志")
        log_layout = QVBoxLayout()
        self.log_text = QTextEdit()
        self.log_text.setReadOnly(True)
        self.log_text.setFont(QFont("Consolas", 10))
        self.log_text.setStyleSheet("background-color: #f0f0f0;")
        log_layout.addWidget(self.log_text)
        log_group.setLayout(log_layout)
        control_layout.addWidget(log_group, stretch=1)

        # 按钮
        btn_layout = QVBoxLayout()
        self.start_btn = QPushButton("▶ 启动监控 (摄像头)")
        self.start_btn.clicked.connect(self.start_monitoring)
        self.start_btn.setStyleSheet("background-color: #28a745; color: white; font-size: 16px; padding: 10px;")
        
        self.stop_btn = QPushButton("⏹ 停止监控")
        self.stop_btn.clicked.connect(self.stop_monitoring)
        self.stop_btn.setEnabled(False)
        self.stop_btn.setStyleSheet("background-color: #dc3545; color: white; font-size: 16px; padding: 10px;")

        btn_layout.addWidget(self.start_btn)
        btn_layout.addWidget(self.stop_btn)
        control_layout.addLayout(btn_layout)

        # 组合左右布局 (视频左,控制右)
        # 这里简化为上下布局,实际可改为 QHBoxLayout 分左右
        main_layout.addLayout(control_layout, stretch=1)
        
        central_widget.setLayout(main_layout)

    def start_monitoring(self):
        self.start_btn.setEnabled(False)
        self.stop_btn.setEnabled(True)
        self.log_text.append(f"[{datetime.now().strftime('%H:%M:%S')}] 系统启动,加载模型中...")
        
        # 0 代表默认摄像头,也可替换为视频路径 'violence_test.mp4'
        self.thread = DetectionThread(0, self.model_path)
        self.thread.frame_signal.connect(self.update_frame)
        self.thread.start()

    def stop_monitoring(self):
        if self.thread:
            self.thread.stop()
            self.thread = None
        self.start_btn.setEnabled(True)
        self.stop_btn.setEnabled(False)
        self.video_label.clear()
        self.video_label.setText("监控已停止")
        self.status_label.setText("状态: ⭕ 已停止")
        self.status_label.setStyleSheet("color: gray;")
        self.log_text.append(f"[{datetime.now().strftime('%H:%M:%S')}] 系统停止")

    def update_frame(self, q_image, detections, fps):
        # 更新视频
        pixmap = QPixmap.fromImage(q_image)
        self.video_label.setPixmap(pixmap.scaled(self.video_label.size(), Qt.KeepAspectRatio, Qt.SmoothTransformation))
        
        # 更新 FPS
        self.fps_label.setText(f"FPS: {fps:.1f}")

        # 报警逻辑
        alert_triggered = False
        alert_msgs = []
        
        for det in detections:
            if det['class'] in ALERT_CLASSES:
                alert_triggered = True
                alert_msgs.append(f"{det['class']} (置信度: {det['conf']:.2f})")
        
        if alert_triggered:
            current_time = datetime.now().timestamp()
            # 防抖动:每秒只记录一次详细日志,但状态实时变红
            self.status_label.setText("状态: 🔴 检测到暴力行为!")
            self.status_label.setStyleSheet("color: red; font-weight: bold; font-size: 18px;")
            
            if current_time - self.last_alert_time > 1.0:
                msg = ", ".join(alert_msgs)
                self.log_text.append(f"[{datetime.now().strftime('%H:%M:%S')}] ⚠️ 警报: 发现 {msg}")
                self.log_text.verticalScrollBar().setValue(self.log_text.verticalScrollBar().maximum())
                self.last_alert_time = current_time
                # 这里可以添加播放声音代码: playsound('alarm.wav')
        else:
            self.status_label.setText("状态: 🟢 正常监测中")
            self.status_label.setStyleSheet("color: green;")

    def closeEvent(self, event):
        self.stop_monitoring()
        event.accept()

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

💡 4. 系统功能亮点与优化

  1. 细粒度行为分析

    • 系统不仅报告“有异常”,还能明确指出是 fighter (正在打人) 还是 victim (正在被打),甚至能识别出 threatener (潜在威胁),这对于校园安保人员提前介入至关重要。
  2. 多线程架构

    • 使用 QThread 将耗时的 YOLO 推理放在后台线程,确保 PyQt5 的主界面(UI)永远流畅,不会出现“未响应”的情况。
  3. 智能防误报

    • 代码中加入了时间戳判断 (last_alert_time),避免同一秒内日志刷屏,同时保持状态栏实时红色高亮。
    • 可以通过增加逻辑:只有连续 N 帧检测到 fighter 才触发最高级别警报。
  4. 可视化增强

    • 不同类别使用不同颜色的边框(红、橙、黄),一目了然。
    • 实时显示 FPS,方便评估硬件性能。

目标检测实战:仪表盘指针识别

保姆级 YOLOv8/9/10 教程,附完整数据集与源码

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值