☰
口罩检测、安全距离与体温测定:Python健康风险监测系统实战
2026/10/15 8:49:29 网站建设 项目流程

把口罩检测、行人安全距离检测和生物测定放到同一个Python项目里,最典型的落地场景就是公共场所的健康风险监测系统。这个项目看起来是三件事,实际上需要合成一条完整的数据流水线:摄像头视频进来,先判断画面里有没有人,再判断人脸上有没有口罩,接着算人与人之间的实际距离,最后把可疑状态和体温读数对齐。我最早是在一个园区出入口的智能化改造里接手这个需求,当时三个功能分别做了原型,联调的时候才发现问题比想象中多。这篇就按我实际走过的路线来写,重点讲清楚每一个环节为什么要那样选、在哪里容易踩坑,以及最终一套可运行的方案长什么样。

1. 项目整体思路:一条流水线处理三种任务

这种项目最容易犯的错,是把口罩检测、安全距离检测和生物测定当成三个独立功能分开做。分开做确实都有现成方案,但放到真实场景里,它们的数据必须共享同一个时间轴和同一个坐标空间,否则告警根本对不上。

1.1 三个需求分别解决什么问题

口罩检测,本质上是判断“当前人员有没有佩戴口罩”,属于目标检测里的分类加定位任务。它既要给出类别,也就是“戴了”还是“没戴”,也要给出框,把人的头部区域框出来,方便后续把所有口罩状态不足的人出现位置标记出来。

行人安全距离检测,本质上不是单纯的检测任务,而是“目标检测 + 跟踪 + 距离换算”的组合。先找到画面里所有人,再通过跟踪算法把不同帧里的同一个人对应起来,然后计算任意两个人之间的距离。这里有个常见误区:很多人直接用像素距离,认为两个矩形框中心越近就越危险,实际并不准确,因为摄像头视角、安装高度、俯仰角都会让像素距离和真实距离产生严重偏差,必须做坐标换算。

生物测定在这个项目里的含义,是把传感器的健康体征数据变成风险信号。最常见的是体温检测,即通过热像仪或测温模组,读取行人额头区域的温度。这个模块要和前面的检测结果联动,不能单独工作。比如一个行人没戴口罩且体温偏高,系统就要给出高等级告警;如果只是没戴口罩但体温正常,就只需要提醒。

1.2 “生物测定”模块在项目里的位置

在计算机视觉项目里看到bioassay这个词,很多人的第一反应是实验室里的生物分析实验。放到这个系统里,它其实是“非接触式人体健康指标测定”的简称。核心是非接触观察到温度特征,再结合检测结果形成判定依据。

从数据流来看,摄像头先将视频帧送进目标检测模型,模型输出两类框:人形框和头部/口罩框。人形框用于计算行人中心点和安全距离,口罩框用于判断佩戴状态。与此同时,热像仪或者红外模组同步输出温度矩阵,程序根据人的位置去提取对应区域的温度值。这个对应过程是项目最核心的联动逻辑。

我实现的时候把整个系统拆成了四个模块:视频采集与同步、目标检测与跟踪、距离计算、温度测定与告警。模块之间用消息队列传递检测结果,每个模块可独立重启,避免单一异常导致整套系统崩溃。

2. 模型选型与框架选择:为什么不能只用传统视觉方案

刚开始有人建议我用传统的图像处理来做,比如用级联分类器检测人脸,用背景差分法找行人,再人工设定距离阈值。听起来简单,实际换到真实场景之后效果很差,光照一亮一暗、行人一多一遮挡,传统方案马上崩。

2.1 口罩检测与行人检测的模型选择

我最终选择的是YOLO体系里的轻量模型。选择原因有三个:一是口罩和行人检测本质上都是目标检测,YOLO这一类单阶段检测器速度快,能在普通工控机上跑到实时帧率;二是YOLO有大量预训练权重,迁移到自己的数据集上收敛很快;三是封装程度高,前处理和NMS这些细节都帮你处理好了,项目调试阶段能省很多时间。

口罩检测不能单独训练一个模型,我建议把“行人”和“口罩”放在同一个模型的不同类别里训练。你可能会问,为什么不单独检测人脸?因为在真实监控画面里,人的头部有时候很小,或者侧脸、低头、手遮挡,单独检测人脸会丢目标。把人形框作为主体,再在头部区域加一个口罩类别,稳定得多。

