分割与超像素算法的比较#

本示例比较了四种流行的低级图像分割方法。由于获得良好的分割结果较为困难,且“良好”的定义通常取决于应用场景,这些方法通常用于获取过分割,也称为超像素。这些超像素随后作为更复杂算法(如条件随机场(CRF))的基础。

Felzenszwalb 基于图的高效分割#

这个在 [1] 中提出的快速2D图像分割算法在计算机视觉社区中非常流行。该算法有一个 scale 参数,影响分割的大小。实际的分割大小和数量可能会有很大差异,取决于局部对比度。

Quickshift 图像分割#

Quickshift 是一种相对较新的 2D 图像分割算法,基于核化均值漂移的近似。因此,它属于局部模式搜索算法家族,并应用于由颜色信息和图像位置组成的 5D 空间 [2]

quickshift 的优点之一是它实际上同时计算了多尺度的层次分割。

Quickshift 有两个主要参数:sigma 控制局部密度近似的尺度,max_dist 选择在生成的层次分割中的一个级别。还有一个在颜色空间距离和图像空间距离之间的权衡,由 ratio 给出。

SLIC - 基于K-Means的图像分割#

该算法简单地在颜色信息和图像位置的5维空间中执行K-means,因此与quickshift密切相关。由于聚类方法较为简单,因此非常高效。为了获得良好的结果,该算法必须在Lab颜色空间中工作。该算法迅速获得势头,现在被广泛使用。详情请参见[3]_。``compactness``参数在颜色相似性和接近性之间进行权衡,如同在Quickshift的情况下,而``n_segments``选择kmeans的中心数量。

梯度图像的紧凑分水岭分割#

与使用彩色图像作为输入不同,分水岭算法需要一个灰度 梯度 图像,其中明亮的像素表示区域之间的边界。该算法将图像视为一个地形,明亮的像素形成高耸的山峰。然后从给定的 标记 开始淹没这个地形,直到不同的洪水盆地在山峰处相遇。每个不同的盆地形成一个不同的图像片段。 [4]

与SLIC一样,有一个额外的 compactness 参数,这使得标记更难淹没远处的像素。这使得分水岭区域形状更加规则。 [5]

Felzenszwalbs's method, SLIC, Quickshift, Compact watershed
Felzenszwalb number of segments: 194
SLIC number of segments: 196
Quickshift number of segments: 695
Watershed number of segments: 256

import matplotlib.pyplot as plt
import numpy as np

from skimage.data import astronaut
from skimage.color import rgb2gray
from skimage.filters import sobel
from skimage.segmentation import felzenszwalb, slic, quickshift, watershed
from skimage.segmentation import mark_boundaries
from skimage.util import img_as_float

img = img_as_float(astronaut()[::2, ::2])

segments_fz = felzenszwalb(img, scale=100, sigma=0.5, min_size=50)
segments_slic = slic(img, n_segments=250, compactness=10, sigma=1, start_label=1)
segments_quick = quickshift(img, kernel_size=3, max_dist=6, ratio=0.5)
gradient = sobel(rgb2gray(img))
segments_watershed = watershed(gradient, markers=250, compactness=0.001)

print(f'Felzenszwalb number of segments: {len(np.unique(segments_fz))}')
print(f'SLIC number of segments: {len(np.unique(segments_slic))}')
print(f'Quickshift number of segments: {len(np.unique(segments_quick))}')
print(f'Watershed number of segments: {len(np.unique(segments_watershed))}')

fig, ax = plt.subplots(2, 2, figsize=(10, 10), sharex=True, sharey=True)

ax[0, 0].imshow(mark_boundaries(img, segments_fz))
ax[0, 0].set_title("Felzenszwalbs's method")
ax[0, 1].imshow(mark_boundaries(img, segments_slic))
ax[0, 1].set_title('SLIC')
ax[1, 0].imshow(mark_boundaries(img, segments_quick))
ax[1, 0].set_title('Quickshift')
ax[1, 1].imshow(mark_boundaries(img, segments_watershed))
ax[1, 1].set_title('Compact watershed')

for a in ax.ravel():
    a.set_axis_off()

plt.tight_layout()
plt.show()

脚本总运行时间: (0 分钟 0.779 秒)

由 Sphinx-Gallery 生成的图库