拍全家福需要什么?要有山、树、天空做背景,也要让爷爷奶奶、孩子每个人坐在该在的位置。如果只拍背景不拍人,或者只拍人不拍背景,那都算不上完整的全家福。图像分割领域也是一样:语义分割只看“这是什么类别的像素”,实例分割只看“这个目标是谁”,而全景分割(Panoptic Segmentation)要一次把两件事都做好——既要像素级地识别天空、道路、草地这些“背景”,也要给每一辆车、每一个人单独编号。它就是给图像拍一张“全家福”。 这篇讲解带你认识全景分割的任务定义、核心概念 stuff 与 thing、评价指标 PQ、经典结构 Panoptic FPN 与 UPSNet,以及它在自动驾驶等场景中的真实应用。你会发现全景分割不是两个任务的简单拼接,而是一套精心设计的统一建模方案。

岗位关联

对 AI 从业者而言,全景分割是目标检测、语义分割与实例分割的综合练兵场,掌握它是进入自动驾驶感知、机器人视觉等方向的硬核加分项。

目录
  1. 可视化演示
  2. 全景分割任务定义
  3. stuff与thing概念
  4. 全景分割核心挑战
  5. PQ评价指标详解
  6. PQ分解与解读
  7. Panoptic FPN结构
  8. UPSNet演进
  9. 全景分割应用落地
  10. AI 应用场景
  11. Python 演示
  12. 常见误区
  13. 面试题

可视化演示

展示全景分割如何统一Stuff背景与Things实例,切换模式观察双分支网络架构与PQ评估指标的构成。

本节配有交互动效(进入视口后自动加载,约 3KB)。

全景分割统一框架 Stuff背景区域(天空/道路/草地)与Things实例(人/车)统一在一张图中标注 每个像素既要有语义类别又有实例ID,实现最完整场景理解 Panoptic = Stuff + Things 全景分割是语义分割与实例分割的集大成者

全景分割任务定义

很多刚入门的人会问:语义分割和实例分割都做了很多年,为什么还要搞一个“全景分割”?回到全家福的比喻:如果只拍风景(语义分割),你能知道背景里有天空和道路,但看不出人群里谁是谁;如果只拍人物特写(实例分割),你能认出每位亲友,但背景全丢了。全家福的意义在于“背景+人物”一次拍齐,全景分割要的正是这个完整画面。

从技术角度看,语义分割为每个像素打一个类别标签;实例分割则为每个 thing 类目标预测一个类别与掩码,但它不关心背景。全景分割把两者统一成一个输出形式:对图像中每一个像素输出“类别 + 实例编号”,并且要求这些区域互不重叠、无空白。这个任务定义看似简单,实则把所有像素都纳入统一的预测责任范围,因此被看作分割任务的“终极形态”。

在数学上,语义分割的输入是一张图像,输出是每个像素的类别;实例分割的输出是一组“类别 + 掩码”;全景分割则是两者合并成一个统一的像素级表示。三个任务的关系可以用下面的式子对照:

所以,全景分割像是摄影师拿出两张底片——一张标出天空和道路,一张标出每辆车和每个人——最后由同一个人把它们拼成一张不留空隙的全家福。这个“由同一个人来拼”正是全景分割区别于“两个任务分开跑”的关键。

