资讯详情

基于STM32单片机设计的红外测温仪(带人脸检测)

由于医学发展的需要,在许多情况下,一般的温度计不能满足快速准确的温度测量要求,如车站、地铁、机场等人口密度较高的地方。

目前设计的红外非接触式测温仪由测温硬件制成 由上位机软件组成,主要用于地铁、车站入口等场所,可准确识别人脸进行温度测量。如果有人温度超标,会发出语音提示,保存当前的人脸照片。

1、 硬件选择和设计理念

(1). 设备端

采用主控单片机STM32F103C8T6.非接触式红外测温模块用于人体测温。

img

(2). 上位机设计理念

上位机采用Qt5设计,Qt5是一套基于C 语言跨平台软件库性能非常强大。目前,许多主流的桌面软件都被使用QT开发。比如: 金山办公旗下-WPS,字节跳动-剪映,暴雪娱乐公司-多个游戏登录器等。Qt在车联网领域也有很多用途,比如哈佛、特斯拉、比亚迪等等。Qt设计。

在测温项目中,上位机和STM32采用串口协议通信,上位机可打开笔记本电脑默认摄像头进行人脸检测;检测人脸时控制STM32测量当前人体的实时温度,然后将温度传输到上位机显示;当温度正常时,上位机显示绿色提示字正常温度,并有语音广播,用笔记本电脑自带的声卡发出语音的声音。如果温度过高,上位机显示红色提示字样温度异常,请重新测量,并有语音广播提示。如果温度过高,上位机显示红色提示字样温度异常,请重新测量,并有语音广播提示。当温度过高时,当前的面部照片将自动保留,照片将存储在当前软件目录下的face文件的命名规则是38.8_2022-01-05-22-12-34.jpg”,其中38.8表示温度值,后面是日期(年月日时分秒)。

(3) 上机运行效果

需要连接上位机STM32设备获取温度数据后,单击软件上的打开摄像头按钮,打开摄像头,以便在检测到人脸时显示当前测量的温度。如果没有连接STM默认情况下,32设备将显示正常的固定温度值。界面右侧的红字表示处理一帧图像需要时间。计算机性能越好,检测速度越快。

(4) 拿到可执行文件后如何运行?

先解压压缩包,进入测温仪上位机-可执行文件目录haarcascade_frontalface_alt2.xml将其复制到C盘根目录。

然后双击“FaceTemperatureCheck.exe”运行程序。

没有连接设备,也可以打开摄像头检测人脸,但温度值是一个固定的正常温度值范围。

二、上位机设计

2.1 安装编译环境

如需编译运行源代码,需先安装Qt5开发环境。

下载地址: https://download.qt.io/official_releases/qt/5.12/5.12.0/

下载后,先断开电脑网络(否则会提示输入QT帐号),然后双击安装包进行安装。

只需选择一个MinGW 32位编译器就够了,详见下面截图,选择MinGW 7.3.0 32-bit之后,点击下一步,等待安装完成。

2.2 软件代码的整体效果

如需完整工程,可在此下载: https://download.csdn.net/download/xiaolong1126626497/85892490

工程打开后(工程文件的后缀是xxx.pro),点击左下角的绿色三角形按钮编译操作程序。

2.3 UI设计界面

2.4 核心代码的人脸检测

