资讯动态

选择性搜索算法详解:从候选区域生成到R-CNN目标检测实战

发布时间:2026/10/15 15:31:27 来源:尧图企业网站定制
简介这份资源是面向计算机视觉初学者与目标检测入门者的选择性搜索Selective SearchPython 实践示例帮助读者理解如何通过超像素分割与区域生长策略生成候选目标区域并衔接 R-CNN、Fast R-CNN 等检测模型。压缩包共 19 个文件以 12 张 png 与 2 张 jpg 图像素材、3 个 py 脚本、1 份 md 说明及 1 份 license 为主整体约 53KB体积轻便便于快速下载与本地运行。其中脚本按步骤拆分覆盖搜索、过滤与特征提取等环节图像素材可直接用于验证算法效果md 文档则提供必要的使用说明。目前已有 285 人学习下载适合希望以最小成本跑通选择性搜索流程、理解候选区域生成原理的读者参考。1. 选择性搜索到底在解决什么问题如果你跑过 R-CNN 系列的代码一定见过 selective_search 这个名字。它不负责分类也不负责回归框它只干一件事从一张图里生成几百到两千个候选区域交给后面的网络去判断。很多人第一次跑目标检测 demo 时卡住不是模型加载失败而是候选区域生成这一步没跑通或者跑出来框的位置完全不对。这个项目就是一个选择性搜索的简单示例用 Python 把分层分组、区域合并、多样性排序这条链路完整走了一遍。适合谁适合正在复现 R-CNN、想搞懂候选区域怎么来的开发者也适合想拿它当图像分割预处理练手的人。它不依赖深度学习框架纯 CPU 就能跑对刚入门计算机视觉的人比较友好。2. 项目结构与核心模块拆解2.1 目录布局与文件职责拿到源码后先别急着跑花两分钟把目录看一遍后面改代码会省很多事。这个示例项目的结构通常比较扁平常见做法是下面这样selective_search/ ├── main.py # 入口读图、调用搜索、画框、保存结果 ├── selective_search.py # 核心算法实现 ├── utils.py # 图像读写、颜色空间转换、相似度计算 ├── config.py # 阈值、尺度、最小区域面积等参数 └── images/ # 测试图片main.py只做流程编排不掺算法逻辑selective_search.py是重点分层分组和区域合并都在这里utils.py放的是被反复调用的工具函数比如把 RGB 转成 HSV、计算两个区域的颜色直方图相似度。我一般会把所有可调参数抽到config.py这样调参时不用在算法文件里翻来翻去。如果你拿到的版本没有 config建议自己拆一个出来这是二次开发时最省心的习惯。2.2 分层分组把像素先切成小区域选择性搜索的第一步不是直接合并而是先做过度分割把图像切成很多小块。常见做法是用 Felzenszwalb 或者类似的分割方法把颜色相近、位置相邻的像素聚成初始区域。这一步决定了后面合并的起点切得太碎合并次数多、速度慢切得太粗又容易漏掉小目标。# utils.py import numpy as np def initial_segmentation(image, scale200, sigma0.8, min_size50): 对输入图像做初始过度分割 :param image: RGB 图像, shape(H, W, 3) :param scale: 分割尺度, 越大区域越少 :param sigma: 高斯平滑核宽度, 抑制噪点 :param min_size: 最小区域像素数, 小于该值的区域会被强制合并 :return: labels, 每个像素所属的区域 id # 这里调用具体分割实现, 返回每个像素的标签 labels _segment(image, scalescale, sigmasigma, min_sizemin_size) return labelsscale控制分割的粗细值越大切出来的区域越少sigma是平滑参数图像噪点多的时候调大一点min_size防止出现只有几个像素的碎片区域。这三个参数在config.py里改不要写死在函数里。初始分割做完后每个区域会带上颜色直方图、纹理梯度直方图和面积、位置信息这些就是后面合并时的判断依据。2.3 区域合并相似度怎么算、按什么顺序合合并是选择性搜索的核心。它维护一个相邻区域对列表每次挑相似度最高的一对合并合并后更新这对新区域和它邻居的相似度再放回列表。相似度由四个分量加权组成颜色、纹理、尺寸、填充。颜色和纹理决定“像不像”尺寸和填充决定“合不合理”。# selective_search.py import numpy as np def similarity(r1, r2, w_color1.0, w_texture1.0, w_size0.5, w_fill0.5): 计算两个区域的综合相似度 :param r1, r2: 区域对象, 含颜色直方图、纹理直方图、bbox、面积 :param w_color: 颜色相似度权重 :param w_texture: 纹理相似度权重 :param w_size: 尺寸相似度权重, 鼓励小区域先合并 :param w_fill: 填充相似度权重, 鼓励合并后外接框更紧凑 :return: 标量相似度, 越大越该合并 s_color hist_intersection(r1.color_hist, r2.color_hist) s_texture hist_intersection(r1.texture_hist, r2.texture_hist) s_size 1.0 - (r1.area r2.area) / total_image_area s_fill 1.0 - (r1.area r2.area) / bbox_area(union_bbox(r1, r2)) return (w_color * s_color w_texture * s_texture w_size * s_size w_fill * s_fill)颜色和纹理用直方图交集来算值在 0 到 1 之间。尺寸相似度这一项容易被忽略它的作用是让面积小的区域优先合并避免一个大区域过早吞掉周围的小块。填充相似度衡量合并后的外接框有多“实”如果两个区域合起来外接框里空了一大片说明它们其实不该合。四个权重在config.py里调默认值在多数自然图像上表现稳定遇到特定场景再微调。合并过程用一个优先队列维护每次弹出相似度最高的一对合并后把新区域和邻居的相似度重新算一遍压回去。这里有个细节合并后要更新的是新区域与它所有邻居的相似度不是只更新被合并的那两个。漏掉这一步后面生成的框会明显偏。2.4 多样性排序为什么最后还要再筛一遍合并到只剩一个区域时我们其实已经记录了整个合并过程中的所有中间区域。如果全拿出来数量太多而且很多是高度重叠的。所以最后要做一次多样性排序按面积从小到大遍历如果某个区域和已选区域的交并比超过阈值就跳过否则保留。# selective_search.py def diverse_selection(regions, iou_thresh0.8): 对候选区域做多样性筛选, 去掉高度重叠的框 :param regions: 合并过程中记录的所有区域 :param iou_thresh: 交并比阈值, 超过则视为重复 :return: 筛选后的候选区域列表 regions sorted(regions, keylambda r: r.area) # 小区域优先 selected [] for r in regions: if all(iou(r.bbox, s.bbox) iou_thresh for s in selected): selected.append(r) return selectediou_thresh调小留下的框更少、更分散调大框更多、重叠更严重。R-CNN 原论文里这个值一般取 0.8 左右。排序时按面积从小到大是为了让小的、可能包含独立目标的区域先被选中大区域如果和已选的小区域重叠太多就被丢掉。这一步做完通常一张图能剩下几百到两千个候选框正好够后面的网络用。3. 从零跑通环境、命令与结果验证3.1 环境准备与依赖安装这个示例不依赖 GPU也不需要深度学习框架Python 3.7 以上就能跑。依赖主要是 numpy、scikit-image、opencv-python 和 matplotlib。我一般用虚拟环境隔离避免和系统里的包打架。# 创建虚拟环境 python -m venv venv source venv/bin/activate # Windows 用 venv\Scripts\activate # 安装依赖 pip install numpy scikit-image opencv-python matplotlib如果你的机器上 scikit-image 装得慢可以先升级 pip。装完后在 Python 里import skimage不报错环境就算好了。注意 opencv-python 和 opencv-contrib-python 不要同时装容易冲突选一个就行。3.2 运行入口与参数说明入口在main.py常见写法是读一张图调用selective_search把候选框画出来保存。# main.py import cv2 from selective_search import selective_search from config import SS_CONFIG if __name__ __main__: img cv2.imread(images/test.jpg)[:, :, ::-1] # BGR 转 RGB regions selective_search( img, scaleSS_CONFIG[scale], sigmaSS_CONFIG[sigma], min_sizeSS_CONFIG[min_size], iou_threshSS_CONFIG[iou_thresh], ) print(f生成候选区域数量: {len(regions)}) vis draw_boxes(img, regions[:200]) # 只画前 200 个, 避免太乱 cv2.imwrite(output.jpg, vis[:, :, ::-1])scale、sigma、min_size控制初始分割iou_thresh控制最后筛选。第一次跑建议先用默认值看输出数量是否在合理范围。如果打印出来只有几十个框多半是scale太大或者min_size太大如果几千个框把iou_thresh调小一点。3.3 结果怎么看才算对跑完后打开output.jpg框应该覆盖住图中主要物体而且同一个物体上不会叠太多重复框。判断标准不是框多而是框的位置有没有落在物体上。如果框全挤在背景或者边缘检查一下颜色空间转换是不是漏了RGB 和 BGR 搞反是新手最常见的翻车点。另外可以打印一下每个区域的面积分布正常情况应该从小到大多个尺度都有如果全是特别大的框说明合并顺序有问题。提示第一次跑建议用一张背景干净、物体突出的图比如单个杯子或一本书方便肉眼判断框准不准。4. 避坑与常见问题排查4.1 框的位置整体偏移现象画出来的框和物体对不上整体偏了一个方向。原因读图时用了 BGR算法内部按 RGB 处理颜色直方图算出来是错的合并顺序跟着乱。解决在入口处统一转成 RGBcv2.imread之后加[:, :, ::-1]或者用cv2.cvtColor(img, cv2.COLOR_BGR2RGB)。4.2 候选框数量异常少现象打印出来只有几十个区域。原因min_size设得太大初始分割阶段小区域被强制合并后面可合并的起点就少了。解决把min_size降到 20 到 50 之间同时检查scale是不是超过 300。这两个参数一起调先保证初始区域数量在几百以上。4.3 运行速度慢到无法接受现象一张 800x600 的图跑了几分钟。原因相似度计算里直方图交集是逐对算的区域多的时候是平方级开销。解决把颜色直方图维度从 75 降到 25 左右纹理直方图维度也降一半另外在合并时只更新新区域和直接邻居的相似度不要全量重算。这两步做完速度通常能快三到五倍。4.4 同一个物体上叠了十几个框现象输出图里一个杯子被十几个框套住。原因iou_thresh设得太大多样性筛选没起到去重作用。解决把iou_thresh从 0.9 降到 0.7 到 0.8 之间重新跑一遍。如果还是多检查排序是不是按面积从小到大排序反了会导致大框先占位小框全被滤掉。4.5 换图后效果波动大现象这张图还行换一张就完全不对。原因固定参数对不同分辨率、不同光照的图适应性有限。解决按图像短边做归一化把图缩到短边 500 左右再跑光照差异大的话在初始分割前加一步直方图均衡。这不是算法 bug是参数没跟着数据走。5. 二次开发把示例改成能用的模块5.1 封装成可调用的候选区域生成器示例代码是脚本式的直接拿去嵌到 R-CNN 流程里不方便。我一般会把它包成一个类初始化时传配置调用时只传图。class SelectiveSearchGenerator: def __init__(self, scale200, sigma0.8, min_size50, iou_thresh0.8): self.scale scale self.sigma sigma self.min_size min_size self.iou_thresh iou_thresh def generate(self, image_rgb): 输入 RGB 图, 返回候选框列表 [(x1, y1, x2, y2), ...] regions selective_search( image_rgb, self.scale, self.sigma, self.min_size, self.iou_thresh ) return [r.bbox for r in regions]这样在检测流程里就是generator.generate(img)一行参数在初始化时定好换数据集时只改构造参数不动调用处。如果你要批量处理可以在类里加一个generate_batch内部用多进程池因为算法本身是 CPU 密集的多进程比多线程有效。5.2 参数调优的验证方法调参不能靠感觉。我一般固定三张图一张单物体、一张多物体、一张背景复杂。每次改完参数记录三个数候选框总数、平均 IoU和标注框比、召回率标注框被覆盖的比例。下面这张表是我在某次调参时的记录供参考scalemin_sizeiou_thresh框数量召回率200500.812000.82300500.87000.762001000.86000.71200500.78000.80从表里能看出来scale从 200 提到 300框数量掉了一半召回率也掉了六个点。min_size翻倍召回率掉得更明显。所以如果下游检测模型对小目标敏感min_size不要轻易调大。iou_thresh从 0.8 降到 0.7框少了但召回率只掉两个点说明去重去掉的多数是冗余框这种调整是划算的。5.3 一个容易忽略的改造点示例里相似度权重是写死的但不同数据集对颜色和纹理的敏感度不一样。比如医学图像纹理更重要自然场景颜色更重要。我一般会把四个权重也提到配置里调参时一起动。另外初始分割如果换成基于超像素的方法对小目标更友好但速度会慢一些这个取舍看你的场景。从那以后我每次改候选区域生成模块都强制先跑一遍三张固定图的召回率对比不看到数字不动下游模型。希望帮到你。本文还有配套的精品资源点击获取

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