8

AI人脸识别测温一体机设计

 2 years ago
source link: https://blog.51cto.com/u_11822586/5091220
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

AI人脸识别测温一体机设计

原创

DS小龙哥 2022-03-10 13:56:06 博主文章分类:STM32项目开发 ©著作权

文章标签 json 人脸识别 数据 文章分类 嵌入式Linux 嵌入式 阅读数354

在AI人工智能发展应用的过程中,人脸识别技术得到了重用。目前在人脸识别相关的技术已经深入到生活方方面面。在公共安全、智能安防、手机认证等多个领域得到应用,比如: 通过人脸识别来解锁手机,通过人脸识别进入某些政务软件平台或是银行APP, 还是各大门店,超市使用的"支付宝刷脸支付"等等,这些应用大大方便了人们生活。

目前,因为新冠疫情防控的需要,人人出门都需要戴口罩,查验健康码和测量体温,在办公大楼门口、地铁口、小区门口、商场门口人流量都比较大,传统的人工测量体温方式,费时费力、效率比较低,而且人工近距离核验温度,易产生交叉感染风险。

当前文章就利用华为云提供的AI人脸识别接口+红外测温传感器MLX90614ESF(DCI)+瑞芯微RK3399完成AI人脸测温一体机设计,方便测量来往人员的体温,减轻防疫防控工作人员的负担。

实现的具体功能: 当检测到人脸时,就测量温度,并检测有没有带口罩;在显示屏上实时显示温度信息,如果温度超出设置值,会通过语音播报提示。如果人员没有戴口罩,会语音提示带口罩。

AI人脸识别测温一体机设计_人脸识别

2. 软硬件设计

(1)核心板采用瑞芯微RK3399,运行ubuntu18.04 64位系统,编译器采用aarch64-linux-gcc。摄像头采用罗技的720p摄像头。

AI人脸识别测温一体机设计_json_02

(2)软件界面采用QT设计,在RK3399的ubuntu18.04系统里可以直接安装QT开发环境完成开发,也可以在PC机上交叉编译后将程序和相关库拷贝过来。

AI人脸识别测温一体机设计_json_03

(3)测温传感器采用MLX90614ESF(DCI),这个是红外非接触式测温传感器,测量距离可达到1米左右,这个模块是IIC协议接口。

AI人脸识别测温一体机设计_人脸识别_04

3. 华为云人脸识别服务

3.1 开通人脸识别服务

官网地址:  https://www.huaweicloud.com/product/face.html

AI人脸识别测温一体机设计_数据_05

AI人脸识别测温一体机设计_人脸识别_06

3.2 人脸识别接口功能

华为云提供的人脸检测可以对输入图片进行人脸检测和分析,输出人脸在图像中的位置、人脸关键点位置、人脸关键属性等信息。支持识别JPG、PNG、JPEG、BMP等格式的图片,上传图片时选择将图片转为Base64编码上传。

(1)接口请求方式: POST

(2)接口请求地址

格式:
https://face.{endpoint}.myhuaweicloud.com/v2/{project_id}/face-detect

示例:
https://face.cn-north-4.myhuaweicloud.com/v2/0e5957be8a00f53c2fa7c0045e4d8fbf/face-detect

(3)请求头的参数

{
 "X-Auth-Token": "******"   
}

X-Auth-Token字段是访问华为云的任何API接口都需要填,获取方法看这里:  https://bbs.huaweicloud.com/blogs/317759 翻到2.3小节。

AI人脸识别测温一体机设计_人脸识别_07

(4)请求Body参数

image_base64字段   : 存放Base64编码后的图片数据,大小不超过8MB,建议小于1MB。

attributes字段     :这个参数可以选择不填,不填就只是返回人脸的在图片里的尺寸位置。如果希望获取更多的属性列表,可以填下面之这些属性:
2:年龄
4:装束(帽子、眼镜)
6:口罩
7:发型
8:胡须
11:图片类型
12:质量
13:表情
21:人脸图片旋转角(顺时针偏转角度),支持0°、90°、180°和270°图片旋转。

多个属性间使用逗号(,)隔开。

(5)响应参数

如果图像里没有人脸,返回的数据是这样的:
{"faces":[]}

如果没有填额外的属性,返回的数据是这样的:
{
 "faces": [
  {
   "bounding_box": {
    "top_left_x": 61,
    "top_left_y": 54,
    "width": 114,
    "height": 151
   }
  }
 ]
}

