基于STM32与OpenMV的非接触式体温监测与身份识别系统设计

📅 发布时间:2026/9/3 2:52:31
基于STM32与OpenMV的非接触式体温监测与身份识别系统设计 简介本资源是一套面向嵌入式AI初学者与智能硬件开发者的完整项目实践方案聚焦无接触式红外体温监测与多模态身份识别场景适用于疫情防控、智慧门禁、校园/办公场所健康核验等实际应用。项目以STM32F103为主控平台融合OpenMV视觉处理、GY906DCI红外测温模块并集成人脸识别基于轻量神经网络模型、口罩检测Adaboost强分类器及OLE跨平台数据对接能力兼顾算法实现与嵌入式工程落地。压缩包共198个文件含41个.h头文件与39个.c源码涵盖USART、TIM、ADC、I2C等外设驱动及核心算法逻辑30个.o与.d编译中间文件体现完整Keil工程结构另有3个Python脚本用于模型预处理、1个.tflite模型文件、1个.hex可烧录固件及配套文档整体8.03MB结构清晰、模块解耦度高。目前已有60人学习下载读者可直接复现软硬协同流程掌握红外温度校准、人脸ROI提取、Adaboost训练样本构建、神经网络部署优化及OLE数据互通等关键技术环节。1. 项目缘起一个“非接触”场景下的刚需最近在做一个社区服务项目需要一套能在入口处快速、自动完成人员体温筛查和身份核验的设备。核心要求就两个非接触和一体化。非接触是为了安全卫生一体化是为了减少人员操作提升通行效率。市面上现成的方案要么是单独的红外测温枪加人工登记效率低下要么是集成度高的商用测温门禁价格昂贵且功能固化难以根据我们的具体场景比如是否需要强制口罩检测进行定制。于是基于手头已有的STM32F103C8T6核心板和OpenMV Cam H7 Plus模组我决定自己动手搭一套。STM32负责系统控制、逻辑处理和外围设备驱动OpenMV则凭借其内置的MicroPython环境和强大的机器视觉库专攻图像处理与识别。再搭配一个常用的MLX90614我用的就是GY-906模块本质是MLX90614的DCI版本红外测温传感器硬件骨架就齐了。目标很明确人走到设备前自动完成人脸检测、身份识别或记录、体温测量并根据设定规则如体温超标、未戴口罩进行声光报警或控制闸机。这听起来像是简单的模块堆砌但实际做下来从传感器数据滤波到人脸识别模型在嵌入式端的部署优化再到多任务间的协调与抗干扰每一步都有不少细节需要打磨。下面我就把整个系统的设计思路、关键实现以及踩过的那些坑毫无保留地分享出来。2. 硬件选型与核心模块功能解析一套稳定的嵌入式系统硬件是地基。选型不仅要考虑功能更要考虑模块间的匹配性、供电以及实际的通信可靠性。2.1 主控与视觉核心STM32F103与OpenMV的分工我选择了经典的“STM32 OpenMV”组合这是一种在资源受限的嵌入式设备上实现智能视觉功能的高效架构。STM32F103C8T6蓝色核心板扮演系统“大脑”和“管家”的角色核心控制运行FreeRTOS实时操作系统管理测温、通信、报警、显示等多个任务。外设驱动通过I2C接口读取MLX90614的温度数据通过UART与OpenMV进行指令与数据交互控制LED指示灯和蜂鸣器进行报警驱动OLED屏幕显示实时信息体温、识别结果、状态预留了PWM输出接口用于后续控制舵机或闸机。逻辑处理判断体温是否超阈值综合OpenMV返回的识别结果陌生人/已知ID、是否戴口罩执行相应的联动动作。OpenMV Cam H7 Plus则作为专用的“视觉协处理器”图像采集与处理负责从摄像头实时获取图像流。算法运行在MicroPython环境中运行我们训练好并转换的人脸检测、人脸识别特征提取与比对以及口罩检测模型。结果上报将识别结果人脸ID、置信度、口罩佩戴状态、人脸坐标框通过串口打包发送给STM32。这种分工的优势在于将计算密集型的图像处理任务从STM32上剥离避免了STM32因处理图像而导致的系统实时性下降。OpenMV专注于它擅长的视觉任务STM32则专注于系统调度和实时控制两者通过串口这个简单的通道高效协作。2.2 非接触测温模块MLX90614GY-906的真相与校准项目标题中的“GY906DCI”其实就是市面上常见的GY-906模块其核心芯片是Melexis的MLX90614ESF-DCI。这是一个数字式红外测温传感器通过I2C接口通信。需要厘清的几个关键点测量对象MLX90614测量的是物体表面温度并非人体核心体温如口腔、耳温。其测量值受环境温度、测量距离、被测物体表面发射率对于皮肤通常取0.98影响显著。DCI版本DCI代表“数字控制接口”是MLX90614的一个子型号与常见的BAA版本主要区别在于出厂校准的温度范围和一些滤波设置但基础驱动和读取方式是一致的。单双探头MLX90614有单区域测量一个点的平均温度和双区域可测两点温差之分。用于人体测温单区域版本S足矣。实际使用中的最大挑战环境补偿与校准。传感器自身虽然带环境温度补偿但要想获得相对准确的人体额温参考值不能直接使用原始读数。我的做法是固定测量距离设计一个机械结构将传感器固定在距人额头约3-5厘米的位置。距离变化会极大影响读数。二次软件校准在恒温环境下如25°C室温用一个准确的水银温度计测量手腕内侧温度接近体表温度同时记录MLX90614的读数。通过多次测量拟合出一个线性补偿公式体表校准温度 a * 传感器原始读数 b。系数a和b需要根据你的具体模块和安装位置实验得出。额温转换通常额温比手腕温度略低。可以参考公共卫生领域的一些经验偏移值例如额温比体表温度低0.3-0.5°C但这仅供参考最严谨的方式是用专业额温计在同一环境下对比校准。注意这套自校准方法旨在获得稳定的、相对准确的趋势值用于筛查“体温异常升高”的个体。它不能也不应作为医疗诊断的依据。任何用于公共场合的体温筛查设备最终都必须与经过计量认证的医用体温计进行比对验证。STM32通过I2C读取温度的代码片段如下使用HAL库// MLX90614 I2C 地址默认7位地址为0x5A 1 0xB4 #define MLX90614_ADDR 0xB4 // 物体温度RAM地址 #define MLX90614_TOBJ1 0x07 float MLX90614_ReadTemp(void) { uint8_t data[2] {0}; uint16_t rawTemp; float temp; // 读取两个字节的温度数据 if(HAL_I2C_Mem_Read(hi2c1, MLX90614_ADDR, MLX90614_TOBJ1, I2C_MEMADD_SIZE_8BIT, data, 2, 100) ! HAL_OK) { return -273.15; // 返回绝对零度表示错误 } rawTemp (data[1] 8) | data[0]; // 低字节在前 temp (float)rawTemp * 0.02 - 273.15; // 转换公式原始值 * 0.02 - 273.15 摄氏度 return temp; }2.3 显示与交互OLED屏幕的选择为了在现场提供即时反馈我选用了一款0.96英寸的128x64 SSD1306 OLED屏幕通过I2C驱动。它功耗低、显示对比度高非常适合嵌入式设备。屏幕上会循环显示实时体温来自MLX90614已校准识别状态“识别中”、“您好XXX”、“陌生人”口罩佩戴状态“口罩OK”或“请佩戴口罩”系统提示“体温正常”或“体温异常请复查”3. 视觉算法在OpenMV上的实现与优化这是项目的核心智能部分。OpenMV的IDE提供了强大的图像处理工具和模型部署功能但如何选择并优化算法以适应嵌入式端的性能约束是关键。3.1 人脸检测为何从Haar Cascade转向LBPOpenMV传统上使用基于Haar特征的级联分类器Haar Cascade进行人脸检测。它虽然经典但在资源受限的OpenMV上运行效率不高且对光照和角度变化比较敏感。我最终采用的是LBP局部二值模式级联分类器。LBP特征的计算速度远快于Haar特征因为它只涉及灰度值的比较操作而不需要计算复杂的矩形区域积分。在OpenMV上LBP分类器能达到更高的帧率这对于需要实时响应的门禁场景至关重要。在OpenMV IDE中你可以直接使用image.find_lbp()函数加载LBP特征文件进行检测。通常你需要准备正样本人脸图片和负样本非人脸图片来训练自己的分类器以获得更好的场景适应性。不过OpenMV社区也提供了预训练的LBP人脸检测模型对于正脸检测效果已经相当不错。# OpenMV 上使用LBP进行人脸检测的示例代码 import sensor, image, time sensor.reset() sensor.set_pixformat(sensor.GRAYSCALE) sensor.set_framesize(sensor.QVGA) # 320x240平衡速度与精度 sensor.skip_frames(time 2000) # 加载LBP特征文件通常是一个.cascade文件 face_cascade image.HaarCascade(frontalface, stages25) # 实际上HaarCascade类也支持加载LBP文件 # 或者使用专门的find_lbp函数取决于固件版本 clock time.clock() while(True): clock.tick() img sensor.snapshot() # 检测人脸 # 注意新版本OpenMV固件可能推荐使用 image.find_features() 并指定 lbpcascade 参数 objects img.find_features(face_cascade, threshold0.75, scale_factor1.25) for r in objects: img.draw_rectangle(r) # 可以在此处将人脸区域裁剪出来用于后续的人脸识别和口罩检测 face_img img.copy(r) # 将检测到的人脸区域信息通过串口发送给STM32 # uart.write(...)3.2 人脸识别嵌入式端的特征比对方案人脸识别不是在OpenMV上训练一个完整的神经网络资源不够而是采用“离线训练在线比对”的模式。离线训练在PC上完成使用OpenCV的face_recognition库或Dlib库在PC上收集已知人员的人脸图片每人10-20张不同角度光线。利用深度学习模型如FaceNet、OpenFace的简化版或Dlib的ResNet人脸识别模型为每张图片提取一个128维或更高的特征向量Face Embedding。这个向量可以看作是人脸的“数字指纹”。将所有已知人员的特征向量和对应ID保存为一个数据库文件如.csv或.pkl。在线识别在OpenMV上运行在OpenMV上我们无法运行庞大的特征提取模型。因此需要将PC上训练好的特征提取模型进行转换和量化使其能在OpenMV上运行。OpenMV支持TensorFlow Lite for Microcontrollers格式的模型。这个过程比较复杂需要将Keras或PyTorch模型转换为TFLite格式然后使用OpenMV提供的nn模块进行加载和推理。OpenMV官方有相关教程但需要一定的模型转换和调试能力。更实用的简化方案如果识别的人数不多50人且对实时性要求不是极端高可以采用一种折中方案——仍在PC上提取特征但将特征数据库和简单的比对逻辑下放到OpenMV。在PC上提取好所有人脸特征向量保存为常量数组嵌入到OpenMV的代码中。在OpenMV上对检测到的人脸区域使用一个轻量级的特征提取器例如基于HOG或LBP的简单特征或者一个非常小的自定义CNN模型提取一个特征向量。将这个特征向量与数据库中预存的特征向量进行比对计算欧氏距离或余弦相似度。距离最近且小于某个阈值则认为是该ID否则标记为陌生人。我采用的正是简化方案。我训练了一个非常小的CNN模型仅3-4个卷积层输入是归一化后的人脸灰度图输出一个32维的特征向量。在PC上用已知人脸数据训练好这个模型后将其转换为OpenMV可用的.tflite模型。虽然识别精度比不上大型模型但在小规模、固定人员的场景下如公司、实验室门禁准确率足以接受且速度飞快。3.3 口罩检测Adaboost与神经网络的抉择口罩检测可以看作一个二分类问题人脸区域是否佩戴口罩。Adaboost算法这是一种经典的集成学习算法。我们可以像训练人脸检测器一样训练一个口罩检测的级联分类器。收集大量“戴口罩人脸”和“不戴口罩人脸”的图片提取HOG或LBP特征然后用Adaboost算法训练一个强分类器。在OpenMV上这个分类器可以以.cascade文件形式加载运行速度极快。优点是速度快、资源消耗小。缺点是特征设计需要技巧且对遮挡、口罩款式、佩戴方式的泛化能力可能不如深度学习模型。神经网络模型使用一个轻量级的CNN分类模型如MobileNetV2的微缩版或SqueezeNet。将裁剪出的人脸区域resize到固定大小如64x64输入网络输出两个节点的概率戴口罩/不戴口罩。优点是准确率高、泛化能力强。缺点是模型加载和推理需要更多的RAM和计算时间可能会影响整体帧率。我的选择与混合策略 考虑到实际场景中人员走到设备前大多是正对摄像头口罩佩戴相对规范我优先选择了基于HOG特征Adaboost的级联分类器。它在我的OpenMV H7 Plus上可以达到接近30FPS的处理速度完全满足实时性要求。为了提升泛化能力我收集了不同颜色、款式的口罩图片进行训练。同时我将神经网络模型作为备用方案。当Adaboost分类器给出置信度不高的结果时例如概率在0.4-0.6之间可以触发一次神经网络模型推理进行“仲裁”。这种混合策略在保证绝大多数情况下高速检测的同时提高了复杂情况下的准确性。在OpenMV上加载并使用自定义.cascade文件进行口罩检测的代码与人脸检测类似。4. 系统软件架构与多任务协同硬件和算法模块准备好后需要用软件将它们有机整合起来确保系统稳定、实时地运行。4.1 STM32端的FreeRTOS任务设计我在STM32上创建了以下几个主要的FreeRTOS任务Temperature_Task(温度采集任务)优先级中。周期性地如每200ms通过I2C读取MLX90614的温度值。关键操作读取原始值后立即应用校准公式并进行简单的软件滤波如一阶滞后滤波或滑动平均滤波以消除单次读数的抖动。输出将滤波后的稳定温度值写入一个全局变量或消息队列供显示和判断任务使用。UART_Receive_Task(串口接收任务)优先级高。阻塞式等待来自OpenMV的串口数据。OpenMV发送的数据帧需要设计一个简单的协议例如[帧头][数据长度][命令字][人脸ID][口罩标志][坐标数据][校验和][帧尾]。关键操作实现一个状态机解析器确保能正确解析不定长的数据包防止粘包、断包。校验和错误的数据包直接丢弃。输出解析成功后将人脸ID、口罩佩戴状态等信息通过消息队列发送给主控逻辑任务。MainCtrl_Task(主控逻辑任务)优先级中。这是系统的“决策中心”。它同时接收来自温度任务的消息队列和串口任务的消息队列。关键逻辑当收到有效的人脸信息时结合当前体温进行判断。规则示例如果体温 37.3°C且识别为已知人员且佩戴口罩则控制绿色LED亮起蜂鸣器短响一声OLED显示欢迎信息并通过PWM驱动舵机打开闸门如果连接了。如果体温 37.3°C则无论识别结果如何立即触发红色LED闪烁和蜂鸣器长鸣报警OLED显示“体温异常”并锁定闸机。如果识别为陌生人或未佩戴口罩则触发黄色LED和特定声音提示OLED显示相应提示闸机不动作。输出向显示任务、报警任务发送控制指令。Display_Task(显示任务)优先级低。根据主控逻辑任务发来的指令刷新OLED屏幕上的内容。为了减少I2C通信负担可以采用差量刷新策略只更新变化的部分。Alarm_Task(报警任务)优先级最高可配置。一旦收到报警指令如高温报警立即抢占式执行控制LED和蜂鸣器发出强烈警示确保异常情况能被立刻察觉。4.2 STM32与OpenMV的通信协议设计两者之间的通信可靠性至关重要。我设计了一个非常简单的文本协议易于调试OpenMV - STM32 (上报识别结果)$FACE,ID,MASK,X,Y,W,H*CS\r\n$FACE帧头。ID识别到的人脸ID-1表示陌生人。MASK1表示戴口罩0表示未戴。X,Y,W,H人脸框的左上角坐标和宽高。*CS校验和从$到*之间所有字符的异或和。\r\n帧尾。STM32 - OpenMV (发送控制指令)$CTRL,CMD,PARAM*CS\r\n$CTRL帧头。CMD命令字如RESET要求OpenMV复位识别状态、GET请求一张图片等。PARAM命令参数。校验和与帧尾同上。在STM32端使用DMA空闲中断的方式接收串口数据是高效且可靠的选择可以避免因任务调度延迟导致的数据丢失。4.3 抗干扰与稳定性处理在实际部署中环境干扰无处不在。红外测温干扰环境热源避免传感器对准空调出风口、窗户阳光直射或发热设备。测量间隙在两个人连续测量之间留出几秒钟时间让传感器和环境温度稳定。可以在软件上设置一个“就绪”状态只有传感器读数稳定后才允许进行下一次有效测量。异常值剔除在软件滤波算法中加入“限幅滤波”如果某次读数与前次差值超过合理范围如2°C则视为干扰丢弃。视觉识别干扰光照变化这是最大的挑战。除了选择LBP这类对光照相对不敏感的特征外可以在OpenMV代码中启用sensor.set_auto_gain()和sensor.set_auto_whitebal()但注意这可能会影响颜色相关的识别如果后续需要。更好的办法是增加补光灯。我使用了一组柔和的白色LED由STM32的GPIO控制在识别时自动点亮极大提升了不同时段识别的稳定性。误检处理对于人脸检测可以通过设置scale_factor和min_neighbors参数来平衡检测率和误检率。对于识别结果引入“连续帧确认”机制。例如要求同一个人脸ID在连续3帧中都被识别到才认为是有效识别否则重置状态。这能有效过滤掉瞬间的误识别。5. 系统集成、调试与实测心得将PCB、传感器、屏幕、摄像头组装进外壳后真正的挑战才刚刚开始。5.1 电源与布线的坑电源噪声MLX90614对电源噪声非常敏感。最初我将它的VCC直接接在开发板的3.3V上发现温度读数会随着STM32或OpenMV的运行尤其是摄像头启动瞬间出现周期性跳变。解决方案为MLX90614模块单独增加一个LC电感电容滤波电路或者使用一颗独立的LDO低压差线性稳压器为其供电。立竿见影读数变得非常平稳。I2C上拉电阻STM32、MLX90614、OLED都挂在同一条I2C总线上。务必确保总线上的上拉电阻通常4.7kΩ已正确连接。有些模块内置了上拉电阻如果多个模块同时使能内置上拉可能导致总线电平拉不高通信失败。最稳妥的办法是只保留一对在主控端的上拉电阻并禁用所有从设备模块上的上拉如果可能。串口电平OpenMV的串口是3.3V电平与STM32直接连接即可。注意交叉连接TX和RX。5.2 模型在OpenMV上的部署与性能调优模型量化如果使用了神经网络模型无论是人脸识别特征提取还是口罩检测务必进行int8量化。这能将模型大小减少约75%并显著提升在OpenMV支持硬件加速上的推理速度。使用TensorFlow Lite转换工具时要指定优化选项。图像尺寸与帧率权衡sensor.set_framesize()的设置对性能影响巨大。QVGA (320x240)是一个很好的起点在保证人脸检测精度的同时提供了可接受的帧率。如果识别距离固定且较近可以尝试更小的分辨率如QQVGA (160x120)帧率会大幅提升。OpenMV脚本优化避免在循环中频繁创建和销毁对象如image.Image()。将find_features或nn.classify()等耗时操作的结果缓存起来如果连续几帧人脸位置变化不大可以复用上一帧的识别结果减少计算量。使用clock.tick()和clock.fps()来监控实际帧率找到性能瓶颈。5.3 现场调试与规则微调设备安装到现场后需要根据实际环境进行微调安装高度与角度摄像头的最佳安装高度约等于普通人脸的高度1.5-1.7米略微俯角。用OpenMV的IDE连接设备实时查看画面确保大多数人走到镜头前时人脸能完整出现在画面中央区域。补光灯角度补光灯不要直射人眼应打向人脸的大致区域形成均匀的漫反射光。可以加一层柔光纸。体温阈值校准在设备安装位置用经过校准的医用额温计测量多位健康人员的额温取平均值作为基准。将设备的报警阈值设置得比这个基准值稍高例如基准是36.5°C阈值可设为37.0°C这样可以减少因个体基础体温差异和环境误差导致的误报警。识别距离标定在软件中可以根据人脸框的像素大小W, H来粗略估计人与摄像头的距离。可以设置一个有效识别距离范围例如人脸框宽度在50到150像素之间超出此范围则不进行识别或测温避免误触发。经过一周的现场试运行和参数微调这套自制的无接触式体温监测与身份识别系统基本能够稳定工作。在每天上下班高峰期能够快速完成人员的通行验证体温异常报警也成功触发过几次后续复查均属实。整个项目的硬件成本远低于商用设备而最大的收获在于对嵌入式AI系统从传感器选型、算法移植到系统集成、抗干扰设计的全流程有了更深刻的理解。这种将想法一步步变为现实并解决其中层出不穷问题的过程正是嵌入式开发的魅力所在。本文还有配套的精品资源点击获取