尊重网格的 Skimage 骨架化或 OpenCV 实现?

问题描述

假设一条直线相交成直角。

RightAngles

并且您想对其进行骨架化以获得(您希望)一个十字形状。相反,使用 sklearn.morphology.skeletonize 获得以下图像:

Holey Cross

我们称之为“有洞的十字架”。

另一方面,您有 OpenCV 和 OpenCV 骨架化功能,这些功能在互联网上的几个博客和答案中随处可见:

def skeletonize(bin: numpy.ndarray,erosion_shape=cv2.MORPH_RECT,kernel_sz: Union[int,Tuple[int,int]] = 3):
    kernel_sz = fix_kernel(kernel_sz)
    kernel = cv2.getStructuringElement(erosion_shape,kernel_sz)

    thresh = bin.copy()
    skeleton = numpy.zeros_like(bin)
    eroded = numpy.zeros_like(bin)
    carry = numpy.zeros_like(bin)

    while (True):
        cv2.erode(thresh,kernel,dst=eroded)
        cv2.dilate(eroded,dst=carry)
        cv2.subtract(thresh,carry,dst=carry)
        cv2.bitwise_or(skeleton,dst=skeleton)
        thresh,eroded = eroded,thresh

        if cv2.countNonZero(thresh) == 0:
            return skeleton

这会产生以下结果:

Gap Cross


因此,浮动的基本 OpenCV 骨架化功能存在错误错误,并且无法使用结构化形状修改 Skimage 骨架化。

有没有办法在python中获得骨架化的十字/加号形状?

解决方法

正如我在评论中指出的,您可以通过拟合霍夫线来清理骨架图像中的交叉点:

enter image description here

#!/usr/bin/env python
"""
https://stackoverflow.com/q/66995948/2912349
"""
import numpy as np
import matplotlib.pyplot as plt

from skimage.morphology import skeletonize
from skimage.transform import probabilistic_hough_line
from skimage.draw import line as get_line_pixels

img = np.zeros((20,20))
img[4:16,6:14] = 1
img[:,10] = 1
img[10,:] = 1

skel = skeletonize(img)

lines = probabilistic_hough_line(skel,line_length=10)

# hough_line() returns the start and endpoint of the fitted lines;
# we need all pixels covered by that line;
cleaned = np.zeros_like(img)
for ((r0,c0),(r1,c1)) in lines:
    rr,cc = get_line_pixels(r0,c0,r1,c1)
    cleaned[rr,cc] = 1

fig,axes = plt.subplots(1,3,sharex=True,sharey=True)
axes[0].imshow(img,cmap='gray')
axes[0].set_title('Raw')
axes[1].imshow(skel,cmap='gray')
axes[1].set_title('Skeleton')
axes[2].imshow(cleaned,cmap='gray')
axes[2].set_title('Hough lines')
plt.show()

如果您想强制水平或垂直适合,可以简单地过滤 lines 以排除非水平和非垂直线:

for ((r0,c1)) in lines:
    if (r0 == r1) or (c0 == c1):
        ...