语义分割: fsem(I)→{cp}p∈Ω,cp∈C实例分割: fins(I)→{(c^k,m^k)}k=1K全景分割: fpan(I)→{(cp,idp)}p∈Ω,全局无重叠\begin{aligned}\text{语义分割: } & f_{sem}(I) \to \{ c_p \}_{p \in \Omega}, \quad c_p \in \mathcal{C} \\\text{实例分割: } & f_{ins}(I) \to \{ (\hat{c}_k, \hat{m}_k) \}_{k=1}^{K} \\\text{全景分割: } & f_{pan}(I) \to \{ (c_p, id_p) \}_{p \in \Omega}, \quad \text{全局无重叠}\end{aligned}
语义分割只回答“像素是什么类”,实例分割只回答“某个 thing 目标在哪”,全景分割同时回答“每个像素属于什么类、是否是一个独立实例”。
  1. 像素集合$\Omega$ 表示图像上全部像素位置,语义分割和全景分割都会遍历它。
    Ω={(x,y)∣0≤x<W,0≤y<H}\Omega = \{ (x,y) \mid 0 \le x < W, 0 \le y < H \}
  2. 语义分割输出对每个像素 $p$ 输出一个类别 $c_p$,不区分个体。
    fsem(I)={cp}p∈Ωf_{sem}(I) = \{ c_p \}_{p \in \Omega}
  3. 实例分割输出对第 $k$ 个实例输出类别 $\hat{c}_k$ 与掩码 $\hat{m}_k$,只覆盖 thing 类。
    fins(I)={(c^k,m^k)}k=1Kf_{ins}(I) = \{ (\hat{c}_k, \hat{m}_k) \}_{k=1}^{K}
  4. 全景分割输出像照片一样完整,每个像素带类别和实例编号,全局不重叠、不遗漏。
    fpan(I)={(cp,idp)}p∈Ωf_{pan}(I) = \{ (c_p, id_p) \}_{p \in \Omega}

stuff与thing概念

拍全家福时,你几乎从不会数背景里有几棵树(背景就是背景,多一棵少一棵无人在意),但你一定会核对每张照片里有没有漏掉某位家人。这正是 stuff 与 thing 的本质差异:stuff 是不可数、形状不规则的背景区域,thing 是可数、边界相对清晰的目标个体。

在数学上,所有的语义类别被分成两个互斥集合:stuff 集合和 thing 集合。stuff 类别包括天空、道路、草地、墙壁等;thing 类别包括人、车、动物、家具等。这样的划分不是随意的,它意味着两种不同的处理逻辑:stuff 只需要像素级分类,thing 则需要在像素级分类之外再做实例区分,为每个目标分配独立编号。因此,一个像素的标签可以用“类别 + 实例号”来表示,实例号对 stuff 统一为 0,对 thing 则逐个递增。

在全景分割的“摄影棚”里,没有哪个像素是“背景板”可以随便糊弄的。这段“背景清单”贯穿拍摄、后期与质检的全流程:哪些元素要上色,哪些元素要编号,直接决定了后面的网络结构和评价指标走向。

C=Cstuff∪Cthing,Cstuff∩Cthing=∅\mathcal{C} = \mathcal{C}_{\text{stuff}} \cup \mathcal{C}_{\text{thing}}, \qquad \mathcal{C}_{\text{stuff}} \cap \mathcal{C}_{\text{thing}} = \varnothing
所有语义类别构成一个全集,被切成“背景 stuff”与“实例 thing”两个互不相交的子集。
  1. 全集拆分所有类别要么是 stuff 要么是 thing,两者合起来就是全部类别。
    C=Cstuff∪Cthing\mathcal{C} = \mathcal{C}_{\text{stuff}} \cup \mathcal{C}_{\text{thing}}
  2. 互斥性一个类别不可能同时是“背景”又“可数实例”。
    Cstuff∩Cthing=∅\mathcal{C}_{\text{stuff}} \cap \mathcal{C}_{\text{thing}} = \varnothing

全景分割核心挑战

全家福的现场总是“混乱而真实”:人多到站不下、光线差、有人站太远看不清。全景分割也一样,它要处理的是一堆混乱的视觉信号。第一个挑战是统一建模:语义分割和实例分割各有各的损失函数和输出头,如果只是分别训练再拼接,会出现“语义说这是天空、实例说这里有一栋楼”的自相矛盾。第二个是类别不均衡:stuff 类像素通常占图像面积的大多数,thing 类目标数量少但信息密度高,一个平均损失容易被背景“淹没”。

第三个挑战是全局一致性:全景图要求每一个像素都有唯一标签,且不同区域不得重叠,而两个分支各自输出时天然会冲突。第四个小目标问题:远处的人、细小的物体容易被漏检,直接影响全景图的完整度。为解决这些挑战,一个自然的思路是把两个任务放进同一个网络里联合优化,用各自的损失函数共同约束模型参数,再通过后处理合并保证全局无重叠。

