ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

基于YOLOv8与MediaPipe的室内老人摔倒检测系统设计与实现

基于YOLOv8与MediaPipe的室内老人摔倒检测系统设计与实现 简介本资源是一套面向计算机、电子信息工程及数学等专业本科生的室内老人摔倒检测系统完整实现适用于课程设计、期末大作业及毕业设计场景聚焦智能健康监护中的关键检测问题。压缩包共110个文件含99个Java核心源码涵盖UserServiceImpl、DeviceServiceImpl等业务逻辑与FileUtil、PasswordEncryptUtil等工具类、3个XML配置文件、1个application.yml、1个SQL建表脚本及CMD/Maven构建相关文件整体仅148KB轻量易读且结构清晰便于理解前后端协同机制与算法集成路径。已有44人学习下载适合中初级开发者快速掌握图像/传感器数据驱动的摔倒识别系统开发全流程。读者可直接复用后端服务架构、安全通信模块与算法调用接口参考NotifyConfigTemplateServiceImpl等模块学习告警联动设计并基于Maven Wrapper实现跨环境一键构建。1. 项目概述一个面向真实场景的毕业设计实战最近几年无论是计算机专业的毕业设计还是课程设计选题越来越倾向于解决实际的社会问题。其中“室内老人摔倒检测系统”就是一个非常典型且有意义的方向。它融合了计算机视觉、Web全栈开发以及物联网的初步思想对于学生而言既能锻炼算法能力又能串联起前后端开发的完整流程是一个含金量很高的综合性项目。这个项目的核心目标很明确通过部署在室内的摄像头实时监测老人的活动状态一旦算法判断发生了摔倒行为系统能立即通过前端界面发出警报并可能联动短信、电话等通知监护人。它不是一个简单的Demo而是一个具备完整数据流、业务逻辑和用户交互的“微系统”。从技术栈上看它通常涵盖Python用于算法开发如OpenCV、YOLO/Pose Estimation模型、Java/Spring Boot或Python/Django/Flask用于构建后端API服务、以及Vue.js/React用于构建管理告警信息的前端界面。很多同学会基于像RuoYi这样的快速开发框架来搭建后端以节省基础CRUD的时间专注于业务逻辑。我之所以认为这个选题好是因为它“麻雀虽小五脏俱全”。你不仅要考虑算法准确率误报和漏报还要设计合理的系统架构处理视频流的实时传输、分析结果的持久化、告警的及时推送以及一个清晰易懂的前端来展示状态和历史记录。接下来我将从系统设计、关键技术选型、具体实现步骤以及那些容易踩坑的细节为你完整拆解这个项目。2. 系统整体架构与核心模块设计一个健壮的摔倒检测系统绝不能是算法、后端、前端三个部分的简单堆砌。我们需要设计一个清晰、解耦、可扩展的数据流架构。下图展示了一个经过实践检验的经典分层架构核心数据流摄像头 - 算法服务 - 后端服务 - 数据库 前端/通知服务2.1 前端模块信息展示与交互中枢前端是系统的“面子”负责将后台的数据和状态直观地呈现给用户通常是护工或家属。一个基础的前端模块应包含以下功能页面实时监控看板这是核心页面。需要展示实时视频流或关键帧图片、当前检测状态如“正常活动”、“疑似摔倒”、“已摔倒”、系统信心度等。可以考虑用卡片、状态指示灯等元素进行可视化。历史告警查询以表格或时间轴形式展示所有历史摔倒告警事件包括发生时间、位置如果多摄像头、处理状态未处理、已确认、误报。设备管理用于管理接入系统的摄像头包括添加、删除、编辑摄像头信息如名称、IP地址、房间位置。系统设置配置告警规则如连续多少帧判定为摔倒才触发告警配置通知方式如是否启用短信、邮件通知以及接收人列表。技术选型建议对于毕业设计Vue 3 Element Plus或React Ant Design是绝佳组合。它们生态成熟组件丰富能让你快速搭建出专业的管理界面。采用前后端分离架构前端通过Axios调用后端RESTful API获取数据。注意前端展示实时视频流是个小难点。通常不建议用WebSocket直接推流这样对带宽和前端压力都大。更常见的做法是算法服务将检测结果包括状态和打框后的图片以高频率如每秒1-2次通过API发送给后端后端再推给前端可用WebSocket或SSE。前端只需定时更新这张结果图片即可。2.2 后端模块业务逻辑与数据调度中心后端是系统的“里子”承担了承上启下的关键作用。它需要提供稳定的API供前端调用同时要处理算法服务传来的检测结果进行逻辑判断、数据存储和触发告警。核心API设计POST /api/alarm接收算法服务推送的检测结果。GET /api/alarms前端查询历史告警记录。PUT /api/alarm/{id}/status更新某条告警的处理状态。GET /api/device/status获取各摄像头连接状态。POST /api/notification/test测试告警通知。技术选型建议Java技术栈Spring Boot MyBatis-Plus MySQL。这是企业级开发最主流的组合资料多生态完整。RuoYi这类开源框架提供了用户管理、权限控制等基础模块能极大加快开发速度让你更专注于摔倒检测特有的业务逻辑。Python技术栈FastAPI或Django REST Framework。如果你的算法也是Python写的选择Python全家桶可以降低语言切换的成本。FastAPI性能好异步支持佳适合高并发的检测结果接收。数据库表结构核心字段alarm_event (告警事件表):id,device_id摄像头ID,event_type如‘fall’,confidence置信度,image_url快照存储路径,status未处理/已处理/误报,created_at。device (设备表):id,name,location,stream_urlRTSP地址,is_active。2.3 摔倒检测算法模块系统的“大脑”这是项目的技术核心直接决定了系统的可用性。摔倒检测算法的发展经历了从传统图像处理到深度学习的过程。1. 传统方法基于姿态估计与规则 这是毕业设计中非常务实且可解释性强的选择。其流程通常是步骤1目标检测。使用YOLOv5/v8等模型从视频帧中检测出“人”这个目标。你可以使用开源预训练模型无需自己标注海量数据。步骤2关键点检测。在检测到的人体框内使用OpenPose、MediaPipe Pose或MMPose等库提取人体的关键骨骼点如头、颈、肩、髋、膝、踝等17或25个点。步骤3特征计算与规则判断。基于关键点计算特征最常用的是人体宽高比摔倒时人体在图像中的包围框通常会变“扁”即宽度增加、高度减小。计算height / width比值突然显著下降可作为特征。躯干与地面的夹角利用髋部和肩部的关键点计算躯干中心线的向量再计算该向量与水平方向的夹角。正常站立时夹角接近90度摔倒时夹角会变得很小。关键点速度与加速度分析髋部或头部关键点在垂直方向上的运动速度。突然的加速下坠是摔倒的强烈信号。步骤4多帧融合与决策。为了避免单帧误判需要引入状态机。例如连续N帧如10帧约0.3秒内上述特征都满足摔倒条件才最终判定为“摔倒”事件并触发告警。2. 深度学习方法端到端检测 这种方法更“黑盒”但可能更精准。你可以收集或开源数据集如Le2i Fall Detection Dataset上训练一个专门用于“摔倒”和“非摔倒”分类的CNN如ResNet, EfficientNet或时空模型如3D CNN, SlowFast。或者使用目标检测模型如YOLO直接检测“摔倒的人”这个类别。这对数据标注的要求较高。对于毕设的务实建议采用“YOLOv8 MediaPipe Pose 规则判断”的Pipeline。理由如下YOLOv8检测精度和速度平衡得很好PyTorch生态部署简单。MediaPipe PoseGoogle开源轻量级CPU上即可实时运行提供稳定的人体关键点。规则判断可解释性强方便调试和调整阈值如height/width 1.2且torso_angle 45度也便于在你的论文中阐述算法原理。3. 核心模块的详细实现与集成3.1 算法服务实现详解我们以“YOLOv8 MediaPipe 规则”方案为例拆解核心代码逻辑。算法服务通常是一个独立的Python进程。# fall_detection_service.py 核心逻辑示意 import cv2 from ultralytics import YOLO import mediapipe as mp import numpy as np import time import requests # 用于调用后端API class FallDetector: def __init__(self, rtsp_url, backend_api_url): self.cap cv2.VideoCapture(rtsp_url) self.yolo_model YOLO(yolov8n.pt) # 加载YOLOv8nano预训练模型 self.mp_pose mp.solutions.pose self.pose self.mp_pose.Pose(static_image_modeFalse, min_detection_confidence0.5) self.backend_url backend_api_url self.fall_status False self.fall_counter 0 self.NECESSARY_CONSECUTIVE_FRAMES 10 # 连续10帧判定为摔倒才报警 def calculate_torso_angle(self, landmarks): # 获取左肩、右肩、左髋、右髋的关键点索引MediaPipe标准 left_shoulder landmarks[self.mp_pose.PoseLandmark.LEFT_SHOULDER] right_shoulder landmarks[self.mp_pose.PoseLandmark.RIGHT_SHOULDER] left_hip landmarks[self.mp_pose.PoseLandmark.LEFT_HIP] right_hip landmarks[self.mp_pose.PoseLandmark.RIGHT_HIP] # 计算肩部和髋部中心点 shoulder_center ((left_shoulder.x right_shoulder.x)/2, (left_shoulder.y right_shoulder.y)/2) hip_center ((left_hip.x right_hip.x)/2, (left_hip.y right_hip.y)/2) # 计算躯干向量 (hip_center - shoulder_center) torso_vector np.array([shoulder_center[0] - hip_center[0], shoulder_center[1] - hip_center[1]]) # 计算垂直向量 (指向下方) vertical_vector np.array([0, 1]) # 计算夹角 dot_product np.dot(torso_vector, vertical_vector) norm_torso np.linalg.norm(torso_vector) norm_vertical np.linalg.norm(vertical_vector) angle np.degrees(np.arccos(dot_product / (norm_torso * norm_vertical))) return angle def process_frame(self, frame): # 1. YOLO检测人 results self.yolo_model(frame, classes[0]) # class 0 是 ‘person’ person_boxes [] for box in results[0].boxes: if box.conf 0.5: # 置信度阈值 x1, y1, x2, y2 map(int, box.xyxy[0]) person_boxes.append((x1, y1, x2, y2)) current_frame_fall False for (x1, y1, x2, y2) in person_boxes: person_roi frame[y1:y2, x1:x2] if person_roi.size 0: continue # 2. MediaPipe姿态估计 roi_rgb cv2.cvtColor(person_roi, cv2.COLOR_BGR2RGB) pose_results self.pose.process(roi_rgb) if pose_results.pose_landmarks: landmarks pose_results.pose_landmarks.landmark # 3. 计算特征 height y2 - y1 width x2 - x1 aspect_ratio height / width if width 0 else 0 torso_angle self.calculate_torso_angle(landmarks) # 4. 应用规则 if aspect_ratio 1.2 and torso_angle 45: current_frame_fall True cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 0, 255), 2) cv2.putText(frame, Fall Detected!, (x1, y1-10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0,0,255), 2) else: cv2.rectangle(frame, (x1, y1), (x2, y2), (0, 255, 0), 2) return frame, current_frame_fall def run(self): while self.cap.isOpened(): ret, frame self.cap.read() if not ret: break processed_frame, is_fall self.process_frame(frame) # 5. 多帧决策逻辑 if is_fall: self.fall_counter 1 else: self.fall_counter max(0, self.fall_counter - 1) # 缓慢复位防止抖动 if self.fall_counter self.NECESSARY_CONSECUTIVE_FRAMES and not self.fall_status: # 触发告警 self.fall_status True print([ALARM] Fall Event Triggered!) # 保存当前帧为图片 timestamp int(time.time()) image_filename ffall_snapshot_{timestamp}.jpg cv2.imwrite(f./snapshots/{image_filename}, processed_frame) # 调用后端API上报告警 alarm_data { deviceId: camera_01, eventType: fall, confidence: 0.95, # 可以根据规则满足程度计算一个置信度 imageUrl: f/snapshots/{image_filename} } try: resp requests.post(f{self.backend_url}/api/alarm, jsonalarm_data, timeout2) except Exception as e: print(fFailed to send alarm to backend: {e}) elif self.fall_counter 0 and self.fall_status: # 恢复正常状态 self.fall_status False print([INFO] Status back to normal.) # 显示画面调试用 cv2.imshow(Fall Detection, processed_frame) if cv2.waitKey(1) 0xFF ord(q): break self.cap.release() cv2.destroyAllWindows() if __name__ __main__: # 使用本地视频文件或RTSP流测试 detector FallDetector(rtsp_urlrtsp://admin:password192.168.1.100/stream1, backend_api_urlhttp://localhost:8080) detector.run()关键参数调优心得NECESSARY_CONSECUTIVE_FRAMES这是平衡灵敏度和误报的关键。值太小如3容易因短暂下蹲、捡东西而误报值太大如30则报警延迟过高。建议在10-15帧对应0.3-0.5秒之间根据实际视频帧率调整。宽高比阈值1.2和躯干角阈值45度这两个值需要你用一些包含摔倒和正常动作如坐下、躺下的视频素材进行反复测试校准。躺下休息和摔倒的姿态有时很相似需要结合其他特征如关键点下落速度来区分。3.2 后端服务与算法服务的对接算法服务通过HTTP POST请求将告警事件推送到后端。后端以Spring Boot为例需要提供一个接收接口// AlarmController.java RestController RequestMapping(/api/alarm) Slf4j public class AlarmController { Autowired private AlarmService alarmService; Autowired private NotificationService notificationService; PostMapping public ResponseEntityVoid createAlarm(RequestBody AlarmEventDTO alarmEventDTO) { log.info(Received alarm event: {}, alarmEventDTO); // 1. 持久化到数据库 AlarmEvent savedEvent alarmService.saveAlarmEvent(alarmEventDTO); // 2. 触发异步通知避免阻塞主线程 CompletableFuture.runAsync(() - { notificationService.sendFallNotification(savedEvent); }); // 3. 可以通过WebSocket或SSE实时向前端推送新告警信息 // webSocketService.sendNewAlarmToAllClients(savedEvent); return ResponseEntity.ok().build(); } }告警通知服务是体现项目完整性的重要一环。除了在前端弹窗还应集成更可靠的通知方式邮件通知使用Spring Boot的spring-boot-starter-mail配置简单。短信通知可以接入阿里云、腾讯云的短信服务SDK。注意这类服务通常需要实名认证和少量费用毕设演示时可以用日志打印代替。语音电话通知集成性要求更高可以考虑使用像Twilio国际或一些国内提供语音呼叫API的云服务。3.3 前端实时展示的实现前端需要实时展示两个信息1. 摄像头的实时检测画面结果快照2. 最新的系统状态和告警列表。对于实时画面不建议直接拉取RTSP流。更高效的做法是算法服务在处理每一帧或每N帧后将画了检测框的结果图保存为一张JPEG图片或编码为base64连同检测状态一起推送给后端。后端提供一个API如GET /api/stream/latest-snapshot返回最新图片的URL或base64数据。前端用img标签通过setInterval定时如每秒一次请求这个接口并更新src属性即可实现“伪实时”视频流开销极小。!-- 在Vue组件中 -- template div h3实时监控/h3 img :srccurrentSnapshotUrl alt实时画面 / p状态: {{ currentStatus }}/p /div /template script setup import { ref, onMounted, onUnmounted } from vue import { getLatestSnapshot } from /api/stream const currentSnapshotUrl ref() const currentStatus ref(正常) let timer null const fetchSnapshot async () { try { const response await getLatestSnapshot() currentSnapshotUrl.value response.data.imageUrl ?t new Date().getTime() // 加时间戳防缓存 currentStatus.value response.data.status } catch (error) { console.error(获取快照失败, error) } } onMounted(() { fetchSnapshot() timer setInterval(fetchSnapshot, 1000) // 每秒轮询一次 }) onUnmounted(() { if (timer) clearInterval(timer) }) /script对于实时告警列表可以使用Server-Sent Events (SSE)或WebSocket。SSE更简单适用于服务器向客户端单向推送的场景。当后端AlarmController收到新告警时可以向所有连接的SSE客户端广播一条消息。4. 项目部署与联调实战指南开发完成后将系统部署起来并稳定运行是毕设演示和论文撰写的关键。推荐使用Docker Compose进行容器化部署这能清晰地隔离服务也方便在答辩的电脑上快速启动整个系统。4.1 使用Docker Compose编排服务编写一个docker-compose.yml文件version: 3.8 services: mysql: image: mysql:8.0 container_name: fall-db environment: MYSQL_ROOT_PASSWORD: rootpassword MYSQL_DATABASE: falldetection ports: - 3306:3306 volumes: - mysql_data:/var/lib/mysql backend: build: ./backend # 指向你的Spring Boot项目Dockerfile所在目录 container_name: fall-backend depends_on: - mysql environment: SPRING_DATASOURCE_URL: jdbc:mysql://mysql:3306/falldetection?useSSLfalseserverTimezoneUTC SPRING_DATASOURCE_USERNAME: root SPRING_DATASOURCE_PASSWORD: rootpassword ports: - 8080:8080 volumes: - ./backend/snapshots:/app/snapshots # 挂载目录用于存放算法服务生成的告警快照 algorithm: build: ./algorithm # 指向你的Python算法服务Dockerfile所在目录 container_name: fall-algorithm depends_on: - backend environment: BACKEND_API_URL: http://backend:8080 RTSP_STREAM_URL: rtsp://your_camera_ip/stream # 替换为实际摄像头RTSP地址 volumes: - ./algorithm/snapshots:/app/snapshots # 与后端共享快照目录 - ./algorithm/models:/app/models # 挂载预训练模型 # 注意算法服务需要访问摄像头在Linux宿主机上可能需要加 --device 参数或使用host网络模式 network_mode: host # 简单起见让容器使用宿主机网络便于访问本地摄像头 frontend: build: ./frontend # 指向你的Vue项目Dockerfile基于nginx所在目录 container_name: fall-frontend depends_on: - backend ports: - 80:80 volumes: mysql_data:各服务Dockerfile要点Backend (Dockerfile): 基于openjdk:17-slim将打包好的jar文件复制进去用java -jar启动。Algorithm (Dockerfile): 基于python:3.9-slim安装opencv-python-headless,ultralytics,mediapipe,requests等依赖将你的fall_detection_service.py复制进去。Frontend (Dockerfile): 使用多阶段构建。第一阶段用node镜像npm run build生成静态文件第二阶段用nginx镜像将静态文件复制到/usr/share/nginx/html。4.2 联调与测试中的常见问题算法服务无法连接摄像头问题在Docker容器内使用cv2.VideoCapture(0)访问本地USB摄像头通常失败。解决对于USB摄像头在docker run时添加参数--device/dev/video0:/dev/video0。对于RTSP/IP摄像头确保容器网络能访问到摄像头IP。使用network_mode: “host”是最直接的但牺牲了部分隔离性。前端图片不更新或跨域问题问题前端轮询到的图片URL不变浏览器可能缓存旧图。解决在图片URL后添加时间戳参数如image.jpg?t${Date.now()}。跨域问题需在后端配置CORSSpring Boot中可通过CrossOrigin注解或全局配置解决。告警延迟过高问题从检测到摔倒到前端显示告警耗时超过3秒。排查用日志打点分析时间消耗在哪个环节。是算法处理单帧太慢优化模型使用YOLOv8n或降低视频分辨率还是网络传输延迟算法和后端部署在同一台机器或者是前端轮询间隔太长调整为500ms误报率居高不下问题系统经常将坐下、躺下等动作误判为摔倒。优化增加特征引入“速度”特征。计算髋部关键点在连续帧间的垂直位移摔倒通常伴随高速下坠。优化阈值收集“摔倒”和“非摔倒”视频片段绘制特征值的分布图寻找最佳分割阈值。引入场景先验如果摄像头固定在客厅可以设定一个“危险区域”如地板附近只有当人的头部关键点进入该区域且满足姿态条件时才报警这样可以过滤掉在沙发上躺下的情况。后端接收不到算法服务的告警问题算法服务日志显示已触发但后端数据库没有记录。排查检查网络连通性在算法容器内curl http://backend:8080/actuator/health。检查后端API路径和端口是否正确。查看后端应用日志确认POST /api/alarm接口是否被调用参数是否正确。检查算法服务中请求的JSON格式是否符合后端DTO定义。5. 从课设到毕设的深度扩展建议如果你做的是课程设计完成上述基础系统已经足够。但如果作为毕业设计你需要体现更多的工作量和深度。以下是一些可行的扩展方向能让你的论文和作品脱颖而出1. 算法层面的优化与对比实现多种算法并进行对比除了规则方法可以再实现一个基于深度学习如SlowFast网络的摔倒检测模型。在同一个测试集上从准确率、召回率、F1分数、推理速度等多个维度对比两种方法的优劣并在论文中详细分析。引入跟踪算法当画面中有多个人时使用DeepSORT或ByteTrack等多目标跟踪算法为每个人分配唯一ID分别进行摔倒检测避免不同人之间的干扰。尝试轻量化部署将训练好的深度学习模型使用ONNX或TensorRT进行转换和加速部署在边缘设备如Jetson Nano上探讨端侧计算的可行性。2. 系统层面的功能增强多摄像头管理与融合设计一个摄像头管理模块支持添加多个摄像头并可在前端切换视图。更高级的可以尝试多视角融合判断减少单视角遮挡造成的漏检。分级告警机制设计“疑似摔倒”低置信度和“确认摔倒”高置信度两级告警。疑似摔倒时前端闪烁提示确认摔倒时才发送短信/电话通知。数据可视化与分析在前端集成ECharts图表展示每日/每周摔倒告警趋势、高频发生时段、常发位置等为看护者提供数据分析能力。移动端适配或小程序开发一个简单的微信小程序或移动端H5页面让家属能随时随地接收告警和查看老人状态。3. 工程化与性能考量视频流处理优化使用多进程或异步IO如asyncio同时处理多个摄像头的流提高吞吐量。消息队列解耦在算法服务和后端服务之间引入RabbitMQ或Kafka。算法服务将告警事件发到消息队列后端服务消费队列。这样能缓冲峰值压力提高系统可靠性。压力测试与性能评估使用JMeter等工具对后端API进行压力测试评估系统能支持的最大摄像头数量。分析系统的瓶颈在哪里CPU、内存、IO。4. 论文写作的核心要点引言部分要清晰阐述人口老龄化背景、摔倒的危害、现有解决方案可简要综述及其不足从而引出你工作的必要性。相关工作系统地分类介绍摔倒检测的各类方法基于穿戴设备、基于环境传感器、基于视觉并指出基于视觉的优缺点。系统设计章节用架构图如使用Draw.io绘制、序列图展示一次告警的数据流、E-R图数据库设计来清晰地表达你的设计。实验与分析章节这是重中之重。必须有自己的数据集即使是从公开数据集划分或自己拍摄少量视频定义清晰的评估指标准确率、召回率、F1值、误报率并给出详细的实验结果表格和图表。对误报案例进行分析并提出改进思路。总结与展望客观总结你的工作成果和不足并对未来可改进的方向提出切实可行的设想如集成多模态传感器、利用联邦学习保护隐私等。完成这样一个项目你收获的将不仅仅是一个能运行的系统和一份毕业论文更是一套解决复杂工程问题的完整方法论从需求分析、技术选型、模块实现、系统集成、调试优化到最终部署展示。这个过程会遇到无数问题而每一个问题的解决都是你能力的一次实实在在的提升。本文还有配套的精品资源点击获取
RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进