///人脸检测代码 bool ImageHandle::opencv_face(QImage qImage) { 
             bool check_flag=0;      QTime time;     time.start();     static CvMemStorage* storage = nullptr;     static CvHaarClassifierCascade* cascade = nullptr;      //模型文件路径     QString face_model_file = QCoreApplication::applicationDirPath() "/" FACE_MODEL_FILE;      //加载分类器:正面检测     cascade = (CvHaarClassifierCascade*)cvLoad(face_model_file.toUtf8().data(), 0, 0, 0 );
    if(!cascade)
    { 
        
        qDebug()<<"分类器加载错误.\n";
        return check_flag;
    }

    //创建内存空间
    storage = cvCreateMemStorage(0);

    //加载需要检测的图片
    IplImage* img = QImageToIplImage(&qImage);

    if(img ==nullptr )
    { 
        
        qDebug()<<"图片加载错误.\n";
        return check_flag;
    }

    double scale=1.2;

    //创建图像首地址,并分配存储空间
    IplImage* gray = cvCreateImage(cvSize(img->width,img->height),8,1);

    //创建图像首地址,并分配存储空间
    IplImage* small_img=cvCreateImage(cvSize(cvRound(img->width/scale),cvRound(img->height/scale)),8,1);
    cvCvtColor(img,gray, CV_BGR2GRAY);
    cvResize(gray, small_img, CV_INTER_LINEAR);
    cvEqualizeHist(small_img,small_img); //直方图均衡
    /* * 指定相应的人脸特征检测分类器,就可以检测出图片中所有的人脸,并将检测到的人脸通过矩形的方式返回。 * 总共有8个参数,函数说明: 参数1:表示输入图像,尽量使用灰度图以加快检测速度。 参数2:表示Haar特征分类器,可以用cvLoad()函数来从磁盘中加载xml文件作为Haar特征分类器。 参数3:用来存储检测到的候选目标的内存缓存区域。 参数4:表示在前后两次相继的扫描中,搜索窗口的比例系数。默认为1.1即每次搜索窗口依次扩大10% 参数5:表示构成检测目标的相邻矩形的最小个数(默认为3个)。如果组成检测目标的小矩形的个数和小于 min_neighbors - 1 都会被排除。如果min_neighbors 为 0, 则函数不做任何操作就返回所有的被检候选矩形框,这种设定值一般用在用户自定义对检测结果的组合程序上。 参数6:要么使用默认值,要么使用CV_HAAR_DO_CANNY_PRUNING,如果设置为CV_HAAR_DO_CANNY_PRUNING,那么函数将会使用Canny边缘检测来排除边缘过多或过少的区域,因此这些区域通常不会是人脸所在区域。 参数7:表示检测窗口的最小值,一般设置为默认即可。 参数8:表示检测窗口的最大值,一般设置为默认即可。 函数返回值:函数将返回CvSeq对象,该对象包含一系列CvRect表示检测到的人脸矩形。 */
    CvSeq* objects = cvHaarDetectObjects(small_img,
                                           cascade,
                                           storage,
                                           1.1,
                                           3,
                                           0/*CV_HAAR_DO_CANNY_PRUNING*/,
                                           cvSize(50,50)/*大小决定了检测时消耗的时间多少*/);

    qDebug()<<"人脸数量:"<<objects->total;

    //遍历找到对象和周围画盒
    QPainter painter(&qImage);//构建 QPainter 绘图对象
    QPen pen;
    pen.setColor(Qt::blue); //画笔颜色
    pen.setWidth(5); //画笔宽度
    painter.setPen(pen); //设置画笔

    CvRect *max=nullptr;

    for(int i=0;i<(objects->total);++i)
    { 
        
        //得到人脸的坐标位置和宽度高度信息
        CvRect* r=(CvRect*)cvGetSeqElem(objects,i);

        if(max==nullptr)max=r;
        else
        { 
        
            if(r->width > max->width || r->height > max->height)
            { 
        
                max=r;
            }
        }
    }

    //如果找到最大的目标脸
    if(max!=nullptr)
    { 
        
        check_flag=true;
        //将人脸区域绘制矩形圈起来
        painter.drawRect(max->x*scale,max->y*scale,max->width*scale,max->height*scale);
    }

    cvReleaseImage(&gray);  //释放图片内存
    cvReleaseImage(&small_img);  //释放图片内存
    cvReleaseHaarClassifierCascade(&cascade); //释放内存-->分类器
    cvReleaseMemStorage(&objects->storage); //释放内存-->检测出图片中所有的人脸

    //释放图片
    cvReleaseImage(&img);

    qint32 time_ms=0;
    time_ms=time.elapsed();

    //耗时时间
    emit ss_log_text(QString("%1").arg(time_ms));

    //保存结果
    m_image=qImage.copy();

    return check_flag;
}

2.5 配置文件(修改参数-很重要)

参数说明:

如果电脑上有多个摄像头,可以修改配置文件里的摄像头编号,具体的数量在程序启动时会自动查询,通过打印代码输出到终端。

如果自己第一次编译运行源码,运行之后,

(1)需要将软件源码目录下的“haarcascade_frontalface_alt2.xml” 文件拷贝到C盘根目录,或者其他非中文目录下,具体路径可以在配置文件里修改,默认就是C盘根目录。

(2)需要将软件源码目录下的“OpenCV-MinGW-Build-OpenCV-3.4.7\x86\mingw\bin”目录里所有文件拷贝到,生成的程序执行文件同级目录下。

这样才能保证程序可以正常运行。

报警温度的阀值范围,也可以自行更改,在配置文件里有说明。

2.6 语音提示文件与背景图

语音提示文件,背景图是通过资源文件加载的。

源文件存放在,源代码的“FaceTemperatureCheck\res”目录下。

自己也可以自行替换,重新编译程序即可生效。

2.7 语音播报与图像显示处理代码