拍摄一张完美全家福的难点从来不只是多按一次快门,而是统筹机位、灯光、站位。全景分割的难点也在于统筹两个分支的损失、特征与输出,让“背景”与“人物”在同一个框架下和谐一致,这正是它比单一分割任务更复杂也更强大的原因。

Lpan=λ1Lsem+λ2Lins\mathcal{L}_{\text{pan}} = \lambda_1 \mathcal{L}_{\text{sem}} + \lambda_2 \mathcal{L}_{\text{ins}}
全景训练损失是语义损失与实例损失的加权组合,通过 $\lambda$ 权重来平衡“背景分类”与“实例分割”两个目标。
  1. 语义损失像素级交叉熵,负责把每个像素正确归类。
    Lsem=−∑p∈Ωlog⁡P(yp=cp)\mathcal{L}_{\text{sem}} = -\sum_{p \in \Omega} \log P(y_p = c_p)
  2. 实例损失包含目标分类、边界框回归和掩码分割三项,专注于 thing 类。
    Lins=Lcls+Lbox+Lmask\mathcal{L}_{\text{ins}} = \mathcal{L}_{\text{cls}} + \mathcal{L}_{\text{box}} + \mathcal{L}_{\text{mask}}
  3. 权重平衡$\lambda_1$ 与 $\lambda_2$ 两个超参数协同两种信号,避免某一方主导。
    Lpan=λ1Lsem+λ2Lins\mathcal{L}_{\text{pan}} = \lambda_1 \mathcal{L}_{\text{sem}} + \lambda_2 \mathcal{L}_{\text{ins}}

PQ评价指标详解

照片拍完,怎么向全家人交代“拍得好不好”?你会说“人都齐了,大家也都没闭眼”——这其实已经点出了 PQ 的精髓:既要数量上不漏人,也要质量上拍得清。PQ(Panoptic Quality,全景质量)就是这样一个同时衡量“找没找到”与“切得准不准”的指标。

PQ 的第一步是匹配:预测出来的每个“段”和真实的每个段做 IoU 计算,大于 0.5 就认为配对成功。接着统计三类:配对成功的 TP、预测了但没匹配上的 FP、漏检的 FN。举例来说,假设图里有 3 个真实段,模型预测出 4 个段,其中 2 个配对成功(IoU 分别为 0.8 和 0.7),另外 2 个预测段是 FP,还有 1 个真实段是 FN。于是 PQ = (0.8 + 0.7) / (2 + 0.5×2 + 0.5×1) ≈ 0.43。可以看出,FP 和 FN 都会明显拉低分数。

PQ 是一种可解释性很强的“口碑”:只要漏掉一个人或误报一个不存在的物体,分数就会明显下降;而每个人拍得多清晰,则由 IoU 累积贡献。这就是全景分割质量评估中最公平的一杆秤。

PQ=∑(p,g)∈TPIoU(p,g)∣TP∣+12∣FP∣+12∣FN∣PQ = \frac{\displaystyle \sum_{(p,g) \in TP} \mathrm{IoU}(p,g)}{\displaystyle |TP| + \frac{1}{2}|FP| + \frac{1}{2}|FN|}
PQ 的分母把 FP 和 FN 各按半个权重惩罚,分子累加所有匹配段的 IoU 值;匹配得越多、边界越准,PQ 越高。
  1. 真阳性 TP预测段与真实段重叠超过 0.5 IoU 才视为匹配。
    IoU(p,g)=∣p∩g∣∣p∪g∣>0.5\mathrm{IoU}(p,g) = \frac{|p \cap g|}{|p \cup g|} > 0.5
  2. 假阳性 FP模型“多画”出来的段,会被计入惩罚。
    ∣FP∣=预测段中没有匹配上真实段的数目|FP| = \text{预测段中没有匹配上真实段的数目}
  3. 假阴性 FN模型漏掉的真实段,同样会被计入惩罚。
    ∣FN∣=真实段中没有被预测段匹配的数目|FN| = \text{真实段中没有被预测段匹配的数目}
  4. 分子总和所有匹配对的 IoU 累加,边界越贴合数值越高。
    ∑(p,g)∈TPIoU(p,g)\sum_{(p,g) \in TP} \mathrm{IoU}(p,g)