填了额外的属性,返回的数据是这样的:
{
 "faces": [
  {
   "bounding_box": {
    "top_left_x": 61,
    "top_left_y": 54,
    "width": 114,
    "height": 151
   },
   "attributes": {
    "age": 30,
    "dress": {
     "glass": "none",
     "hat": "none"
    },
    "mask": "none",
    "hair": "short",
    "beard": "none",
    "phototype": "internet photo",
    "quality": {
     "total_score": 0.62109375,
     "blur": 0.3359375,
     "pose": 0.266357421875,
     "occlusion": 0.330810546875,
     "illumination": 0.378662109375
    },
    "expression": {
     "type": "neutral",
     "probability": 0.9991200566291809
    }
   }
  }
 ]
}

3.3 调试接口

地址:  https://apiexplorer.developer.huaweicloud.com/apiexplorer/debug?product=FRS&api=DetectFaceByFile

如果最开始想体验一下接口,了解参数的含义,可以先使用在线调试接口测试一下效果。

现在人脸检测的调试接口可以直接在网页上选择本地图片,不用再传bash64数据,测试更加方便。

AI人脸识别测温一体机设计_人脸识别_08

4. 设计设备端程序

4.1 调用人脸检测接口

//人脸检测
void Widget::FaceCheck(QImage image)
{
    QString requestUrl;
    QNetworkRequest request;

    //存放图片BASE64编码
    QString imgData;

    //设置请求地址
    QUrl url;

    //人脸检测请求地址
    requestUrl = QString("https://face.%1.myhuaweicloud.com/v2/%2/face-detect")
            .arg(SERVER_ID)
            .arg(PROJECT_ID);

    //设置数据提交格式
    request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json"));

    //将图片进行Base64编码
    imgData = QString(toBase64(image)); //编码后的图片大小不超过2M
    //设置token
    request.setRawHeader("X-Auth-Token",Token);

    //构造请求
    url.setUrl(requestUrl);
    request.setUrl(url);

    QString post_param=QString
               ("{"
                 "\"image_base64\": \"%1\","
                 "\"attributes\":%2"
                "}").arg(imgData).arg("6");

    //发送请求
    manager->post(request, post_param.toUtf8());
}

4.2 接口数据解析

    if(function_select==6)
    {
        //解析数据
        QJsonParseError json_error;
        QJsonDocument document = QJsonDocument::fromJson(replyData, &json_error);
        if(json_error.error == QJsonParseError::NoError)
        {
            //判断是否是对象,然后开始解析数据
            if(document.isObject())
            {
                QJsonObject obj = document.object();
                //解析错误代码
                if(obj.contains("faces"))
                {
                    QJsonArray face_arr=obj.take("faces").toArray();

                    for(int i=0;i<face_arr.size();i++)
                    {
                        QJsonObject object=face_arr.at(i).toObject();
                        if(object.contains("bounding_box"))
                        {
                            QJsonObject obj1=object.take("bounding_box").toObject();

                            int top_left_x=0;
                            int top_left_y=0;
                            int width=0;
                            int height=0;

                            if(obj1.contains("top_left_x"))
                            {
                                top_left_x=obj1.take("top_left_x").toInt();
                            }
                            if(obj1.contains("top_left_y"))
                            {
                                top_left_y=obj1.take("top_left_y").toInt();
                            }
                            if(obj1.contains("width"))
                            {
                                width=obj1.take("width").toInt();
                            }
                            if(obj1.contains("height"))
                            {
                                height=obj1.take("height").toInt();
                            }

                            qDebug()<<"top_left_x:"<<top_left_x;
                            qDebug()<<"top_left_y:"<<top_left_y;
                            qDebug()<<"width:"<<width;
                            qDebug()<<"height:"<<height;
                        }

                        //属性
                        QString mask;
                        if(object.contains("attributes"))
                        {
                            QJsonObject obj1=object.take("attributes").toObject();
                            mask=obj1.take("mask").toString();
                            qDebug()<<"带口罩的状态:"<<mask;
                        }
                    }
                }
             }
         }
    }

4.3 token获取

