注意
转到末尾下载完整的示例代码。 或者在您的浏览器中通过 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()
张氏方法与李氏方法
skeletonize
[Zha84] 通过对图像进行连续的传递来实现,它会移除物体边界上的像素。 这会一直持续到无法再移除任何像素为止。 图像与一个掩码进行相关,该掩码将每个像素分配一个范围为 [0…255] 的数字,对应于其 8 个相邻像素的每个可能的模式。 然后使用一个查找表将像素分配一个值为 0、1、2 或 3 的值,这些值在迭代期间会被选择性地移除。
skeletonize(..., method='lee')
[Lee94] 使用八叉树数据结构来检查像素的 3x3x3 邻域。 该算法通过迭代地扫描图像并移除每次迭代中的像素来执行,直到图像停止变化。 每次迭代都包含两个步骤:首先,会组装一个待移除像素的候选列表;然后,会依次重新检查该列表中的像素,以更好地保留图像的连接性。
请注意,李氏方法 [Lee94] 旨在用于 3-D 图像,并且会针对这些图像自动选择。 出于说明目的,我们将此算法应用于 2-D 图像。
一种用于细化数字图案的快速并行算法,T. Y. Zhang 和 C. Y. Suen,Communications of the 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.332 秒)