zoukankan      html  css  js  c++  java
  • 基于树莓派4B实现的口罩识别检测设计

    硬件环境:

      树莓派4B开发板

      树莓派摄像头,淘宝有卖,30rmb以内的盗版亲测可用。。

      有线音箱,用于播报检测到异常时的语音播报使用

    软件环境:

      Debian-Pi-Aarch64:树莓派安装的操作系统,git链接:https://gitee.com/openfans-community/Debian-Pi-Aarch64/

      vnc:实现远程连接树莓派

      emq:一个mqtt服务器,用于将口罩识别结果上传到服务器,远程查看,链接:https://www.emqx.cn/products/broker

      qt:远程查看结果的界面程序设计语言

      python:口罩识别结果本地检测,语音播放控制,树莓派mqtt数据上传

      opencv:摄像头人脸数据采集,人脸数据显示等

      paddle-lite:百度的深度学习平台,用于口罩检测算法,链接:https://aistudio.baidu.com/aistudio/index

    实现功能:

      1.树莓派口罩检测结果实时显示

      2.通过检测结果实现语音播报自动控制

      3.数据上传服务器远程监测结果

    前期准备:

      树莓派操作系统安装烧写,vnc远程连接等

      opencv等环境配置

      口罩识别方案测试:本设计核心功能完全参考https://aistudio.baidu.com/aistudio/projectdetail/2077064

    最终效果展示

    口罩识别部分代码:

      1 void RunTime(std::string det_model_dir,
      2               std::string class_model_dir,
      3               cv::VideoCapture cap) {
      4     cv::Mat img;
      5     cap >> img;
      6     // Prepare
      7     float shrink = 0.2;
      8     int width = img.cols;
      9     int height = img.rows;
     10     int s_width = static_cast<int>(width * shrink);
     11     int s_height = static_cast<int>(height * shrink);
     12 
     13     // Detection
     14     MobileConfig config;
     15     config.set_model_dir(det_model_dir);
     16 
     17     // Create Predictor For Detction Model
     18     std::shared_ptr<PaddlePredictor> predictor =
     19         CreatePaddlePredictor<MobileConfig>(config);
     20 
     21     // Get Input Tensor
     22     std::unique_ptr<Tensor> input_tensor0(std::move(predictor->GetInput(0)));
     23     input_tensor0->Resize({1, 3, s_height, s_width});
     24     auto* data = input_tensor0->mutable_data<float>();
     25 
     26     // Do PreProcess
     27     std::vector<float> detect_mean = {104.f, 117.f, 123.f};
     28     std::vector<float> detect_scale = {0.007843, 0.007843, 0.007843};
     29     pre_process(img, s_width, s_height, detect_mean, detect_scale, data, false);
     30 
     31     // Detection Model Run
     32     predictor->Run();
     33 
     34     // Get Output Tensor
     35     std::unique_ptr<const Tensor> output_tensor0(
     36         std::move(predictor->GetOutput(0)));
     37     auto* outptr = output_tensor0->data<float>();
     38     auto shape_out = output_tensor0->shape();
     39     int64_t out_len = ShapeProduction(shape_out);
     40 
     41     // Filter Out Detection Box
     42     float detect_threshold = 0.3;
     43     std::vector<Object> detect_result;
     44     for (int i = 0; i < out_len / 6; ++i) {
     45       if (outptr[1] >= detect_threshold) {
     46         Object obj;
     47         int xmin = static_cast<int>(width * outptr[2]);
     48         int ymin = static_cast<int>(height * outptr[3]);
     49         int xmax = static_cast<int>(width * outptr[4]);
     50         int ymax = static_cast<int>(height * outptr[5]);
     51         int w = xmax - xmin;
     52         int h = ymax - ymin;
     53         cv::Rect rec_clip =
     54             cv::Rect(xmin, ymin, w, h) & cv::Rect(0, 0, width, height);
     55         obj.rec = rec_clip;
     56         detect_result.push_back(obj);
     57       }
     58       outptr += 6;
     59     }
     60 
     61     // Classification
     62     config.set_model_dir(class_model_dir);
     63 
     64     // Create Predictor For Classification Model
     65     predictor = CreatePaddlePredictor<MobileConfig>(config);
     66 
     67     // Get Input Tensor
     68     std::unique_ptr<Tensor> input_tensor1(std::move(predictor->GetInput(0)));
     69     int classify_w = 128;
     70     int classify_h = 128;
     71     input_tensor1->Resize({1, 3, classify_h, classify_w});
     72     auto* input_data = input_tensor1->mutable_data<float>();
     73     int detect_num = detect_result.size();
     74     std::vector<float> classify_mean = {0.5f, 0.5f, 0.5f};
     75     std::vector<float> classify_scale = {1.f, 1.f, 1.f};
     76     float classify_threshold = 0.5;
     77     for (int i = 0; i < detect_num; ++i) {
     78       cv::Rect rec_clip = detect_result[i].rec;
     79       cv::Mat roi = img(rec_clip);
     80 
     81       // Do PreProcess
     82       pre_process(roi,
     83                   classify_w,
     84                   classify_h,
     85                   classify_mean,
     86                   classify_scale,
     87                   input_data,
     88                   true);
     89 
     90       // Classification Model Run
     91       predictor->Run();
     92 
     93       // Get Output Tensor
     94       std::unique_ptr<const Tensor> output_tensor1(
     95           std::move(predictor->GetOutput(1)));
     96       auto* outptr = output_tensor1->data<float>();
     97 
     98       // Draw Detection and Classification Results
     99       cv::rectangle(img, rec_clip, cv::Scalar(0, 0, 255), 2, cv::LINE_AA);
    100       std::string text = outptr[1] > classify_threshold ? "wear mask" : "no mask";
    101       std::cout << outptr[1] << std::endl;
    102 
    103 
    104     if(outptr[1] < 0.5)
    105     {
    106             ofstream outfile;
    107             outfile.open("../result.txt");
    108         outfile << "000000000" << endl;
    109         outfile.close();
    110     }
    111     else
    112     {            
    113         ofstream outfile;
    114             outfile.open("../result.txt");
    115         outfile << "111111111" << endl;
    116         outfile.close();
    117     }
    118 
    119 
    120       int font_face = cv::FONT_HERSHEY_COMPLEX_SMALL;
    121       double font_scale = 1.f;
    122       int thickness = 1;
    123       cv::Size text_size =
    124           cv::getTextSize(text, font_face, font_scale, thickness, nullptr);
    125       float new_font_scale = rec_clip.width * 0.7 * font_scale / text_size.width;
    126       text_size =
    127           cv::getTextSize(text, font_face, new_font_scale, thickness, nullptr);
    128       cv::Point origin;
    129       origin.x = rec_clip.x + 5;
    130       origin.y = rec_clip.y + text_size.height + 5;
    131       cv::putText(img,
    132                   text,
    133                   origin,
    134                   font_face,
    135                   new_font_scale,
    136                   cv::Scalar(0, 255, 255),
    137                   thickness,
    138                   cv::LINE_AA);
    139     }
    140     cv::imshow("Mask Detection Demo", img);
    141 
    142 
    143 
    144 }

    基本流程:获取人脸数据->获取检测结果->将检测结果存储在文件中->结果视频展示

    python或者检测结果、播放音频、数据上传到mqtt服务器代码

    #!usr/bin/python
    # coding=utf-8
    import pyttsx3
    import time
    #import pygame
    import paho.mqtt.client as mqtt
    import os
    audio_file = '../audio/tips.mp3'
    
    def on_connect(client, userdata, flags, rc):
        print("Connected with result code: " + str(rc))
    
    def on_message(client, userdata, msg):
        print(msg.topic + " " + str(msg.payload))
    
    client = mqtt.Client()
    client.on_connect = on_connect
    client.on_message = on_message
    client.connect('192.168.31.149', 1883, 600) # 600u4e3akeepaliveu7684u65f6u95f4u95f4u9694
    
    #pygame.mixer.init()
    #pygame.mixer.music.load('abc.wav')  
    #pygame.mixer.music.set_volume(5)
    
    while(1):
        time.sleep(2)
        try:
            f = open('../mask/mask_detection_demo/code/result.txt', 'rb')
            a = f.read()
            if len(a)>6:
                print(a[5])
                if a[5] == 48:
                    flag = 0
                    print("no mask")
                    client.publish('topic', payload='000000', qos=0)
    #               pygame.mixer.music.play()
                    os.system('mpv '+audio_file)
                elif a[5] == 49:
                    flag = 1
                    print("wear mask")
                    client.publish('topic', payload='11111', qos=0)
                else:
                    flag =2
                    print("error code")
            else:
                print("len code == 0")
        finally:
            if f:
                f.close()
            
        # if flag == 0:
            # playsound('./audio.mp3')
            # voice.say(text)
            # voice.runAndWait()
            # print("1")

    qt界面代码:检测结果监控,需要安装在qt下安装配置mqtt库:参考https://www.cnblogs.com/bliss-/p/12378226.html

    #include "QMqttClientTool.h"
    #include "QDebug"
    #include <QtWidgets/QMessageBox>
    #include <QByteArray>
    #include <unistd.h>
    QMqttClientTool::QMqttClientTool(QWidget *parent)
        : QWidget(parent)
    {
    
        //    this->setMaximumSize(600,400);
        //    this->setMinimumSize(600,400);
        this->resize(600,600);
        this->setWindowTitle("口罩检测系统");
        m_client             =  new QMqttClient(this);
        m_client ->setClientId("mqtt_ClientId");
        btnConnect           =  new QPushButton(this);
        btnPublish           =  new QPushButton(this);
        btnSubscribe           =  new QPushButton(this);
        clean                  = new QPushButton(this);
        qlbHostNameTag       =  new QLabel(this);
        qlbHostPortTag       =  new QLabel(this);
        qlbPubLishTopicTag   =  new QLabel(this);
        qlbSubscribeTopicTag   =  new QLabel(this);
        qlbPublishMessageTag =  new QLabel(this);
        qleHostName          =  new QLineEdit(this);
        //    qleHostName->setText("localhost");
        qleHostPort          =  new QLineEdit(this);
        //    qleHostPort->setText("1883");
        qlePublishTopic      =  new QLineEdit(this);
        //    qlePublishTopic->setText("/World");
        qleSubscribeTopic      =  new QLineEdit(this);
        //    qleSubscribeTopic->setText("/World");
        qlePublishMessage    =  new QLineEdit(this);
        //    qlePublishMessage->setText("hello");
    
        brower = new QTextBrowser(this);
    
    //    label_ver = new QLabel("<u>wangnimei_1216@163.com<u>",this);
        label_ver = new QLabel("<u>基于树莓派4B的口罩检测系统--黑龙江大学乘风破疫队<u>",this);
        QFont ft;
        ft.setPointSize(15);
        ft.setBold(1);
    
        qlbHostNameTag->move(6,6);
        qlbHostNameTag->setText("Host");
        qlbHostNameTag->setFont(ft);
        qlbHostNameTag->setMaximumSize(65,35);
        qlbHostNameTag->setMinimumSize(65,35);
    
        qleHostName->move(60,6);
        qleHostName->setFont(ft);
        //qleHostName->setText("a1aDaWbRIge.iot-as-mqtt.cn-shanghai.aliyuncs.com");
        qleHostName->setText("127.0.0.1");
        qleHostName->setMaximumSize(200,35);
        qleHostName->setMinimumSize(200,35);
    
        qlbHostPortTag->move(270,6);
        qlbHostPortTag->setText("Port");
        qlbHostPortTag->setFont(ft);
    
        qlbHostPortTag->setMaximumSize(65,35);
        qlbHostPortTag->setMinimumSize(65,35);
    
        qleHostPort->move(324,6);
        qleHostPort->setFont(ft);
        qleHostPort->setText("1883");
        qleHostPort->setMaximumSize(60,35);
        qleHostPort->setMinimumSize(60,35);
    
        btnConnect->move(390,6);
        btnConnect->setText("Connect");
        btnConnect->setFont(ft);
        btnConnect->setMaximumSize(120,35);
        btnConnect->setMinimumSize(120,35);
    
        qlbPubLishTopicTag->move(6,50);
        qlbPubLishTopicTag->setText("PublishTopic");
        qlbPubLishTopicTag->setFont(ft);
    
        qlbPubLishTopicTag->setMaximumSize(130,35);
        qlbPubLishTopicTag->setMinimumSize(130,35);
    
         qlbPubLishTopicTag->setHidden(1);
    
        qlePublishTopic->move(145,50);
        qlePublishTopic->setFont(ft);
        qlePublishTopic->setText("/a1aDaWbRIge/bliss/user/update");
        qlePublishTopic->setMaximumSize(240,35);
        qlePublishTopic->setMinimumSize(240,35);
    
            qlePublishTopic->setHidden(1);
    
        btnPublish->move(390,50);
        btnPublish->setText("Publish");
        btnPublish->setFont(ft);
        btnPublish->setMaximumSize(120,35);
        btnPublish->setMinimumSize(120,35);
    btnPublish->setHidden(1);
    
        qlbPublishMessageTag->move(6,94);
        qlbPublishMessageTag->setText("PublishMessage");
        qlbPublishMessageTag->setFont(ft);
        qlbPublishMessageTag->setMaximumSize(160,35);
        qlbPublishMessageTag->setMinimumSize(160,35);
    qlbPublishMessageTag->setHidden(1);
    
        qlePublishMessage->move(170,94);
        qlePublishMessage->setFont(ft);
        qlePublishMessage->setText("{"led","on"}");
        qlePublishMessage->setMaximumSize(400,35);
        qlePublishMessage->setMinimumSize(400,35);
    qlePublishMessage->setHidden(1);
    
        btnSubscribe->move(390,94+50);
        btnSubscribe->setText("Subscribe");
        btnSubscribe->setFont(ft);
        btnSubscribe->setMaximumSize(120,35);
        btnSubscribe->setMinimumSize(120,35);
    
        qlbSubscribeTopicTag->move(6,94+50);
        qlbSubscribeTopicTag->setText("PublishTopic");
        qlbSubscribeTopicTag->setFont(ft);
        qlbSubscribeTopicTag->setMaximumSize(130,35);
        qlbSubscribeTopicTag->setMinimumSize(130,35);
    
        qleSubscribeTopic->move(145,94+50);
        qleSubscribeTopic->setFont(ft);
        qleSubscribeTopic->setText("topic/#");
        qleSubscribeTopic->setMaximumSize(240,35);
        qleSubscribeTopic->setMinimumSize(240,35);
    
        QFont font;
        font.setPointSize(10);
        //    font.setBold(1);
        brower->move(6,94+50+50);
        brower->resize(500,360);
        brower->setFont(font);
    
        clean->move(500+10,94+100);
        clean->setText("Clean");
        clean->setFont(ft);
        clean->setMaximumSize(80,35);
        clean->setMinimumSize(80,35);
    
        label_ver->move(6,560);
        /*username*/
        username_label=new QLabel(this);
        username_edit=new QLineEdit(this);
    
        username_label->move(6,390);
        username_label->setText("username:");
        username_label->setFont(ft);
        username_label->setMaximumSize(100,35);
        username_label->setMinimumSize(100,35);
    username_label->setHidden(1);
        username_edit->move(110,390);
        username_edit->setFont(ft);
        username_edit->setText("bliss&a1aDaWbRIge");
        username_edit->setMaximumSize(300,35);
        username_edit->setMinimumSize(300,35);
        username_edit->setHidden(1);
        /*password*/
        password_label=new QLabel(this);
        password_edit=new QLineEdit(this);
    
        password_label->move(6,440);
        password_label->setText("password:");
        password_label->setFont(ft);
        password_label->setMaximumSize(100,35);
        password_label->setMinimumSize(100,35);
        password_label->setHidden(1);
    
        password_edit->move(110,440);
        password_edit->setFont(ft);
        password_edit->setText("252E42329C0440AFA9C372ED9F8505C7C80F9A03EF20FC6E0FDAAC7299A38774");
        password_edit->setMaximumSize(300,35);
        password_edit->setMinimumSize(300,35);
         password_edit->setHidden(1);
    
        /*clientid*/
        clientid_label=new QLabel(this);
        clientid_edit=new QLineEdit(this);
    
        clientid_label->move(6,490);
        clientid_label->setText("clientId:");
        clientid_label->setFont(ft);
        clientid_label->setMaximumSize(100,35);
        clientid_label->setMinimumSize(100,35);
        clientid_label->setHidden(1);
    
        clientid_edit->move(110,490);
        clientid_edit->setFont(ft);
        clientid_edit->setText("bliss&a1aDaWbRIge|timestamp=123456,securemode=3,signmethod=hmacsha256,lan=C|");
        clientid_edit->setMaximumSize(600,35);
        clientid_edit->setMinimumSize(600,35);
        clientid_edit->setHidden(1);
    
    
        connect(btnConnect,SIGNAL(clicked()),this,SLOT(on_btnConnect_clicked()));
        connect(btnPublish,SIGNAL(clicked()),this,SLOT(on_btnPublish_clicked()));
        connect(btnSubscribe,SIGNAL(clicked()),this,SLOT(on_btnSubcribe_clicked()));
        connect(clean,SIGNAL(clicked()),this,SLOT(on_btnClean_clicked()));
        connect(m_client,SIGNAL(messageReceived(const QByteArray , const QMqttTopicName)), this,SLOT(on_recived_msg( const QByteArray , const QMqttTopicName)));
    }
    
    QMqttClientTool::~QMqttClientTool()
    {
        this->m_client=NULL;
    }
    
    void QMqttClientTool::on_btnConnect_clicked()
    {
        //未连接服务器则连接
        if (m_client->state() == QMqttClient::Disconnected) {
            if((qleHostName->text()==NULL) || (qleHostPort->text()==NULL))
                return;
    
            m_client->setHostname(qleHostName->text());
            m_client->setPort(qleHostPort->text().toInt());
            m_client->setUsername(username_edit->text());
            m_client->setPassword(password_edit->text());
            m_client->setClientId(clientid_edit->text());
            m_client->connectToHost();
            usleep(1000*10);
            if(m_client->state() != QMqttClient::Disconnected){
                btnConnect->setText(tr("Disconnect"));
                qleHostName->setEnabled(false);
                qleHostPort->setEnabled(false);
            }
        } else {//断开连接
            btnConnect->setText(tr("Connect"));
            qleHostName->setEnabled(true);
            qleHostPort->setEnabled(true);
            m_client->disconnectFromHost();
        }
    }
    
    void QMqttClientTool::on_btnPublish_clicked()
    {
        if(m_client->state()== QMqttClient::Disconnected)
        {
            QMessageBox::critical(this, QLatin1String("Error"), QLatin1String("mqtt is disconnect"));
            return;
        }
        int res=m_client->publish(qlePublishTopic->text(),qlePublishMessage->text().toUtf8(),0,false);
        qDebug()<<qlePublishMessage->text().toUtf8();
        qDebug()<<qlePublishTopic->text();
        qDebug()<<res;
        //QMessageBox::critical(this, QLatin1String("Error"), QLatin1String("publish message Error"));
    
    }
    
    void QMqttClientTool::on_btnSubcribe_clicked()
    {
        if(m_client->state()== QMqttClient::Disconnected){
            QMessageBox::critical(this, QLatin1String("Error"), QLatin1String("mqtt is disconnect"));
            return;
        }
        m_client->subscribe(qleSubscribeTopic->text(),0);
        const QString content ="["+QDateTime::currentDateTime().toString("hh:mm:ss.zzz")+"]"
                +"Subcribe:" + QLatin1String("Topic:")
                +  qleSubscribeTopic->text()+ QLatin1Char('
    ');
        //this->brower->insertPlainText(content);
    
        qDebug()<<qleSubscribeTopic->text();
    
    }
    
    void QMqttClientTool::on_recived_msg( const QByteArray &message, const QMqttTopicName &topic)
    {
        if(message[2]=='0')
        {
            const QString content ="["+QDateTime::currentDateTime().toString("hh:mm:ss.zzz")+"]"
                    +  QLatin1String(":")+ "未佩戴口罩" + QLatin1Char('
    ');
            this->brower->insertPlainText(content);
        }
        else
        {
            const QString content ="["+QDateTime::currentDateTime().toString("hh:mm:ss.zzz")+"]"
                    +  QLatin1String(":")+ "已佩戴口罩" + QLatin1Char('
    ');
            this->brower->insertPlainText(content);
        }
    }
    
    //清理bower数据
    void QMqttClientTool::on_btnClean_clicked()
    {
        this->brower->clear();
    
    }

     以上代码在修改一部分配置信息后基本上都是可以直接运行测试的

    运行流程

    1.运行emq
      1.1 在emq安装路径下bin文件中打开cmd:"dos"
      1.2 运行 emq console
    2.在mask目录下运行 sudo ./run.sh
    3.运行python代码
      3.1 sudo gedit test.py打开py文件
      3.2 修改192.168.31.149 为 服务器地址 保存退出
      3.2 运行 python3.7 test.py
    4.运行桌面程序,依次
      4.1 点击Connect 连接服务器
      4.2 点击Subscribe 订阅消息

    他只是向前航行,脚下是沉静碧蓝的大海,而头顶是金色的太阳。
  • 相关阅读:
    web.xml
    ibatis配置
    ibatis基本语法
    XML文件解析
    进制转换
    BaseAction
    【编译】StreamInsight简介
    秒懂C#通过Emit动态生成代码
    百度地图应用开发(二)
    ListView与Adapter的那些事儿
  • 原文地址:https://www.cnblogs.com/bliss-/p/14917373.html
Copyright © 2011-2022 走看看