骨架化#

骨架化将二进制物体缩减为 1 像素宽的表示。 这对于特征提取和/或表示物体的拓扑结构很有用。

skeletonize 通过对图像进行连续的传递来实现。 在每次传递中,会识别边界像素,并在不破坏相应物体连接性的条件下将其移除。

from skimage.morphology import skeletonize
from skimage import data
import matplotlib.pyplot as plt
from skimage.util import invert

# Invert the horse image
image = invert(data.horse())

# perform skeletonization
skeleton = skeletonize(image)

# display results
fig, axes = plt.subplots(nrows=1, ncols=2, figsize=(8, 4), sharex=True, sharey=True)

ax = axes.ravel()

ax[0].imshow(image, cmap=plt.cm.gray)
ax[0].axis('off')
ax[0].set_title('original', fontsize=20)

ax[1].imshow(skeleton, cmap=plt.cm.gray)
ax[1].axis('off')
ax[1].set_title('skeleton', fontsize=20)

fig.tight_layout()
plt.show()
original, skeleton

张氏方法与李氏方法

skeletonize [Zha84] 通过对图像进行连续的传递来实现,它会移除物体边界上的像素。 这会一直持续到无法再移除任何像素为止。 图像与一个掩码进行相关,该掩码将每个像素分配一个范围为 [0…255] 的数字,对应于其 8 个相邻像素的每个可能的模式。 然后使用一个查找表将像素分配一个值为 0、1、2 或 3 的值,这些值在迭代期间会被选择性地移除。

skeletonize(..., method='lee') [Lee94] 使用八叉树数据结构来检查像素的 3x3x3 邻域。 该算法通过迭代地扫描图像并移除每次迭代中的像素来执行,直到图像停止变化。 每次迭代都包含两个步骤:首先,会组装一个待移除像素的候选列表;然后,会依次重新检查该列表中的像素,以更好地保留图像的连接性。

请注意,李氏方法 [Lee94] 旨在用于 3-D 图像,并且会针对这些图像自动选择。 出于说明目的,我们将此算法应用于 2-D 图像。

[Zha84]

一种用于细化数字图案的快速并行算法,T. Y. Zhang 和 C. Y. Suen,Communications of the ACM,1984 年 3 月,第 27 卷,第 3 期。

[Lee94] (1,2)

T.-C. Lee、R.L. Kashyap 和 C.-N. Chu,通过 3-D 中轴面/轴细化算法构建骨架模型。 计算机视觉、图形和图像处理,56(6):462-478,1994 年。

import matplotlib.pyplot as plt
from skimage.morphology import skeletonize

blobs = data.binary_blobs(200, blob_size_fraction=0.2, volume_fraction=0.35, rng=1)

skeleton = skeletonize(blobs)
skeleton_lee = skeletonize(blobs, method='lee')

fig, axes = plt.subplots(1, 3, figsize=(8, 4), sharex=True, sharey=True)
ax = axes.ravel()

ax[0].imshow(blobs, cmap=plt.cm.gray)
ax[0].set_title('original')
ax[0].axis('off')

ax[1].imshow(skeleton, cmap=plt.cm.gray)
ax[1].set_title('skeletonize')
ax[1].axis('off')

ax[2].imshow(skeleton_lee, cmap=plt.cm.gray)
ax[2].set_title('skeletonize (Lee 94)')
ax[2].axis('off')

fig.tight_layout()
plt.show()
original, skeletonize, skeletonize (Lee 94)

中轴骨架化

物体的中轴是所有具有多个最靠近物体边界的点的集合。 它通常被称为拓扑骨架,因为它是一个物体 1 像素宽的骨架,与原始物体具有相同的连接性。

在这里,我们使用中轴变换来计算前景物体的宽度。 由于函数 medial_axis 除了中轴之外还会返回距离变换(使用关键字参数 return_distance=True),因此可以使用此函数来计算中轴所有点的背景距离。 这提供了对物体局部宽度的估计。

对于分支较少的骨架,应优先使用 skeletonize

from skimage.morphology import medial_axis, skeletonize

# Generate the data
blobs = data.binary_blobs(200, blob_size_fraction=0.2, volume_fraction=0.35, rng=1)

# Compute the medial axis (skeleton) and the distance transform
skel, distance = medial_axis(blobs, return_distance=True)

# Compare with other skeletonization algorithms
skeleton = skeletonize(blobs)
skeleton_lee = skeletonize(blobs, method='lee')

# Distance to the background for pixels of the skeleton
dist_on_skel = distance * skel

fig, axes = plt.subplots(2, 2, figsize=(8, 8), sharex=True, sharey=True)
ax = axes.ravel()

ax[0].imshow(blobs, cmap=plt.cm.gray)
ax[0].set_title('original')
ax[0].axis('off')

ax[1].imshow(dist_on_skel, cmap='magma')
ax[1].contour(blobs, [0.5], colors='w')
ax[1].set_title('medial_axis')
ax[1].axis('off')

ax[2].imshow(skeleton, cmap=plt.cm.gray)
ax[2].set_title('skeletonize')
ax[2].axis('off')

ax[3].imshow(skeleton_lee, cmap=plt.cm.gray)
ax[3].set_title("skeletonize (Lee 94)")
ax[3].axis('off')

fig.tight_layout()
plt.show()
original, medial_axis, skeletonize, skeletonize (Lee 94)

形态学细化

形态学细化(在 thin 函数中实现)的工作原理与 skeletonize 相同:在每次迭代中从边界移除像素,直到无法移除任何像素而不会改变连接性为止。 不同的移除规则可以加快骨架化速度并导致不同的最终骨架。

thin 函数还接受一个可选的 max_num_iter 关键字参数,用于限制细化迭代的次数,从而生成相对较粗的骨架。

from skimage.morphology import skeletonize, thin

skeleton = skeletonize(image)
thinned = thin(image)
thinned_partial = thin(image, max_num_iter=25)

fig, axes = plt.subplots(2, 2, figsize=(8, 8), sharex=True, sharey=True)
ax = axes.ravel()

ax[0].imshow(image, cmap=plt.cm.gray)
ax[0].set_title('original')
ax[0].axis('off')

ax[1].imshow(skeleton, cmap=plt.cm.gray)
ax[1].set_title('skeleton')
ax[1].axis('off')

ax[2].imshow(thinned, cmap=plt.cm.gray)
ax[2].set_title('thinned')
ax[2].axis('off')

ax[3].imshow(thinned_partial, cmap=plt.cm.gray)
ax[3].set_title('partially thinned')
ax[3].axis('off')

fig.tight_layout()
plt.show()
original, skeleton, thinned, partially thinned

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

由 Sphinx-Gallery 生成的图库