类别设置我用了三种:person(行人)、mask(佩戴了口罩)、no_mask(未佩戴口罩)。注意person和mask/no_mask是有重叠关系的。这不是问题,后处理里可以通过框的坐标做逻辑关联。比如一个人的框里出现了no_mask框,就认为这人没戴口罩。

2.2 距离测量方案的取舍

距离测量有三种常见路线:单目加透视变换、双目立体视觉、深度相机直接取深度。三种路线我都试过,最终选了单目加透视变换。

双目立体视觉精度高,但需要两个摄像头做硬件标定,安装位置必须严格固定,镜头的基线距离一旦变动误差就会很大。深度相机像结构光或者ToF方案,在室内近距离效果很好,但是放到园区出入口这种户外一段距离,阳光干扰非常明显,有效距离会缩短很多。

单目加透视变换看起来简单,但它利用了“摄像头固定”这个前提。安装位置固定、角度固定,场景地面是一个平面,那我就可以通过在视频画面上标定几个真实世界坐标点,计算出一个映射矩阵,把画面中的像素坐标映射到地面物理坐标。对安全距离监测来说,这足够了。合适的人只需要关心地面上人与人的间隔,不需要拿到空间三维坐标。

提示:单目方案的前提是摄像头不发生移动。固定摄像头使用云台控制转动,建议在算法层面对角度变化做补偿,否则映射矩阵需要自动重新计算,工作量会大很多。

2.3 热像仪与普通摄像头配合的接口设计

我的测温模块一开始想用热像仪直接输出温度数据,然后通过API读取。真正调试时发现,热像仪画面分辨率往往很低,跟可见光摄像头画面不是同一个视野,必须做画面配准。

最简单可靠的方法是通过像素映射:在部署时把可见光画面和热像仪画面显示在同一张调试界面里,用鼠标选取四个共同参考点,比如门框角、路灯柱、地砖接缝这些明显标志,计算出仿射变换矩阵。之后,可见光画面中检测到的人脸区域中心点,经过矩阵变换,就能对应到热像仪的温度像素位置,并读取该点附近的温度值。

温度读取并不是取单点,而是取一个以对应点为中心的小矩形区域里的最高温度。因为在真实场景里,温度值收到设备误差和遮挡影响,单点读数不够稳定,取最高温度能避免额头中心刚好落在眉毛位置时温度偏低的问题。

3. 训练口罩检测与行人检测模型:容易被忽略的细节

模型训练看起来是把数据集扔进去跑几百轮就能出结果,实际上有很多细节会直接影响现场效果。尤其是口罩检测这种类别之间外观差异很大的任务,看起来容易,但要解决遮挡、小目标、复杂背景的时候全在细节里。

3.1 数据集收集和标注规范

口罩检测的数据集可以从公开的口罩检测数据集里找,也可以自己采集。我的经验是两个都要做,只靠公开数据集会在现场遇到“公共场所真实分布”和“数据集分布”不一致的情况。比如公开数据集里很多人带的是医用外科口罩,颜色统一,现场却可能带各种颜色口罩、围巾、甚至拿手挡嘴,模型会傻眼。

标注的时候统一用YOLO格式,每个标注文件对应一张图片,行格式是: 类别索引 中心点x 中心点y 宽度 高度 所有值都是相对于图像宽高归一化后的比例。举个例子,一个不算大的口罩框写在txt文件里就是:1 0.45 0.32 0.12 0.18类别索引为1表示“已戴口罩”,框位置在图片水平中心偏左、垂直约三分之一处,框宽度约占图宽12%,高度占图高18%。

我一开始踩过一个坑:同一张图里既标“人”又标“口罩”,但口罩框被生成了很多错误的“大框”,把整个上半身框进去了。这样导致训练时模型学到的是“戴了一块白色大区域”,而不是口罩本身。后来矫正标注策略:口罩框只标脸部下半部分覆盖口罩的部分,不要往外扩太多;人形框可以依据整体人轮廓稍微贴紧,但不要在重叠目标较多时把两个相邻人框进同一个框里。

