基于YOLOv5+pyqt5的跌倒检测系统(含pyqt页面、训练好的模型)

image-20240623154808782

简介

跌倒是老年人和身体不便者常见的意外事故,及时检测和处理跌倒事件对于保障他们的安全至关重要。为了提高对跌倒事件的监控效率,我们开发了一种基于YOLOv5目标检测模型的跌倒检测系统。本报告将详细介绍该系统的实际应用与实现,包括系统架构、功能实现、使用说明、检测示例、数据集获取与介绍、YOLOv5模型介绍及其训练过程。

系统架构

系统组成

  1. 用户界面(GUI):基于PyQt5开发,支持图像、视频和实时摄像头检测功能。
  2. 检测模型:基于YOLOv5的目标检测模型,用于识别跌倒事件。
  3. 视频处理模块:处理视频流,实现实时跌倒检测。
  4. 数据管理模块:负责数据的加载、保存及标注。

工作流程

  1. 用户加载图像/视频或启动摄像头
  2. 系统调用YOLOv5模型进行跌倒检测
  3. 检测结果显示在GUI上,包括跌倒事件的位置和时间
  4. 用户可以保存检测结果

功能实现

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_())

使用说明

  1. 加载图像/视频
    • 点击“Open Image”按钮加载待检测的图像。
    • 点击“Open Video”按钮加载待检测的视频文件。
    • 点击“Open Camera”按钮启动摄像头进行实时跌倒检测。
  2. 显示结果
    • 界面实时显示检测到的跌倒事件及其位置和时间。
    • 显示实时帧率(FPS)、进度、检测统计信息等。
  3. 保存结果
    • 点击“Save Result”按钮保存当前检测结果。

检测示例

系统能够准确检测和标注出图像或视频中的跌倒事件,如下图所示:

image-20240623154740788

image-20240623154855554

数据集获取与介绍

数据集介绍

为了训练和评估模型,我们使用了一个包含大量跌倒事件图像和视频的公开数据集。数据集包含以下内容:

  1. 图像和视频数量:数据集中包含2000个标注好的视频片段和5000张图像。
  2. 标注信息:每个视频和图像都包含详细的跌倒事件标注,包括跌倒的起始和结束时间、位置等。

数据集获取

数据集可以通过以下链接获取:

  • 公开数据集下载链接

下载后,将数据集解压到指定目录,并根据YOLOv5格式进行组织。

YOLOv5介绍

YOLOv5简介

YOLOv5(You Only Look Once Version 5)是一个先进的目标检测模型,由Ultralytics团队开发。与其前身相比,YOLOv5在速度和精度上有了显著提升,能够在实时应用中表现出色。

官方模型

YOLOv5提供了多种预训练模型,分别适用于不同的检测任务和需求。我们选择了适合跌倒检测的YOLOv5s模型,并在此基础上进行了微调,以适应具体的检测需求。

训练过程

数据准备

  1. 数据标注:使用LabelImg等工具对数据集进行标注,生成YOLOv5格式的标注文件。
  2. 数据划分:将数据集划分为训练集、验证集和测试集,比例为7:2:1。

模型训练

  1. 环境配置:在训练前,配置好所需的深度学习环境,包括安装PyTorch、YOLOv5等依赖项。

  2. 训练配置:设置训练参数,如学习率、批量大小、训练轮数等。

  3. 模型训练

    :使用以下命令启动训练:

    bash
    复制代码
    python train.py --img 640 --batch 16 --epochs 50 --data data.yaml --weights yolov5s.pt --cache
    
  4. 模型评估:在验证集上评估模型性能,记录精度、召回率、mAP等指标。

模型优化

  1. 超参数调整:根据评估结果调整学习率、批量大小、数据增强策略等超参数。
  2. 迁移学习:使用预训练模型进行迁移学习,提高模型在特定任务上的表现。

模型部署

  1. 模型保存:将训练好的模型保存为权重文件(如yolov5s_fall.pt)。
  2. 集成到系统:将模型集成到跌倒检测系统中,实现实时检测功能。

结论

本报告详细介绍了基于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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/web/32647.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

虚拟机IP地址频繁变化的解决方法

勾八动态分配IP,让我在学习redis集群的时候,配置很多的IP地址,但是由于以下原因导致我IP频繁变动,报错让我烦恼!!!! 为什么虚拟机的IP地址会频繁变化? 虚拟机IP地址频繁…

终极解决方案,传统极速方案,下载软件的双雄对决!

在数字资源日益丰富的今天,下载管理器成为了我们日常生活中不可或缺的工具。市场上两款备受欢迎的下载管理软件——Internet Download Manager(IDM)和迅雷11,它们以各自的特色和优势,满足了不同用户群体的需求。 软件…

uniapp使用伪元素实现气泡

uniapp使用伪元素实现气泡 背景实现思路代码实现尾巴 背景 气泡效果在开发中使用是非常常见的,使用场景有提示框,对话框等等,今天我们使用css来实现气泡效果。老规矩,先看下效果图: 实现思路 其实实现这个气泡框的…

自动驾驶规划中使用 OSQP 进行二次规划 代码原理详细解读

