SLIC_超像素算法

SLIC 超像素算法

一、超像素是什么

超像素把图像从像素网格重新组织成有意义的局部区域,每个区域由颜色相近、位置相邻的一堆像素组成。SLIC = S imple L inear I terative Clustering,直译「简单线性迭代聚类」。

和下采样的区别:下采样丢像素、损失分辨率;超像素保留全部像素,只是换一种组织方式,物体边界保留在区域边界上。


二、工作原理

2.1 初始化聚类中心

在图像上均匀撒 K 个种子点(用户指定的期望超像素数),种子间距:

复制代码
S = √(N / K)   其中 N = 图像总像素数

撒完种子还有一步容易漏掉:把每个种子挪到自己 3×3 邻域内梯度最小的位置。种子要是正好压在边缘上,第一轮聚类就会被边缘两侧的像素来回拉扯。

2.2 搜索范围限制

每个像素只和它周围 2S × 2S 窗口内的聚类中心比较,而不是全图 K 个中心都比一遍。

复制代码
               2S
  ┌─────────────────────┐
  │                     │
  │      · 聚类中心      │
  │      搜索区域        │
  │                     │
  └─────────────────────┘

窗口内最多碰到 4 个左右的中心,总比较次数和像素数成正比,这就是 SLIC 复杂度 O(N) 的来源。也正因为只跟附近中心比较,远处的同色像素不会聚到同一个超像素------空间局部性是这么来的。

但注意,这一步并不保证单个超像素内部连通。细缝、噪声会在区域里切出「飞地」,连通性是迭代结束后靠后处理强制的,见 2.4 第 4 步。

2.3 距离度量

同时考虑颜色距离(CIELAB 空间)和空间距离(xy 坐标):

复制代码
d_color = √((l₁ - l₂)² + (a₁ - a₂)² + (b₁ - b₂)²)
d_space = √((x₁ - x₂)² + (y₁ - y₂)²)

归一化后加权求和:

D = √((d_color / m)² + (d_space / S)²)
参数 作用
m 控制超像素的紧凑程度。m 越大 → 结果越接近方形网格;m 越小 → 更贴合物体边界
S 搜索范围,由 K 自动决定

2.4 迭代优化

复制代码
1. 每个像素在 2S×2S 邻域内分配到 D 最小的聚类中心
2. 更新聚类中心:取区域内像素的平均 Lab 和 xy
3. 重复 1-2,通常迭代 10 次左右(收敛很快,再多次数收益不大)
4. 强制连通性后处理:按标签做连通域检查,
   不连通的小碎片(实现里常用阈值 N/K/4)重新分配给邻近超像素

第 4 步顺带解决了空区域问题------迭代后个别中心可能一个像素都没分到。


三、输出格式

输出 说明
labels 整数矩阵,尺寸同原图,值范围 0 ~ K-1。每个像素的值表示它属于哪个超像素
属性列表 每个超像素的平均颜色、像素坐标列表、面积、质心等可计算属性

关于 K 值:K 不是精确值,只是用户指定的期望目标。初始撒 K 个种子,迭代后过小的区域被合并,最终实际超像素数约 0.9K ~ K。


四、超像素 vs 聚类(如 k-means)

SLIC 可以当成局部化的 k-means,加了两条约束:特征里混入空间坐标、搜索范围限制在 2S×2S 邻域。展开对比:

普通聚类(k-means) 超像素(SLIC)
目标 全局数据分组 生成局部、紧凑、边界贴合的区域
特征 只考虑颜色/特征 颜色 + 空间坐标
空间连通性 不保证,同一类可能分散在图中各处 聚类阶段同样不保证,靠后处理强制
搜索范围 全图 限制在 2S×2S 邻域
复杂度 O(N × K × 迭代次数) O(N × 迭代次数)
结果形式 离散的类别标签 分块区域,贴合物体边界

示例对比:

复制代码
原图:左上角蓝天,右下角蓝天

k-means:左上角蓝色像素 + 右下角蓝色像素 → 同一类
   SLIC:左上角蓝色像素 → 超像素A,右下角蓝色像素 → 超像素B(搜索范围限制,天然分开)

五、适用场景

场景 说明
语义分割预处理 在超像素上跑分类器(随机森林、k-NN),而非逐像素。样本量从百万级降到百级
视频跟踪/目标分割 以超像素为节点构建图模型,跟踪超像素而非像素
深度学习的替代输入 超像素特征作为网络输入,减少计算量
图像抠图/编辑 用户点击超像素而非像素选取区域,交互更高效
深度估计/立体匹配 以超像素为匹配基元,比逐像素鲁棒

排第一的「语义分割预处理」是超像素最经典的用法,也是「快 + 降噪」收益最直观的地方:

复制代码
逐像素:
  200 万像素 × 每个像素独立预测
  → 孤立噪点导致结果散乱(胡椒盐噪声)

超像素:
  SLIC 聚合成 200 个区域
  每个区域已是相邻像素的平均/聚合 → 天然去噪
  分类器只处理 200 个样本,少了 4 个数量级
  → 结果平滑,边界整齐

六、超像素分类完整流程

把 SLIC + 分类器 + CRF 三个环节串起来,讲清「用超像素做语义分割」从头到尾怎么走。

6.1 整体流程

复制代码
训练阶段:
  模板图 → SLIC → 超像素标签图
       → 人工给【每个】超像素打标签(关键,不是只选几个)
       → 每个超像素算一组特征
       → (特征, 标签) 喂给分类器(SVM / 随机森林 / MLP)

预测阶段:
  新图 → SLIC → 超像素
       → 每个超像素算同样的一组特征
       → 分类器预测 → 每个超像素一个类别概率
       →(可选)CRF 后处理 → 平滑结果
       → 类别映射回像素 → 分割图

