首页 / 资讯中心 / 文章详情

MATLAB+GUI实时人体异常行为检测系统设计:背景差分与SVM分类实践

MATLAB+GUI实时人体异常行为检测系统设计:背景差分与SVM分类实践 ★ FEATURED ARTICLE
简介一套基于 MATLAB 实现的实时人体异常行为检测识别系统附有图形用户界面面向视频监控与安全防范场景也适合计算机视觉方向的项目实战学习。资源压缩包共包含 769 个文件其中 6 个 .m 文件是主程序与函数源码1 个 .fig 保存 GUI 界面布局3 个 .avi 与 1 个 .mp4 提供步行、慢跑、快跑等测试视频755 个 .jpg 图片可用于人体样本与行为分类训练测试此外还有说明文档整体约 18.16MB便于快速下载与解压使用。目前已有 265 人浏览学习。可运行主界面并调用摄像头或视频文件进行检测通过源码可以理解实时视频帧读取、人体目标检测、运动特征提取以及异常行为判别的完整流程同时还能借鉴 GUI 中视频输入控制、结果展示、参数调节等模块的编写方法。对希望尽快搭建人体异常行为预警原型或想在 MATLAB 环境下深入掌握计算机视觉与 GUI 开发的读者都是一份不错的实践资料。1. 实时人体异常行为检测为什么说 MATLAB GUI 是快速验证的优选路径监控大屏前坐一天真正需要关注的异常往往只有几秒——跌倒、奔跑、挥手、打架。实时人体异常行为检测要做的就是从连续的图像流里把它们自动挑出来并给出提示。这套带 GUI 的 MATLAB 完整工程就是围绕这个场景落地的读取摄像头或视频文件实时检测异常行为在界面里框出目标并触发报警全程不需要部署推理服务器一台装有 MATLAB 的普通电脑就能跑通。资源适合三类人正在做 MATLAB 图像处理大作业的学生、需要快速验证算法的研究员、以及想把人体检测 demo 改造成可演示原型的一线工程师。代码结构清楚换摄像头、调阈值、加行为类别都留了明确的修改入口。2. 姿态提取与动作特征算法选型和技术底座2.1 背景差分做人形检测前先把“动起来的东西”找出来这套系统的前置任务是把人体从背景里分离出来。常见做法是用混合高斯背景模型也就是 MATLAB 里vision.ForegroundDetector封装好的那个实现。它会对画面里每个像素维护多个高斯分布用来描述该位置在不同时刻的颜色波动哪些分布占比高就判定为背景偏离背景模型的像素就标记为前景也就是“当前帧有什么东西在动”。% 创建前景检测器这里建议保留句柄方便后续调参 fgDetector vision.ForegroundDetector( ... NumTrainingFrames, 50, ... % 取前50帧做背景训练 AdaptLearningRate, 0.005, ... % 背景更新速度调小则更“记旧账” NumGaussians, 3, ... % 每个像素用3个高斯分量描述 MinimumBackgroundRatio, 0.6); % 某分布累计占比到0.6即视为背景这段代码是系统的第一道闸门。NumTrainingFrames决定系统开机后需要多少帧来建立干净的背景模型值设大一点能减少初始阶段的鬼影但开机后等待时间变长。AdaptLearningRate是背景模型对场景变化的学习速率0.005 属于中档室内固定摄像头下表现平稳室外有树叶晃动、水面反光时需要降到 0.001~0.002否则这些“非人”运动会被持续吸收为背景。NumGaussians用 3 个分量就能覆盖大多数固定摄像头场景分量越多越能处理多模态背景但计算量也会上浮。前景掩码输出后通常要接一次形态学闭运算把人体内部因为衣服纹理产生的破洞连通也把边缘毛刺去掉。这个步骤在代码里用vision.MorphologicalClose做结构元素选 7×7 矩形太小连通不完整太大容易把相邻两个人连成一个目标。调参时可以先看单帧掩码效果再批量跑不要上来就调分类器。2.2 人体检测与关键点优先考虑计算量而非精度背景差分能拿到“有东西在动”但拿不到“这是一整个人”。下一步要在前景区域上做人体框检测。MATLAB 自带peopleDetectorACF、peopleDetectorCascade和基于深度学习的检测器CPU 环境下优先用 ACF帧率比深度学习模型高一个数量级检测精度对监控场景足够。% 对当前帧做人形检测这里选用ACF检测器 detector peopleDetectorACF(caltech); [bboxes, scores] detect(detector, I); % ACF分数大于阈值的框才保留阈值取决于场景和采样间隔 keep scores 2; bboxes bboxes(keep, :); scores scores(keep);这段代码的要点在于“分数阈值”并没有通用值。ACF 返回的 scores 在不同视频源、不同分辨率下分布差异很大我一般会先跑一段带标注的录像统计正常帧和异常帧的分数分布再定阈值。阈值设太低背景里一些类人纹理会被框出来设太高晚上低照度下真实的人反而漏检。这里不做深度学习关键点检测是因为本场景只需要人的整体框和重心位置不需要精确到脚踝、手腕的骨骼坐标。实时性优先精度够用就行。2.3 动作特征设计把框的变化翻译成可判别的数值拿到人体框后异常行为的判别依据来自框本身的几何特征。跌倒最典型的特征是人体高宽比从站姿的 4~5 急剧掉到 0.3 以下同时重心快速下移并在地面高度附近停留。奔跑的特征是重心水平位移速度大且连续若干帧保持高速。挥拳这类上半身行为则表现为框内上部区域的像素变化频繁。把这几个信号组织成特征向量分类器才有东西可学。% 从人体框与历史信息中提取单帧特征prevBbox来自上一帧 function feat extractFrameFeat(bbox, prevBbox, ratioThreshold) w bbox(3); h bbox(4); cx bbox(1) w / 2; cy bbox(2) h / 2; ratio h / max(w, eps); % 高宽比跌倒时剧烈下降 speed hypot(cx - prevBbox(1), cy - prevBbox(2)); % 重心水平位移速度 areaChange (w * h) / max(prevBbox(3) * prevBbox(4), eps); % 低高宽比 低速 重心偏低是“倒地静止”的联合信号 fallHint double(ratio 1.2 speed 0.08 cy size(prevBbox, 1) * 0.6); feat [ratio, speed, areaChange, cx / 640, cy / 480, fallHint]; end特征里最后汇总了 5 个连续量加 1 个逻辑量。ratio直接反映姿势speed反映运动剧烈程度areaChange反映目标在前进或站立时的面积扩张。cx/640、cy/480这两个归一化位置分量很有用监控画面里不同位置发生异常后续分类器能借助位置信息区分“在墙边滑倒”和“在通道里快跑”。fallHint是我在调试中发现非常有效的经验特征它把“低高宽比低速位于画面下半部”三个条件合并成一个维度比让 SVM 自己去组合这三个量更容易收敛。实际项目中我还会追加一个“地面停留帧数”特征用于区分倒地不起和弯腰捡东西。2.4 滑动窗口与统计压缩避免把时序问题当成单帧问题单帧特征的缺陷是抖动太大。站姿的人弯一下腰高宽比瞬间就变了。所以系统里要引入时间维度做法是维护一个滑动窗口存储近 30 帧的特征向量再对窗口内的每个特征取均值、最大值、最小值和标准差最终压成一个低维向量再送进分类器。这里有个工程取舍直接把 30×6180 维数据丢给分类器理论上可行但训练集不大时特别容易过拟合。压缩成统计量后特征维度降到 24 维SVM、随机森林都能在几百个样本上稳定收敛。窗口长度选 30 帧对应 1 秒既足够覆盖一次跌倒的完整过程又不会因为窗口过长把跑步这类快速行为平滑掉。窗口滑动的实现不做逐帧重算用队列结构先进先出每来一帧就更新队尾、弹出队首再重算统计量计算开销很小。3. 系统实现GUI 界面、实时视频流与检测链路接线3.1 App Designer 搭建界面用 UIAxes 而不是 axes这套系统的图形界面用 App Designer 实现。主界面包含一块视频显示区、开始/停止按钮、异常状态指示灯、以及一个显示当前行为类别的文本框。组件选择上有一个容易被忽视的点视频显示必须用 UIAxes不能用传统 axes。UIAxes 设计目标就是支持高频的imshow刷新和交互回调传统 axes 在新版 MATLAB 中只是兼容存在实时刷新时性能瓶颈会很突出。界面的回调逻辑并不复杂。开始按钮的回调里创建视频读取对象和定时器停止按钮的回调里清空定时器并释放摄像头占用。状态指示灯用一个 Lamp 组件正常时亮绿色异常时亮红色同时文本框打印异常类型和置信度。参数区放三个可编辑字段检测阈值、报警帧数、视频源编号方便现场调试。3.2 用 timer 驱动采集循环让 UI 在检测过程中保持可操作实时系统最忌讳在主线程里写死循环。很多第一次接触这个资源的人会习惯性写成while hasFrame(vidObj) ... end结果界面一运行就卡死按钮点不动、窗口拖不动。原因很简单MATLAB 的 UI 事件循环被 while 占用根本没机会处理鼠标消息。正确做法是让定时器对象按固定周期回调每次回调只处理一帧。% 在“开始检测”回调中创建定时器Period单位是秒 vidSrc webcam(app.CameraIDEditField.Value); % 打开指定摄像头 tImg timer( ... TimerFcn, (~,~) frameLoop(app), ... % 每周期执行一次帧处理 Period, 1/30, ... % 目标30帧/秒 ExecutionMode, fixedRate); % 固定速率不累计延迟 start(tImg);这段代码里有几个细节。ExecutionMode设为fixedRate后每帧间隔按绝对时间计算不会像fixedSpacing那样因为回调执行时间波动而漂移。回调中只做三件事读取一帧、调检测函数、刷新画面。如果检测函数跑得太慢宁可让Period放大到 1/20 也不要让 UI 卡顿。摄像头对象在停止回调中要显式clear vidSrc否则下次启动会报“摄像头已被占用”这是 MATLAB 图像采集最常见的翻车点之一。3.3 检测与显示解耦跳帧检测的接线方式实时链路里最大的性能矛盾来自检测耗时。背景差分加 ACF 检测每帧大约需要 40~80ms这就注定无法在每帧都完整检测。我的做法是每 3 帧做一次完整检测中间两帧只刷新画面不重新检测。画面刷新用上一帧的结果叠加框和标签视觉上基本无感但系统整体帧率能稳定在 20fps 以上。定时器回调里用一个帧计数变量frameIdx模 3 为 0 时执行检测流程否则直接显示原始帧。检测函数内部还要做一步“滞后处理”当前检测不到人体而上一帧检测到时不立刻清空画面而是用vision.KalmanFilter预测上一帧的框位置继续显示 5 帧等目标重新出现。这一步能显著减少跳绳、拍手这类动作产生的目标闪烁。真实项目里“检测目标在画面里跳进跳出”比“检测不到”更影响观感卡尔曼平滑是性价比很高的补丁。4. 分类器训练与调参从特征到异常判定的完整闭环4.1 构造训练集正负样本怎么采集最省力分类器的输入是 2.4 节生成的统计压缩特征。单样本的结构可以描述为下表特征组包含内容维度高宽比统计均值、最大值、最小值、标准差4重心速度统计均值、最大值、最小值、标准差4面积变化统计均值、最大值、最小值、标准差4位置统计归一化 x、y 的均值与标准差4倒地提示统计滑动窗口内 fallHint 的均值1地面停留帧数窗口内低重心且低速的总帧数1首尾帧特征窗口首帧与尾帧的高宽比、速度4合计 22 维。正样本收集方式建议直接录制异常演示视频人工标注行为开始和结束的帧号然后截取窗口生成样本。负样本来源更广正常行走、站立聊天、弯腰整理东西、拿快递等日常动作都要覆盖。容易犯的错误是只录“站着不动”作为负样本导致分类器把“任何运动”都视为异常误报率爆炸。负样本里一定要包含弯腰、坐下、下蹲这类与跌倒外观接近的动作。4.2 SVM 训练与参数语义样本准备好后训练 SVM 二分类器。MATLAB 的fitcsvm是核心入口参数注释如下% 训练二分类支持向量机检测异常行为 mdl fitcsvm(featMat, labels, ... KernelFunction, rbf, ... % RBF核能刻画非线性决策边界 BoxConstraint, 10, ... % 增大约束减小训练误差但防过拟合需配合交叉验证 Standardize, true, ... % 标准化各维度防止高宽比压倒速度特征 KernelScale, auto, ... % 自动估计RBF核宽度 CrossVal, on, ... % 开启10折交叉验证 KFold, 10); accuracy 1 - kfoldLoss(mdl);BoxConstraint是这条代码里最值得解释的参数。它控制对误分类样本的惩罚力度值越大训练时越努力把每一个样本都分对但决策边界会变得复杂泛化能力下降值越小边界更平滑能容忍少量难分样本。10 这个初值是我在类似特征维度下的常用起点训练完先看交叉验证准确率再在 1~100 之间对数扫描两轮。Standardize必须设为 true否则高宽比这个量纲在几十的量级上会直接支配速度特征。RBF 核默认适合大多数情况不要急着换多项式核或线性核。4.3 随机森林作为备选什么时候不该迷信 SVM资源里同时提供了随机森林的备选实现用fitcensemble打包 Bagging 树。SVM 在小样本、特征维度低时速度优势明显但它的决策边界依赖核函数的选择调参经验不足的人容易在核宽度上踩坑。随机森林几乎没有需要精细调整的参数NumLearningCycles设 100各树用随机特征子集默认设置下就能得到稳定结果缺点是在本场景中推理速度略慢单帧大约多 2~5ms。我的经验做法是样本量少于 300 时优先 SVM样本量过千后优先随机森林这两类分类器在这个任务上的准确率差距通常不超过 3 个百分点不必追求“最优算法”。4.4 时序投票在分类器后加一道后悔药分类器输出的是单窗口的决策但一两个异常窗口并不能构成真正的行为。工程上我习惯在分类器后面再加投票逻辑连续 5 个滑动窗口中有 3 个判定为异常才真正触发报警。% 维护一个5元素的环形缓冲记录最近5个窗口的判定结果 function isAlarm voteAlarm(app, currentVote) app.voteBuf [app.voteBuf(2:end), currentVote]; % 队列滚动 if sum(app.voteBuf) 3 % 5帧中有3帧异常 isAlarm true; else isAlarm false; end end这段代码把瞬时误判挡在了报警门外。voteBuf初始化为全 0 的 1×5 数组每来一个新判定就推进一位。阈值为什么选 3 而不是 5因为真实跌倒过程中前期有低高宽比特征的帧数通常只有 20 帧左右窗口切分的边界效应会导致部分窗口落在动作前段、特征不够典型。5 取 3 既保证连续性又保留一定容错。报警后系统会自动保存触发前后各 10 秒的视频片段方便事后复核这个功能在演示时特别加分。5. 实时系统的常见坑性能瓶颈、误检与工程细节排查5.1 点击开始按钮后界面卡死现象点击“开始检测”后整个窗口失去响应拖动窗口出现“白框”只能强制关闭 MATLAB。原因回调函数里用了while循环逐帧读视频循环体内没有让出 UI 事件处理MATLAB 界面线程被完全阻塞。这个坑几乎所有第一次实现实时 GUI 的人都会遇到不是代码逻辑错误而是事件模型用错了。解决把 while 循环改成 timer 定时驱动每周期只处理一帧。回调函数保持短小不要在回调里做耗时的模型推理、特征可视化等操作把耗时工作拆到独立的检测函数中回调只负责取结果和刷新 UI。5.2 弯腰捡东西被判定为跌倒现象画面里有人正常弯腰捡文件系统连续触发跌倒报警频繁误报。原因只用了单帧高宽比特征。弯腰和跌倒前期的外观非常接近高宽比都明显下降仅靠形状无法区分。解决给判定增加时序条件跌倒必须满足重心先快速下移、随后 5 帧以上维持在画面低处且几乎不移动。也就是说只把“倒地”而不是“弯腰”判为异常。特征向量中需要加入地面停留帧数与重心下降速度两个维度并在投票缓冲里要求连续窗口满足低速条件误报就能压下去。5.3 接入深度学习姿态模型后帧率暴跌现象把检测段换成 OpenPose 一类关键点模型后帧率从 25fps 跌到 3fps实时性完全丧失。原因深度学习关键点模型的单帧推理耗时 200~400ms而定时器周期只有 33ms计算量远超系统吞吐能力。解决放弃在每帧上做关键点提取只对 ACF 人体框做轻量特征计算确有骨骼需求时每 10 帧做一次关键点推理中间用速度与位置插值补齐。用深度学习不是不行但要把它放到“低频辅助”的位置而不是主链路里。另外我一般会检查gpuDevice是否可用MATLAB 的深度学习推理在 CPU 和 GPU 上耗时差距近 10 倍偶尔是环境配置不到位导致速度异常。5.4 人体静坐 40 秒后从前景中消失现象监控画面中有人坐在椅子上长时间不动几十秒后前景掩码里再也找不到这个人系统认为这是一张空画面。原因背景模型的AdaptLearningRate设得偏大坐姿的人被缓慢吸收为背景。前景检测器本身没有“这曾经是个人”的记忆像素颜色一旦被纳入背景分布再想分离出来就需要下一次运动。解决把AdaptLearningRate降到 0.002 左右同时定期重置背景模型。更稳妥的方法是叠加一层基于 ACF 的人体区域检测即使前景掩码为空只要 ACF 能检测到人形轮廓就强制保留该区域的检测状态。这个兜底逻辑对防漏检非常有效代价是每帧多几十毫秒计算。5.5 换台电脑后报错找不到工具箱或函数现象代码在自己的机器上跑得好好的换一台电脑就报Undefined function vision.ForegroundDetector。原因目标机没有安装 Computer Vision Toolbox 或 Image Processing Toolbox。MATLAB 的 license 是按工具箱授权的脚本本身不携带依赖这个问题在把代码发给别人或找人代跑程序时频繁出现。解决交付前在命令行执行ver查看已安装工具箱列表明确标注依赖项。如果目标用户没有完整 MATLAB 授权就用 MATLAB Compiler 打独立 exe目标机只需要安装对应版本的 MATLAB Runtime。需要特别确认的是 Runtime 的版本号必须与打包时一致R2024a 打包的程序在 R2023b 的 Runtime 上无法运行。6. 进阶把原型推向实时与交付的最后一公里6.1 用卡尔曼跟踪补足跳帧空窗跳帧检测虽然保住了帧率但检测结果天然带有间隔。与其等待每 3 帧做一次完整检测不如在中间帧用卡尔曼滤波器预测目标的运动轨迹。vision.KalmanFilter的构造需要指定运动模型和数据维度对矩形框跟踪用 4 维状态就可以中心点 x、y框宽、框高。% 卡尔曼滤波器的初始化与单步预测 kal vision.KalmanFilter(ConstantVelocity, ... StateCovariance, 10*eye(4), ... ProcessNoise, 1e-2, ... % 过程噪声越大越“相信测量” MeasurementNoise, 1e-1); % 测量噪声越大越“怀疑检测框” predBox kal(bboxes(1, :)); % 每次调用同时完成预测和修正过程噪声与测量噪声是一对相互作用的值测量噪声调大滤波器会更平滑地跟随检测框但响应延迟增加过程噪声调大跟踪更积极但也更容易被误检框带偏。经验上先固定测量噪声为 1e-1再扫描过程噪声。跟踪器的输出不参与特征计算只用于画面叠加和报警连续性判断能避免检测器本身的框抖动放大分类器误判。6.2 把 demo 打包成独立 exe原型验证完成后如果要在现场电脑上演示直接用 MATLAB 打开工程是最省事的方式但对方不一定有完整工具箱。打包是更稳妥的交付形态。在 MATLAB 里进入compiler.build.standaloneApplication流程主函数包含创建 GUI 的入口工具会自动拉取依赖。需要提前检查两点一是摄像头采集支持包是否在依赖列表里二是确认打包机与目标机 Runtime 版本一致。我踩过一次 Runtime 版本不匹配的坑打包后 exe 一运行就闪退排查了近一个小时才发现是 Runtime 装错了版本从那以后每次打包前都强制检查version -runtime并在交付说明里写明 Runtime 版本号。希望这套系统的拆解记录能帮你在复现和改造时少走弯路尤其是 GUI 实时性这个最隐蔽的坑早绕开早省心。本文还有配套的精品资源点击获取
阅读完成 · 觉得有帮助?
咨询建站