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 订阅消息

    他只是向前航行,脚下是沉静碧蓝的大海,而头顶是金色的太阳。
  • 相关阅读:
    LSMW TIPS
    Schedule agreement and Delfor
    Running VL10 in the background 13 Oct
    analyse idoc by creation date
    New Journey Prepare
    EDI error
    CBSN NEWS
    Listen and Write 18th Feb 2019
    Microsoft iSCSI Software Target 快照管理
    通过 Microsoft iSCSI Software Target 提供存储服务
  • 原文地址:https://www.cnblogs.com/bliss-/p/14917373.html
Copyright © 2011-2022 走看看