PQ分解与解读

前述 PQ 公式可以拆成两个更直观的因子。有些同学会问:能不能把“人都到齐没有”和“人拍得清楚没有”分开看?答案是可以。分子先除以 TP,得到匹配段的平均 IoU,这是 SQ(分割质量);分母中剩余的比例部分则是 RQ(识别质量),它本质上就是 F1 分数。两者相乘,恰好回到 PQ。

当我们需要诊断一个全景分割模型“差在哪里”时,就可以看 RQ 和 SQ 各自的表现:RQ 低说明漏检误检严重,模型“没找到人”;SQ 低说明边界粗糙,模型“找到了人但切得不齐”。这种可解释性让 RQ 和 SQ 成为论文和工程中几乎必附的指标。

好的全家福 = 每个人都到场(高 RQ)× 每个人都清晰(高 SQ)。如果只按人数评判而不顾清晰度,或只夸清晰却漏掉了人,这张照片都算不上好。两者相乘、缺一不可,这就是 PQ 分解给我们的工程直觉。

PQ=∑(p,g)∈TPIoU(p,g)∣TP∣⏟SQ×∣TP∣∣TP∣+12∣FP∣+12∣FN∣⏟RQPQ = \underbrace{\frac{\displaystyle \sum_{(p,g) \in TP} \mathrm{IoU}(p,g)}{|TP|}}_{SQ} \times \underbrace{\frac{|TP|}{|TP| + \frac{1}{2}|FP| + \frac{1}{2}|FN|}}_{RQ}
SQ 回答“匹配上的区域边界有多准”,RQ 回答“有多少实例被正确找到”,二者相乘得到全景质量。
  1. 分割质量 SQ先只看已经配对成功的段,求它们 IoU 的平均。
    SQ=1∣TP∣∑(p,g)∈TPIoU(p,g)SQ = \frac{1}{|TP|} \sum_{(p,g) \in TP} \mathrm{IoU}(p,g)
  2. 识别质量 RQ与目标检测的 F1 同理,同时惩罚漏检与误检。
    RQ=∣TP∣∣TP∣+12∣FP∣+12∣FN∣RQ = \frac{|TP|}{|TP| + \frac{1}{2}|FP| + \frac{1}{2}|FN|}
  3. 两者相乘PQ 等于 SQ 与 RQ 的乘积,任何一方落后都会拉低整体。
    PQ=SQ×RQPQ = SQ \times RQ

Panoptic FPN结构

把任务想清楚后,就需要一个能“拍全景”的框架。Panoptic FPN 是 2019 年提出的经典全景分割网络,它的设计巧思可以概括为“一台相机,两条光影”:共享一个 FPN(特征金字塔网络)作为骨干,再引出两个分支,一个负责 stuff 区域的语义分割,一个负责 thing 区域的实例分割。

两条分支共享骨干特征,因此计算高效,也能互相利用特征信息。但对最终输出而言,还需要一种机制把它们合成一张“无重叠的全景图”。于是 Panoptic FPN 使用了区域合并算法:每个候选段有一个置信分数,将候选段按分数从高到低排序,分数高的先被写入全景图,后写入的只在空白区域生效。这就像修图时先把最重要的主体定好位置,再把背景天与道路填满剩余之处。

Panoptic FPN 的合并策略像极了摄影师后期修图:先把最重要的主体(高分数段)定好位置,再把背景天与道路填满剩余之处,所有元素各就其位,互不遮挡。这个“先重要、后背景”的顺序,保证了全景图的全局一致。

