两阶段目标检测——RoI Pooling与RoIAlign特征提取详解

下面详细讲 RoI Pooling / RoIAlign 是如何提取候选框特征的

它们解决的核心问题是:

RPN 生成的候选框大小各不相同,但后面的分类器/检测头要求输入是固定大小的特征。

所以 RoI Pooling / RoIAlign 的作用就是:

从共享特征图中,把每个候选框对应的区域"裁出来",并转换成固定尺寸的特征,比如 7×7×C


1. 为什么需要 RoI 特征提取?

假设 RPN 生成了 3 个候选框:

text 复制代码
proposal A:100 × 80
proposal B:240 × 160
proposal C:50 × 120

它们大小不同。

但是后面的检测头通常希望输入固定尺寸,比如:

text 复制代码
7 × 7 × C

其中:

text 复制代码
7 × 7:固定空间大小
C:通道数,比如 256、512、1024

如果不统一尺寸,后面的全连接层或分类头无法批量处理这些 proposal。

所以需要一种操作,把任意大小的候选框区域变成固定大小特征。

这就是:

text 复制代码
RoI Pooling / RoIAlign

2. RoI 是什么?

RoI 是 Region of Interest,中文叫"感兴趣区域"。

在两阶段目标检测中:

text 复制代码
RPN 生成的 proposal
   ↓
作为 RoI
   ↓
送入 RoI Pooling / RoIAlign

也就是说,每一个候选框就是一个 RoI。

例如:

text 复制代码
RoI 1:可能是一只猫
RoI 2:可能是一辆车
RoI 3:可能是背景

RoI Pooling / RoIAlign 要做的是:

在 backbone 生成的共享特征图上,取出每个 RoI 对应的局部特征。


3. 整体流程

以 Faster R-CNN 为例:

text 复制代码
输入图像
   ↓
Backbone 提取共享特征图
   ↓
RPN 生成 proposals
   ↓
将 proposals 映射到特征图上
   ↓
RoI Pooling / RoIAlign 提取固定大小特征
   ↓
检测头分类 + 边框回归

注意:RoI Pooling / RoIAlign 不是在原图像素上裁剪,而是在 特征图 上裁剪。


4. 原图坐标如何映射到特征图?

RPN 生成的 proposal 通常是原图坐标,例如:

text 复制代码
原图大小:800 × 600
proposal:[x1=160, y1=120, x2=480, y2=360]

但是 backbone 输出的特征图可能比原图小很多,比如下采样 16 倍:

text 复制代码
原图:800 × 600
特征图:50 × 38
stride = 16

那么原图上的 proposal 要映射到特征图上:

text 复制代码
x1' = x1 / 16 = 160 / 16 = 10
y1' = y1 / 16 = 120 / 16 = 7.5
x2' = x2 / 16 = 480 / 16 = 30
y2' = y2 / 16 = 360 / 16 = 22.5

所以在特征图上的 RoI 大约是:

text 复制代码
[10, 7.5, 30, 22.5]

问题来了:特征图上的坐标可能是小数。

这正是 RoI Pooling 和 RoIAlign 的重要区别之一。


5. RoI Pooling 怎么做?

RoI Pooling 的目标是把任意大小的 RoI 转换成固定大小。

比如固定输出:

text 复制代码
7 × 7 × C

它的步骤可以分成 4 步。


5.1 第一步:把 proposal 映射到特征图

假设原图中的 proposal 映射到特征图后是:

text 复制代码
左上角:(10.2, 7.6)
右下角:(30.8, 22.4)

RoI Pooling 会先做量化,也就是取整:

text 复制代码
左上角:(10, 8)
右下角:(31, 22)

这一步会产生一定位置误差。


5.2 第二步:把 RoI 区域划分成固定数量的 bin

如果目标输出是:

text 复制代码
7 × 7

那么 RoI Pooling 会把这个 RoI 区域划分成:

text 复制代码
7 行 × 7 列 = 49 个小格子

每个小格子叫一个 bin

可以想象成把候选框区域切成 49 块:

text 复制代码
+---+---+---+---+---+---+---+
| 1 | 2 | 3 | 4 | 5 | 6 | 7 |
+---+---+---+---+---+---+---+
| 8 | 9 |10 |11 |12 |13 |14 |
+---+---+---+---+---+---+---+
| ...                         |
+---+---+---+---+---+---+---+
|43 |44 |45 |46 |47 |48 |49 |
+---+---+---+---+---+---+---+

不管原来的 RoI 是大是小,都会被切成 7×7 个 bin。


5.3 第三步:每个 bin 内做池化

在每个 bin 里面,对特征值做池化。

最常见的是 max pooling

也就是说:

text 复制代码
每个 bin 中取最大值

对于每一个通道都这样做。

如果特征图有 C 个通道,那么每个 bin 会得到 C 个值。

最终 49 个 bin 得到:

text 复制代码
7 × 7 × C

这就是该 RoI 的固定大小特征。


5.4 第四步:送入检测头

得到固定大小特征后,检测头就可以处理了:

text 复制代码
RoI 特征:7 × 7 × C
   ↓
分类分支
   ↓
判断类别:猫 / 狗 / 车 / 背景

RoI 特征:7 × 7 × C
   ↓
回归分支
   ↓
精修边界框

6. RoI Pooling 的核心问题:量化误差

RoI Pooling 最大的问题是:它会多次取整

主要有两个地方会量化:

text 复制代码
1. proposal 坐标映射到特征图时取整
2. RoI 划分成 bin 时,bin 边界也可能取整

例如原本特征图坐标是:

text 复制代码
[10.2, 7.6, 30.8, 22.4]

RoI Pooling 会变成:

text 复制代码
[10, 8, 31, 22]

看起来误差不大,但映射回原图后,因为 stride 可能是 16 或 32,误差会被放大。

例如特征图上差 1 个像素,原图可能差:

text 复制代码
16 个像素

对于普通目标检测,这种误差可能还可以接受;但对于实例分割、关键点检测这种需要精确对齐的任务,误差就比较明显。


7. RoIAlign 怎么做?

RoIAlign 是 Mask R-CNN 提出的改进。

它的核心思想是:

不再粗暴取整,而是保留浮点坐标,用双线性插值精确采样。

RoIAlign 的目标和 RoI Pooling 一样:

text 复制代码
把任意大小 RoI 转换成固定大小特征

比如:

text 复制代码
7 × 7 × C

但实现方式更精细。


8. RoIAlign 的步骤

8.1 第一步:保留浮点坐标

假设 RoI 映射到特征图后是:

text 复制代码
[10.2, 7.6, 30.8, 22.4]

RoI Pooling 会取整。

但 RoIAlign 不取整,直接保留:

text 复制代码
[10.2, 7.6, 30.8, 22.4]

这一步就是所谓的 align

它保证 RoI 在特征图上的位置和原图位置更精确对应。


8.2 第二步:划分成固定数量的 bin

和 RoI Pooling 类似,如果输出是:

text 复制代码
7 × 7

RoIAlign 也会把 RoI 划分成:

text 复制代码
7 × 7 个 bin

但 bin 的边界也可以是小数。

例如某个 bin 的范围可能是:

text 复制代码
x: 10.2 到 13.14
y: 7.6 到 9.71

它不会强制取整成整数边界。


8.3 第三步:在每个 bin 内采样

RoIAlign 不直接对整数网格区域做 max pooling。

它会在每个 bin 中选取若干个采样点。

例如每个 bin 采样 2×2 个点:

text 复制代码
bin 内采样点:
p1, p2
p3, p4

这些采样点的位置通常也是小数坐标。

例如:

text 复制代码
(11.3, 8.1)
(12.7, 8.1)
(11.3, 9.2)
(12.7, 9.2)

8.4 第四步:双线性插值

问题是:特征图只在整数网格点上有值。

比如特征图上有:

text 复制代码
(11, 8)
(12, 8)
(11, 9)
(12, 9)

但 RoIAlign 想取的位置可能是:

text 复制代码
(11.3, 8.6)

这个位置没有直接的特征值。

怎么办?

使用 双线性插值

它会根据周围 4 个整数点的特征值,按距离加权算出小数点位置的特征值。

可以理解为:

text 复制代码
离哪个点近,哪个点贡献更大
离哪个点远,哪个点贡献更小

比如采样点更靠近 (11, 9),那 (11, 9) 的特征值权重就更大。


8.5 第五步:聚合采样点

每个 bin 中有多个采样点,每个采样点通过双线性插值得到特征值。

然后 RoIAlign 会把这些采样点的值聚合起来。

常见方式是:

text 复制代码
平均池化

或者某些实现中使用最大池化。

最终每个 bin 输出一个特征值,每个通道都这样做。

最后得到:

text 复制代码
7 × 7 × C

9. RoI Pooling 和 RoIAlign 的区别

最核心区别是:

RoI Pooling 会取整,RoIAlign 不取整。

对比项 RoI Pooling RoIAlign
坐标处理 会量化取整 保留浮点坐标
bin 边界 通常取整 不取整
采样方式 对整数区域池化 对浮点位置采样
特征获取 max pooling 双线性插值 + 聚合
对齐精度 较低 更高
常见模型 Fast R-CNN / Faster R-CNN Mask R-CNN
对分割任务 不够精细 更适合

一句话总结:

text 复制代码
RoI Pooling 是"粗略裁剪 + 池化"
RoIAlign 是"精确对齐 + 插值采样"

10. 一个具体例子

假设某个 proposal 在原图上是:

text 复制代码
[x1=160, y1=96, x2=416, y2=352]

backbone 的 stride 是 16。

映射到特征图:

text 复制代码
[x1'=10, y1'=6, x2'=26, y2'=22]

这个 RoI 在特征图上大小是:

text 复制代码
宽:16
高:16

如果输出是:

text 复制代码
4 × 4

那么每个 bin 大小就是:

text 复制代码
宽:16 / 4 = 4
高:16 / 4 = 4

RoI Pooling 会在每个 4×4 的区域里做 max pooling,最后得到:

text 复制代码
4 × 4 × C

如果这个 RoI 坐标刚好都是整数,RoI Pooling 和 RoIAlign 的差距可能不大。

但如果 RoI 是:

text 复制代码
[x1'=10.3, y1'=6.7, x2'=26.8, y2'=22.2]

RoI Pooling 会取整,RoIAlign 不取整。

RoIAlign 会在更准确的小数位置采样,所以对齐更精确。


11. 为什么叫 Align?

因为它要解决的是 特征和原图之间的错位问题

在目标检测中,候选框来自原图坐标,而特征来自下采样后的特征图。

如果映射和池化时不断取整,就会导致:

text 复制代码
原图中的目标位置
和
特征图中提取的位置
不完全对齐

这种错位对检测框可能影响不算特别大,但对 mask 影响很大。

比如实例分割要判断每个像素属于不属于目标:

text 复制代码
猫的边缘
人的轮廓
车的边界

如果 RoI 特征和原图位置没有对齐,预测出来的 mask 边缘就可能偏移。

RoIAlign 的目的就是:

text 复制代码
让 RoI 特征和原图目标位置更准确对齐

12. RoIAlign 为什么对 Mask R-CNN 很重要?

Mask R-CNN 不仅要预测框,还要预测每个目标的像素级 mask。

检测框只需要大概框住目标即可,但 mask 需要更精确的空间信息。

如果使用 RoI Pooling:

text 复制代码
候选框位置被取整
bin 边界被取整
特征和原图产生偏移

mask 分支就会受到影响。

RoIAlign 通过:

text 复制代码
不取整
浮点坐标
双线性插值

保留了更准确的空间位置信息,因此实例分割效果明显更好。


13. RoI Pooling / RoIAlign 输出的特征长什么样?

假设 backbone 输出特征图是:

text 复制代码
50 × 38 × 256

RPN 生成了 300 个 proposal。

RoIAlign 输出大小设为:

text 复制代码
7 × 7

那么输出就是:

text 复制代码
300 × 7 × 7 × 256

含义是:

text 复制代码
300:有 300 个候选框
7 × 7:每个候选框被统一成固定空间大小
256:每个位置有 256 维特征

然后检测头会对每个候选框的 7×7×256 特征进行分类和回归。


14. RoI 特征提取后的检测头怎么用?

得到 RoI 特征后,通常有两种处理方式。

Faster R-CNN 检测头

常见流程:

text 复制代码
RoI 特征:7 × 7 × C
   ↓
flatten
   ↓
全连接层
   ↓
分类输出
   ↓
边框回归输出

输出包括:

text 复制代码
类别概率
边框偏移量

Mask R-CNN 检测头

Mask R-CNN 会有多个分支:

text 复制代码
RoIAlign 特征
   ├── 分类分支
   ├── 边框回归分支
   └── mask 分支

其中 mask 分支通常会使用更高分辨率的 RoI 特征,比如:

text 复制代码
14 × 14

或者经过反卷积上采样后得到:

text 复制代码
28 × 28

用于预测每个实例的二值 mask。


15. 用类比理解

可以把 RoI Pooling / RoIAlign 想象成从地图上裁剪区域。

RoI Pooling

像是:

text 复制代码
先把目标区域的坐标四舍五入到网格线上
再裁剪
再压缩成固定大小

好处是简单快。

坏处是:

text 复制代码
位置可能有偏差
边缘不够精细

RoIAlign

像是:

text 复制代码
不强行对齐到整数网格
而是保留精确坐标
在小数位置通过插值读取信息

好处是位置更准。

尤其适合:

text 复制代码
实例分割
关键点检测
高精度定位

16. 最简总结

RoI Pooling / RoIAlign 都是为了:

把不同大小的候选框区域,转换成固定大小的特征,供第二阶段检测头分类和边框回归使用。

区别是:

text 复制代码
RoI Pooling:
候选框坐标和 bin 边界会取整,使用 max pooling,速度快但有量化误差。

RoIAlign:
不取整,保留浮点坐标,使用双线性插值采样,空间对齐更准确。

在现代两阶段检测器中,尤其是 Mask R-CNN 及其后续模型里,通常更倾向使用:

text 复制代码
RoIAlign

因为它能更好地保持候选框和特征之间的位置对齐。

RoI Pooling 与 RoIAlign:两阶段目标检测中的特征提取核心

相关推荐
oioihoii3 小时前
我的第一次移动端 AI 办公:在地铁上把 Bug 修了
人工智能·bug
_Evan_Yao3 小时前
从 select 到 epoll,再到 Agent 循环:如何用 I/O 多路复用撑起千军万马?
java·数据库·人工智能·后端
数智工坊3 小时前
面向具身操作的视觉-语言-动作模型:让机器人真正理解并执行人类指令
论文阅读·人工智能·算法·机器人
xwz小王子3 小时前
首个VAM RL后训练框架:VAMPO如何优化机器人操作的视觉动态
大数据·人工智能·机器人
GISer_Jing3 小时前
从前端到AI Agent工程师:技能升级与职业跃迁指南
前端·人工智能·ai编程
Kingairy3 小时前
主流AI 七层关系:Token→提示词→上下文→Agent→Harness→MCP→Skills
人工智能·测试工具
筠筠喵呜喵3 小时前
保姆教程:基于Copilot构建AI Agent
人工智能·copilot
莱图加机械加工3 小时前
人形机器人迈向量产:国产精密制造的突破口
人工智能·机器人·制造·精密零件加工·莱图加·机器人执行器定制·灵巧手零件加工
Yuk丶3 小时前
LPM的AI 角色三大核心技术实现:长效记忆、人格锁定、低延迟口语化
人工智能·ai·ue4·虚幻·ue4客户端开发