《论文阅读13》Efficient Urban-scale Point Clouds Segmentationwith BEV Projection

一、论文

  • 研究领域: 城市级3D语义分割
  • 论文:Efficient Urban-scale Point Clouds Segmentationwith BEV Projection
  • 清华大学,新疆大学
  • 2021.9.19
  • 论文github
  • 论文链接

二、论文概要

2.1主要思路

提出了城市级3D语义分割新的方法,将3D点云语义分割任务转移到2D鸟瞰图分割问题。 分为以下三步:3D到BEV投影、稀疏BEV图像分割和BEV到3D重新映射。

注: BEV: Bird's Eye View

BEV投影是指鸟瞰视角(Bird's Eye View,简称BEV)的一种从上方观看对象或场景的视角,就像鸟在空中俯视地面一样。在自动驾驶和机器人领域,通过传感器(如LiDAR和摄像头)获取的数据通常会被转换成BEV表示,以便更好地进行物体检测、路径规划等 。

2.1.1 实现步骤

  • 3D到BEV投影 

1、城市规模的点云地图被预先划分成边长小于400米的网格。

2、我们进一步生成了25× 25 m2的正方形,放大倍数为20倍。

使用滑动窗口来得到BEV投影,伪代码如下:

 

  • 稀疏BEV图像分割 

考虑到BEV图像上投影点云的显著稀疏性,这将在标记和模型学习中引入严重的噪声,因此有必要对投影进行像素级完成,特别是对于不同类点周围的内部区域和边缘。在我们的实验中,我们迭代地对每个图像中的每个通道进行三次2D最大池化。标签的渐进变化如图4所示。

对于从左到右,我们呈现原始BEV标签和具有一次/两次/三次最大池化完成的标签。

BEV投影生成的图像,设计了一个基于注意力的多模态融合网络,有效地融合了RGB和几何细节。与单模态网络相比,分割效果取得了一定的提高,进一步验证了RGB颜色对分割的意义。 

 

  • BEV到3D重新映射

对于3D重映射,我们存储每个投影窗口的绝对x/y坐标,并使用主题查询原始大规模点云中的提取位置以获得2D分割输出。对应于相同像素的点将被赋值为与像素相同的类。之后,我们能够评估3D语义分割性能。

2.2 主要贡献

1、针对大规模无人机点云数据稀疏、处理负担重的问题,设计了一种大规模无人机点云数据预处理方法,即将三维点云投影到密集的鸟瞰图上

2、对于BEV投影生成的图像,设计了一个基于注意力的多模态融合网络,有效地融合了RGB和几何细节。与单模态网络相比,分割效果取得了一定的提高,进一步验证了RGB颜色对分割的意义。 

提出了一种新的方法,并设计了一种新的图像分割网络。

 

2.3 实验表现

 与其他已发表方法的比较结果。我们使用ResNet-34和HRNet实现了我们的模型,这两个模型都在SensatUrban数据集上实现了具有竞争力的平均IoU和整体准确性。

三、论文全文

基于BEV投影的城市尺度点云高效分割

摘要:近年来,点云分析已经吸引了研究人员的目光,而3D语义分割仍然是一个问题。大多数深度点云模型直接在3D点云上进行学习,这将受到城市规模数据严重稀疏和极端数据处理负载的影响。为了解决这一挑战,我们建议将三维点云转移到密集的鸟瞰图投影。在这种情况下,由于类不平衡减少和利用各种2D分割方法的可行性,分割任务被简化。我们进一步设计了一个基于注意力的融合网络,可以对投影图像进行多模态学习。最后,2D输出被重新映射以生成3D语义分割结果。为了证明我们的方法的好处,我们在SensatUrban数据集上进行了各种实验,其中我们的模型呈现出竞争力的评估结果(61.17% mIoU和91.37% OverallAccuracy)。我们希望我们的工作可以启发进一步探索点云分析。

  • 介绍

3D语义分割是点云学习的关键技术,其目的是为每个单独的点数据分配语义标签,已广泛应用于自动驾驶[1],虚拟现实[2],3D重建[3]等。虽然深度学习在2D语义分割任务中表现突出,但它无法直接处理不规则,无序和非结构化的点数据[4]。因此,目前有几种方法[5]-[11]将非结构化点转换为某些有效的中间表示,例如体素[7],[12]和多视图[10],[13],[14],以利用经典CNN模型处理点云。随着对三维场景理解需求的不断增加,提出了越来越多的三维点云数据集。从室内数据集(例如,S3DIS [15]和ScanNet [16])到道路级数据集(例如,SemanticKITTI [17]),数据集的空间大小也更大。最近的工作[3],[18]提出了城市级数据集,为大规模数据集的语义分割带来了一些新的挑战。

  • 室内数据集(例如,S3DIS [15]和ScanNet [16])
  • 道路级数据集(例如,SemanticKITTI [17]),数据集的空间大小也更大
  • [3],[18]提出了城市级数据集

与基于LiDAR的数据集不同,这些城市规模的点云大多是从无人机摄影测量中获得的,这可能导致数据集中的以下特征。首先,无人机摄影测量的扫描不均匀,扫描区域不集中,捕获的图像边缘有散乱的区域。其次,重建的点云部分缺失。我们在SensatUrban [3]数据集中观察到这种现象,一个典型的例子是,在对点云进行可视化后,屋顶下没有对应的墙点,这使得屋顶似乎悬浮在空中。有趣的是,我们发现基于无人机的点云中垂直点的类别重叠率较低,例如,SensatUrban为2.3%,这意味着鸟瞰图是一种合适的投影方法,它更简单,更有效,并且能够最大限度地保留点细节。

此外,对于投影图像,具有更丰富标记的2D像素级数据集可以用于预训练。因此,在本文中,我们提出了一个BEV投影分割方法来处理城市规模的三维分割问题。

我们的主要贡献是:

1)对城市规模的点云进行点级分析;