//图像处理的结果
void Widget::slot_HandleImage(bool flag,QImage image)
{ 
        
    bool temp_state=0;

    //检测到人脸
    if(flag)
    { 
        
        //判断温度是否正常
        if(current_temp<MAX_TEMP && current_temp>MIN_TEMP)
        { 
        
            temp_state=true;
            //显示温度正常
            ui->label_temp->setStyleSheet("color: rgb(0, 255, 127);font: 20pt \"Arial\";");
            ui->label_temp->setText(QString("%1℃").arg(current_temp));
        }
        else //语音播报,温度异常
        { 
        
            temp_state=false;
            //显示温度异常
            ui->label_temp->setStyleSheet("color: rgb(255, 0, 0);font: 20pt \"Arial\";");
            ui->label_temp->setText(QString("%1℃").arg(current_temp));
        }

        //获取当前ms时间
        long long currentTime = QDateTime::currentDateTime().toMSecsSinceEpoch();

        //判断时间间隔是否到达
        if(currentTime-old_currentTime>AUDIO_RATE_MS)
        { 
        
            //更改当前时间
            old_currentTime=currentTime;
            //温度正常
            if(temp_state)
            { 
        
                //语音播报,温度正常
                QSound::play(":/res/ok.wav");
            }
            //温度异常
            else
            { 
        
                //语音播报,温度异常
                QSound::play(":/res/error.wav");

                //拍照留存
                QString dir_str = QCoreApplication::applicationDirPath()+"/face";

                //检查目录是否存在,若不存在则新建
                QDir dir;
                if (!dir.exists(dir_str))
                { 
        
                    bool res = dir.mkpath(dir_str);
                    qDebug() << "新建目录状态:" << res;
                }

                //目录存在就保存图片
                QDir dir2;
                if (dir2.exists(dir_str))
                { 
        
                    //拼接名称
                    QDateTime dateTime(QDateTime::currentDateTime());
                    //时间效果: 2020-03-05 16:25::04 周一
                    QString qStr=QString("%1/%2_").arg(dir_str).arg(current_temp);
                    qStr+=dateTime.toString("yyyy-MM-dd-hh-mm-ss-ddd");
                    image.save(qStr+".jpg");
                }
            }
        }
    }
    else  //不显示温度
    { 
        
        ui->label_temp->setStyleSheet("color: rgb(0, 255, 127);font: 20pt \"Arial\";");
        ui->label_temp->setText("----");
    }

    //处理图像的结果画面
    ui->widget_player->slotGetOneFrame(image);
}

2.8 STM32的温度接收处理代码

//刷新串口端口
void Widget::on_pushButton_flush_uart_clicked()
{ 
        
    QList<QSerialPortInfo> UartInfoList=QSerialPortInfo::availablePorts(); //获取可用串口端口信息
    ui->comboBox_ComSelect->clear();
    if(UartInfoList.count()>0)
    { 
        
        for(int i=0;i<UartInfoList.count();i++)
        { 
        
             if(UartInfoList.at(i).isBusy()) //如果当前串口 COM 口忙就返回真,否则返回假
             { 
        
                   QString info=UartInfoList.at(i).portName();
                   info+="(占用)";
                   ui->comboBox_ComSelect->addItem(info); //添加新的条目选项
             }
             else
             { 
        
                  ui->comboBox_ComSelect->addItem(UartInfoList.at(i).portName()); //添加新的条目选项
             }
        }
    }
    else
    { 
        
        ui->comboBox_ComSelect->addItem("无可用COM口"); //添加新的条目选项
    }
}

//连接测温设备
void Widget::on_pushButton_OpenUart_clicked()
{ 
        
    if(ui->pushButton_OpenUart->text()=="连接测温设备")  //打开串口
    { 
        
        ui->pushButton_OpenUart->setText("断开连接");

        /*配置串口的信息*/
        UART_Config->setPortName(ui->comboBox_ComSelect->currentText());  //COM的名称
        if(!(UART_Config->open(QIODevice::ReadWrite)))      //打开的属性权限
        { 
        
            QMessageBox::warning(this, tr("状态提示"),
                                           tr("设备连接失败!\n请选择正确的COM口"),
                                           QMessageBox::Ok);
                ui->pushButton_OpenUart->setText("连接测温设备");
                return;
        }
    }
    else //关闭串口
    { 
        
        ui->pushButton_OpenUart->setText("连接测温设备");
        /*关闭串口-*/
        UART_Config->clear(QSerialPort::AllDirections);
        UART_Config->close();
    }
}

//读信号
void Widget::ReadUasrtData()
{ 
        
    /*返回可读的字节数*/
    if(UART_Config->bytesAvailable()<=0)
    { 
        
        return;
    }

    /*定义字节数组*/
    QByteArray rx_data;

    /*读取串口缓冲区所有的数据*/
    rx_data=UART_Config->readAll();

    //转换温度
    current_temp=rx_data.toDouble();
}

标签: 绿色矩形连接器200mm矩形连接器

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台