数据集规模方面,我最终使用了大约8000张图片,其中约2000张是口罩佩戴情况复杂的现场采集图。每个类别单张图平均出现2到3个目标。如果目标是做系统原型,这个规模足够了;但要做到生产级稳定,建议把复杂场景图片扩展到两万张以上。

3.2 训练配置与后处理要点

训练使用的命令大概长这样:

python train.py --model yolov8n.pt --data mask_pedestrian.yaml --epochs 120 --img 640 --batch 16

一开始直接用并不稳定,因为有些公开数据集里图片分辨率不高,我用一个简单脚本把较短边缩放到640,同时做了随机翻转、随机色度变换、随机马赛克增强。虽然YOLO训练自带Mosaic增强,但针对现场光照条件,我额外把亮度随机增强的范围调到比较大,防止晚上摄像头画面太暗时模型失效。

后处理上的关键是置信度的选择。口罩检测的置信度阈值不能统一设为0.5。行人框可以保持0.5,因为漏检一个人会导致整个距离计算缺一块,后果比较严重;口罩框阈值可以提高到0.6到0.7,因为把“没带口罩”判成“戴了”更危险,少报警宁可要准,不要频繁误报。

NMS(非极大值抑制)的作用是在同一目标附近合并多个重叠框。检测器可能对同一个人脸输出三四个高度重叠的口罩框,NMS会把它们合并成一个。对人群密集的场景,NMS的IoU阈值建议从默认值往下调一点,比如0.5到0.4,否则两个近距离的人的口罩框可能被合并成一个框,导致后续温度提取取到错误位置。

3.3 模型轻量化与推理加速

我用的是YOLOv8n,n代表nano轻量版,单张图耗时短。但现场如果人流较大,纯CPU推理还是会掉帧,我的建议是优先用支持GPU推理的工控机,或者把模型导出为TensorRT格式做推理加速。导出来后,单张图推理时间可以从毫秒级进一步缩短到更稳定,400万像素级别的视频流能跑到实时。

如果开发环境不方便装高性能推理引擎,还有一个折中方案:每隔一帧做一次完整检测,中间帧用跟踪算法补充目标位置。这样在保持实时性的同时降低计算压力。

4. 安全距离计算:从像素坐标换算出真实米数

这段是整个项目里最容易被人忽视、却最影响结果的部分。直接用矩形框中心点做像素欧氏距离,得到的是“图片距离”,不是“地面距离”。在一个俯视角度较大的摄像头画面里,画面底部的两个人可能实际相距很远,画面顶部的两个人可能实际距离很近,单纯比较像素距离会把判断搞反。

4.1 固定摄像头下的透视映射

在固定摄像头拍摄的二维画面中,我可以选择地面上的四个点,记录它们的像素坐标,同时按照真实地面位置给这四个点赋一组等比例的物理坐标。假设我要测量的是地面上的距离,那就把四个点分别映射到一个矩形地面区域的四个角点。

代码里就是用OpenCV的透视变换函数:

import numpy as np import cv2 src = np.float32([[x1, y1], [x2, y2], [x3, y3], [x4, y4]]) dst = np.float32([[0, 0], [image_width, 0], [image_width, image_height], [0, image_height]]) # 计算透视矩阵 M = cv2.getPerspectiveTransform(src, dst)

这个方法的前提是四个源点要在地面平面上,并且尽量分布在画面中需要检测距离的整个区域。不要把四个点都集中在角落,这样计算出来的映射精度会很低。

实际距离换算比例如何确定?可以在地面上摆两个已知间距的标记物,比如一把长度已知的卷尺,拉出一个恰好为2米的线段,在画面里读取线段两端像素坐标。然后把这个已知物理距离和像素距离的比例作为标定系数。

这里要注意的是,透视变换后的坐标已经不是图像平面坐标了,而是“俯视矩形区域”的坐标,在这个矩形区域里,可以用固定比例把坐标差换算成物理米数。换算方式:

已知两个点经过透视变换后的坐标分别是(x_a, y_a)和(x_b, y_b),则物理距离:

real_world_dist = math.sqrt((x_a - x_b) ** 2 + (y_a - y_b) ** 2) / scale

其中scale是“每米对应的变换后像素数”,需要在标定矩形中放一个已知长度的参考物来确定。

4.2 标定参考物与实际测试

