STM32与OpenCV实现低成本人脸红外测温仪

张开发
2026/4/10 15:42:28 15 分钟阅读

分享文章

STM32与OpenCV实现低成本人脸红外测温仪
1. 项目概述这个基于STM32和OpenCV的人脸红外测温仪项目是我在疫情期间开发的一个实用型嵌入式系统。它完美结合了嵌入式硬件的数据采集能力和计算机视觉的目标识别技术实现了非接触式的体温监测功能。整套系统由下位机STM32F103C8T6MLX90614和上位机QtOpenCV两部分组成通过串口通信实现数据交互。提示这个项目特别适合电子工程、计算机相关专业的学生作为毕业设计也适用于创客爱好者制作实用的防疫设备。整套硬件成本可以控制在100元以内。我在开发过程中遇到了不少坑比如MLX90614的温度漂移问题、OpenCV人脸检测的误报问题等这些都会在后续章节详细说明解决方案。这个系统实测精度可以达到±0.3℃响应时间小于500ms完全满足日常体温筛查的需求。2. 硬件系统设计2.1 核心硬件选型STM32F103C8T6最小系统作为项目的主控芯片我选择了经典的蓝莓派开发板主要基于以下几点考虑价格低廉约15元丰富的外设接口I2C、USART等充足的性能72MHz主频成熟的开发环境Keil MDK实际使用中我发现这款芯片的ADC精度一般但用于处理MLX90614的数字输出完全够用。需要注意的是市面上有些兼容板可能存在晶振不准的问题建议购买正版ST芯片的开发板。MLX90614红外测温模块这是项目的核心传感器我选择的是BAA版本测量范围-20℃~120℃主要参数精度±0.5℃人体温度范围内视场角35°接口I2C默认地址0x5A响应时间100ms注意市场上有些劣质模块可能存在校准问题建议购买带原厂校准的版本价格约50元。我在测试中发现某些山寨模块在环境温度变化时会出现明显漂移。2.2 硬件电路设计I2C接口电路MLX90614通过I2C与STM32通信具体连接方式MLX90614 STM32 VCC → 3.3V GND → GND SCL → PB6 SDA → PB7我在PCB设计时特别注意了以下几点SCL/SDA线上加了4.7kΩ上拉电阻电源端并联了100nF去耦电容传感器与MCU距离控制在10cm以内串口通信电路使用CH340G芯片实现USB转TTL连接方式STM32 CH340G PA9(TX) → RXD PA10(RX) → TXD调试时发现如果波特率设置过高如500000bps会出现数据丢失。最终选择115200bps作为通信速率实测稳定可靠。3. 下位机软件设计3.1 温度采集实现MLX90614的驱动代码主要包含以下几个部分// 初始化I2C接口 void MLX90614_Init(void) { GPIO_InitTypeDef GPIO_InitStruct; I2C_InitTypeDef I2C_InitStruct; // 使能时钟 RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); RCC_APB1PeriphClockCmd(RCC_APB1Periph_I2C1, ENABLE); // 配置GPIO GPIO_InitStruct.GPIO_Pin GPIO_Pin_6 | GPIO_Pin_7; GPIO_InitStruct.GPIO_Mode GPIO_Mode_AF_OD; GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOB, GPIO_InitStruct); // 配置I2C I2C_InitStruct.I2C_Mode I2C_Mode_I2C; I2C_InitStruct.I2C_DutyCycle I2C_DutyCycle_2; I2C_InitStruct.I2C_OwnAddress1 0x00; I2C_InitStruct.I2C_Ack I2C_Ack_Enable; I2C_InitStruct.I2C_AcknowledgedAddress I2C_AcknowledgedAddress_7bit; I2C_InitStruct.I2C_ClockSpeed 100000; // 100kHz I2C_Init(I2C1, I2C_InitStruct); I2C_Cmd(I2C1, ENABLE); } // 读取温度数据 float MLX90614_ReadTemp(void) { uint16_t rawData; float temp; // 读取RAM地址0x07的数据物体温度 I2C_ReadData(I2C1, MLX90614_ADDR, 0x07, rawData); // 数据转换 temp (float)rawData * 0.02 - 273.15; return temp; }实际使用中我增加了滑动平均滤波算法来平滑数据波动#define FILTER_SIZE 5 float tempFilter[FILTER_SIZE]; uint8_t filterIndex 0; float GetFilteredTemp(void) { float sum 0; float newTemp MLX90614_ReadTemp(); // 更新滤波器数组 tempFilter[filterIndex] newTemp; filterIndex (filterIndex 1) % FILTER_SIZE; // 计算平均值 for(int i0; iFILTER_SIZE; i) { sum tempFilter[i]; } return sum / FILTER_SIZE; }3.2 串口通信协议设计为了确保数据传输的可靠性我设计了一个简单的通信协议字节位置内容说明00xAA帧头1-2TempHigh/Low温度值整数小数3Checksum校验和高低温字节异或40x55帧尾对应的发送函数实现void USART_SendTemp(float temp) { uint8_t buffer[5]; uint16_t tempInt (uint16_t)(temp * 100); // 转换为整数 buffer[0] 0xAA; // 帧头 buffer[1] (tempInt 8) 0xFF; // 高字节 buffer[2] tempInt 0xFF; // 低字节 buffer[3] buffer[1] ^ buffer[2]; // 校验和 buffer[4] 0x55; // 帧尾 for(int i0; i5; i) { USART_SendData(USART1, buffer[i]); while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) RESET); } }4. 上位机软件设计4.1 Qt界面框架上位机使用Qt5开发主要界面元素包括视频显示区域QLabel温度显示区域QTextEdit串口配置面板QComboBoxQPushButton报警状态指示灯QLedIndicator界面布局采用QVBoxLayout和QHBoxLayout组合实现确保在不同分辨率下都能正常显示。4.2 OpenCV人脸检测实现我测试了两种人脸检测算法最终选择了效果更好的DNN模型// 加载预训练模型 cv::dnn::Net net cv::dnn::readNetFromCaffe( deploy.prototxt, res10_300x300_ssd_iter_140000.caffemodel); // 人脸检测函数 std::vectorcv::Rect detectFaces(cv::Mat frame) { cv::Mat blob cv::dnn::blobFromImage(frame, 1.0, cv::Size(300, 300), cv::Scalar(104, 177, 123)); net.setInput(blob); cv::Mat detections net.forward(); std::vectorcv::Rect faces; for(int i0; idetections.size[2]; i) { float confidence detections.atfloat(0, 0, i, 2); if(confidence 0.7) { // 置信度阈值 int x1 static_castint(detections.atfloat(0, 0, i, 3) * frame.cols); int y1 static_castint(detections.atfloat(0, 0, i, 4) * frame.rows); int x2 static_castint(detections.atfloat(0, 0, i, 5) * frame.cols); int y2 static_castint(detections.atfloat(0, 0, i, 6) * frame.rows); faces.emplace_back(x1, y1, x2-x1, y2-y1); } } return faces; }提示模型文件较大约20MB建议在程序启动时异步加载避免界面卡顿。4.3 温度显示与报警逻辑温度显示的核心代码如下void MainWindow::updateTemperature(float temp) { QString tempStr QString::number(temp, f, 1) ℃; // 报警逻辑 if(temp 37.3 || temp 35.0) { ui-tempLabel-setStyleSheet(color: red; font-size: 24px;); // 语音报警防重复 static QTime lastAlertTime; if(lastAlertTime.elapsed() 10000) { // 10秒间隔 QTextToSpeech::say(体温异常请复查); lastAlertTime.start(); } } else { ui-tempLabel-setStyleSheet(color: green; font-size: 24px;); } ui-tempLabel-setText(tempStr); }5. 系统集成与调试5.1 硬件组装要点传感器安装角度MLX90614需要正对人脸建议安装在支架上与地面成15°仰角测量距离最佳测量距离为5-15cm太远会导致精度下降环境温度补偿可以在STM32端增加DS18B20测量环境温度对MLX90614读数进行补偿5.2 常见问题排查问题1温度读数不稳定检查电源是否稳定建议用示波器观察3.3V纹波增加软件滤波算法如前面提到的滑动平均确保传感器与被测物体之间没有气流干扰问题2人脸检测漏检调整摄像头曝光参数尝试不同的检测模型Haar/DNN增加图像预处理直方图均衡化问题3串口通信失败检查波特率设置两端必须一致确认TX/RX线没有接反测试时可以先使用串口调试助手验证硬件连接6. 项目优化与扩展在实际使用中我发现还可以做以下改进增加蓝牙/WiFi模块实现无线数据传输使用TinyML在STM32端实现轻量级人脸检测开发手机APP替代Qt上位机增加数据库存储功能记录历史体温数据结合RFID技术实现人员身份识别这个项目最让我自豪的是它的实用性和低成本。在疫情期间我帮助本地社区中心部署了5台这样的设备大大提高了他们的防疫工作效率。整套系统的硬件成本不到100元但实现了商业设备上千元的功能。

更多文章