π=sortdesc({sk}),按 π 顺序写入全图\pi = \mathrm{sort}_{\mathrm{desc}}(\{s_k\}), \quad \text{按 } \pi \text{ 顺序写入全图}
区域合并算法将候选段按置信度从高到低排序,高置信度段优先占位,避免重复覆盖。
  1. 候选段得分每个区域 $k$ 都有置信度 $s_k$,它等于类别概率乘掩码概率。
    sk=Pcls(k)×Pmask(k)s_k = P_{\text{cls}}(k) \times P_{\text{mask}}(k)
  2. 降序排列从高到低排序所有候选段,得到写入顺序 $\pi$。
    π=sortdesc({sk})\pi = \mathrm{sort}_{\mathrm{desc}}(\{s_k\})
  3. 顺序写入按 $\pi$ 把区域依次填充到全景图,重叠部分归先写入者。
    全景图=⋃k∈π区域k,重叠处先写者胜\text{全景图} = \bigcup_{k \in \pi} \text{区域}_k, \quad \text{重叠处先写者胜}

UPSNet演进

Panoptic FPN 虽经典,但两条分支毕竟占用两套计算资源。UPSNet 尝试“一位摄影师拿一台相机就够了”:在共享主干的思路下,UPSNet 将语义分支特征与实例分支特征拼接在一起,用一个可变形卷积模块做特征融合。可变形卷积最大的特点在于:它的卷积核采样点可以随目标外形做自适应偏移,因此分割边界更贴合人、车这类形状多变的 thing。

UPSNet 还有一个关键设计——“统一头部分类”:它让 stuff 与 thing 的分数对齐到同一个分类空间,避免“两个分支说法不一”的问题,使得预测更稳定。论文中还使用 LogSumExp 等技巧,把 thing 分支的多类别分数压缩为前景概率,与 stuff 分支一起做像素级分类。相比 Panoptic FPN,UPSNet 在速度和精度上都有明显提升,体现了全景分割从“双分支并联”走向“单主干统一”的演进方向。

如果 Panoptic FPN 是两个摄影师分工配合,那 UPSNet 就是一个“全能摄影师”——单镜头里巧妙切换焦距(可变形卷积),一次快门就能拍出背景与人物都清晰整齐的全家福。这种“少即是多”的设计思路,也成为后续全景分割网络的重要参考。

Fpan(u)=σ(D([ Fsem(u) ; Fins(u) ]))F_{\text{pan}}(u) = \sigma \left( \mathcal{D} \left( [\, F_{\text{sem}}(u) \,;\, F_{\text{ins}}(u)\, ] \right) \right)
UPSNet 将语义与实例特征拼接后,用可变形卷积融合,最后通过激活函数输出全景分类分数。
  1. 特征拼接将同一位置 $u$ 的语义特征 $F_{\text{sem}}(u)$ 与实例特征 $F_{\text{ins}}(u)$ 拼在一起。
    [ Fsem(u) ; Fins(u) ][\, F_{\text{sem}}(u) \,;\, F_{\text{ins}}(u)\, ]
  2. 可变形卷积$\mathcal{D}$ 的采样点可以自适应偏移,适配目标几何形变。
    D(x)=∑jwj⋅x(u+Δuj)\mathcal{D}(x) = \sum_{j} w_j \cdot x(u + \Delta u_j)
  3. 最终分类通过激活函数 $\sigma$ 输出全景分类分数,score 维度覆盖所有类别。
    Fpan(u)∈R∣C∣F_{\text{pan}}(u) \in \mathbb{R}^{|\mathcal{C}|}

全景分割应用落地

全景分割正在从论文走进真实世界,像“全家福模板”一样被各行各业直接复用。自动驾驶是最典型的落地场景:车辆需要同时识别车道线、路边沿(stuff)以及前方车辆、行人(thing),缺少任何一类信息,规划和控制都可能做出危险判断。工业质检中,生产线的背景传送带、治具(stuff)与产品缺陷(thing)需要同时分割,既能保证不停线,也能精确框出每个瑕疵。

智慧城市的街景分析通过全景分割,可将建筑物立面、天空与树木分离出来,同时枚举每一扇窗户、每一辆车;机器人导航同样依赖它,将房间墙壁、地面与散落的物品统一建模,才能安全地规划路径。可以说,凡是需要“完整场景理解”的视觉任务,全景分割都是一种比单独语义或实例分割更直接、更统一的选择。它让 AI 不再“只见物而不见景”,也不再“只见景而不见物”。

