尊重网格的 Skimage 骨架化或 OpenCV 实现?
Skimage skeletonize or OpenCV implementation that respects a grid?
假设一条直线以直角相交。
并且您想将其骨架化以获得(您希望的)十字形状。相反,使用 sklearn.morphology.skeletonize
获得以下图像:
我们称它为“多孔十字架”吧。
另一方面,您有 OpenCV 和 OpenCV skeletonize 函数,它们在 Internet 上流传在几个博客和此处的答案中:
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, kernel, dst=carry)
cv2.subtract(thresh, carry, dst=carry)
cv2.bitwise_or(skeleton, carry, dst=skeleton)
thresh, eroded = eroded, thresh
if cv2.countNonZero(thresh) == 0:
return skeleton
这个结果如下:
因此,浮动的基本 OpenCV 骨架化函数有问题或不正确,并且 Skimage 骨架化无法使用结构化形状进行修改。
有没有办法在python中获得骨架化的cross/plus标志形状?
正如我在评论中指出的那样,您可以通过拟合霍夫线来清理骨架化图像中的交叉点:
#!/usr/bin/env python
"""
"""
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, c0), (r1, c1)) in lines:
if (r0 == r1) or (c0 == c1):
...
假设一条直线以直角相交。
并且您想将其骨架化以获得(您希望的)十字形状。相反,使用 sklearn.morphology.skeletonize
获得以下图像:
我们称它为“多孔十字架”吧。
另一方面,您有 OpenCV 和 OpenCV skeletonize 函数,它们在 Internet 上流传在几个博客和此处的答案中:
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, kernel, dst=carry)
cv2.subtract(thresh, carry, dst=carry)
cv2.bitwise_or(skeleton, carry, dst=skeleton)
thresh, eroded = eroded, thresh
if cv2.countNonZero(thresh) == 0:
return skeleton
这个结果如下:
因此,浮动的基本 OpenCV 骨架化函数有问题或不正确,并且 Skimage 骨架化无法使用结构化形状进行修改。
有没有办法在python中获得骨架化的cross/plus标志形状?
正如我在评论中指出的那样,您可以通过拟合霍夫线来清理骨架化图像中的交叉点:
#!/usr/bin/env python
"""
"""
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, c0), (r1, c1)) in lines:
if (r0 == r1) or (c0 == c1):
...