备注
转到末尾 下载完整示例代码。或在浏览器中通过 Binder 运行此示例。
骨架化#
骨架化将二值对象简化为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()

张的方法 vs 李的方法
skeletonize [Zha84] 通过多次遍历图像,移除对象边界的像素来工作。这个过程持续进行,直到没有更多的像素可以被移除。图像与一个掩码相关联,该掩码为每个像素分配一个在范围 [0…255] 内的数字,对应于其8个相邻像素的每种可能模式。然后使用查找表为像素分配0、1、2或3的值,这些值在迭代过程中被选择性地移除。
skeletonize(..., method='lee') [Lee94] 使用八叉树数据结构来检查一个像素的 3x3x3 邻域。该算法通过迭代地扫描图像,并在每次迭代中移除像素,直到图像停止变化。每次迭代包括两个步骤:首先,组装一个待移除的候选列表;然后,从这个列表中顺序重新检查像素,以更好地保持图像的连通性。
需要注意的是,Lee的方法 [Lee94] 是为3D图像设计的,并且会自动选择用于这些图像。为了说明的目的,我们将此算法应用于2D图像。
一种用于细化数字模式的快速并行算法,T. Y. Zhang 和 C. Y. Suen,《ACM 通讯》,1984年3月,第27卷,第3期。
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()

中轴骨架化
一个物体的中间轴是所有在其边界上有多个最近点的点的集合。它通常被称为*拓扑骨架*,因为它是一个与原始物体具有相同连通性的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()

形态学细化
形态学细化,在 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()

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