2)提出了一种基于BEV投影算法的多模态融合分割模型;

3)我们在SensatUrban数据集上对我们的方法进行了评估,我们的竞争结果证明了我们设计的有效性。

  • 相关工作

A.语义分割

通常,根据输入网络的点云数据的形式,现有的大多数3D语义分割方法可以分为三类:基于点、基于3D表示和基于投影。

基于点的方法直接处理原始点云,其代表方法是PointNet,计算开销大。虽然[19],[20]对PointNet进行了一些有益的改进,但由于这些方法直接处理sprase数据,因此仍然难以加速。最近的RandLA-Net [2]引入了随机采样和轻型网络架构,大大加快了模型的速度。然而,如[21]中所提到的,基于点的方法中不可忽视的问题是,由低效的随机存储器访问引起的处理sprase数据的大量时间浪费(80%),这意味着实际上只有少量的时间用于提取特征。此外,大的存储器开销也是一个严重的问题。

基于3D表示的方法将原始点云数据变换成某些3D表示(例如,体素和晶格),然后利用3D卷积[5]-[8]。然而,很难平衡分辨率和内存之间的关系[21],[22]。分辨率越低,同一网格中的点融合在一起,导致点云信息丢失越严重。分辨率越高,计算开销和内存使用量越大。此外,预处理和后处理步骤需要大量时间[23]。

  • 分辨率越低,同一网格中的点融合在一起,导致点云信息丢失越严重。
  • 分辨率越高,计算开销和内存使用量越大

基于投影的方法利用成熟的2D卷积模型来处理从3D点云投影的图像,而不是直接处理点。基于投影的方法包括几个特定的类别,如多视图,基于球面的方法。多视图方法[10],[13],[14]将点云投影到多个虚拟相机视图中。例如,[10]利用多流CNN来处理从每个视图生成的图像,然后融合每个点的不同图像的预测分数,[13]定义了旋转相机并提出了Katz投影来选择每个相机角度中的点,[14]在不同的相机位置生成深度图像和RGB图像。[24]利用球面投影方法将三维点云转换为图像,利用SqueezeSeg网络进行分割,并应用条件随机场(CRF)对分割结果进行优化。[11]提出了基于SqueezeSeg的上下文聚合模块(CAM)来扩展感受野,并且[4]引入了空间自适应卷积(SAC)来进一步提高分割精度。

基于投影的方法包括几个特定的类别:

  • 多视图方法[10],[13],[14]将点云投影到多个虚拟相机视图中。
  • 利用球面投影方法将三维点云转换为图像

 B 大规模场景的语义分割

