SLIC算法分割超像素原理及Python实现

超像素(SuperPixel),就是把原本多个像素点,组合成一个大的像素。比如,原本的图片有二十多万个像素,用超像素处理之后,就只有几千个像素了。后面做直方图等处理就会方便许多。经常作为图像处理的预处理步骤。

在超像素算法方面,SLIC Superpixels Compared to State-of-the-art Superpixel Methods这篇论文非常经典。论文中从算法效率,内存使用以及直观性比较了现有的几种超像素处理方法,并提出了一种更加实用,速度更快的算法——SLIC(simple linear iterative clustering),名字叫做简单的线性迭代聚类。其实是从k-means算法演化的,算法复杂度是O(n),只与图像的像素点数有关。

这个算法突破性的地方有二:

  1. 限制聚类时搜索的区域(2Sx2S),这样将k-means算法的复杂度降为常数。整个算法的复杂度为线性。
  2. 计算距离时考虑LAB颜色和XY距离,5维。这样就把颜色和距离都考虑进去了。通过M可以调整颜色和距离的比重,灵活性强,超像素更加规则。

SLIC算法原理

整个算法的输入只有一个,即超像素的个数K。

图片原有N个像素,要分割成K个像素,那么每个像素的大小是N/K。超像素之间的距离(即规则情况下超像素的边长)就是S=√N/K。

我们的目标是使代价函数(cost function)最小。具体到本算法中,就是每个像素到所属的中心点的距离之和最小。

首先,将K个超像素种子(也叫做聚类,即超像素的中心),均匀撒到图像的像素点上。

一次迭代的第一步,对每个超像素的中心,2S范围内的所有像素点,判断他们是否属于这个超像素。这样之后,就缩短了像素点到超像素中心的距离。

一次迭代的第二步,对每个超像素,将它的超像素中心移动到这个超像素的中点上。这样也缩短了像素点到超像素中心的距离。

一般来说,迭代10是聚类效果和计算成本折中的次数。

SLIC算法步骤

  1. 撒种子。将K个超像素中心分布到图像的像素点上。
  2. 微调种子的位置。以K为中心的3×3范围内,移动超像素中心到这9个点中梯度最小的点上。这样是为了避免超像素点落到噪点或者边界上。
  3. 初始化数据。取一个数组label保存每一个像素点属于哪个超像素。dis数组保存像素点到它属于的那个超像素中心的距离。
  4. 对每一个超像素中心x,它2S范围内的点:如果点到超像素中心x的距离(5维)小于这个点到它原来属于的超像素中心的距离,那么说明这个点属于超像素x。更新dis,更新label。
  5. 对每一个超像素中心,重新计算它的位置。
  6. 重复4 5 两步。

伪代码(来自论文)

Python实现SLIC

最新版本的代码请看这里:https://github.com/laixintao/slic-python-implementation

效果如下:

Lenna图像在M=30,K=500时第一次迭代产生的超像素图。

Lenna图像在M=30,K=500时第10次迭代产生的超像素图。

SLIC算法分割超像素原理及Python实现”已经有6条评论

  1. 你好, 非常感谢你的代码,我发现了几个小问题:
    1. self.cluster_index += 1 因为对于每个对象cluster_index 都等于 1, 所以这样的话每个self.cluster_index都会等于2, 起不到index的作用, 建议改成Cluster.cluster_index += 1
    2. gradient = self.data[w + 1][h + 1][0] – self.data[w][h][0] + \ 的w和h和别处是反的

    • 谢谢指出!第一个我觉得你说的对,源代码也是写到了class的属性里面,应该是我写错了但是代码能work就没注意到。第2个我不太确定,得明天调试一下。写着写着调来调去的我也不知道自己写的什么了……

      这个代码其实写的比较乱,这篇论文读着好玩的,就试了一下。代码可能存在别的漏洞,要小心使用哦~

  2. 你好:) 我又发现了一个问题, 在update_cluster函数里面, 你是取了h和w的平均值, 然后取图中对应位置的l,a,b; 这样得到的结果和slic官网上c++代码得到的结果不太一样, 我看了一下发现他们对l,a,b也取了平均

    • l,a,b平均值这个做法应该是论文里面的,我上面的代码只参考了论文,别处的实现可能带有优化。不过不好意思,我现在回去看这个代码也看不懂了…… 要解释的话只有从头复习一遍论文…… 帮不上你了。你可以调试对比一下。

      • 我明白了,如果把SLIC看成是clustering, 那论文里面就是在[x, y, l, a, b] 5维空间的clustering,5维向量取平均得到的新的中心不一定是图上的点; 你当时可能考虑新的中心应该是图上实际存在的点

        • 隐约记得是这样的,我记得我没有做按照自己想法的处理,都是照着论文上来的。你看论文上有没有推荐这样处理不在图像上的点?这个算法好像供自己调节的只有两个参数,写出来的结果应该不会差太多。

Leave a comment

电子邮件地址不会被公开。 必填项已用*标注