作为图像分割领域的集大成者,全景分割把背景与实例放进同一个建模框架,用 PQ 指标给出统一评价,用 Panoptic FPN 等结构完成实际预测。掌握它的核心思想,不仅是对分割技术的系统梳理,更是理解先进视觉系统的关键一步。

AI 应用场景

自动驾驶的街道全景感知

阶段:感知融合

解决的问题:传统方案把语义分割和实例分割拆成两个模型,输出时间不同步,且类别体系冲突。例如遮挡区域的像素可能同时被“道路”和“车辆”预测占用,给下游规划带来困惑。全景分割用一套统一输出格式解决这个问题,每个像素只有一个标签。

具体案例:某自动驾驶团队将车载摄像头画面输入轻量化全景分割网络,一次性得到“可行驶区域、车道线(stuff)+ 车辆、行人(thing)”的完整语义图层,后端规划模块直接查表判断路径。实测中因分割不一致导致的急刹车次数下降了约 40%。

工业质检:背景与缺陷同框判定

阶段:视觉检测

解决的问题:在电子元件贴片检测中,PCB 板底色、焊盘区域属于 stuff,焊锡缺陷、元件偏移属于 thing。传统模板匹配算法对背景变化极其敏感,而全景分割把背景和缺陷统一建模,能同时输出“缺陷实例”和“背景状态”,大幅减少误报。

具体案例:某半导体厂在晶圆检测中引入全景分割模型,将电路走线作为 stuff、灰尘颗粒作为 thing,系统既能报告颗粒位置,也能判断它是否落在关键线路上,实现从“检出缺陷”到“理解缺陷影响”的升级。

Python 演示

python108 行
"""全景分割极简演示:合成一张"全家福"场景,用连通域算法做语义分割与实例分割,并计算 PQ/RQ/SQ 指标。"""import numpy as np  def create_scene():    """生成 40x40 合成图像:0天空 / 1道路 / 2汽车 / 3行人"""    img = np.zeros((40, 40), dtype=np.int32)    img[:18, :] = 0          # 天空占上 18 行    img[18:, :] = 1          # 道路占下 22 行    img[5:14, 6:16] = 2      # 车 1    img[22:31, 18:27] = 2    # 车 2    img[25:32, 7:12] = 3     # 行人    return img  def split_instances(img):    """对 thing 类别做四连通域编号,stuff 区域编号为 0。"""    h, w = img.shape    ins = np.zeros((h, w), dtype=np.int32)    seen = np.zeros((h, w), dtype=bool)    obj_id = 1    for y in range(h):        for x in range(w):            cls = img[y, x]            if cls not in (2, 3) or seen[y, x]:                continue            stack = [(y, x)]            seen[y, x] = True            while stack:                cy, cx = stack.pop()                ins[cy, cx] = obj_id                for dy, dx in ((-1, 0), (1, 0), (0, -1), (0, 1)):                    ny, nx = cy + dy, cx + dx                    if 0 <= ny < h and 0 <= nx < w and not seen[ny, nx] and img[ny, nx] == cls:                        seen[ny, nx] = True                        stack.append((ny, nx))            obj_id += 1    return ins  def make_prediction(gt):    """模拟一个不完美的分割模型:车 1 缺一角、行人变小。"""    pred = gt.copy()    pred[10:16, 8:14] = 0     # 车 1 车身被削掉一块    pred[27:32, 7:12] = 1     # 行人下部分被预测成道路    return pred  def to_segments(sem, ins):    """把 (类别, 实例号) 映射到像素集合,形成全景分割的段。"""    segs = {}    h, w = sem.shape    for y in range(h):        for x in range(w):            key = (sem[y, x], ins[y, x])            segs.setdefault(key, set()).add((y, x))    return segs  def seg_iou(pa, pb):    inter = len(pa & pb)    union = len(pa) + len(pb) - inter    return inter / union if union else 0.0  def compute_pq(gt_sem, gt_ins, pd_sem, pd_ins, thr=0.5):    """计算 PQ / RQ / SQ,规则:IoU 大于 thr 才算匹配。"""    gt_segs = to_segments(gt_sem, gt_ins)    pd_segs = to_segments(pd_sem, pd_ins)    used = set()    tp_ious = []    for pk, pset in pd_segs.items():        best_key = None        best_iou = thr        for gk, gset in gt_segs.items():            if gk in used or gk[0] != pk[0]:                continue            s = seg_iou(pset, gset)            if s > best_iou:                best_iou = s                best_key = gk        if best_key is not None:            used.add(best_key)            tp_ious.append(best_iou)    tp = len(tp_ious)    fp = len(pd_segs) - tp    fn = len(gt_segs) - tp    sq = sum(tp_ious) / tp if tp else 0.0    rq = tp / (tp + 0.5 * fp + 0.5 * fn)    return sq * rq, rq, sq  def main():    gt = create_scene()    gt_ins = split_instances(gt)    pd = make_prediction(gt)    pd_ins = split_instances(pd)    pq, rq, sq = compute_pq(gt, gt_ins, pd, pd_ins)    print("真实实例数:", len(set(gt_ins.flatten())) - 1)    print("预测实例数:", len(set(pd_ins.flatten())) - 1)    print("PQ=%.3f RQ=%.3f SQ=%.3f" % (pq, rq, sq))  if __name__ == "__main__":    main()
目的:用合成小场景演示“语义分割 + 实例分割 → 全景分割”的流程,并实现 PQ / RQ / SQ 的完整计算。
  1. img[5:14, 6:16] = 2在合成图上放置一辆“车”,用不同数值模拟不同类别。
  2. def split_instances(img):对 thing 类别做四连通域编号,类似给每个“家人”发编号。
  3. stack = [(y, x)]用深度优先搜索把相邻同类像素归入同一个实例。
  4. key = (sem[y, x], ins[y, x])用“类别 + 实例号”组成全景分割中的一个“段”。
  5. if s > best_iou:只有 IoU 超过 0.5 才认为匹配成功,这是 PQ 计算的关键。
  6. rq = tp / (tp + 0.5 * fp + 0.5 * fn)识别质量相当于 F1 分数,同时惩罚漏检与误检。
  7. sq = sum(tp_ious) / tp if tp else 0.0分割质量取匹配段的平均 IoU,衡量边界贴合度。