在最近的工作中,已经提出了几个由无人机拍摄的城市尺度3D点云数据集[3],[18],[25],其中最大的是SensatUrban [3]数据集,其覆盖面积为7.64×106 m2,具有30亿个注释点。然而,这些大而密集的数据集给语义分割带来了新的挑战。

城市尺度3D点云数据集: 

  • 最大的是SensatUrban

首先,面对海量数据,预处理方法的选择,例如,数据分区、下采样等。意义重大。其次,城市规模点云存在类分布不均衡的问题。第三,基于无人机的数据集和基于激光雷达的数据集之间的一个显着差异是,前者包含RGB特征。对于大规模数据集,是否将RGB特征纳入网络以及如何有效地利用RGB特征值得考虑。最近的工作,例如RandLA-Net [2]和BAAF-Net [23]利用RGB颜色并取得了积极的分割结果。对于BEV投影生成的图像,我们设计了一个基于注意力的多模型融合网络,有效地融合了RGB和几何细节。与单模态网络相比,分割效果取得了一定的提高,进一步验证了RGB颜色对分割的意义。


海量数据预处理方法:

  • 数据分区
  • 下采样等

近年来,已经提出了几种针对大型数据集的语义分割算法[2],[9],[26],[27]。例如,RandLA-Net [2]引入了随机采样以提高计算和内存的效率,TagentConv [9]利用基于切线卷积的U型网络进行大型和密集数据集的语义分割,SPGraph [27]提出了一种新的点云表示(SPG),能够捕获3D点的上下文结构。需要提出更多的大规模点云分割算法。

  • 方法:

A 问题陈述

3D点云语义分割的目的是为每个单独的点分配语义标签,而2D分割是为每个像素分配特定的标签。在某种程度上,这两种类型的任务具有相似的目的和解决方案。根据我们上面的陈述,可以将3D点云语义分割任务转移到2D鸟瞰图分割问题。主要过程包括鸟瞰图映射和2D多模态分割。

B 鸟瞰投影为什么合理

当我们将一个任务转移到另一个任务时,它要求输入数据和预期输出的一致性。为了评估我们的想法,我们在构建模型之前进行点级分析。我们首先将3D点投影到BEV图上(将在下文中详细描述)并计算重叠率。在投影中以0.04m为单位进行坐标缩放时,约有25.44%的点会丢失。对于那些点密集的地方,比例将提高到50%或更多。然而,我们发现大多数重叠点属于与顶部点相同的类别。类重叠率低于2.3%,mIoU可达93.7%。在这种情况下,可以将3D分割任务转移到2D BEV分割。我们的目标是在BEV图像上进行精确识别

C 鸟瞰图

为了优化这种大型点云的数据处理负载,我们将整个工作分为三个部分:3D到BEV投影、稀疏BEV图像完成和BEV到3D重新映射。 前两个部分的处理在下面的算法1中被呈现为伪代码。

我们设置一个滑动窗口来处理点并生成BEV图像。在投影之前,我们需要初始化参数gscale,gsize ,gstep,它控制滑动窗口的缩放,大小和移动步骤。对于每个滑动步骤,我们通过x/y坐标对点进行排序,并从当前BEV投影窗口开始/结束坐标中查询点,之后将删除处理过的点以减少后续数据处理量。为了获得最佳的参数,我们测试了不同的投影尺度从0.01到0.04的空间重叠率,如图3所示。当我们将点云的尺度设置在[0.01,0.03]时,会导致点云不同部分的重叠分布非常接近,即城市尺度点云中的点的最小间距在[0.03,0.05](m)以内。此外,根据我们的投影图像数量估计,合适的窗口长度在[20,50](m)以内。因此,我们将参数设置为gscale = 0.05,gsize = gstep = 25。然而,我们也建议多尺度,多尺寸和多步采样,以便在未来的工作或其他类似的任务中更好地训练。

对于单个滑动窗口中的点,我们通过积分x/y坐标将点映射到像素。这将不可避免地带来值量化的损失,但是,如果我们在3D重映射中进行相同的过程,它不会影响标签检索过程。BEV图使用顶部的点进行更新,生成具有颜色和z坐标值的RGB和海拔(Alt)图像。考虑到BEV图像上投影点云的显著稀疏性,这将在标记和模型学习中引入严重的噪声,因此有必要对投影进行像素级完成,特别是对于不同类点周围的内部区域和边缘。在我们的实验中,我们迭代地对每个图像中的每个通道进行三次2D最大池化。标签的渐进变化如图4所示。

