ARTICLE DETAIL

资讯详情

深耕郑州网站建设与运营推广的一线实战洞察。

基于Python+OpenCV+FFmpeg的智慧养老系统实战:跌倒检测与Web监控

基于Python+OpenCV+FFmpeg的智慧养老系统实战:跌倒检测与Web监控 简介这是一套面向高校毕业设计与课程设计场景的智慧养老系统完整项目包基于 Python、OpenCV、Web 与 FFmpeg 构建适合计算机视觉、人工智能方向的学生及需要综合实战案例的开发者。系统分为 Web 管理端与摄像头群组两部分通过多路模拟摄像头实时分析老人情绪、摔倒、闯入禁区、义工互动及陌生人出现等事件并即时写入数据库、更新报表帮助管理人员快速响应。技术栈覆盖 OpenCV 人脸检测与录入、FaceNet 单样本人脸识别、Mini-Xception 表情识别、Happy-Elder-Care-Net 微笑与陌生人检测、OpenPose 摔倒判定、GF(4) 交互检测、质心跟踪入侵追踪以及 Nginx-RTMP 直播推流。压缩包共 1078 个文件约 316.77MB包含 68 个 py 源码、30 个 vue 前端页面、78 个 css 样式、60 个 vcxproj 工程文件及 caffemodel、prototxt 等模型权重另附答辩 pptx 与项目文档。已有 238 人学习可帮助读者快速理解多模块协同的视觉养老系统架构与实现思路。1. 智慧养老系统为什么值得用 PythonOpenCVWebFFmpeg 做一遍养老院最真实的痛点不是缺摄像头而是摄像头后面没人盯。护工三班倒夜里一个人要看十几路画面老人跌倒、久坐不起、走出电子围栏这些事靠人眼盯屏基本等于玄学。这套智慧养老系统的核心思路就是用 Python 把 OpenCV 的视觉能力和 FFmpeg 的流处理能力串起来再套一层 Web 页面给护工和管理者看形成一个能落地、能答辩、能继续迭代的完整项目。它适合三类人一是做计算机视觉大作业或毕业设计的学生需要一个有真实场景、有前后端、有视频链路的题目二是想入门 PythonOpenCV 的开发者需要一个比识别猫狗更有说服力的练手项目三是养老机构里懂点技术的负责人想先跑一个低成本原型验证可行性。整套东西不依赖昂贵硬件一台带摄像头的普通 PC 或一块树莓派就能起步Web 端用浏览器就能访问FFmpeg 负责把 RTSP 流拉下来转成浏览器能播的格式。下面按先跑通最小链路再补视觉算法最后做 Web 和避坑的顺序讲清楚。2. 把视频链路先跑通FFmpeg 拉流、转码与 Web 可播格式2.1 为什么视频链路要单独拎出来做很多人一上来就写 OpenCV 的跌倒检测结果发现摄像头画面根本进不了浏览器或者延迟高到护工看到的是十秒前的画面。智慧养老系统里视频链路是地基地基不稳上面算法再准也没用。常见做法是摄像头用 RTSP 输出FFmpeg 负责拉流并转成 HLS 或 HTTP-FLVWeb 端用 video 标签或 flv.js 播放。OpenCV 则从同一路 RTSP 或本地文件里取帧做分析两条链路互不干扰。这里有个选型理由要说清楚为什么不直接用 OpenCV 的 VideoCapture 推给 Web因为 OpenCV 的 imshow 是本地窗口没法直接给浏览器而把每帧转成 JPEG 再通过 WebSocket 推延迟和 CPU 占用都很难看。FFmpeg 在转码和封装上是专业工具OpenCV 专注做视觉计算各干各的活系统才稳。2.2 用 FFmpeg 把 RTSP 转成 HLS 的最小命令先确认 FFmpeg 装好Windows 下去官网下载压缩包解压后把 bin 目录加进 PATHLinux 下 apt 或源码编译都行。下面这条命令是把一路 RTSP 转成 HLS供 Web 端播放ffmpeg -rtsp_transport tcp -i rtsp://admin:password192.168.1.64:554/Streaming/Channels/101 \ -c:v libx264 -preset ultrafast -tune zerolatency \ -c:a aac -f hls -hls_time 2 -hls_list_size 3 \ -hls_flags delete_segments /var/www/hls/room1.m3u8逻辑说明-rtsp_transport tcp强制用 TCP 拉流避免 UDP 丢包导致花屏-c:v libx264把摄像头常见的 H.264/H.265 统一转成浏览器兼容的 H.264-preset ultrafast -tune zerolatency是低延迟的关键牺牲一点压缩率换实时性-hls_time 2 -hls_list_size 3表示每个切片 2 秒、列表保留 3 个延迟大概在 6 到 8 秒对养老监护够用。如果要求更低延迟可以换 HTTP-FLV用-f flv输出到支持 FLV 的流媒体服务Web 端用 flv.js 播放延迟能压到 2 秒内。参数怎么改摄像头分辨率高、CPU 弱的时候加-s 1280x720降分辨率带宽紧张就调-b:v 1500k限制码率多路摄像头就写多个 FFmpeg 进程或用-f tee分流。失败时先看 FFmpeg 的报错最常见的是 RTSP 地址错、账号密码没 URL 编码、防火墙挡了 554 端口。2.3 OpenCV 从同一路流取帧的写法视觉分析这条线用 OpenCV 的 VideoCapture 直接读 RTSPimport cv2 # RTSP 地址注意密码里的特殊字符要 URL 编码 rtsp_url rtsp://admin:password192.168.1.64:554/Streaming/Channels/101 cap cv2.VideoCapture(rtsp_url, cv2.CAP_FFMPEG) # 设置缓冲区为 1减少延迟累积 cap.set(cv2.CAP_PROP_BUFFERSIZE, 1) if not cap.isOpened(): raise RuntimeError(无法打开视频流检查地址和网络) while True: ret, frame cap.read() if not ret: # 流断了尝试重连 cap.release() cap cv2.VideoCapture(rtsp_url, cv2.CAP_FFMPEG) continue # 这里放后续的视觉处理 cv2.imshow(monitor, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()逻辑说明cv2.CAP_FFMPEG指定用 FFmpeg 后端解码比默认后端对 RTSP 支持更好CAP_PROP_BUFFERSIZE设成 1 能明显降低延迟否则 OpenCV 会缓存一堆旧帧。参数上如果只是做分析不需要显示把 imshow 去掉能省不少 CPU。常见坑是ModuleNotFoundError: No module named opencv那是没装 opencv-pythonpip install opencv-python即可如果报cv2.error跟 GStreamer 相关Linux 下装libgstreamer1.0-dev或改用 FFmpeg 后端。3. 视觉算法落地跌倒、久坐与区域入侵怎么用 OpenCV 实现3.1 先想清楚养老场景要检测什么养老监护不需要识别几百类物体核心就三件事跌倒、长时间不动、走出安全区域。这三件事用 OpenCV 加轻量模型就能做不必上重型深度学习。跌倒检测的常见思路是人体框的宽高比突变加中心点快速下移久坐检测是统计人体框在某个区域内的停留时长区域入侵是判断人体框和预设多边形有没有交集。选型上人体检测可以用 HOGSVMOpenCV 自带零额外依赖或 YOLO 的轻量版前者适合答辩演示后者适合真实部署。3.2 用 HOG 做人体检测并判断跌倒的最小代码import cv2 import numpy as np hog cv2.HOGDescriptor() hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector()) # 记录上一帧的人体框用于判断跌倒 prev_boxes [] def detect_fall(frame, prev_boxes): # 检测人体winStride 和 padding 影响速度和精度 boxes, weights hog.detectMultiScale(frame, winStride(8, 8), padding(16, 16), scale1.05) falls [] for (x, y, w, h) in boxes: aspect w / float(h) # 正常站立宽高比小于 0.6跌倒时接近或大于 1 if aspect 0.9: falls.append((x, y, w, h)) return boxes, falls cap cv2.VideoCapture(rtsp://admin:password192.168.1.64:554/Streaming/Channels/101) while True: ret, frame cap.read() if not ret: break frame cv2.resize(frame, (640, 480)) boxes, falls detect_fall(frame, prev_boxes) for (x, y, w, h) in boxes: cv2.rectangle(frame, (x, y), (x w, y h), (0, 255, 0), 2) for (x, y, w, h) in falls: cv2.rectangle(frame, (x, y), (x w, y h), (0, 0, 255), 3) cv2.putText(frame, FALL, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.9, (0, 0, 255), 2) cv2.imshow(fall detection, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()逻辑说明HOG 检测器返回人体框宽高比是判断跌倒最直观的特征。参数上winStride越小越准但越慢scale是金字塔缩放步长1.05 是精度和速度的折中。这段代码只是演示真实场景要加连续帧确认避免一个人弯腰就被误报。常见误报来源是坐姿和蹲下解决办法是结合中心点下移速度做二次判断。3.3 久坐和区域入侵用多边形和计时器实现久坐检测不需要复杂模型维护一个字典记录每个人体框中心点进入某个区域的时间戳超过阈值就报警。区域入侵用cv2.pointPolygonTest判断中心点是否在多边形内import cv2 import time # 定义安全区域多边形坐标按实际画面标定 safe_zone np.array([[100, 100], [500, 100], [500, 400], [100, 400]], np.int32) sit_start {} # 记录每个人进入久坐区域的时间 def check_zone(frame, boxes): alerts [] for i, (x, y, w, h) in enumerate(boxes): cx, cy x w // 2, y h // 2 # 判断中心点是否在安全区域内 inside cv2.pointPolygonTest(safe_zone, (cx, cy), False) 0 if not inside: alerts.append((intrusion, (x, y, w, h))) # 久坐判断在区域内停留超过 30 分钟 if inside: if i not in sit_start: sit_start[i] time.time() elif time.time() - sit_start[i] 1800: alerts.append((sedentary, (x, y, w, h))) else: sit_start.pop(i, None) return alerts逻辑说明pointPolygonTest返回正值表示点在多边形内负值在外。久坐阈值 1800 秒按实际需求调演示时可以改成 30 秒方便看效果。参数上安全区域坐标要用鼠标事件在画面上标定别硬编码。这套逻辑的边界是多人重叠时人体框会合并导致 ID 跳变真实部署建议上轻量跟踪算法如 CSRT 或 ByteTrack。4. Web 端怎么把视频和告警串起来Flask 接口与前端播放4.1 后端用 Flask 暴露视频和告警接口Web 层不需要多复杂Flask 足够。核心是两个接口一个返回 HLS 播放地址或直接代理视频流一个返回最新告警列表。告警数据可以存 SQLite也可以放内存队列答辩演示用内存就够。from flask import Flask, jsonify, render_template import sqlite3 app Flask(__name__) def init_db(): conn sqlite3.connect(alerts.db) conn.execute(CREATE TABLE IF NOT EXISTS alerts (id INTEGER PRIMARY KEY, type TEXT, time TEXT, room TEXT)) conn.commit() conn.close() app.route(/) def index(): return render_template(index.html) app.route(/api/alerts) def get_alerts(): conn sqlite3.connect(alerts.db) rows conn.execute(SELECT type, time, room FROM alerts ORDER BY id DESC LIMIT 20).fetchall() conn.close() return jsonify([{type: r[0], time: r[1], room: r[2]} for r in rows]) app.route(/api/stream/room) def get_stream(room): # 返回该房间的 HLS 地址前端用 video 标签播放 return jsonify({url: f/static/hls/{room}.m3u8}) if __name__ __main__: init_db() app.run(host0.0.0.0, port5000)逻辑说明/api/alerts给前端轮询告警/api/stream返回播放地址。参数上生产环境别用 Flask 自带服务器换 gunicorn 或 uwsgihost0.0.0.0是为了局域网内其他设备能访问。注意 Web 服务器安全别把调试模式开到公网debugTrue只在本地用。4.2 前端用 video 标签加轮询展示前端页面用原生 HTMLJS 就行video 标签播 HLS 需要 hls.jsSafari 原生支持video idplayer controls autoplay muted/video ul idalert-list/ul script srchttps://cdn.jsdelivr.net/npm/hls.jslatest/script script const video document.getElementById(player); const src /static/hls/room1.m3u8; if (Hls.isSupported()) { const hls new Hls(); hls.loadSource(src); hls.attachMedia(video); } else { video.src src; } // 每 5 秒拉一次告警 setInterval(async () { const res await fetch(/api/alerts); const data await res.json(); document.getElementById(alert-list).innerHTML data.map(a li${a.time} ${a.room} ${a.type}/li).join(); }, 5000); /script逻辑说明hls.js 负责把 m3u8 切片喂给 video 标签轮询接口刷新告警列表。参数上轮询间隔 5 秒对养老场景够用太频繁会增加服务器压力。如果要做 Web 端实时视频HLS 延迟偏高可以换 WebSocket 推 JPEG 帧或 HTTP-FLV但复杂度上升答辩演示 HLS 足够。4.3 告警写库和视觉进程的衔接视觉进程检测到跌倒后要写进数据库并让 Web 端能看到。最简单的方式是视觉进程直接写 SQLiteWeb 端读同一个库import sqlite3 from datetime import datetime def save_alert(alert_type, room): conn sqlite3.connect(alerts.db) conn.execute(INSERT INTO alerts (type, time, room) VALUES (?, ?, ?), (alert_type, datetime.now().strftime(%Y-%m-%d %H:%M:%S), room)) conn.commit() conn.close()逻辑说明SQLite 支持多进程读写但并发高时会锁库。演示场景没问题真实部署建议换 PostgreSQL 或加消息队列。参数上时间格式统一用字符串存方便前端直接显示。注意别在视觉主循环里频繁开闭数据库连接可以攒一批再写。5. 避坑与排查从环境到部署的 5 个血泪教训5.1 现象pip 装完 opencv 还是报 ModuleNotFoundError原因装的是 opencv-python 但 Python 环境不对或者虚拟环境没激活或者装成了 opencv-contrib-python 和 opencv-python 冲突。解决先pip list | grep opencv看装了什么统一用pip install opencv-python虚拟环境里重装。Linux 下如果报cv2.error跟 libGL 相关装libgl1-mesa-glx。5.2 现象FFmpeg 拉流几小时后卡死原因RTSP 流断开后 FFmpeg 没退出或者 HLS 切片堆积占满磁盘。解决加-timeout参数让 FFmpeg 超时退出用 supervisor 或 systemd 守护进程自动重启HLS 加delete_segments标志自动删旧切片定期清理目录。5.3 现象Web 端视频延迟十几秒原因HLS 切片太长或者 OpenCV 和 FFmpeg 抢同一路流导致解码慢。解决-hls_time降到 1 到 2 秒-hls_list_size设 3OpenCV 分析用低分辨率子码流FFmpeg 转码用主码流别让两者抢资源。5.4 现象跌倒检测误报频繁原因HOG 检测器对坐姿、弯腰敏感宽高比阈值太松。解决加连续帧确认比如连续 5 帧都判定跌倒才报警结合中心点下移速度只有快速下移才触发阈值从 0.9 调到 1.0 以上减少误报。5.5 现象局域网其他设备访问不了 Web 页面原因Flask 默认只监听 127.0.0.1或者防火墙挡了 5000 端口。解决app.run(host0.0.0.0)Windows 防火墙放行端口Linux 用ufw allow 5000。注意别把服务暴露到公网养老数据涉及隐私局域网内用就行。6. 让系统更像产品多路管理、告警去重与答辩演示技巧多路摄像头管理是这套系统从 demo 走向可用的关键。我一般会写一个配置文件把每个房间的 RTSP 地址、HLS 输出路径、安全区域坐标都放进去用 Python 读配置批量启动 FFmpeg 进程和 OpenCV 分析线程。这样加一个房间只改配置不用动代码。配置用 YAML 或 JSON 都行下面是个 YAML 示例rooms: - name: room1 rtsp: rtsp://admin:password192.168.1.64:554/Streaming/Channels/101 hls: /var/www/hls/room1.m3u8 safe_zone: [[100, 100], [500, 100], [500, 400], [100, 400]] - name: room2 rtsp: rtsp://admin:password192.168.1.65:554/Streaming/Channels/101 hls: /var/www/hls/room2.m3u8 safe_zone: [[80, 80], [480, 80], [480, 380], [80, 380]]告警去重是另一个容易被忽略的点。同一个人跌倒视觉进程可能连续报十次护工看到一堆重复告警会麻木。我的做法是给每个告警加一个冷却时间同一房间同一类型告警 60 秒内只写一次库。实现上用一个字典记录上次告警时间写库前判断一下就行。这个细节在答辩时讲出来评委能看出你考虑过真实使用场景。答辩演示有个技巧别只放一段录好的视频现场用手机开个 RTSP 推流或者用本地视频文件模拟让评委看到从视频输入到 Web 告警的完整链路。演示前把阈值调低比如久坐 30 秒就报警跌倒检测放宽一点保证现场能触发。同时准备一个翻车预案万一网络断了切到本地视频文件继续演示别让答辩卡在拉流上。最后说个我自己的习惯这套系统我做完后会把每个模块的启动命令写成一个 shell 脚本答辩前跑一遍确认全链路通。视觉算法部分我会留一个--debug开关打开就显示检测框关掉就只写告警方便调试和演示切换。智慧养老这个方向技术不是最难的难的是把视频、算法、Web 和真实场景的约束捏在一起跑通一次完整的链路比单独调一个检测模型有价值得多。希望帮到你。本文还有配套的精品资源点击获取
返回列表