# 第十一届中国软件杯A4赛道总决赛三等奖作品 **Repository Path**: JSGIS/CDSystem ## Basic Information - **Project Name**: 第十一届中国软件杯A4赛道总决赛三等奖作品 - **Description**: 第十一届“中国软件杯”A4赛道:遥感图像智能解译平台总决赛三等奖作品 - **Primary Language**: Go - **License**: Apache-2.0 - **Default Branch**: develop - **Homepage**: None - **GVP Project**: No ## Statistics - **Stars**: 0 - **Forks**: 1 - **Created**: 2024-05-16 - **Last Updated**: 2024-05-16 ## Categories & Tags **Categories**: Uncategorized **Tags**: None ## README # 遥感解译系统 ## 1. 介绍 第十一届“中国软件杯”大赛A4遥感赛道作品,实现了以下功能: - 目标提取(对卫星图像中的道路进行提取) - 变化检测(检测同一区域两个时期的卫星图像的建筑变化情况) - 目标检测(检测卫星图像中的操场) - 地物分类(对卫星图像中出现的物体进行语义级分割) 该系统运行在WEB平台,用户仅需用浏览器登陆相应网址即可体验。 ## 2. 概要设计 ### 2.1 需求分析 #### 2.1.1 功能需求 - **系统介绍:** 系统在主页对主要功能进行介绍,并将效果图进行展示以便吸引用户继续体验。 - **图片上传功能:** 用户可以上传自己的图片,系统能够校验用户上传图片的分辨率。 - **图像处理功能:** 系统能够对用户上传的图片进行 **目标检测、变化检测、目标提取、地物分类** 等分析,并通过一定的后处理方法将结果以更形象的方式呈现给用户。 - **用户自行调整图像展示方式:** 目标检测、地物分类功能需要用户根据自己的需求对图像的可视化效果进行调整,比如调整目标检测的置信度阈值、地物分类中被标记的类别。 #### 2.1.2 非功能需求 - **用户交互友好:** 图片上传采用拖拽式上传,并用醒目的标记提示用户,地物分类中用户可通过下拉菜单选择要标记的类别,目标检测中用户通过拖拽滑动条来调整置信度阈值。 - **响应速度快:** 该系统涉及到大图像上传以及使用神经网络技术处理图像,具有一定的时间开销,需要尽可能减少用户等待时间以优化用户体验。 - **高可用性:** 由于使用了神经网络技术处理图像,因此当系统访问量过大时容易出现显存溢出而导致体统崩溃的情况,需要对此进行优化以增强系统的可用性。 ### 2.2 系统架构设计 系统的整体架构如下图所示: #### 2.2.1 视图层(view) 该系统向用户呈现的页面包括一个主页面和四个功能页面,主页面用来向用户介绍系统功能并呈现系统处理的效果图,另外四个功能页面分别对应目标检测、变化检测、目标提取、地物分类等任务,为用户提供接口让其自行上传卫星图片,并展示处理结果。该层接受用户获取相应页面的GET请求,并将请求转发给业务逻辑层。 #### 2.2.2 接口调用层(api) 同视图层一样,也是直接面向浏览器客户端的,用于接受客户端发来的接口调用请求,主要包括图像推理以及后处理的请求,该系统中接口调用请求均为POST请求,最后将请求传发给业务逻辑层。 #### 2.2.2 业务逻辑层(service) 接受用户浏览器客户端发送来的http请求,并解析相应参数,调用对应接口获取数据来组装Response消息,并返回给视图层和接口调用层,主要功能有填充页面模板数据、调用数据库层接口和图像处理接口。 #### 2.2.3 数据库层(dao) 直接同数据库进行交互,并对外提供调用接口,在该系统中的主要的数据库操作为插入和查询数据。 #### 2.2.4 图像处理接口服务(Infer API) 将部署的模型和一些后处理函数进行封装并对外提供可通过http协议的POST请求调用的接口,主要包括推理请求接口和后处理请求接口,推理请求接口接受的参数格式如下 ``` { 'task': 'Seg' | 'CD' | 'PDet' | 'Det', 请求任务: 目标提取 | 变化检测 | 地物分类 | 目标检测 'img_a': '', 待处理的图片base64编码 'img_b': '' 仅变化检测使用,后时序图 } ``` 返回的数据如下 ``` { 'code': 状态码 'prod': 预测图 'label': 标签(未处理,用于存入数据库中) 'time': 处理时长 'err': 错误信息 } ``` 后处理请求接口接受的数据如下: ``` { 'task': 'Seg' | 'CD' | 'PDet' | 'Det', 请求任务: 目标提取 | 变化检测 | 地物分类 | 目标检测 'postfunc': '', 后处理函数 'label': '', 推理标签 'image': '', 原图 'param': '', 后处理请求参数 } ``` 其中当postfunc为default时则调用默认的后处理函数。 返回的数据如下: ``` { 'code': 状态码 'prod': 预测图 'time': 处理时长 'err': 错误信息 } ``` ## 3. 详细设计 主要从该系统总体分为Web服务器、GPU服务器两个部分,此章将从Web服务器、GPU服务器以及系统部署方案三方面进行介绍。 ### 3.1 Web服务器设计与实现 Web服务器使用 _Golang_ 语言 _Gin_ 框架编写,前端页面以模板语言的形式编写,非前后端分离项目。 #### 3.1.1 视图层设计 视图层包含浏览器页面模板和Web服务端接受浏览器GET请求的函数。 浏览器页面使用 _HTML5、CSS3、Jquary_ 框架编写页面,包含一个主页面和四个功能页面,主页面以百叶窗的形式向用户介绍该系统的功能,并在左边提供了相关参考文献的链接。 - 目标提取:提供用户上传图片的接口、切换图片的接口、下载处理后的图片的接口以及显示系统处理结果(包括响应时间、推理时间、错误信息等)的接口,推理过的图片暂存在左边的候选框内,供用户切换。 - 变化检测:提供给用户上传图片的接口,用户同时仅能上传两张图像,系统会检测用户上传的图像是否完整以及分辨率是否相同,另外提供给用户下载结果的接口。 - 目标检测:包含目标提取页的全部功能,并且额外提供给用户调整置信度阈值的接口。 - 地物分类:包含目标提取页的全部功能,并且额外提供给用户选择需要标注的类别的接口。 图像上传均已拖拽式上传的方式实现。 服务端的view层接受浏览器发来的一下路由的GET请求,并将其转发给业务逻辑层获取解析模板必要的数据,并将最终将解析的页面返回给浏览器。 - "/" - "/CdSeg" - "/PSeg" - "/Sseg" - "/Det" #### 3.1.2 接口调用层 接受浏览器发来的POST请求,并解析POST的参数,最终转发给业务逻辑层处理,将业务逻辑层打包好的Response以JSON形式返回给浏览器,路由如下: - "/api/infer" 用于模型推理,当用户上传一张图像时发送该请求。PSOT请求参数如下: ``` { 'task': 'Seg' | 'CD' | 'PDet' | 'Det', 请求任务: 目标提取 | 变化检测 | 地物分类 | 目标检测 'img_a': '', 待处理的图片base64编码 'img_b': '' 仅变化检测使用,后时序图 } ``` 返回数据如下 ``` { 'image': '' 输入图片的md5码 'code': '' 状态码 'prod': '' 预测图 'time': '' aip处理时长 'err': '' 错误信息 } ``` - "/api/postprocess" 当用户更改推理结果的呈现效果时发送该请求,仅会在目标检测页面和地物分类页面发送。 请求参数如下: ``` { 'task': 'Seg' | 'CD' | 'PDet' | 'Det', 请求任务: 目标提取 | 变化检测 | 地物分类 | 目标检测 'image': '' 输入图片的md5码 'postfunc': '', 后处理函数 'param': '', 后处理请求参数 } ``` 返回数据同infer #### 3.1.3 业务逻辑层设计 向视图层和接口调用层提供接口。 对于视图层转发来的GET请求,将从配置文件中读取数据,并将数据打包返回给视图层。 对于接口调用层转发来的POST请求,提供两个接口函数 1. **InferToApi(ir InferRequest) (ClientResponse,error):** 该接口函数主要功能为处理前端的推理图像请求,并返回最终需要给客户端返回的响应数据以及错误信息。 先将InferRequest中输入图像的base64字符串编码成MD5,以此为索引调用数据库层的查询接口判断是否存在对应的标签,如果存在则调用图像处理接口服务中的后处理接口,使用该任务的默认后处理函数并获取响应结果,如果不存在则调用图像处理接口服务中的图像推理接口进行推理,将得到的结果存入数据库中。最后将处理结果和输入图像的MD5码以及图像处理接口服务返回的错误信息填充到ClientResponse中,交给接口调用层。 2. **PostToApi(pps PostParams)(ClientResponse,error)** 该接口函数主要功能为处理前端的后处理请求,并返回最终需要给客户端返回的响应数据以及错误信息。 先判断数据库中是否存在索引为PostParams里MD5值的记录,如果不存在则抛出错误,如果存在则调用图像处理接口服务中的后处理接口,用用户指定的后处理函数来处理图像,并将最终的结果和错误信息打包交给接口调用层。 #### 3.1.4 数据库设计 为了降低系统响应时间提高用户体验,需要将推理结果缓存到数据库中。由于不同任务的预测标签的模态不同,所以这里选择MongoDB来存储数据。集合中包含的字段如下表所示: | Infer Res | |-----------| | Key(MD5) | | Image | | label | 为了提高查询效率,选用输入图像的MD5码作为索引。 另外Web服务器的数据库层内部维护一个MongoDB连接池并对外提供查询( `SaveProd(pi ProdInfo) (err error)` )和插入(`GetLabelAndImage(image string) (label, image_data string, err error)`)接口。 #### 3.1.5 其他 该部分出现的各结构体的字段和含义请参考[model/infer.go](https://gitee.com/hanchaoqi/CDSystem/blob/master/model/infer.go) ### 3.2 GPU服务器(图像处理接口服务)设计与实现 该部分使用PaddleRS库进行模型的训练与部署,使用Opencv和SkImage工具库设计了一系列后处理函数,并利用Python的Flask框架将其封装为可用过HTTP的POST调用的接口。 #### 3.2.1 模型和数据集的选取 - **目标提取:** 使用[Massachusetts Roads道路提取数据集](https://www.cs.toronto.edu/~vmnih/data/)。该数据集的训练集包含804幅大小为1500x1500的三波段影像,每幅影像均配有道路提取标签。该任务为典型的二值语义分割任务,因此这里选用ResNet50-DeepLabV3,backbone迁移ImageNet上的预训练权重并在该数据集上微调。 - **变化检测:** 使用的[数据集](https://aistudio.baidu.com/aistudio/datasetdetail/134796)包括赛事的变化检测任务所需训练(training)和验证(evaluation)数据,以及测试(testing)影像对。train_data.zip对应训练/验证集,其中共含有637个遥感影像对以及对应的二值变化标签,每个时相的影像均包含RGB三个波段(亮度值已量化到0-255),长、宽均为1024。test_data.zip对应测试集,其中仅包含双时相影像对,而不提供变化标签。从数据集所给的标注来看,该任务也可以转化成二值语义分割问题,本例选用HRNet18-BIT模型进行训练。 - **地物分类:** 使用飞[桨常规赛:遥感影像地块分割数据集](https://aistudio.baidu.com/aistudio/datasetdetail/77571)。该赛题由2020 CCF BDCI 遥感影像地块分割赛题优化而来,旨在对遥感影像进行像素级内容解析,对遥感影像中感兴趣的类别进行提取和分类。比赛所用的数据集亦是对BDCI数据集的简化。数据集共有5类,是一个多类别语义分割任务,这里同样选取ResNet50-DeepLabV3,并迁移在ImageNet上的预训练权重在该数据集上进行微调。 - **目标检测:** 使用[RSOD遥感影像目标检测数据集](https://github.com/RSIA-LIESMARS-WHU/RSOD-Dataset-)包含4种类型的遥感地物目标(本项目仅使用其中的playground类)。对于目标检测任务来说,本例选用端到端的PPYOLO模型,迁移在COCO上的预训练权重,并在该数据集上微调。 #### 3.2.2 模型部署 使用PaddleRS中的exprot_model.py将训练好的动态图模型转换为静态图模型,并调用paddlers.deploy.Predictor来加载模型并推理图像。 为了方便客户端调用该方法,将其封装成 `paddleInferancer` 类。 ``` paddleInferancer: model_path:paddle静态图模型路径 use_gpu:是否启用GPU推理 post_process:默认后处理函数 默认后处理函数的参数应为(原始预测标签,输入原图),且返回值为opencv格式或np.ndarray use_windows:是否启用滑窗推理 window_size:滑窗推理窗口尺寸 stride:滑窗推理滑动步长 def inferOne(self, im_a, im_b = None):-> tuple[prob, label, time] //推理一张图像,im_a为输入图像,im_b为处理变化检测任务时的后时序图,返回处理好的图像,模型推理的标签以及推理所用的时间。 ``` #### 3.2.3 后处理函数设计 pass ### 3.3 系统部署方案 由于该项目利用了深度学习技术加之遥感图像一般分辨率很高,因此该系统处理图像时对显存的开销极大而且响应时间也一般较长,普通的云服务器很难胜任。为了降低系统响应时间,优化用户体验,我们选择如下部署方案: 将Web服务端部署以及图像处理接口服务的后处理接口部署到云主机上,用户通过浏览器访问该主机的ip来打开系统,另外将图像处理接口服务的图像推理接口部署到GPU服务器上,且仅由web服务器通过http协议访问,由于GPU服务器缺少公网ip,因此我们用frp技术对GPU服务器做了一个内网穿透。 将图像处理接口服务部署到云主机上的原因是为了降低图像传输的通信开销。 另外考虑到当用户请求量过大时,GPU服务器容易出现显存溢出的情况,从而使系统的可用性大打折扣,为了提高系统可用性,在web服务器中使用channel对GPU服务器推理接口的最大同时调用数做了限制。 ## 4. 其他 ### 4.1 环境依赖 - Web服务端: go 1.17 github.com/BurntSushi/toml v1.1.0 github.com/gin-contrib/multitemplate v0.0.0-20220606235416-8e12065b5cb8 github.com/gin-gonic/gin v1.8.1 go.mongodb.org/mongo-driver v1.9.1 - 图像处理请求接口: PaddleRS flask_cors Flask - 数据库: mongodb v3.6.8 ### 4.2 安装与使用说明 1. `git clone https://gitee.com/hanchaoqi/CDSystem.git master` 2. `cd ./CDSystem` 3. windows下直接运行main.exe;Linux下执行如下指令 ``` - go build -o main main.py - ./main ``` 4. `cd ./InferApi` 5. `python -u "./main.py"` 6. 浏览器输入localhost:8080/即可访问。