6.2 三个常见误区

误区一:只选几个超像素当训练样本

错。监督学习需要每个训练样本都有标签,没标签的超像素模型学不到。要给所有(或足够多)超像素打标签,像填色游戏。

误区二:只用 RGB 均值当特征

太弱。RGB 对光照敏感(见第七节)。常用更强的特征向量:

  • Lab 均值(SLIC 本身就在 Lab 空间,比 RGB 稳)
  • 颜色直方图(每通道分 bin)
  • 纹理特征:LBP、Gabor、梯度直方图(HOG)
  • 形状/统计:面积、紧凑度、方差

误区三:特征里用绝对坐标

新图物体位置变了 → 直接翻车。分类特征别用绝对质心坐标 (x,y),除非物体位置固定(见第九节)。

6.3 为什么加 CRF(可选后处理)

分类器对每个超像素独立预测,可能出现「一块区域里冒出几个不同标签的孤岛」。CRF 接在分类器后面,根据「颜色相近的邻居该一致」做空间平滑,消除孤岛,同时保留颜色跳变的真实边界。

细节另见 CRF 条件随机场,这里只讲它在流程里的位置。


七、对光照的敏感性

SLIC 的距离度量包含颜色距离(Lab 空间),光源变化会拉偏颜色值,导致:

  • 同区域的像素颜色差异变大 → 本该属于同一物体的区域被分裂为多个超像素
  • 边界偏移,不再严格对齐物体边缘

补救方式:

  1. 归一化处理:对每张图做标准化(减去均值除以标准差),抵消光照波动
  2. 调大 m:注意方向别搞反------m 在分母上,调大 m 才是压低颜色项权重、让超像素更依赖空间位置;调小 m 反而更贴颜色边界、对光照更敏感
  3. 改用光照不变特征:如 LBP 纹理、梯度直方图替代原始 RGB/Lab
  4. 工业场景直接换方法:光源固定时,差影法比 SLIC 更稳定

八、C++ 实现

OpenCV(推荐,最方便)

cpp 复制代码
#include <opencv2/ximgproc.hpp>

cv::Mat image = cv::imread("image.jpg");

// 注意参数语义:createSuperpixelSLIC(image, 算法类型, region_size, ruler)
//   region_size 就是正文里的 S(超像素近似边长),不是超像素数 K!
//   想要约 K 个超像素,按 S = √(N/K) 反推:500×500 图想要 ~200 个 → region_size = 35
//   ruler 就是紧凑度 m
cv::Ptr<cv::ximgproc::SuperpixelSLIC> slic =
    cv::ximgproc::createSuperpixelSLIC(image, cv::ximgproc::SLIC, 35, 10.0f);

slic->iterate(10);

cv::Mat labels, contour_mask;
slic->getLabels(labels);                  // 每像素的超像素编号
slic->getLabelContourMask(contour_mask);  // 超像素边界 mask

int num_superpixels = slic->getNumberOfSuperpixels();

两个容易踩的坑:

  • createSuperpixelSLIC(image, SLIC, 200) 看起来像「要 200 个超像素」,实际 200 是 region_size------500×500 的图跑出来只有 ~6 个大块
  • 取边界用 getLabelContourMask,OpenCV 里没有 getLabelContours 这个函数

算法类型除了 SLIC 还有 SLICO(自适应 m,OpenCV 默认)和 MSLIC(取中值更新中心,对噪声更稳)。

性能参考(500×500 图)

参数 OpenCV 耗时 说明
K=1000, 迭代10次 15~40 ms 默认配置
K=1000, 迭代5次 8~20 ms 减少迭代
K=200 10~25 ms 减少超像素数
  • 现代桌面 CPU 约 20ms,ARM 嵌入式约 50~100ms
  • 纹理丰富的图迭代收敛慢,略慢一些
  • OpenCV 预编译版自带 SIMD 优化,运行时按 CPU 能力选指令集路径

VLFeat(轻量 C 库)

也提供 SLIC 实现,适合嵌入式环境。


九、不适合的场景

  • PCB 元件错位检测:元件位置偏移会改变超像素图,不能靠「比较超像素」来检测缺陷
  • 高精度工业测量:超像素边界不是亚像素精度
  • 物体位置不固定的场景:全局分类时质心坐标特征会失效
  • 光照频繁变化的环境:除非先做归一化(详见第七节)
相关推荐
苏打豆1 小时前
CRISP源码阅读——基于ROS2力矩反馈控制器与速度加速度零空间
c++·线性代数·算法·矩阵·机器人
一木 之林1 小时前
Stable Diffusion 详解:潜空间扩散原理、三件套分工与 diffusers 文生图实战
人工智能·计算机视觉·stable diffusion
小小龙学IT2 小时前
snap7 开源西门子 S7 通信协议库深度解析
c++·开源
小溪学编程3 小时前
从 C++ 的规范变迁看语言发展
jvm·c++·面试
shoufeipin90hou4 小时前
光选机的“除尘与风选“配套边界:分选精度上不去,可能问题不在相机
数码相机·计算机视觉
ShineWinsu4 小时前
对于Redis:string类型的解析
java·c++·redis·分布式·缓存·面试·string
YYYing.5 小时前
【设计模式系列 (七) 】桥接模式
c++·后端·设计模式·桥接模式
YOLO数据集集合5 小时前
无人机视角行人与车辆检测数据集 | 无人机航拍 行人检测 车辆检测 智慧城市 公共安全9140期
人工智能·目标检测·无人机·智慧城市·车辆识别·无人机视角
高山有多高5 小时前
【Linux笔记】Linux自定义Shell
linux·c++