今天早上我有这个想法,我发现scikit-image
可能可以解决问题。简单来说,我想删除轮廓光栅图像中的水平标签和其他不必要的特征,并获得轮廓线的位置。
喜欢这张图片: contour image with features to be removed。
但是看了一会儿后,我不确定是否可以做到。我的考虑如下:
1)find_contours
可以找到轮廓线,但我认为还包括所有其他功能(箭头和标签)。
2)关闭可能会删除标签,但我发现轮廓线也被删除了,我认为这是因为它们只是细线,如果使用关闭功能,亮区域将被连接。
3)箭头主要与轮廓线连接,因此这些特征不能视为单个对象。它们可能是最难移除的部分。
我想得到的帮助是知道是否可以删除标签和箭头以获得skimage
中的等高线。如果是这样,我会继续学习这个包。
答案 0 :(得分:2)
以下是您问题的部分解决方案。基本思想是将互连线的网络视为图形,并删除该图的小边缘,因为它们(大部分)对应于箭头和标签。第一步是计算二值化阶段的骨架。
当然结果并不完美,你可以调整下面脚本的不同参数来找到你认为最好的解决方案。如果您需要在大量图像上重复此分割,您还可以尝试手动选择要保留的图形边缘作为训练集,并使用机器学习算法对要保留的边缘进行分类(使用边缘的特征,例如长度,其他连接边的数量,方向,直线度......)。
import numpy as np
import matplotlib.pyplot as plt
from skimage import io, morphology
from scipy import ndimage
def skel_to_graph(skel):
"""
Transform skeleton into its branches and nodes, by counting the number
of neighbors of each pixel in the skeleton
"""
convolve_skel = 3**skel.ndim * ndimage.uniform_filter(skel.astype(np.float))
neighbors = np.copy(skel.astype(np.uint8))
skel = skel.astype(np.bool)
neighbors[skel] = convolve_skel[skel] - 1
edges = morphology.label(np.logical_or(neighbors == 2, neighbors ==1),
background=0)
nodes = morphology.label(np.logical_and(np.not_equal(neighbors, 2),
neighbors > 0), background=0)
length_edges = np.bincount(edges.ravel())
return nodes, edges, length_edges
# Open image and threshold
image = io.imread('contours.png')
im = image < 200
im = morphology.binary_closing(im, np.ones((5, 5)))
# Remove small connected components (small arrows)
only_big = morphology.remove_small_objects(im, 400)
# Skeletonize to get 1-pixel-thick lines
skel = morphology.skeletonize(only_big)
skel_big = morphology.remove_small_objects(skel, 30, connectivity=2)
nodes, edges, length_edges = skel_to_graph(skel_big)
# Keep only long branches of the skeleton
# The threshold can be adjusted
threshold = 35
long_edges = (length_edges < threshold)[edges]
edges[long_edges] = 0
# Visualize results
plt.figure(figsize=(10, 10))
plt.imshow(image, cmap='gray', interpolation='nearest')
plt.contour(edges > 0, [0.5], colors='red', linewidths=[2])
plt.axis('off')
plt.tight_layout()
plt.show()