查看原文
其他

FastDeploy+英特尔NUC+大疆无人机梦幻联动!推动智慧城市巡检应用落地

将AI进行到底的 百度AI 2023-03-16



智慧城市旨在利用大数据、物联网(IoT)、人工智能和 5G 等数字技术,提高政府公共服务水平、社会治理效能,推动经济增长,不断增强人民群众的获得感、安全感和幸福感。自十四五规划以来,国家和各大主要城市一直加速推进新型智慧城市分级分类建设,但在实施的过程中也遇到了一些问题和困难。

在智慧城市 AI 部署落地中,常见的问题有边缘设备硬件不统一、跨平台开发成本高和模型推理速度优化难度大等。聚焦到 AI 系统的使用者本身,智慧城市的落地也有很多阻碍,比如环境工程师在户外采集数据时,如果要做到实时采集实时分析存储入库,必须要背上配有显卡的工作站到户外,同时还要带上 XXXXL 号移动电源解决供电问题。其重量对环境工程师而言无疑是超负荷的。

为了解决软件工程师开发难度大的问题,本方案演示了 FastDeploy (OpenVINO) + 轻量化模型的 AI 工作流模式,希望能为使用者提供更轻便、简单和高效的解决方案。

本项目利用无人机控制端自带的实时消息传输协议(RTMP)将低空无人机的实时图像传输到推理硬件设备,通过模型推理计算绿化覆盖率、建筑率、车辆数量、人群数量等指标,可用于城市大规模环境监测、国土低空遥感、道路交通巡检和无人机低空安防等领域。

本任务是对无人机图像数据流的实时推理,对推理速度有极高的要求。同时为了减少开发难度和迁移成本,我们采用了 X86 CPU 架构的英特尔 NUC 迷你电脑套件作为推理硬件,软件选择了 FastDeploy 推理部署工具箱快速开发后端 OpenVINO 推理引擎,加速 AI 模型推理。此外,在 AI 模型选择上,我们分别选择了飞桨 PP-LiteSeg 和飞桨 PP-YOLO Tiny 两个轻量化模型来完成语义分割和目标检测任务。

项目整体流程

如上图所示,首先需要在 NUC 上架设 RTMP 推流服务,无人机 APP 客户端连接内网 RTMP 服务器,实现无人机的图像实时通过路由器向 NUC 设备传输。NUC 设备端获得图像后,渲染至 PySide 前端的显示窗口,同时 FastDeploy 线程执行语义分割和目标检测的推理任务,并把结果和可视化图像实时渲染至前端窗口。


 开发环境准备 


核心软硬件

英特尔 NUC 迷你电脑套件

(型号:NUC8i5BEH)

FastDeploy >= 0.2.1

PaddleDetection >= 2.5

PaddleSeg >= 2.6

PySide6 >= 6.3.2


可选软硬件(户外实时采集时用)

大疆系列无人机及 DJI Fly APP

路由器(用于内网 RTMP 传输)


英特尔 NUC 迷你电脑硬件


 无人机实时图传 
RTMP(Real-Time Messaging Protocol,实时消息传送协议)是一个设计用来实时数据通信的网络协议,现多用于直播设备与支持 RTMP 协议的服务器之间进行音视频和数据通信。本项目无人机和推理硬件设备之间的实时图传环节利用的是大疆控制端 APP 的 RTMP 推流服务,为了最大限度地减少图传时间延迟,我们直接在英特尔 NUC 上利用 Nginx 搭建 RTMP 服务。
英特尔 NUC 预装的操作系统是 Windows10,所以可以直接下载带 RTMP 模块的 Nginx。
🔗下载链接http://nginx-win.ecsds.eu/download/nginx%201.7.11.3%20Gryphon.zip


下载到本地后解压,在 nginx/conf 目录下新建一个文件,命名为 nginx.conf,输入内容如下。
worker_processes  1;

events {
    worker_connections  1024;
}

rtmp {
    server {
        listen 8899;
        chunk_size 4000;
        application live {
             live on;
             allow publish all;
             allow play all;
        }
    }
}


然后打开 cmd 命令行窗口,进入到 Nginx 的目录下,输入 nginx 启动 Nginx 服务,如图所示即为启动成功。


此时,我们需要在 cmd 命令行输入 ipconfig 命令查询 NUC 设备的内网 IPv4 地址。