我实际标定时,是在地面用胶带贴了两条平行线,保持固定间距。比如我贴出一条约3米长的标尺,再在标尺两端放置两个明显物体作为标记点,摄像头画面里就能准确读取标记点的像素坐标,然后算出比例。标定完成后,又放了一个0.6米间距的物体,验证测出来的结果是否和实际一致。实测误差大约在5%到10%之间,妥满足安全距离监测精度。

如果只是做快速原型而不是精确部署,也不一定非要贴胶带。可以利用已知宽度的地砖接缝。比如地砖宽度是0.6米,就在画面里选中两条接缝线,手动定位两个角点当作物理距离参考,也能得到一个大概的映射关系。

提示:标定要在地面上进行,而不是在墙面上进行。摄像头画面里的人站在地面,距离也应该以地面位置为基准。如果标定点贴在墙体上,会让画面中越靠近墙的地面距离误差越大。

4.3 告警逻辑与跟踪稳定性

算出任意两个人之间的地面距离之后,告警逻辑就简单了:只要两个人之间的距离小于设定阈值,比如1米,就认为违反安全距离要求,进而把两人的ID加入告警队列。

但只靠单帧判断会产生大量抖动。一个人正常走路时,不同帧里检测框会上下摆动,底部中心点可能在前后几十像素范围变化,算出来的距离会在临界值附近反复跳动。解决办法是给每个跟踪ID维护一个距离均值,采用滑动窗口过滤,窗口长度为10到15帧。连续多帧都低于阈值,才真正触发告警。这样可以大幅减少误报。

跟踪算法方面,不要自己从零写。固定摄像头场景可以先用简单的IOU匹配,逐帧计算当前检测框和历史轨迹框的交并比,如果大于0.3就认为属于同一个ID。如果场景里存在遮挡、行人快速交叠,则建议用ByteTrack这类更稳定的跟踪器。

5. 生物测定模块:温度联动与二次确认机制

生物测定模块不只是读取温度数值,还要负责温度数据和其他检测信息的融合。我把它做成一个独立的判定单元,内部输入三类数据:人员检测框、口罩佩戴状态、温度读数。最终输出的是风险等级。

5.1 测温对齐与数据读取

温度读数的对齐问题在第2部分提过,这里展开讲实现细节。摄像头画面里检测到了人脸或头部区域后,用仿射变换矩阵把该区域的中心点映射到热像仪画面的像素坐标。热像仪输出的是浮点温度矩阵,直接从这个矩阵里取对应点附近一个小邻域内的最大值。

如果你的热像仪没有开放的SDK,不让直接获取温度矩阵,那就只能在部署时做一次点对点匹配测试:在热像仪软件里手动记录目标区域的平均温度,然后在自己的程序里输入同一时刻的检测信息,比对两边误差。误差通常在正负0.3度左右,对风险判断足够的。

测温的帧率不需要太高。目标检测可能每帧都在跑,但温度数据平均每秒刷新一次就够了,两次测温之间用上一次最近的读数组合。这样可以稳定测温模块,也可以降低热像仪数据传输压力。

5.2 判定规则与告警分级

我设计的判定规则不是一刀切的高温报警,而是分成三级:

第一级:风险提示。行人没戴口罩,体温正常。系统只在画面里显示黄框,记录一条日志,不推送紧急告警。 第二级:重点关注。行人佩戴了口罩,但体温高于阈值。系统显示橙框,并且给管理人员发一条注意级别的消息。 第三级:高危告警。行人没戴口罩,同时体温高于阈值。系统显示红框,立即推送告警,并在本地保存前后各10秒的视频快照。

这三级规则表面很简单,但实际部署时还是需要小心阈值设定。传统体温阈值适合作为医学参考,现场不同,额头温度、环境温度、个体差异都有影响。我不会把告警判断完全依赖一个固定温度阈值,实际操作是增加一个“环境参考温度”的概念。在摄像头视野边缘放一个不被人遮挡的小区域,读取环境温度作为基准,当目标温度比环境基准高出一定数值时,才判断为异常。

这样会比固定阈值可靠很多。比如中午户外环境温度高,人的额头温度相对环境温度差值小,但体温正常;如果只看绝对阈值,可能会把一整个排队人群全标成异常。

