简介
跌倒是老年人和身体不便者常见的意外事故,及时检测和处理跌倒事件对于保障他们的安全至关重要。为了提高对跌倒事件的监控效率,我们开发了一种基于YOLOv5目标检测模型的跌倒检测系统。本报告将详细介绍该系统的实际应用与实现,包括系统架构、功能实现、使用说明、检测示例、数据集获取与介绍、YOLOv5模型介绍及其训练过程。
系统架构
系统组成
- 用户界面(GUI):基于PyQt5开发,支持图像、视频和实时摄像头检测功能。
- 检测模型:基于YOLOv5的目标检测模型,用于识别跌倒事件。
- 视频处理模块:处理视频流,实现实时跌倒检测。
- 数据管理模块:负责数据的加载、保存及标注。
工作流程
- 用户加载图像/视频或启动摄像头。
- 系统调用YOLOv5模型进行跌倒检测。
- 检测结果显示在GUI上,包括跌倒事件的位置和时间。
- 用户可以保存检测结果。
功能实现
import sys
import cv2
import torch
import numpy as np
import time
import os
from PyQt5.QtWidgets import QApplication, QMainWindow, QPushButton, QFileDialog, QLabel, QVBoxLayout, QWidget, \QHBoxLayout, QSlider, QMessageBox
from PyQt5.QtGui import QImage, QPixmap, QFont
from PyQt5.QtCore import QTimer, QThread, pyqtSignal, Qt, QMutex, QWaitConditionclass YoloV5Detector:def __init__(self):self.model = torch.hub.load('ultralytics/yolov5', 'custom', path="./yolov5_fall.pt")def detect_image(self, image_path):image = cv2.imread(image_path)results = self.model(image)return resultsdef detect_frame(self, frame):results = self.model(frame)return resultsclass VideoProcessor(QThread):frame_processed = pyqtSignal(np.ndarray)fps_signal = pyqtSignal(float)progress_signal = pyqtSignal(str)object_count_signal = pyqtSignal(int)category_count_signal = pyqtSignal(dict)def __init__(self, video_path=None, use_camera=False, output_dir='output'):super().__init__()self.video_path = video_pathself.use_camera = use_cameraself.running = Falseself.paused = Falseself.mutex = QMutex()self.condition = QWaitCondition()self.detector = YoloV5Detector()self.out = Noneself.output_dir = output_dirdef run(self):self.running = Trueif self.use_camera:cap = cv2.VideoCapture(0)else:cap = cv2.VideoCapture(self.video_path)if not cap.isOpened():return# Create unique filename based on current timecurrent_time = time.strftime("%Y%m%d_%H%M%S")os.makedirs(self.output_dir, exist_ok=True)output_file = os.path.join(self.output_dir, f'output_{current_time}.mp4')fourcc = cv2.VideoWriter_fourcc(*'mp4v')fps = cap.get(cv2.CAP_PROP_FPS)if fps == 0: # If fps cannot be obtained, set a default valuefps = 30width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))self.out = cv2.VideoWriter(output_file, fourcc, fps, (width, height))total_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))duration = total_frames / fpslast_time = time.time()frame_count = 0while self.running:self.mutex.lock()if self.paused:self.condition.wait(self.mutex)self.mutex.unlock()ret, frame = cap.read()if not ret:break#frame = cv2.resize(frame, (640, 640))results = self.detector.detect_frame(frame)annotated_frame = results.render()[0]self.frame_processed.emit(annotated_frame)object_count = len(results.xyxy[0]) # Number of detected objectscategories = results.names # Object category namescategory_counts = {category: (results.pred[0][:, -1] == i).sum().item() for i, category in categories.items()}non_zero_category_counts = {cat: count for cat, count in category_counts.items() if count > 0}self.object_count_signal.emit(object_count)self.category_count_signal.emit(non_zero_category_counts)if self.out:self.out.write(annotated_frame)frame_count += 1if frame_count % 10 == 0:current_time = frame_count / fpsprogress_text = f'{self.format_time(current_time)} / {self.format_time(duration)}'self.progress_signal.emit(progress_text)current_time = time.time()show_fps = 1.0 / (current_time - last_time)last_time = current_timeself.fps_signal.emit(show_fps)cap.release()if self.out:self.out.release()def format_time(self, seconds):mins, secs = divmod(seconds, 60)return f'{int(mins):02}:{int(secs):02}'def pause(self):self.paused = Truedef resume(self):self.paused = Falseself.condition.wakeAll()def stop(self):self.running = Falseself.resume()self.wait()class MainWindow(QMainWindow):def __init__(self):super().__init__()self.setWindowTitle('跌倒检测系统')self.setGeometry(100, 100, 1000, 700)self.layout = QVBoxLayout()self.label = QLabel(self)self.layout.addWidget(self.label)self.fps_label = QLabel(self)self.fps_label.setFont(QFont('Arial', 14))self.layout.addWidget(self.fps_label)self.object_count_label = QLabel(self)self.object_count_label.setFont(QFont('Arial', 14))self.layout.addWidget(self.object_count_label)self.category_count_label = QLabel(self)self.category_count_label.setFont(QFont('Arial', 14))self.layout.addWidget(self.category_count_label)self.progress_label = QLabel(self)self.progress_label.setFont(QFont('Arial', 14))self.layout.addWidget(self.progress_label)self.slider = QSlider(Qt.Horizontal)self.slider.setRange(0, 100)self.slider.setValue(0)self.slider.sliderPressed.connect(self.pause_video)self.slider.sliderReleased.connect(self.resume_video)self.layout.addWidget(self.slider)button_layout = QHBoxLayout()self.btn_image = QPushButton('Open Image', self)self.btn_image.setFont(QFont('Arial', 14))self.btn_image.clicked.connect(self.open_image)button_layout.addWidget(self.btn_image)self.btn_video = QPushButton('Open Video', self)self.btn_video.setFont(QFont('Arial', 14))self.btn_video.clicked.connect(self.open_video)button_layout.addWidget(self.btn_video)self.btn_camera = QPushButton('Open Camera', self)self.btn_camera.setFont(QFont('Arial', 14))self.btn_camera.clicked.connect(self.open_camera)button_layout.addWidget(self.btn_camera)self.btn_save = QPushButton('Save Result', self)self.btn_save.setFont(QFont('Arial', 14))self.btn_save.clicked.connect(self.save_result)button_layout.addWidget(self.btn_save)self.layout.addLayout(button_layout)self.container = QWidget()self.container.setLayout(self.layout)self.setCentralWidget(self.container)self.cap = Noneself.current_frame = Noneself.video_processor = Nonedef open_image(self):self.stop_video_processing()file_name, _ = QFileDialog.getOpenFileName(self, 'Open Image', '', 'Images (*.png *.xpm *.jpg *.jpeg *.bmp)')if file_name:self.show_loading_message(True)results = YoloV5Detector().detect_image(file_name)self.current_frame = results.render()[0]self.display_image(self.current_frame)self.fps_label.setText('')self.progress_label.setText('')self.object_count_label.setText('')self.category_count_label.setText('')self.show_loading_message(False)def open_video(self):self.stop_video_processing()file_name, _ = QFileDialog.getOpenFileName(self, 'Open Video', '', 'Videos (*.mp4 *.avi *.mov *.mkv)')if file_name:self.show_loading_message(True)self.start_video_processing(file_name)def open_camera(self):self.stop_video_processing()self.show_loading_message(True)self.start_video_processing(use_camera=True)def show_loading_message(self, show):self.btn_image.setEnabled(not show)self.btn_video.setEnabled(not show)self.btn_camera.setEnabled(not show)self.btn_save.setEnabled(not show)if show:QApplication.setOverrideCursor(Qt.WaitCursor)else:QApplication.restoreOverrideCursor()def start_video_processing(self, video_path=None, use_camera=False):self.video_processor = VideoProcessor(video_path=video_path, use_camera=use_camera)self.video_processor.frame_processed.connect(self.display_image)self.video_processor.fps_signal.connect(self.update_fps)self.video_processor.progress_signal.connect(self.update_progress)self.video_processor.object_count_signal.connect(self.update_object_count)self.video_processor.category_count_signal.connect(self.update_category_count)self.video_processor.start()self.show_loading_message(False)def stop_video_processing(self):if self.video_processor is not None:self.video_processor.stop()self.video_processor = Nonedef pause_video(self):if self.video_processor is not None:self.video_processor.pause()def resume_video(self):if self.video_processor is not None:self.video_processor.resume()def update_fps(self, fps):self.fps_label.setText(f'FPS: {fps:.2f}')def update_progress(self, progress):self.progress_label.setText(progress)def update_object_count(self, count):self.object_count_label.setText(f'Object Count: {count}')def update_category_count(self, category_counts):category_count_text = 'Category Counts: ' + ', '.join([f'{cat}: {count}' for cat, count in category_counts.items()])self.category_count_label.setText(category_count_text)def display_image(self, frame):# 将当前帧存储在实例变量中self.current_frame = frame# 将帧从 BGR(OpenCV 格式)转换为 RGB 格式# OpenCV 默认使用 BGR 格式,而 QImage 期望的是 RGB 格式rgb_frame = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)# 获取帧的尺寸height, width, channel = frame.shape# 计算 QImage 构造函数所需的每行字节数# 这等于图像的宽度乘以通道数(RGB 为 3)bytes_per_line = 3 * width# 从 RGB 帧数据创建一个 QImage# 使用数据、宽度、高度、每行字节数和图像格式来创建 QImageconvert_to_Qt_format = QImage(rgb_frame.data, width, height, bytes_per_line, QImage.Format_RGB888)scaled_image = convert_to_Qt_format.scaled(1000, 600, aspectRatioMode=1)# 将缩放后的 QImage 设置为 QLabel 的图像self.label.setPixmap(QPixmap.fromImage(scaled_image))# 确保图像在 QLabel 中居中self.label.setAlignment(Qt.AlignCenter)def save_result(self):if self.current_frame is not None:file_name, _ = QFileDialog.getSaveFileName(self, 'Save Image', '', 'Images (*.png *.jpg *.jpeg *.bmp)')if file_name:cv2.imwrite(file_name, self.current_frame)elif self.video_processor:self.video_processor.stop()self.video_processor.wait()self.video_processor = Noneif __name__ == '__main__':app = QApplication(sys.argv)window = MainWindow()window.show()sys.exit(app.exec_())
使用说明
- 加载图像/视频:
- 点击“Open Image”按钮加载待检测的图像。
- 点击“Open Video”按钮加载待检测的视频文件。
- 点击“Open Camera”按钮启动摄像头进行实时跌倒检测。
- 显示结果:
- 界面实时显示检测到的跌倒事件及其位置和时间。
- 显示实时帧率(FPS)、进度、检测统计信息等。
- 保存结果:
- 点击“Save Result”按钮保存当前检测结果。
检测示例
系统能够准确检测和标注出图像或视频中的跌倒事件,如下图所示:
数据集获取与介绍
数据集介绍
为了训练和评估模型,我们使用了一个包含大量跌倒事件图像和视频的公开数据集。数据集包含以下内容:
- 图像和视频数量:数据集中包含2000个标注好的视频片段和5000张图像。
- 标注信息:每个视频和图像都包含详细的跌倒事件标注,包括跌倒的起始和结束时间、位置等。
数据集获取
数据集可以通过以下链接获取:
- 公开数据集下载链接
下载后,将数据集解压到指定目录,并根据YOLOv5格式进行组织。
YOLOv5介绍
YOLOv5简介
YOLOv5(You Only Look Once Version 5)是一个先进的目标检测模型,由Ultralytics团队开发。与其前身相比,YOLOv5在速度和精度上有了显著提升,能够在实时应用中表现出色。
官方模型
YOLOv5提供了多种预训练模型,分别适用于不同的检测任务和需求。我们选择了适合跌倒检测的YOLOv5s模型,并在此基础上进行了微调,以适应具体的检测需求。
训练过程
数据准备
- 数据标注:使用LabelImg等工具对数据集进行标注,生成YOLOv5格式的标注文件。
- 数据划分:将数据集划分为训练集、验证集和测试集,比例为7:2:1。
模型训练
-
环境配置:在训练前,配置好所需的深度学习环境,包括安装PyTorch、YOLOv5等依赖项。
-
训练配置:设置训练参数,如学习率、批量大小、训练轮数等。
-
模型训练
:使用以下命令启动训练:
bash 复制代码 python train.py --img 640 --batch 16 --epochs 50 --data data.yaml --weights yolov5s.pt --cache
-
模型评估:在验证集上评估模型性能,记录精度、召回率、mAP等指标。
模型优化
- 超参数调整:根据评估结果调整学习率、批量大小、数据增强策略等超参数。
- 迁移学习:使用预训练模型进行迁移学习,提高模型在特定任务上的表现。
模型部署
- 模型保存:将训练好的模型保存为权重文件(如
yolov5s_fall.pt
)。 - 集成到系统:将模型集成到跌倒检测系统中,实现实时检测功能。
结论
本报告详细介绍了基于YOLOv5的跌倒检测系统,包括系统架构、功能实现、使用说明、检测示例、数据集获取与介绍、YOLOv5模型介绍以及训练过程。该系统通过PyQt5提供了友好的用户界面,支持图像、视频和实时摄像头的跌倒检测,具有较高的检测精度和实时性。未来可以进一步优化模型和系统,以提升跌倒检测的准确性和应用范围。
完整资料地址
- yolov5预训练模型地址:https://github.com/ultralytics/yolov5
- 本文项目完整链接:链接:链接:https://pan.baidu.com/s/1cd-IAjNpHefD92LQDgU93A?pwd=7j5z
- 包含: PyQT用户交互页面、训练好的检测模型(yolov5s)、几张测试图片、一段测试视频
- 提取码:7j5z
- 数据集:转载链接:https://blog.csdn.net/guyuealian/article/details/130250738