对于从左到右,我们呈现原始BEV标签和具有一次/两次/三次最大池化完成的标签。

对于3D重映射,我们存储每个投影窗口的绝对x/y坐标,并使用主题查询原始大规模点云中的提取位置以获得2D分割输出。对应于相同像素的点将被赋值为与像素相同的类。之后,我们能够评估3D语义分割性能。

1、初始化参数gscale,gsize ,gstep,它控制滑动窗口的缩放,大小和移动步骤

  • 合适的窗口长度在[20,50](m)以内
  • 参数设置为gscale = 0.05,gsize = gstep = 25

2、通过x/y坐标对点进行排序,并从当前BEV投影窗口开始/结束坐标中查询点,之后将删除处理过的点以减少后续数据处理量

3、单个滑动窗口中的点,我们通过积分x/y坐标将点映射到像素

3D重映射,我们存储每个投影窗口的绝对x/y坐标,并使用主题查询原始大规模点云中的提取位置以获得2D分割输出。对应于相同像素的点将被赋值为与像素相同的类

 

D.最大值多模态分割

通过BEV投影的高度和RGB图像,我们可以利用多模态网络从数据的不同方面进行学习。为了快速开发一个合适的模型,我们考虑一个编码器-解码器网络UNet作为我们的基线,不仅因为它的流行模型架构,而且因为它在修改,训练和推理方面的效率。它包括编码器中的4个块和解码器中的5个块,其中两个是ResNet-34块,最后四层使用转置卷积,其余是卷积块。所有卷积块都有一个批量归一化层和一个ReLU层,所有内核大小都是3x 3。编码器中的每个块都用虚线链接到解码器中的相应块,该虚线将它们的输出连接起来以检索低级特征。

通常,多模态融合依赖于各层中的特征通信。在此基础上,提出了一种灵活的多级融合网络,支持不同时间、不同地点的多管道数据融合。熔合层包括若干恒定形状的熔合块。每个块接受来自两个管道的两个相等形状的张量,并采用注意力层从连接的特征图中选择关键通道。以这种方式,熔合块倾向于丢弃不相关的特征,并且熔合在随后的层中容易被激活的那些特征。对于注意力块,我们参考我们以前的工作??,提出了一种用于语义分割的跨通道多模态融合注意块。之后,我们添加1x1卷积以降低维度,并针对图像特征和融合特征、海拔特征和融合特征重复这样的融合块。重要的是外块保持特征图的恒定形状,这意味着我们可以根据需要堆叠具有各种网络形状的无限块。

  • 实验

 A setup 

数据集:SensatUrban [3]在英国3个大城市采集,包含2847M个点,覆盖真实的世界7.64× 106m2的面积,是目前最大的3D点云数据集。在获得无人机拍摄的区域图像序列后,从这些图像重建SensatUrban点云数据集。它包含13个语义类,包括地面、建筑物、交通道路等大类和自行车、铁路、桥梁等小类。在实验中,37个点云用于训练,6个点云用于测试。每个点包含三维坐标、RGB颜色和语义类的特征。请注意,由于缺乏测试集标签,我们将训练集随机分为4:1,使用80%的数据进行训练,使用20%的数据进行测试。所有测试数据都不用于训练。

度量:我们将我们的模型与几个使用不同方法(例如,基于点的方法、基于投影的方法等)并且最近出版。选择平均IoU(mIoU)和总体准确度(OA)作为评价指标。

实施情况:我们在训练中使用交叉熵作为损失函数。考虑到不同类间的不平衡性,我们使用对数倒数权值来调整学习中的损失。我们将批处理大小设置为8,将输入大小设置为投影大小500 x500。我们的模型在两个GPU上训练,RTX 3090具有24 G RAM和E5- 2678 v3 CPU。此外,我们使用以下软件设置:Ubuntu 16.04 64位操作系统,Python 3.6,gcc5.4.0,PyTorch 1.7与CUDA 11.0硬件加速。

B. Results

