ARTICLE DETAIL

资讯详情

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

基于Python+OpenCV+FFmpeg的智慧养老跌倒检测系统实战

基于Python+OpenCV+FFmpeg的智慧养老跌倒检测系统实战 简介这是一套面向高校毕业设计与课程设计场景的智慧养老系统完整项目包基于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样式、40个png界面图、多个caffemodel与prototxt模型文件以及答辩pptx和项目docx文档。已有238人学习适合作为毕业设计参考、课程大作业模板或视觉项目二次开发基础。1. 智慧养老系统为什么值得用 PythonOpenCVWebFFmpeg 做一遍养老院护工半夜巡房最怕的是老人跌倒后没人知道子女白天上班最想知道的是爸妈今天有没有按时吃饭、有没有在活动室待太久。这类需求听起来像产品经理的活但落到毕业设计或课程设计上它其实是一条非常完整的技术链路摄像头采集视频流FFmpeg 负责推流和转码OpenCV 做画面里的目标检测与行为判断Python 把算法和业务串起来Web 端给护工和家属一个能看的界面。这套组合不是堆技术名词而是每一层都有明确的活要干。如果你正在找计算机视觉大作业或者计算机视觉项目又不想只做一个“识别猫狗”的 demo智慧养老是一个能讲出业务价值、又能把 Python、OpenCV、Web、FFmpeg 四个点串成一条线的题目。它适合有一定 Python 基础、学过 OpenCV 图像处理、想拿一个完整系统去答辩的人。下面我按实际落地的顺序把选型理由、环境搭建、视频链路、检测逻辑、Web 展示和踩坑记录拆开讲能照着复现也能看到边界在哪。2. 环境与依赖把 Python、OpenCV、FFmpeg 装到能跑通第一帧2.1 Python 与 OpenCV 的版本匹配很多人卡在第一步不是不会写代码而是装完 OpenCV 之后import cv2直接报ModuleNotFoundError: No module named opencv或者报cv2.error: OpenCV(4.4.0) ...这种带路径的错。血泪经验是不要用系统自带的 Python也不要在同一个环境里混装 conda 和 pip 的 OpenCV。我一般会建一个干净的虚拟环境Python 选 3.8 到 3.10 之间太新的版本有些预编译包还没跟上。# 创建虚拟环境名字叫 smart_elder python -m venv smart_elder # Windows 激活 smart_elder\Scripts\activate # Linux / macOS 激活 source smart_elder/bin/activate # 安装核心依赖opencv-python 选带 contrib 的版本方便后续扩展 pip install opencv-python4.8.1.78 opencv-contrib-python4.8.1.78 pip install numpy flask这里opencv-python和opencv-contrib-python版本号必须一致否则会出现函数找不到或者底层库冲突。numpy不用手动指定版本pip 会自动匹配 OpenCV 的依赖。装完之后用下面这段代码验证能打印出画面尺寸和帧率才算环境通了。import cv2 # 打开默认摄像头如果用的是 RTSP 流就换成对应地址 cap cv2.VideoCapture(0) # 检查是否成功打开 if not cap.isOpened(): print(摄像头打开失败检查设备占用或驱动) exit() # 读取一帧 ret, frame cap.read() if ret: print(画面尺寸:, frame.shape) # (高, 宽, 通道) print(OpenCV 版本:, cv2.__version__) cap.release()VideoCapture(0)里的 0 是摄像头索引笔记本一般用 0外接 USB 摄像头可能是 1 或 2。如果返回retFalse先确认摄像头没被其他程序占用Linux 下还要看/dev/video*权限。这一步跑通后面所有图像处理才有意义。2.2 FFmpeg 安装与推流命令的最小验证FFmpeg 在这个系统里干两件事把摄像头或视频文件转成 Web 能播的格式以及把处理后的画面推给前端。Windows 下去官网下载压缩包解压后把bin目录加到系统 PATHLinux 下apt install ffmpeg就行。装完在命令行敲ffmpeg -version能输出版本信息就说明可用。最小验证命令是用 FFmpeg 把一段本地视频转成 HLS 切片模拟 Web 端播放的场景# 把 input.mp4 转成 HLS切片时长 2 秒输出到 hls 目录 ffmpeg -i input.mp4 -c:v libx264 -c:a aac -f hls -hls_time 2 -hls_list_size 0 -hls_segment_filename hls/seg_%03d.ts hls/index.m3u8-c:v libx264指定视频编码器-c:a aac指定音频编码器-hls_time 2表示每个切片 2 秒-hls_list_size 0让 m3u8 保留所有切片。生成index.m3u8和一堆.ts文件后用浏览器打开一个支持 HLS 的播放器就能看到画面。如果这一步就卡住先别急着写 Python把 FFmpeg 命令单独跑通能省掉后面一半的排查时间。提示Windows 下路径里有空格时给路径加英文双引号否则 FFmpeg 会把空格当成参数分隔。3. 视频链路从摄像头采集到 Web 端能看的实时画面3.1 用 OpenCV 读帧、FFmpeg 推流的管道设计智慧养老系统里视频链路通常有两种做法。一种是 OpenCV 直接读 RTSP 流处理完用cv2.imshow显示但这样 Web 端看不到另一种是 OpenCV 读帧处理后把帧写给 FFmpeg 的 stdin由 FFmpeg 推成 HLS 或 FLVWeb 端再拉流播放。第二种才是能落地的方案。下面是一个把 OpenCV 处理后的帧推给 FFmpeg 的最小示例推流地址用本地文件模拟实际部署时换成 SRS 或 Nginx-RTMP 的地址import cv2 import subprocess # FFmpeg 推流命令从 stdin 读原始帧编码后输出 FLV ffmpeg_cmd [ ffmpeg, -y, # 覆盖输出 -f, rawvideo, # 输入格式为原始视频 -vcodec, rawvideo, -pix_fmt, bgr24, # OpenCV 默认 BGR -s, 640x480, # 输入分辨率必须和帧一致 -r, 25, # 输入帧率 -i, -, # 从 stdin 读 -c:v, libx264, -preset, ultrafast, # 编码速度优先 -tune, zerolatency, # 低延迟 -f, flv, rtmp://127.0.0.1/live/elder ] # 启动 FFmpeg 子进程 pipe subprocess.Popen(ffmpeg_cmd, stdinsubprocess.PIPE) cap cv2.VideoCapture(0) cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640) cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480) while True: ret, frame cap.read() if not ret: break # 这里可以插入检测逻辑比如画框、报警 pipe.stdin.write(frame.tobytes()) # 把帧写给 FFmpeg cap.release() pipe.stdin.close() pipe.wait()关键参数是-s 640x480和-r 25必须和 OpenCV 里设置的采集分辨率、帧率一致否则 FFmpeg 会按错误的尺寸解析原始数据画面会花屏或者直接报错。-preset ultrafast和-tune zerolatency是为了降低延迟代价是画质稍微差一点但养老场景里看清人有没有摔倒比看清人脸细节更重要。如果推流到 SRS 存在延迟先检查-r和-g参数关键帧间隔太大也会让首屏变慢。3.2 Web 端播放器的选择与延迟取舍Web 端播放实时视频常见做法是 HLS 或 HTTP-FLV。HLS 兼容性好但延迟通常在 5 到 10 秒HTTP-FLV 延迟能压到 1 到 3 秒但需要 flv.js 这类库。养老系统里如果只是看护工站的大屏HLS 够用如果要做到跌倒后 2 秒内弹窗就得用 FLV。前端用 flv.js 的代码大概是这样video idlive controls autoplay muted/video script srchttps://cdn.jsdelivr.net/npm/flv.js1.6.2/dist/flv.min.js/script script // 判断浏览器是否支持 flv.js if (flvjs.isSupported()) { var player flvjs.createPlayer({ type: flv, url: http://127.0.0.1:8080/live/elder.flv // 换成实际流地址 }); player.attachMediaElement(document.getElementById(live)); player.load(); player.play(); } /scripttype: flv告诉 flv.js 用 FLV 协议解析url指向流媒体服务器暴露的地址。如果页面一直转圈先看浏览器控制台有没有跨域报错再确认流媒体服务器的 HTTP 端口是否开放。注意不要在前端直接写死内网 IP部署时用相对路径或者配置项否则换一台机器就要改代码。注意Web 端播放实时视频时浏览器可能会因为自动播放策略拦截声音加muted属性可以绕过需要声音时再让用户手动点一下。4. 计算机视觉检测跌倒、久坐、区域入侵怎么落地4.1 用 OpenCV 做人体检测与跌倒判断OpenCV 自带 HOG 行人检测器虽然精度不如深度学习模型但胜在不需要额外权重文件适合课程设计快速出效果。跌倒判断的思路是检测到人体框后计算框的宽高比正常站立时高大于宽跌倒时宽大于高或者框的中心点突然下移。import cv2 # 初始化 HOG 行人检测器 hog cv2.HOGDescriptor() hog.setSVMDetector(cv2.HOGDescriptor_getDefaultPeopleDetector()) cap cv2.VideoCapture(0) while True: ret, frame cap.read() if not ret: break # 缩放一下加快检测速度 frame cv2.resize(frame, (640, 480)) # 检测人体返回矩形框和权重 boxes, weights hog.detectMultiScale(frame, winStride(8, 8)) for (x, y, w, h) in boxes: # 计算宽高比 ratio w / float(h) # 宽高比大于 1.2 且置信度足够判定为疑似跌倒 if ratio 1.2: cv2.rectangle(frame, (x, y), (x w, y h), (0, 0, 255), 2) cv2.putText(frame, FALL, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2) else: cv2.rectangle(frame, (x, y), (x w, y h), (0, 255, 0), 2) cv2.imshow(elder_monitor, frame) if cv2.waitKey(1) 0xFF ord(q): break cap.release() cv2.destroyAllWindows()winStride(8, 8)控制滑动窗口步长值越小检测越细但越慢。ratio 1.2这个阈值不是固定的摄像头角度不同结果差别很大建议先录几段老人站立和模拟跌倒的视频用同样的代码跑一遍看实际 ratio 分布再定阈值。HOG 的误报率不低实际项目里我一般会加一个“连续 N 帧都判定为跌倒才报警”的逻辑避免弯腰捡东西被误报。4.2 区域入侵与久坐提醒的参数设置养老院经常需要知道老人有没有进入危险区域比如开水房、楼梯口。做法是在画面里画一个多边形区域检测到人体框的中心点落在区域内就触发提醒。OpenCV 的pointPolygonTest可以判断点是否在多边形内。import cv2 import numpy as np # 定义危险区域多边形顶点按实际画面调整 danger_zone np.array([[100, 100], [400, 100], [400, 300], [100, 300]], np.int32) def is_in_zone(center, polygon): # 返回正数表示在内部负数在外部 result cv2.pointPolygonTest(polygon, center, False) return result 0 # 假设 boxes 是上一段检测到的人体框 for (x, y, w, h) in boxes: center (x w // 2, y h // 2) if is_in_zone(center, danger_zone): cv2.putText(frame, DANGER ZONE, (x, y - 10), cv2.FONT_HERSHEY_SIMPLEX, 0.8, (0, 0, 255), 2)danger_zone的四个顶点要根据摄像头实际画面来标最好在 Web 端提供一个配置页面让护工自己画而不是写死在代码里。久坐提醒则是记录人体框中心点在一定时间内是否移动超过阈值如果 10 分钟内位移小于 20 像素就认为老人可能长时间没动。这个逻辑用 Python 的time和简单的队列就能实现不需要复杂模型。提示HOG 检测在逆光和夜间效果会明显下降如果养老院走廊光线不好建议加一个红外摄像头或者改用轻量级深度学习模型但那是另一个话题了。5. 避坑与排查那些让系统跑不起来的常见问题5.1 摄像头被占用导致 OpenCV 读帧失败现象是cap.read()一直返回False或者程序启动后画面全黑。原因通常是摄像头被其他程序占用比如腾讯会议、OBS 或者另一个 Python 进程。解决方法是先关掉所有可能用到摄像头的软件Linux 下用lsof /dev/video0查看占用进程Windows 下在设备管理器里看摄像头状态。如果用的是 RTSP 流检查网络是否通、账号密码是否正确。5.2 FFmpeg 推流花屏或绿屏现象是 Web 端播放时画面花屏、绿屏或者只有上半部分。原因几乎都是 OpenCV 送给 FFmpeg 的帧尺寸和 FFmpeg 命令里的-s参数不一致。比如 OpenCV 采集的是 1280x720但 FFmpeg 命令写的是 640x480FFmpeg 会按 640x480 去解析 1280x720 的原始数据结果就是错位。解决方法是把cap.set的分辨率和-s参数统一并且在推流前打印frame.shape确认。5.3 Web 端播放器报跨域或 404现象是 flv.js 或 HLS 播放器控制台报 CORS 错误或者请求 m3u8 返回 404。原因是流媒体服务器的 HTTP 服务没有开启跨域头或者切片文件路径不对。解决方法是检查流媒体服务器配置HLS 的 m3u8 和 ts 文件要在同一个 HTTP 目录下FLV 的地址要带上正确的应用名和流名。如果前端和后端不在同一个端口需要在流媒体服务器上加Access-Control-Allow-Origin头。5.4 OpenCV 版本冲突导致函数找不到现象是代码里用了cv2.dnn或者cv2.xfeatures2d运行时报AttributeError。原因是装的是opencv-python而不是opencv-contrib-python或者两个包版本不一致。解决方法是先pip uninstall opencv-python opencv-contrib-python再重新安装同一版本的 contrib 包。如果还是不行检查虚拟环境是否激活有时候 pip 装到了全局环境里。5.5 检测逻辑误报太多导致护工不信任现象是系统频繁报警但护工跑过去发现老人只是弯腰系鞋带。原因是单帧判断太敏感没有做时序过滤。解决方法是在报警前加一个计数器连续 5 帧以上都判定为跌倒才触发并且把报警截图和短视频存下来方便护工回看确认。这个改动不大但能显著提升系统的可用性。6. 答辩与文档怎么把系统讲成一个完整的故事6.1 答辩 PPT 的技术路线图怎么画答辩 PPT 不需要把每个函数都讲一遍评委想听的是“你为什么这么选”和“你解决了什么问题”。技术路线图可以按“采集层 → 处理层 → 应用层”来画采集层写摄像头和 FFmpeg处理层写 OpenCV 检测和 Python 业务逻辑应用层写 Web 展示和报警推送。每一层标注一个关键参数比如采集层标 640x48025fps处理层标 HOG 宽高比阈值应用层标 FLV 延迟 2 秒。这样评委一眼就能看出你不是随便拼的。6.2 项目文档里必须写清楚的三个表项目文档里最容易被忽略但答辩时最容易被问的是参数表、测试表和对比表。参数表列出摄像头分辨率、帧率、检测阈值、报警延迟测试表列出不同光照、不同角度下的检测准确率和误报率对比表列出 HOG 和深度学习模型在速度、精度、部署难度上的差异。这三个表不用很复杂但要有真实数据哪怕是自己在宿舍模拟的几组测试也比空着强。测试场景检测次数正确次数误报次数准确率白天站立5047394%白天模拟跌倒3026486.7%夜间站立50381276%这张表是我自己在走廊里用笔记本摄像头跑出来的夜间准确率明显下降答辩时主动说出来反而显得你做过真实测试比硬吹 99% 要可信。6.3 一个让系统更稳的小技巧如果时间允许在 OpenCV 检测之前加一个简单的帧差法做运动检测只有画面里有运动时才跑 HOG静止画面直接跳过。这样 CPU 占用能降一半树莓派上也能跑得动。代码就是在循环里加两行# 保存上一帧计算帧差 gray cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY) if prev_gray is not None: diff cv2.absdiff(prev_gray, gray) if diff.mean() 2: # 画面几乎没变化 prev_gray gray continue prev_gray graydiff.mean() 2这个阈值根据实际画面噪声调整光线变化大的场景要调高一点。这个技巧不改变检测逻辑但能让系统在没人经过时安静下来护工也不会被无意义的报警烦到。我自己做这类系统最大的教训是不要一上来就追求深度学习模型先把 OpenCV 传统方法和 FFmpeg 链路跑通能出画面、能报警、能在 Web 端看到再去考虑换模型。很多毕业设计翻车不是因为算法不够先进而是因为视频链路没通答辩时演示不出来。希望帮到你。本文还有配套的精品资源点击获取
返回列表