打开 DJI Fly APP,找到 RTMP 直播推流,填入推流地址:rtmp://192.168.31.246:8899/live



APP 推流配置完成之后,可以在 NUC 设备端调用 OpenCV 的 API 进行拉流操作以获取无人机实时画面,Python 实现代码如下。


import cv2
rtmpUrl = 'rtmp://192.168.31.246:8899/live'
vid = cv2.VideoCapture(rtmpUrl)
while vid.isOpened():
    ret,frame = vid.read()
    cv2.imshow('RTMP Test',frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break
vid.release()
cv2.destroyAllWindows()


运行这段代码后,Python 程序会实时获取无人机 APP 实时推送的 RTMP 流数据并更新到 OpenCV 窗口显示,运行效果如下图。



 FastDeploy 

 模型推理部署 


打通了无人机图像实时传输的环节之后,我们进入核心的推理部署环节。由以上 Python 代码可以看出,RTMP 数据流经过 OpenCV 解码后得到图像帧 (frame),因此推理环节的工作本质就是将每一帧图像输入模型然后得到结果并将输出结果可视化。本环节主要分为三个步骤:模型动静转换、推理脚本编写和前端集成。


 模型动静转换 


首先,我们需要把使用 PaddleSeg 和 PaddleDetection 开发套件训练好的动态图模型转换成静态图模型,这一步利用两个套件分别提供的脚本即可简单完成。已经训练好的动态图模型可以在 AI Studio 项目中获取。


🔗链接

https://aistudio.baidu.com/aistudio/projectdetail/4535658


语义分割目标检测动态图模型和语义分割分别在 AI Studio 项目中 ppyolo_inference_model 和 output_ppliteseg_stdc1/best_model/ 目录下,分别调用对应的动静转换脚本将两个动态图模型转换成静态图。


▎PaddleSeg


python PaddleSeg/export.py \
       --config ppliteseg_stdc1.yml \ #配置文件路径,根据实际情况修改
       --model_path output_ppliteseg_stdc1/best_model/model.pdparams \ 
# 动态图模型路径,根据实际情况修改
       --save_dir inference_ppliteseg_stdc1 \ # 导出目录
       --input_shape 1 3 512 1024 #模型输入尺寸


PaddleDetection


python PaddleDetection/tools/export_model.py \
       -c PaddleDetection/configs/ppyolo/ppyolo_tiny_650e_coco.yml \ # 配置文件路径,根据实际情况修改
       --output_dir=./ppyolo_inference_model \ # 保存模型的路径
       -o weights=ppyolo_tiny_650e_coco.pdparams # 动态图模型路径

注:模型转换的详细教程可参考https://github.com/PaddlePaddle/PaddleSeg/blob/release/2.6/docs/model_export_cn.mdhttps://github.com/PaddlePaddle/PaddleClas/blob/release/2.4/README_ch.md


完成转换之后,我们能分别得到两套 model.pdmodel 和 model.pdiparams 文件以及对应的 yaml 配置文件。


 基于 FastDeploy 开发 

 OpenVINO 推理模块 


本项目使用的是英特尔 NUC 迷你电脑套件,选择 FastDeploy 的 OpenVINO 后端作为推理部署解决方案。以往使用 OpenVINO 需要下载套件、安装和配置,过程比较繁琐,因此我采用了 FastDeploy 的部署方案,调用其内置的 OpenVINO 推理后端进行快速开发、部署。FastDeploy 的预编译库安装和使用教程可参考官方 Github 文档。


🔗链接

https://github.com/PaddlePaddle/FastDeploy


因为考虑到程序的适用性和多种硬件环境兼容,我首先写了 Option 配置,根据不同的硬件选择不同的推理后端,在 CPU 环境中,默认使用 OpenVINO 作为推理后端。


import cv2
import numpy as np
import fastdeploy as fd
from PIL import Image
from collections import Counter

def FastdeployOption(device=0):
    option = fd.RuntimeOption()
    if device == 0:
        option.use_gpu()
    else:
        # 使用OpenVino推理
        option.use_openvino_backend()
        option.use_cpu()
    return option


然后,将语义分割模型推理代码封装成一个类,方便前端快速调用。在 init 方法中,直接调用了 SegModel()函数进行模型初始化(热加载),通过 SegModel.predict()完成结果的推理,得到推理结果之后执行 postprocess()对结果进行解析,提取建筑和绿地的像素数量,统计图像占比,得到环境要素的占比结果。最后调用 FastDeploy 内置的 vis_segmentation()可视化函数,对推理结果进行可视化。


class SegModel(object):
    def __init__(self, device=0) -> None:
        self.segModel = fd.vision.segmentation.ppseg.PaddleSegModel(
            model_file = 'inference/ppliteseg/model.pdmodel',
            params_file = 'inference/ppliteseg/model.pdiparams',
            config_file = 'inference/ppliteseg/deploy.yaml',
            runtime_option=FastdeployOption(device)
        )

    def predict(self, img):
        segResult = self.segModel.predict(img)
        result = self.postprocess(segResult)
        visImg = fd.vision.vis_segmentation(img, segResult)
        return result, visImg

    def postprocess(self, result):
        resultShape = result.shape
        labelmap = result.label_map
        labelmapCount = dict(Counter(labelmap))
        pixelTotal = int(resultShape[0] * resultShape[1])
        # 统计建筑率和绿地率
        buildingRate, greenRate = 00
        if 8 in labelmapCount:
            buildingRate = round(labelmapCount[8] / pixelTotal* 1003
        if 9 in labelmapCount:
            greenRate = round(labelmapCount[9] / pixelTotal * 100 , 3)

        return {"building": buildingRate, "green": greenRate}


同理,直接调用 FastDeploy 的 PPYOLO()方法完成模型的推理,经过后处理格式化数据之后调用对应的可视化函数 vis_detection()进行渲染。


class DetModel(object):
    def __init__(self, device=0) -> None:
        self.detModel = fd.vision.detection.PPYOLO(
            model_file = 'inference/ppyolo/model.pdmodel',
            params_file = 'inference/ppyolo/model.pdiparams',
            config_file = 'inference/ppyolo/infer_cfg.yml',
            runtime_option=FastdeployOption(device)
        )
        # 阈值设置
        self.threshold = 0.3

    def predict(self, img):
        detResult = self.detModel.predict(img.copy())
        result = self.postprocess(detResult)
        visImg = fd.vision.vis_detection(img, detResult, self.threshold, 2)
        return result, visImg

    def postprocess(self, result):
        # 得到结果
        detIds = result.label_ids
        detScores = result.scores
        # 统计数量
        humanNum, CarNum = 00
        for i in range(len(detIds)):
            if detIds[i] == 0 and detScores[i] >= self.threshold:
                humanNum += 1
            if detIds[i] == 2 and detScores[i] >= self.threshold:
                CarNum += 1
        return {"human": humanNum, "car": CarNum}


把 PP-LiteSeg 语义分割模型和 PP-YOLO Tiny 目标检测模型封装成类之后,保存为 inferEngine.py 文件,以供后续前端代码调用。

 结合 PySide6 

 开发可视化 GUI 界面 


前端开发使用的是 PySide6,界面源代码可在文章最后的 Github 项目链接中获取。整体而言开发难度不大,主要的难点在于三个视频播放的组件同时更新导致的程序卡死或者延时问题。


在本项目中应用的解决方法是用多线程,把三个视频播放组件的后端分开三个独立的线程,一个线程(displayThread)把实时视频流原画推送到前端更新,另外两个线程(segThread 和 detThread)同步完成语义分割和目标检测推理实时视频帧图像并将后处理之后的推理结果图像更新到前端组件上。具体代码如下所示(main.py)。


向下滑动查看所有内容


最后执行 python main.py 运行程序,查看推理效果。



 总结 


FastDeploy 是一个帮助开发者快速部署深度学习模型的推理部署工具箱,内置了包括 OpenVINO、TensorRT、ONNX Runtime、Paddle Inference 后端,正在集成 Paddle Lite、RKNN 等推理后端。并对各后端进行了针对性的优化,很好地兼容了英特尔 NUC 迷你主机的硬件,无需另外安装 OpenVINO 套件和配置环境,同时也免去了调优提速的烦恼,降低了开发者的学习成本和部署成本,提高了部署开发效率。目前已经支持包括飞桨等生态60+热门模型。更多 AI 模型的推理部署,可前往 FastDeploy 的 GitHub 了解。


🔗链接

https://github.com/PaddlePaddle/FastDeploy


● 往期精彩

火箭发动机喷流的“监察队长”:基于飞桨探索火箭发动机真空羽流流场的快速计算

FastDeploy秒解模型部署难题,助力智慧农业应用快速落地



您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存