我们使用三个主干实现了我们的模型,UNet和ResNet34,Deeplabv3和ResNet101,OCRNet和HRNet。最后两个模型被训练以探索在我们的BEV分割框架下的潜在性能。我们在表I中展示了分割结果(重新映射到3D点云并在3D中进行评估)。与现有的模型相比,我们的模型可以实现相当有竞争力的结果,在大多数classed和整体performancee在OA,mAcc,和mIoU。缺点是我们的BEV分割仍然无法识别一些小物体,如自行车,因为它们在投影图像中占用的像素也非常有限。在未来的工作中,融合3D和我们的BEV模型可能会解决这个问题。可视化如图5所示。

  • CONCLUSION

针对大规模无人机点云数据稀疏、处理负担重的问题,设计了一种大规模无人机点云数据预处理方法,即将三维点云投影到密集的鸟瞰图上。此外,我们还提出了一种基于注意力的多模态融合网络来分割生成的二维图像,充分利用RGB颜色和几何信息。我们在SensatUrban数据集上获得了61.17%的mIoU和91.37%的OverallAccuracy测试结果。我们希望我们的工作可以启发大规模的点云语义分割任务。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/36571.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

1.SpringMVC接收请求参数及数据回显:前端url地址栏传递参数通过转发显示在网页

1、SpringMVC 处理前端提交的数据 1.1 提交的域名和处理方法的参数不一致,使用注解解决 1.2 提交的域名和处理方法的参数不一致,使用注解解决 1.3 提交的是一个对象 2、前端url地址栏传递的是一个参数 请求地址url:http://localhost:8080/s…

测试开发工程师到底是做什么的?

一二三线互联网公司对测试开发工程师的要求: 现在很多测试的同事对测试开发工程师的认识都有一定的误差。 我最早在阿里的时候和测试开发工程师沟通的时候,发现阿里的测试开发工程师,他们基本上都分为两种,一种是业务类型的&…

Python基础教程: json序列化详细用法介绍

前言 嗨喽,大家好呀~这里是爱看美女的茜茜呐 Python内置的json模块提供了非常完善的对象到JSON格式的转换。 废话不多说,我们先看看如何把Python对象变成一个JSON: d dict(nameKaven, age17, sexMale) print(json.dumps(d)) # {"na…

【Linux】环境变量

目录 一、环境变量的概念二、 常见的环境变量1.查看环境变量的方法2.PATH3.HOME4.SHELL 三、环境变量的相关指令四、命令行参数 一、环境变量的概念 环境变量(environment variables)一般是指在操作系统中用来指定操作系统运行环境的一些参数 如:我们在编写C/C代码的…

Prometheus技术文档-基本使用-配置文件全解!!!!!

简介: Prometheus是一个开源的系统监控和告警系统,由Google的BorgMon监控系统发展而来。它主要用于监控和度量各种时间序列数据,比如系统性能、网络延迟、应用程序错误等。Prometheus通过采集监控数据并存储在时间序列数据库中,…

【视频】使用OBS将MP4推流至腾讯云直播

1、下载OBS OBS官网:https://obsproject.com/ OBS支持Win、Mac、Linux,如果下载速度很慢,建议使用迅雷下载 2、OBS推流设置 2.1 添加场景 默认会有一个“场景”,如果想继续添加可以点击“+”按钮 2.2 添加媒体源 1)点击“来源”窗口中“+”按钮 2)支持的媒体源如…

安装Tomac服务器——安装步骤以及易出现问题的解决方法

文章目录 前言 一、下载Tomcat及解压 1、选择下载版本(本文选择tomcat 8版本为例) 2、解压安装包 二、配置环境 1、在电脑搜索栏里面搜索环境变量即可 2、点击高级系统设置->环境变量->新建系统变量 1) 新建系统变量,变量名为…

【学会动态规划】最大子数组和(19)

目录 动态规划怎么学? 1. 题目解析 2. 算法原理 1. 状态表示 2. 状态转移方程 3. 初始化 4. 填表顺序 5. 返回值 3. 代码编写 写在最后: 动态规划怎么学? 学习一个算法没有捷径,更何况是学习动态规划, 跟我…

Linux:Shell编辑之文本处理器(sed)

目录 绪论 1、sed的原理:读取 执行 显示 三个过程 2、sed 文本内容处理工具,文件过大怎么办? 3、sed的操作选项 3.1 常用选项 3.2 操作符 3.3 行号的范围打印 3.4 对包含指定字符串的内容进行打印 3.5 删 3.5.1 正则表达式删除 3.6…

