图像特征检测

Har*_*per 4 opencv artificial-intelligence image-recognition edge-detection

我正在开发一个应用程序来识别圆形/椭圆形内的线状特征。形状如下所示(此处显示两个):

形状

  • 形状本身在圆形和椭圆形之间可能略有不同。
  • 形状内部最多有 5 条线,它们位于每个形状的大致相同区域。
  • 这些线的长度、粗细、旋转和曲率可能略有不同。
  • 这些线有时会稍微接触/相交。
  • 通常正好有 5 个,但有时可能会完全丢失一行。
  • 我不在乎颜色,黑白阈值很好。

每个对象(超过 100 个)都将通过视频单独捕获;捕获是一个手动/物理过程(即我每次都拿着相机)。我可以完全控制相机,因此我可以在每次拍摄时始终如一地定位它。

现在我正在尝试使用 OpenCV 进行识别。我能够修改示例“人脸识别”应用程序以使用另一个 Haar 标识符 XML 文件,但这似乎只能处理外部圆/椭圆的检测。

我有兴趣为每个样本生成一个对象,以描述用于进一步处理的 5 条内部线:

{
    1: { length: 20, avg_thick: 2.3 },
    2: { length: 4, avg_thick: 2.0 },
    3: { length: 9.1, avg_thick: 2.1 },
    4: { length: 2, avg_thick: 1.9 },
    5: { length: 17, avg_thick: 2.1 }
}
Run Code Online (Sandbox Code Playgroud)

这是我第一个涉及图像识别的项目。我应该使用/研究什么算法或程序来实现这一目标?谢谢!

更新:

由于图像将是手工拍摄的,因此它们不是纯黑/白。尝试应用阈值会使形状内的(假装)线条有时会消失。我怎样才能改善阈值结果?

Ale*_*x I 5

如果直线近似直线,则使用霍夫变换查找所有直线,使用霍夫变换的圆形版本查找所有圆/椭圆(然后您可以检查是否找到了边界圆/椭圆,以及哪些线在里面例如)。

如果线条不直:您的意思是“狭窄的细长区域”而不是线条,对吗?:) 你必须骨架化(可能是阈值第一)。有用的教程:“使用 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()
Run Code Online (Sandbox Code Playgroud)

上面程序的输出

这会在您上面发布的图像上产生合理的结果,并且(检查线条粗细效果)在这些图像放大 10 倍的版本上也会产生合理的结果。它不处理相交线,也许您可​​以为此做一个图形算法。此外,您确实需要以某种方式排除外圆(它似乎总是 n=1,因为标记发生在左上角,并且它找到的第一个标记区域是圆)。

编辑:如何(或是否)阈值是一个有趣的问题。您可以尝试自动阈值处理,可能基于 Otsu 的方法,或者基于高斯混合(示例)。我认为您可能会通过某种背景和前景颜色亮度的统计模型,结合局部自适应阈值来获得最佳结果。真的取决于你的图像的性质。