常见误区

误区代码里同时调用一个语义分割模型和一个实例分割模型,把两个输出简单拼在一起不就算全景分割了吗?

正解这就像让两位摄影师各拍各的,最后拼出来的照片要么重叠、要么有空白。全景分割需要共享特征、联合损失与合并策略来保证全局无重叠、不遗漏,这些只有统一设计的网络才能做到。

为何常见:全景分割的输出看起来确实是“语义结果 + 实例结果”的叠加,直观上很容易理解成并联两个模型。

误区PQ 和 mIoU 一样,都是比较逐像素分类准确率的指标,只是换了个名字。

正解mIoU 是纯像素级操作,而 PQ 先把分割结果按照实例匹配,匹配不上的段(FP/FN)都会被额外惩罚;PQ = RQ × SQ 也说明它同时衡量“找没找到”和“切得准不准”,更像检测与分割的混合指标。

为何常见:两者都出现在分割论文里,都基于 IoU 概念,初学者容易把它们的数学形式混为一谈。

误区背景就是“摆设”,只要车辆、行人等目标不漏检,全景分割任务就算做好了。

正解在自动驾驶里,车道线、路沿都是 stuff,一旦分割错误就会导致越线;PQ 对 stuff 和 thing 平等对待,任一类别漏检都会被扣分。理解场景语义时,背景往往决定“可不可以走”,而实例决定“要不要避开”。

为何常见:人的注意力天然容易被移动物体(thing)吸引,而忽视大面积静态背景,这种认知偏差被带到了任务理解中。

面试题

Q1. 全景分割与语义分割最关键的区别是什么?

单选题 · easy

  • A.全景分割只处理背景区域
  • B.全景分割额外区分实例编号← 正确答案
  • C.语义分割需要实例掩码
  • D.两者在任务上完全一致

答案:B。语义分割只给每个像素一个类别标签,不区分个体;全景分割在类别之外还要给 thing 类目标编号,这是最本质的差异。A 说反了,C 说反,D 明显错误。

