如果线条近似直线,则使用霍夫变换查找所有线条,使用霍夫变换的圆形版本查找所有圆/椭圆(然后您可以检查是否找到了边界圆/椭圆,以及哪些线条在里面例如)。
如果线条不直:您的意思是“狭窄的细长区域”而不是线条,对吗?:) 你必须骨架化(可能首先是阈值)。有用的教程:“使用 OpenCV-Python 进行骨架化”。由于您还需要宽度(= 从骨架到边缘的距离),请使用skimage.morphology.medial_axis (..., return_distance=True)。您可能还需要一些方法来穿过每个骨架的分支并修剪短分支(抱歉,没有现成的东西已经这样做了)。
Haar 类型的方法根本不起作用,它仅适用于(甚至理论上)具有固定相对位置和形状的特征。您想要某种几何特征提取算法,而不是图像识别。
编辑: python中的示例代码:
import numpy, scipy, scipy.ndimage, skimage.morphology, matplotlib.pyplot
img = scipy.ndimage.imread("test.png")
# quick and dirty threshold
binary_img = img[:,:,0] < 0.1
# skeletonize
skel_binary, skel_distances = skimage.morphology.medial_axis(binary_img, return_distance=True)
# find individual lines
structure_element = scipy.ndimage.generate_binary_structure(2,2)
skel_labels, num_skel_labels = scipy.ndimage.measurements.label(skel_binary, structure=structure_element)
for n in range(1, num_skel_labels + 1):
# make a binary label for this line
line = (skel_labels == n)
# calculate width from skeleton
mean_width = 2 * numpy.mean( skel_distances[ line ] )
print "line %d: width %f" % (n, mean_width)
# you need some way to find the ends of a line
# perhaps the most distant pair of points?
# show the labels
# the circle is also labelled
# you need some way to check which label is the circle and exclude that
matplotlib.pyplot.imshow(skel_labels)
matplotlib.pyplot.show()
这会在您在上面发布的图像上产生合理的结果,并且(检查线条粗细是否有效)在这些图像的放大 10 倍版本上。它不处理相交的线,也许你可以为此做一个图形算法。此外,您确实需要以某种方式排除外圈(它似乎总是 n=1,因为标记发生在左上角,并且它找到的第一个标记区域是圆圈)。
编辑:如何(或是否)阈值是一个有趣的问题。您可以尝试自动阈值化,可能基于 Otsu 的方法,或者基于高斯混合(示例)。我认为您可能会通过某种背景和前景颜色和亮度的统计模型以及局部自适应阈值处理获得最佳结果。真的取决于你的图像的性质。