目录 1 问题描述 什么是稀疏矩阵 CSC 形式 QP Path Planning 问题 1. Cost function 1.1 The first term: 1.2 The second term: 1.3 The thrid term: 1.4 The forth term: 对 Qx 矩阵公式的验证 整体 Q 矩阵(就是 P 矩阵,二次项的权重矩阵&…

java打印菱形和空心菱形

java打印菱形 菱形分上下两个部分。其中上部分同打印金字塔;下部分循环部分i是递减 (ps:菱形层数只能为奇数) import java.util.Scanner;public class Lingxing{public static void main(String[] args) {Scanner myScanner new Scanner(S…

Android View点击事件分发原理,源码解读

View点击事件分发原理,源码解读 前言1. 原理总结2.1 时序图总结2.2 流程图总结 2. 源码解读2.1 Activity到ViewGroup2.2 ViewGroup事件中断逆序搜索自己处理点击事件ViewGroup总结 2.3 ViewOnTouchListeneronTouchEvent 3. 附录:时序图uml代码 前言 两年…

Nginx Proxy Manager反向代理Jackett

1 说明 最近折腾nas,发现npm反向代理Jackett后出现无法访问的问题,是因为外网访问jackett (例如https://domain.com:7373/jackett/UI/Dashboard)时,url会被重定向到https://domain.com/jackett/UI/Login?ReturnUrl%2Fjackett%2FUI%2FDashbo…

ubuntu链接mysql

C链接mysql 报错 sudo apt-get update sudo apt-get install libmysqlclient-dev 指令编译 g -o mysql_example mysql_example.cpp -I/usr/include/mysql -lmysqlclient g mysql_test.cpp mysql_config --cflags --libs 安装mysql sudo apt updatesudo apt install mysql-…

Java程序之动物声音“模拟器”

题目: 设计一个“动物模拟器”,希望模拟器可以模拟许多动物的叫声和行为,要求如下: 编写接口Animal,该接口有两个抽象方法cry()和getAnimalName(),即要求实现该接口的各种具体的动物类给出自己的叫声和种类…

尹会生:从零开始部署翻译助手【总结】

安装docker安装dify 工具准备 Docker 简介:可以在不同电脑上运行相同的容器,类似于把软件装在便携箱子里,随身携带。 优点:安装Docker可以简化部署过程,避免安装许多依赖性软件。 网址:https://www.docke…

【TOOL】ceres学习笔记(二) —— 自定义函数练习

文章目录 一、曲线方程1. 问题描述2. 实现方案 一、曲线方程 1. 问题描述 现有数学模型为 f ( x ) A e x B s i n ( x ) C x D f(x)Ae^xBsin(x)Cx^D f(x)AexBsin(x)CxD ,但不知道 A A A 、 B B B 、 C C C 、 D D D 各参数系数,实验数据中含有噪声…

基于Java作业管理系统设计和实现(源码+LW+调试文档+讲解等)

💗博主介绍:✌全网粉丝10W,CSDN作者、博客专家、全栈领域优质创作者,博客之星、平台优质作者、专注于Java、小程序技术领域和毕业项目实战✌💗 🌟文末获取源码数据库🌟 感兴趣的可以先收藏起来,…

Java——集合(一)

前言: Collection集合,List集合 文章目录 一、Collection 集合1.1 集合和数组的区别1.2 集合框架1.3 Collection 集合常用方法1.4 Collction 集合的遍历 二、List 集合2.1 List 概述2.2 List集合的五种遍历方式2.3 List集合的实现类 一、Collection 集合 1.1 集合和…

Vitis Accelerated Libraries 学习笔记--OpenCV 安装指南

目录 1. 简介 2. 安装过程 2.1 安装准备 2.2 编译并安装 XRT 2.2.1 下载 XRT 源码 2.2.2 安装依赖项 2.2.3 构建 XRT 2.2.4 打包 DEB 2.2.5 安装 XRT 2.3 编译并安装 OpenCV 2.3.1 下载 OpenCV 源码 2.3.2 创建目录 2.3.3 设置环境变量 2.3.4 构建 opencv 3. 总…

ping命令返回结果实例分析

测试在各相关情况下ping命令回复信息。 网络环境搭建如下图所示: 【1】R1、R2、PC1和PC2没有配置,测试ping命令回复 在路由器没有配置端口IP地址和路由,PC没有配置IP地址、子网掩码和网关的情况下,PC2 ping 192.168.1.1。 在PC没…

加速鸿蒙生态共建,蚂蚁mPaaS助力鸿蒙原生应用开发创新

6月21日-23日,2024华为开发者大会(HDC 2024)如期举行。在22日的【鸿蒙生态伙伴SDK】分论坛中,正式发布了【鸿蒙生态伙伴SDK市场】,其中蚂蚁数科旗下移动开发平台mPaaS(以下简称:蚂蚁mPaaS&#…

QtCreator/VS中制作带有界面的动态库

1、首先创建动态库项目 class UNTITLED25_EXPORT Untitled25 {public:Untitled25(); };2、直接右键创建同名窗口类进行覆盖 3、引入global头文件并添加到处宏</

【SSM】

Spring常见面试题总结 Spring 基础 什么是 Spring 框架? Spring 是一款开源的轻量级 Java 开发框架&#xff0c;旨在提高开发人员的开发效率以及系统的可维护性。 我们一般说 Spring 框架指的都是 Spring Framework&#xff0c;它是很多模块的集合&#xff0c;使用这些模块…

转让神州开头的无区域科技公司需要多少钱

您好&#xff0c;我公司现有2家无区域神州名称的公司转让。所谓无区域名称是公司名称中不带有行政区划、及行业特点的公司名称&#xff0c;都是需要在工商总,局核准名称的&#xff0c;对于民营企业来说也比较喜欢这种名称名称很大气&#xff0c;现在重核更严格了&#xff0c;所…

Docker如何安装redis

目录 1. 拉取redis的镜像文件 2. 创建redis的容器卷 3. 准备reids的配置文件 4. 以配置文件启动redis 1. 拉取redis的镜像文件 # 默认安装最新版本 如果需要指定版本 docker pull redis:版本号 docker pull redis 详细版本请看dockerhub的官网&#xff1a; hub.docker…