Q2. 在全景分割中,以下哪类属于 thing(实例类)?

单选题 · easy

  • A.天空
  • B.道路
  • C.行人← 正确答案
  • D.草地

答案:C。thing 是可数、边界清晰的个体目标,行人符合;天空、道路、草地都属于不可数的 stuff 背景类。

Q3. 计算 PQ 时,预测段与真实段的 IoU 匹配阈值通常取多少?

单选题 · easy

  • A.0.3
  • B.0.5← 正确答案
  • C.0.7
  • D.0.9

答案:B。Panoptic Quality 的通用约定是 IoU > 0.5 视为匹配,0.3 过松、0.7 和 0.9 过严,都不是标准设定。

Q4. 某个预测段没有匹配到任何真实段,PQ 指标将它记作什么?

单选题 · mid

  • A.TP,真阳性
  • B.FP,假阳性← 正确答案
  • C.FN,假阴性
  • D.TN,真阴性

答案:B。模型预测了区域但真实图中不存在对应段,属于“多画出来”的假阳性 FP;FN 是真实存在却漏检,TP 是正确匹配,TN 在 PQ 中不参与统计。

Q5. PQ = RQ × SQ 中,SQ(分割质量)衡量的是什么?

单选题 · mid

  • A.识别质量,衡量漏检误检率
  • B.分割质量,衡量边界贴合度← 正确答案
  • C.分类质量,衡量类别准确率
  • D.检测质量,衡量候选框回归精度

答案:B。SQ 是对所有匹配段求平均 IoU,反映边界是否贴合;RQ 才负责识别与匹配。C 和 D 都不是全景分割的官方因子。

Q6. Panoptic FPN 合并两个分支结果时,按什么顺序写入全景图?

单选题 · mid

  • A.随机顺序填充
  • B.按面积从大到小
  • C.按置信度从高到低← 正确答案
  • D.按类别字典排序

答案:C。区域合并算法将每个候选段的置信度分数从高到低排序,高置信度段优先占位,后写入者只能在空白处生效,以此保证全局无重叠。

Q7. UPSNet 相比 Panoptic FPN 的核心改进是什么?

单选题 · hard

  • A.取消实例分支,只保留语义
  • B.用可变形卷积融合两个分支← 正确答案
  • C.不再使用 FPN 特征金字塔
  • D.只对 stuff 类做像素分类

答案:B。UPSNet 将语义特征与实例特征拼接,并用可变形卷积融合,采样点可自适应偏移,使边界更贴合目标;它还保留两个分支而非取消,因此 A、C、D 均不符合。

Q8. 下列哪些属于 stuff(背景类)?

多选题 · easy

  • A.天空← 正确答案
  • B.汽车
  • C.草地← 正确答案
  • D.行人

答案:AC。stuff 是不可数的背景区域,天空和草地符合;汽车与行人可数且有独立身份,属于 thing 类。

Q9. 关于 PQ 指标,下列说法正确的是?

多选题 · mid

  • A.PQ 越大分割效果越好← 正确答案
  • B.PQ 只关注 thing 类目标
  • C.PQ 兼顾识别与分割← 正确答案
  • D.PQ 值可以小于零

答案:AC。PQ 越大越好,且通过 RQ × SQ 同时体现识别与分割质量;它对 stuff 和 thing 都适用,B 错;PQ 的分子是非负 IoU、分母为正,因此不可能小于零,D 错。

Q10. 关于 PQ = RQ × SQ 的说法,正确的是?

多选题 · extreme

  • A.RQ 等价于 F1-score 指标← 正确答案
  • B.SQ 是匹配段的平均 IoU 值← 正确答案
  • C.FP 与 FN 惩罚权重同为 0.5← 正确答案
  • D.分割质量越高 PQ 一定越高

答案:ABC。RQ = TP / (TP + ½FP + ½FN),分子分母同乘 2 后与 F1 完全一致;SQ 是匹配段 IoU 的平均;分母中 FP、FN 系数均为 0.5。D 错在 PQ = RQ × SQ,RQ 很低时 SQ 再高也无法让 PQ 升高。