void Widget::GetToken()
{
    //表示获取token
    function_select=3;

    QString requestUrl;
    QNetworkRequest request;

    //设置请求地址
    QUrl url;

    //获取token请求地址
    requestUrl = QString("https://iam.%1.myhuaweicloud.com/v3/auth/tokens")
                 .arg(SERVER_ID);

    //自己创建的TCP服务器,测试用
    //requestUrl="http://10.0.0.6:8080";

    //设置数据提交格式
    request.setHeader(QNetworkRequest::ContentTypeHeader, QVariant("application/json;charset=UTF-8"));

    //构造请求
    url.setUrl(requestUrl);

    request.setUrl(url);

    QString text =QString("{\"auth\":{\"identity\":{\"methods\":[\"password\"],\"password\":"
    "{\"user\":{\"domain\": {"
    "\"name\":\"%1\"},\"name\": \"%2\",\"password\": \"%3\"}}},"
    "\"scope\":{\"project\":{\"name\":\"%4\"}}}}")
            .arg(MAIN_USER)
            .arg(IAM_USER)
            .arg(IAM_PASSWORD)
            .arg(SERVER_ID);

    //发送请求
    manager->post(request, text.toUtf8());
}

4.4 摄像头初始化

//查找系统可用摄像头
void Widget::Find_CameraNumber()
{
    //清空列表
    ui->comboBox_camera_number->clear();

    /*查找电脑当前可用摄像头*/
    cameras = QCameraInfo::availableCameras();
    if(cameras.count())
    {
        for(int i=0;i<cameras.count();i++)
        {
            ui->comboBox_camera_number->addItem(tr("%1").arg(i));
        }
        ui->pushButton_start_camera->setEnabled(true);
    }
    else
    {
        QMessageBox::warning(this,tr("提示"),"本机没有可用的摄像头!\n"
                                                 "软件作者:DS小龙哥\n"
                                                 "BUG反馈:[email protected]");
        ui->pushButton_start_camera->setEnabled(false);
    }

    /*摄像头没有启动时,按钮不可用*/
    ui->pushButton_find->setEnabled(false);
    ui->pushButton_delete->setEnabled(false);
    ui->pushButton_update->setEnabled(false);
    ui->pushButton_register->setEnabled(false);
}


//启动摄像头
void Widget::on_pushButton_start_camera_clicked()
{
    //摄像头启动标志
    if(camera_flag) //如果摄像头已经启动一次,再次启动需要将之前的空间释放掉
    {
        camera->stop();
        delete camera;
        ui->horizontalLayout_2->removeWidget(videoWidget);
        delete videoWidget;
    }

    camera_flag=1;  //标志摄像头已经启动一次

    //摄像头启动之后,就无法在重复启动
    ui->pushButton_start_camera->setEnabled(false);

   /*创建摄像头对象,根据选择的摄像头打开*/
   camera = new QCamera(cameras.at(ui->comboBox_camera_number->currentIndex()));

   /*构造捕获的对象*/
   camera_image_capture = new QCameraImageCapture(camera);

   /*设置捕获的目的地*/
   camera_image_capture->setCaptureDestination(QCameraImageCapture::CaptureToFile);

   //设置截图输出、缓冲区格式、分辨
   camera_image_capture->setCaptureDestination(QCameraImageCapture::CaptureToBuffer);
   camera_image_capture->setBufferFormat(QVideoFrame::PixelFormat::Format_Jpeg);

   //设置截图的图片尺寸
   iamge_setting.setResolution(320,240);
   camera_image_capture->setEncodingSettings(iamge_setting);

   //关联捕获的信号,发出捕获截图信号时,发出信号
  connect(camera_image_capture,&QCameraImageCapture::imageCaptured,this,&Widget::processCapturedImage);

   /*配置摄像头捕获模式为帧捕获模式*/
   camera->setCaptureMode(QCamera::CaptureViewfinder);

   videoWidget = new QVideoWidget();
   videoWidget->setMinimumSize(320,240);

   //将摄像头显示窗口加入到布局中
   ui->horizontalLayout_2->insertWidget(0,videoWidget);

   /*设置取景器显示*/
   camera->setViewfinder(videoWidget);

   /*启动摄像头*/
   camera->start();

   /*摄像头启动时,按钮可用*/
   ui->pushButton_find->setEnabled(true);
   ui->pushButton_delete->setEnabled(true);
   ui->pushButton_update->setEnabled(true);
   ui->pushButton_register->setEnabled(true);
}

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK