想象你收到一条紧急求助:邻居的猫咪“咪咪”走丢了,最后出现在一张城市卫星照片里。你打开照片,街道、楼房、公园尽收眼底,可你盯着屏幕看了十分钟——咪咪呢?它明明在这张图里,但在 1024×768 的照片上,一只猫可能只占 6×6 个像素。凑近屏幕,你看到的只是一团模糊的灰红色。要靠这么一丁点像素认出“这是猫”,还得分辨它到底在哪个街区、哪条巷子里,这就是小目标检测(Small Object Detection)要解决的问题。 整篇讲义就是一个完整的“寻猫作战方案”:先定义“多小才算小”(小目标定义),再分析为什么难找(检测难点),接着搭建不同高度的瞭望台共享信息(FPN 特征金字塔)、放大照片(高分辨率输入)、推理咪咪爱去鱼市和公园(上下文信息),最后把这套方案带到遥感油田、自动驾驶和工业质检的真实战场。你会发现,技术学习和“找一只几个像素大的小猫”竟如此同构。
小目标检测是遥感、自动驾驶、工业质检等场景的核心能力。掌握它,意味着你能处理真实世界中占比最大的长尾场景——本讲义帮你建立从原理到实战的完整直觉。
可视化演示
展示系统处理流水线、实时性能指标曲线及多方案对比分析,包含数据流转、吞吐延迟监控与方案评估。
本节配有交互动效(进入视口后自动加载,约 3KB)。
系统可视化 处理流程:输入→处理→模型→输出 性能监控:实时指标 P=L×T
小目标定义
咪咪到底多小才算“小”?如果它占了半张照片,你一眼就能找到;如果它只有 6×6 像素,就得动用全套技术。所以寻猫任务的第一步,不是找猫,而是先立一把“尺子”:把“小”这个模糊的字眼量化成可以比较的数字。没有这把尺子,研究者之间无法交流,模型效果也无从对比。
计算机视觉界最常用的尺子是 COCO 数据集给出的经验标准:目标面积小于 32×32 像素,就称为小目标。为什么会是 32?因为主流骨干网络经过约 5 次下采样,32 像素的边长刚好能在最高层特征图上保留 1 个有效响应点——再小就连“存在感”都没有了。除了绝对像素,还有相对定义:目标面积占整张图像面积不足 1% 时,也常被视为小目标。
这把尺子还有一个重要刻度:尺度是相对的。同样的咪咪,在近景照片里可能占几百像素,在遥感卫星图里却只有十几个像素;同一辆油罐车,近处拍摄是“大目标”,高空俯瞰就成了“小目标”。所以小目标检测本质上是“成像尺度导致的特征稀缺”问题。
所以当你在卫星图上把咪咪的轮廓框出来,数一数里面有多少像素,就能立刻判断它是不是“小目标”。尺子立好了,下面就该看看为什么小目标这么难找。
- 面积公式目标在图像中占据的像素总数,由目标框的宽和高相乘得到
- 经验阈值COCO 协议以边长 32 像素作为小目标的分界线
- 判定式实际面积小于 1024 个像素时,该目标划入“小目标”范畴
检测难点
咪咪只有几个像素,你要认出“这是猫”,得看清猫耳朵、猫尾巴的轮廓。可这几个像素经过卷积神经网络一层层下采样后,就像把一张照片不断缩小:先是猫眼消失,接着耳朵糊成一团,最后只剩一个难以辨认的点。信息丢得越多,算法就越难回答“这是什么东西”。
现代骨干网络(如 ResNet)通常有 32 倍的下采样,这意味着一个 32×32 的小目标经过 5 次缩放后,在最高层特征图上只剩下 1×1 个特征点。分类分支在这个点上几乎拿不到判别性信息——它只能看到“这里有个东西”,却分不清是猫还是灰色石块。这就是小目标检测的第一个难点:特征信息不足。
第二个难点是定位精度差。小目标本身只有几个像素,预测框只要偏移两三个像素,与真实框的重叠度(IoU)就会断崖式下降,目标很容易被判为漏检或误检。第三个难点是背景干扰:小目标在特征图上与噪声、同类小物体几乎难以区分,模型经常把墙角的暗斑当成咪咪,或者把咪咪当成墙角的暗斑。
看,没人能在 1×1 的点上认出咪咪。要破解这个难题,聪明的做法是:别让高层那一个点孤军奋战,而是让不同层次的“瞭望台”共享情报。
- 缩放比例卷积网络每层下采样按 stride 缩小特征图,目标宽高同步变小
- 向上取整为保证特征坐标是整数,分别对宽高向上取整
- 幸存特征相乘得到下采样后目标剩余的特征点数
- 极端坍缩当 s=32 且目标为 32×32 时,幸存点数只剩 1×1
FPN特征金字塔
寻猫队派了三架无人机,分别悬停在 300 米、150 米、50 米高空。300 米高的无人机视野最大,报告:“东城区鱼市附近有一团可疑的红色。”50 米高的无人机立刻把镜头对准鱼市,逐条街扫过去,终于锁定:那就是咪咪!高空负责“大概在哪儿”,低空负责“确认是不是”——两者情报一旦打通,寻猫效率立刻翻倍。
特征金字塔网络(FPN,Feature Pyramid Network)沿用了这个思路。第一步是自底向上路径:骨干网络从 C1 到 C5 逐层下采样,低层保留高分辨率细节(猫耳朵的轮廓),高层浓缩全局语义(“鱼市附近”)。第二步是自顶向下路径:把 P3、P4 等高层特征不断上采样放大,向低层传递语义信息。第三步是横向连接:用 1×1 卷积把同一尺寸的低层细节与上采样来的高层语义逐元素相加,产出 P2、P3、P4、P5 多尺度特征。
对小目标最关键的是 P2 层,因为它分辨率最高、细节最完整,同时又通过融合获得了高层语义的“指导”。检测器可以分头行动:小目标交给 P2,中等目标交给 P3/P4,大目标交给 P5。这就像寻猫队给三架无人机分配任务:低空负责小猫,中空负责小推车,高空负责楼房——各司其职又互通有无。
瞭望台之间通了情报,咪咪在图上被找回来的概率大增。但别急,还有一个基础问题:如果镜头本身就模糊,再多的瞭望台也白搭。接下来我们给寻猫队换一台高分辨率相机。
- 低层细节C2 是自底向上路径中分辨率最高的特征层,保留小目标的轮廓细节
- 放大高层Upsample 把 P3 特征图放大到与 C2 相同的宽高
- 横向相加同尺寸的细节特征与语义特征逐元素相加,信息互补
- 卷积融合1×1 卷积在保持空间尺寸的同时完成通道间的融合与降维
高分辨率输入
有了瞭望台还不够,镜头本身的清晰度同样决定成败。想象一下:你把卫星图从 1024×1024 放大到 2048×2048,咪咪从 6×6 像素变成 12×12 像素,耳朵轮廓、眼睛位置立刻清晰起来,低空无人机不用再靠猜。
在技术层面,放大输入图像的效果可以用“有效步长”来解释:网络自身的 stride=16 是固定的,但如果输入边长放大 S 倍,目标在特征图上的有效大小也放大 S 倍,相当于有效步长变成了 16/S。换句话说,原来 1×1 的特征点能描述咪咪的整个身体,现在 2×2 甚至 4×4 的特征点能分别描述耳朵、眼睛、尾巴——特征信息瞬间充裕起来。
天上不会掉免费的午餐。输入放大 2 倍,卷积层的计算量大约是原来的 4 倍(宽高各放大 2 倍,相乘即 4 倍)。显存和算力吃不消时,工程上常用“切块检测”(tiling):把大图切成若干有重叠的小块分别送入网络,检测完再按坐标拼回全景图。这就像寻猫队把全城地图裁成 16 张,每人拿一张仔细找,最后合并大家的发现。
高分辨率镜头让咪咪的细节清晰了,但它还有个短板:它不知道咪咪喜欢去鱼市。再清晰的镜头,也比不上一点点常识。这就是上下文信息的用武之地。
- 缩放因子S 表示输入图像边长的放大倍数,宽和高分别变为原来的 S 倍
- 像素总量卷积计算量与输入像素总数成正比,放大后像素数为两者乘积
- 平方增长整理得到 S 的平方倍
上下文信息
老练的寻猫队员不会在全城盲找。他们先问几个问题:咪咪爱吃什么?爱去哪些地方?——爱晒太阳的窗台、卖鱼的集市、铺满落叶的公园。于是他们把搜索范围从“全城”缩小到“鱼市周边 500 米”。这不是碰运气,这叫上下文信息:用场景和时间线索辅助判断物体位置。
在小目标检测里,上下文信息分两类。第一类是全局上下文:把整张图的场景语义提取出来,让检测器知道“这是鱼市,很可能出现猫”。实现上可以用场景分类分支,也可以用自注意力机制让每个位置都“看”一眼全图。第二类是区域上下文:利用目标周围的邻接物体关系,比如行人旁边更可能有宠物,车道标线旁更可能出现小锥桶——单个小目标难以识别时,它的“邻居”就是最好的路标。
融合方式也很直观:把目标的局部特征 f_local 和全局上下文特征 f_global 做拼接或加权相加,得到 f_out。这样 P2 层上的咪咪不再是一个孤立的小红点,而是“鱼市场景中、鱼摊旁、带耳朵轮廓的小红点”。特征还是那些特征,但有了上下文加持,分类分支的置信度会大幅提升。
至此,“寻猫工具箱”已经齐全:尺子(定义)、问题清单(难点)、瞭望台(FPN)、高清镜头(高分辨率)、常识(上下文)。现在该把这套装备带出实验室,去真实世界执行任务了。
- 局部特征目标所在小区域提取到的外观特征,回答“它长什么样”
- 全局特征整张图或大范围上下文聚合出的语义特征,回答“它可能在哪儿”
- 融合符号⊕ 表示拼接(concat)或逐元素相加(add)操作
- 融合输出带上下文信息的特征,兼具细节分辨力与场景判断力
典型应用
当年在卫星图里找咪咪的小队,如今拿着同一套技术在现实世界出任务。第一站是遥感图像:油田里那些直径几米的油罐、海面上十几米长的船只,在几百公里高的卫星照片里只有几十甚至几个像素。遥感算法工程师用高分辨率输入配合 FPN,在超大遥感图上逐块扫描,从“芝麻点”里识别出油罐和船,靠的就是这套寻猫逻辑。
第二站是自动驾驶。车辆在空旷道路上行驶时,100 米外的一个行人可能只有 20×20 像素,却关乎生死。感知系统必须同时做三件事:用更大的输入分辨率保住行人的像素,用 FPN 让多尺度特征协同工作,再用上下文(斑马线、路口、车灯亮起的区域)预判行人可能出现的位置。这里的“猫”,是每个不可忽视的远方交通参与者。
第三站是工业质检。PCB 电路板上一条 2×2 像素的划痕、手机屏幕上一粒针尖大小的气泡,本质上都是小目标检测。产线相机把局部区域拉近后送入检测网络,再用上下文规则过滤(划痕通常沿走线方向、气泡通常在玻璃边缘区域),把不良品拦在出厂之前。F1 分数、漏检率、误检率,就是这支“寻猫队”的绩效 KPI。
从卫星图里找咪咪,到产线上找划痕,小目标检测的底层逻辑始终是同一套:定义尺度、弥补信息、融合细节与语义、善用上下文。理解了这场“寻猫游戏”,你就理解了这门技术的灵魂。
- 飞行高度H_flight 表示传感器到地面的距离,越高则视场越大
- 像元与焦距p_pixel 是感光元件的物理尺寸,f 是镜头焦距
- GSD 公式三者相除得到单个像素覆盖的地面尺寸
- 工程含义想让卫星“看见”咪咪那么大甚至更小的目标,必须把 GSD 压到目标尺寸以下
AI 应用场景
遥感图像中的油罐与船只识别
阶段:模型部署与检测推理
解决的问题:传统人工判读遥感影像耗时巨大,一名判读员一天只能处理几百平方公里;且小目标在低分辨率下极易漏检。AI 用高分辨率切块 + FPN 多尺度融合,把检测逻辑变成“先大范围扫,再小范围瞧”。
具体案例:某油田巡检项目需要对 2 万平方公里的卫星影像识别油罐目标。工程师将影像切为 1024×1024 的块,输入带 FPN 的检测网络,用 P2 层捕捉小油罐特征,最终漏检率从人工目视的 18% 降到 3% 以下。
自动驾驶中的远景行人感知
阶段:数据预处理与实时感知
解决的问题:传统单尺度检测器对 100 米外的行人几乎失效——目标只有 20×20 像素,下采样后特征完全坍缩。AI 方案采用高分辨率输入(如 1920×1080)配合 FPN 的 P2 特征层,并利用斑马线、路口等上下文线索提升召回率。
具体案例:某自动驾驶公司的高速领航系统,在夜间将相机增益调高并保持 2 倍输入分辨率,配合上下文注意力模块,将 150 米外静止行人的检出距离从 80 米提升到 120 米,为紧急制动争取了宝贵的 1.5 秒。
工业质检中的微小缺陷检测
阶段:模型训练与端侧推理
解决的问题:PCB 板上的划痕仅 2-3 个像素,传统视觉算法依赖人手工调阈值,换一条产线就得重新标定。AI 将局部区域高倍率成像后输入小目标检测网络,用上下文规则排除噪声干扰。
具体案例:某电子厂在回流焊后检测产线上 PCB 的微小气泡,采用“局部放大成像 + FPN + 灰度上下文过滤”,误检率从 8% 降至 1.2%,产线节拍保持在每片 0.8 秒。
Python 演示
import numpy as np def make_scene(size=256, seed=7): rng = np.random.default_rng(seed) img = rng.normal(0, 0.05, (size, size)).astype(np.float32) img[61:67, 61:67] += 1.0 # 6x6 small object (cat) img[150:210, 100:160] += 0.6 # 60x60 large object (house) return img def down(feat, k=2): # simulate stride-2 pooling like CNN downsampling h = feat.shape[0] // k * k w = feat.shape[1] // k * k return feat[:h, :w].reshape(h // k, k, w // k, k).mean(axis=(1, 3)) def up(feat, shape): # nearest-neighbor upsample for top-down path kh = shape[0] // feat.shape[0] kw = shape[1] // feat.shape[1] return np.kron(feat, np.ones((kh, kw), dtype=np.float32)) def build_fpn(img, levels=3): cs = [img] # bottom-up: C1 -> C2 -> C3 for _ in range(levels - 1): cs.append(down(cs[-1])) ps = [cs[-1]] # top-down fusion for i in range(levels - 2, -1, -1): ps.insert(0, cs[i] + up(ps[0], cs[i].shape)) return cs, ps def obj_points(feat, size=256, thr=0.5): d = size // feat.shape[0] return int((feat[61 // d:67 // d, 61 // d:67 // d] > thr).sum()) def main(): img = make_scene() cs, ps = build_fpn(img) print("levels:", len(cs), "small object 6x6 pixels") for i, c in enumerate(cs): print("C%d %dx%d valid points: %d" % (i + 1, c.shape[0], c.shape[1], obj_points(c))) print("after FPN, P1 valid points: %d (detail restored)" % obj_points(ps[0])) if __name__ == "__main__": main()
img[61:67, 61:67] += 1.0在背景噪声上放置一个 6×6 像素的小目标,模拟卫星图中的咪咪rng.normal(0, 0.05, (size, size))生成微弱背景噪声,模拟真实场景的干扰def down(feat, k=2)模拟 stride=2 的池化下采样,每次把特征图边长减半.reshape(h // k, k, w // k, k).mean(axis=(1, 3))每 2×2 窗口取均值,等效于平均池化def up(feat, shape)用 np.kron 做最近邻上采样,对应 FPN 自顶向下路径的放大操作ps.insert(0, cs[i] + up(ps[0], cs[i].shape))FPN 核心融合:低层细节 + 上采样后的高层语义def obj_points(feat, ...)统计小目标区域中超过阈值的有效特征点数量print("C%d ..." ...)输出 36 → 9 → 1 的坍缩曲线,与 FPN 融合后的恢复结果
常见误区
误区小目标看不清,直接用图像处理库把图放大 2 倍再送进网络,应该就能检测出来了吧?
正解普通插值放大(双线性、最近邻)只是在“补像素”,并没有引入任何新信息,就像把一张模糊的证件照放大,五官并不会因此变清晰。真正有效的是采集端的原生高分辨率输入(换更密的传感器、更长的焦距),或者让网络在训练时就适配高分辨率输入。单纯插值放大只会增加计算量,小目标的特征坍缩问题依旧存在。
为何常见:生活中的“放大”直觉让人误以为尺寸变大=信息变多,忽略了插值只是对已有信息的重采样。
误区FPN 不就是把图片缩成好几个尺寸分别检测吗?相当于把网络跑好几遍。
正解FPN 的核心不是“多个尺度副本同时检测”,而是自底向上的特征提取 + 自顶向下的语义注入 + 横向连接融合。它只跑一遍骨干网络,通过“高分辨率和低层细节”与“低分辨率和高层语义”的双向融合,让每一层特征同时具备细节和语义。这更像三架无人机互通情报,而不是三架无人机重复拍同一张照片。
为何常见:名字里带“金字塔”容易让人联想到图像金字塔,从而误以为是简单多尺度输入。
误区只要把模型换成带 FPN 的 SOTA 结构,小目标检测效果自然就上去了,数据不用管。
正解真实数据集中小目标占比往往极低——MS COCO 中小于 32×32 的目标只占约 10%,模型天然偏向学习样本多的大目标。结构再强,如果没有对遥感图或远景数据做小目标增广、复制粘贴、重采样,模型依然“看不见”小猫。结构是引擎,数据是汽油,缺一不可。
为何常见:开源榜单一讨论就是模型结构,实验的注意力容易被架构吸引,忽略了数据分布这个隐性瓶颈。
误区既然上下文有用,那我把网络的感受野做到最大,让每个特征都看到全图,小目标一定更强。
正解盲目的超大感受野会引入大量无关背景,反而稀释目标特征,就像寻猫时盯着整张城市地图,眼睛反而抓不住鱼市那个小红点。有效的上下文是有选择的:全局场景先验 + 区域邻接关系,而不是无差别地把所有背景都塞进特征里。上下文要“该看的看,不该看的忽略”。
为何常见:感受野和上下文都被理解为“看得更广”,让人误以为广就是好,忽略了选择的必要性。
面试题
Q1. 根据 COCO 数据集的经验标准,满足什么条件的目标被称为小目标?
- A.面积小于 32×32 像素← 正确答案
- B.面积小于 16×16 像素
- C.面积小于 64×64 像素
- D.面积小于 128×128 像素
答案:A。COCO 协议将面积小于 32×32 像素(即 1024 像素)的目标定义为小目标。16×16 过于严格,64×64 和 128×128 则是中目标甚至大目标的范畴。这把尺子的意义是让研究者有统一的对比基准。
Q2. 小目标经过深层 CNN 后特征信息不足,最本质的原因是什么?
- A.stride 下采样使目标在特征图上坍缩成极少像素← 正确答案
- B.小目标在图像中颜色太浅
- C.原始图像文件被过度压缩
- D.分类器训练轮数不够多
答案:A。深层 CNN 的 32 倍下采样把 32×32 的目标压缩成 1×1 的特征点,判别信息几乎消失。颜色、压缩、训练轮数都不是根本原因——即使颜色鲜艳,像素不够多照样无法提取轮廓特征。
Q3. FPN 中“自顶向下”路径的主要作用是什么?
- A.高层语义与低层细节相互融合← 正确答案
- B.缩小特征图来减少计算量
- C.提高图像的整体亮度
- D.对锚框进行聚类分析
答案:A。自顶向下路径把高层浓缩的语义信息上采样放大,逐层与低层细节融合,让“哪里可能有目标”和“目标长什么样”合二为一。它不负责减少计算或图像增强,也跟锚框聚类无关。
Q4. FPN 中的横向连接通常使用什么卷积?
- A.1×1 卷积← 正确答案
- B.7×7 卷积
- C.5×5 卷积
- D.空洞卷积
答案:A。1×1 卷积能在不改变空间尺寸的前提下完成通道压缩与融合,计算量小、实现简单,因此成为 FPN 横向连接的标准选择。大卷积核反而会引入额外计算与混合干扰。
Q5. 以下哪些方法能有效改善小目标检测?
- A.使用高分辨率输入图像← 正确答案
- B.利用上下文信息辅助← 正确答案
- C.将训练图像缩小一半
- D.引入特征金字塔融合← 正确答案
答案:ABD。高分辨率输入增加小目标像素、上下文提供场景线索、FPN 融合多尺度特征,三者都能缓解特征坍缩。把训练图像缩小一半反而让小目标像素更少,适得其反。
Q6. 输入图像边长放大 2 倍后,卷积层计算量大致变为多少?
- A.扩大为原来的 2 倍
- B.扩大为原来的 4 倍← 正确答案
- C.保持大小不变
- D.缩小为原来的一半
答案:B。计算量与输入像素总数成正比,宽高各放大 2 倍后像素总数为原来的 4 倍,所以计算量约扩大 4 倍。这也是为什么高分辨率方案必须配合切块检测或算力优化。
Q7. 以下哪些属于小目标检测的典型工业应用场景?
- A.遥感图像中识别油罐与船只← 正确答案
- B.自动驾驶检测远处行人← 正确答案
- C.工业质检发现微小划痕← 正确答案
- D.给照片添加美颜滤镜
答案:ABC。遥感油罐、海上船只、远景行人、微小划痕都只有极少像素,是小目标检测的典型战场。美颜滤镜属于图像编辑,不涉及目标检测任务。
Q8. 网络已带 FPN,只把锚框尺寸列表从 {32,64,128} 扩大到 {4,8,16},对小目标提升有限,最本质的原因是什么?
- A.缺的不是锚框而是有效特征← 正确答案
- B.小目标颜色通常偏暗
- C.大锚框计算耗时太长
- D.小目标不应有锚框
答案:A。锚框只是预置的候选位置,真正决定能否检出的是特征图上是否保留足够的判别信息。小目标经下采样后特征坍缩,即使锚框尺寸匹配,分类分支也认不出猫,必须靠 FPN、高分辨率输入或上下文补充特征。颜色和计算耗时都不是本质原因,小目标当然需要锚框匹配。
Q9. 在遥感影像中,GSD(地面采样距离)越小说明什么?
- A.单个像素覆盖的地面越小,能看清更小目标← 正确答案
- B.图像压缩率变得更高
- C.无人机飞行高度变得更高
- D.目标移动速度变得更快
答案:A。GSD 是单个像素对应的地面实际尺寸。GSD 越小,每个目标能占到的像素就越多,小目标自然更清晰。飞行高度越高 GSD 反而越大,压缩率和目标速度与 GSD 无直接关系。
Q10. 关于上下文信息在小目标检测中的使用,下列说法正确的有哪些?
- A.全局上下文能先缩小搜索范围← 正确答案
- B.上下文要与目标先验一致← 正确答案
- C.盲目扩大感受野必然提升效果
- D.区域上下文利用邻接物体线索← 正确答案
答案:ABD。全局上下文提供场景先验帮助缩小搜索范围,区域上下文利用邻居物体辅助判断,二者都要求与目标先验一致才有意义。盲目扩大感受野会引入无关背景,并不必然提升效果。