深入浅出 栈和队列(附加循环队列、双端队列)

栈和队列 一、栈 概念与特性二、Stack 集合类及模拟实现1、Java集合中的 Stack2、Stack 模拟实现 三、栈、虚拟机栈、栈帧有什么区别?四、队列 概念与特性五、Queue集合类及模拟实现1、Queue的底层结构(1)顺序结构(2)链…

Golang-使用 gvm 进行版本控制

当你想为每个项目切换 go 版本时,gvm (Go Version Manager) 很方便。 这里,我将介绍“如何在Mac上安装gvm”和“如何使用gvm” 使用准备 仅适用于 Mac 的准备工作 按照MacOSX 要求中的说明执行以下命令。 xcode-select --install brew update brew …

C++(Qt)软件调试---将调试工具安装到AeDebug(11)

C(Qt)软件调试—将调试工具安装到AeDebug(11) 文章目录 C(Qt)软件调试---将调试工具安装到AeDebug(11)1、前言1.1 使用的调试工具 2、调试器安装1.1 WinDbg1.2 procdump1.3 DrMinGW1.4 vsjitdebugger 更多精彩内容👉个…

深入了解Linux运维的重要性与最佳实践

Linux作为开源操作系统的代表,在企业级环境中的应用越来越广泛。而在保障Linux系统的正常运行和管理方面,Linux运维显得尤为关键。本文将介绍Linux运维的重要性以及一些最佳实践,帮助读者更好地了解和掌握Linux系统的运维技巧。 首先&#xf…

OPENCV C++(十)gramm矫正+直方图均衡化

两者都是只对单通道使用,对多通道的话 就需要分离通道处理再合并通道 两种方法,第一个要运算次数太多了,第二个只需要查表 伽马矫正函数,这里用第二种方法,且写法有点高级 int gammaCorrection(cv::Mat srcMat, cv::…

Java【Spring】使用注解, 更简单的存储和获取 Bean

文章目录 前言一、存储 Bean1, 配置文件2, 五大类注解Bean 的命名规则 3, 方法注解Bean 的命名规则 二、获取 Bean1, 属性注入2, Setter 注入3, 构造方法注入4, Autowired 和 Resource 的区别5, 同一个类型的多个 Bean 注入问题 总结 前言 各位读者好, 我是小陈, 这是我的个人主…

【网络基础实战之路】实现RIP协议与OSPF协议间路由交流的实战详解

系列文章传送门: 【网络基础实战之路】设计网络划分的实战详解 【网络基础实战之路】一文弄懂TCP的三次握手与四次断开 【网络基础实战之路】基于MGRE多点协议的实战详解 【网络基础实战之路】基于OSPF协议建立两个MGRE网络的实验详解 PS:本要求基于…

FreeRTOS(任务通知)

资料来源于硬件家园:资料汇总 - FreeRTOS实时操作系统课程(多任务管理) 目录 一、任务通知的概念 1、概念 2、发送通知给任务的方式 3、任务通知使用限制 二、任务通知的运行机制 三、任务通知的API函数 1、任务通知的数据结构 2、常用的API函数 3、函数x…

opencv实战项目 手势识别-实现尺寸缩放效果

手势识别系列文章目录 手势识别是一种人机交互技术,通过识别人的手势动作,从而实现对计算机、智能手机、智能电视等设备的操作和控制。 1. opencv实现手部追踪(定位手部关键点) 2.opencv实战项目 实现手势跟踪并返回位置信息&…

基于低代码和数字孪生技术的电力运维平台设计

电力能源服务商在为用能企业提供线上服务的时候,不可避免要面对用能企业的各种个性化需求。如果这些需求和想法都要靠平台厂家研发人员来实现,那在周期、成本、效果上都将是无法满足服务运营需要的,这也是目前很多线上能源云平台应用效果不理…

【状态模式】拯救if-else堆出来的屎山代码

前言 我想大家平时都在开发重都遇见过屎山代码,这些屎山代码一般都是由于复杂且庞大的if-else造成的,状态模式,是一种很好的优化屎山代码的设计模式,本文将采用两个业务场景的示例来讲解如何使用状态模式拯救屎山代码。 目录 前…