5.3 数据保留与隐私边界

每分钟都在保存所有行人温度数据和画面,在真实部署中极易触碰隐私边界。项目上线前我特别做了一条原则:只保留触发告警时段的数据,正常人员的检测结果只保存为日志摘要,原始视频帧不落地。

告警个人的画面,也只保留裁剪后的目标区域和对应时间戳,不保存整条画面录像。这样既保留了追溯能力,又避免大量无关人员的信息被记录。数据加严口令控制,仅现场运维人员可访问。

这条原则不是技术层面能不能做的问题,而是应用这类系统时必须考虑的安全底线。技术方案再成熟,如果采集了不必要的数据,会给项目留下很大隐患。

6. 现场部署排查:常见问题与避坑实录

这类系统做出来是一回事,现场稳定运行是另一回事。我把调试过程中最常遇到的问题和最终解法整理成一张表,适合作为你部署时的速查清单。

6.1 高频问题速查表

现场现象典型原因解决办法
口罩佩戴状态频繁误报阈值或数据集分布问题口罩类别置信度调到0.6以上,补充现场采集数据
距离告警一直抖单帧距离波动大加滑动窗口均值,连续多帧低于阈值才告警
户外逆光时检测不到人成像过曝摄像头开HDR或设置自动曝光,必要时加遮阳罩
测温偏高或偏低反射面或未对齐调整热像仪发射率设置,重新做点对点匹配
行人快速交叠时ID乱跳简单IOU跟踪失效改用ByteTrack,并增加外观特征匹配
CPU推理速度不够模型过大或硬件弱换nano级模型,或导出轻量推理格式
人群密集时NMS把相邻目标合并IoU阈值过高降低NMS IoU阈值到0.4左右
夜间摄像头画面模糊夜视能力不足使用支持红外补光摄像头,重新校准距离映射

上表列的每个问题我都实际遇到过,其中“ID乱跳”的影响最大。ID一旦跳变,距离告警会把同一个人的前后帧当成不同的人,产生大量无效告警。如果项目时间紧,可以直接先固定摄像头,用比较保守的跟踪策略,哪怕跟踪ID切换慢一点,也比稳定跳动强。

6.2 现场安装调节的几条经验

安装高度和角度决定项目成功一半。摄像头最好安装在3米到4米的高度,略向下俯视。这个角度既能完整覆盖人的头部区域,又能看到脚底附近的地面区域,距离标定和口罩检测都能兼顾。

摄像头正面迎着人流比侧向安装好。侧向安装可以看清面部侧面轮廓,对口罩检测有利;但人从画面一侧走进来的时候,头部会突然出现在画面边缘,检测框稳定性会比较差。正面安装可以让人物从画面中部走进来,跟踪稳定,口罩检测效果也足够好。

光线问题一定要提前计划。户外部署时,逆光导致的检测失效很常见,建议摄像头安装位置尽量避开太阳直射方向。无法避免时,首选支持宽动态和自动曝光的工业相机,通过调参把人物脸部的曝光压低,让脸部阴影少一些。

6.3 项目后续还可以扩展什么

这套架构做完之后,扩展性比预期好。口罩检测模块可以替换为安全帽检测,或者工地反光背心检测,距离检测部分完全复用。生物测定模块如果以后要接入更多健康指标,比如呼吸率、心率估计,也只是增加一个信号提取模块,不用改主流程。

我比较推荐的一个扩展方向,是加上行为分析规则。目前只是“站点监测”,也就是人进来了,检测状态、判断距离,然后告警。如果再加入目标轨迹分析,就具备“行为监测”能力,比如判断排队人群是否持续聚集、某个区域聚集时间是否超限。这会大幅提升系统的实际价值。

结尾就先落在这里。项目做到后期,我发现真正有价值的部分反而不是模型准确率提升了多少个点,而是整套系统在现场能够稳定、可控、不扰民地运行。像这种涉及公共场景的监测系统,技术上的稳妥和隐私上的克制同等重要。如果你正准备照着这个标题做原型,建议先从最小功能闭环开始:单摄像头、一个检测模型、一个透视矩阵、一套温度联动规则,把数据链路跑通后再逐步加模块。能跑通最小闭环,后续所有优化才有意义。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询