图像特征检测

时间:2013-01-01 21:49:07

标签: opencv artificial-intelligence image-recognition edge-detection

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

Shapes

  • 圆形和椭圆形之间的形状本身可能略有不同。
  • 形状内最多有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 }
}

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

更新

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

2 个答案:

答案 0 :(得分:4)

如果直线大致笔直,请使用Hough transform查找所有直线,使用Hough变换的圆形版本查找所有圆/椭圆(然后可以检查是否已找到边界圆/椭圆) ,例如,在其中的哪些行。

如果线条不直:你的意思是“狭长区域”不是线条,对吗? :)你必须骨化(可能是门槛)。有用的教程:“Skeletonization using 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()

Output from program above

这会对您在上面发布的图像产生合理的结果,并且(对于检查线条厚度的工作情况)放大10倍的图像版本。它不处理相交线,也许你可以为它做一个图算法。你还需要以某种方式排除外圈(它似乎总是n = 1,因为标签从左上角发生,而它找到的第一个标记区域是圆圈。)

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

答案 1 :(得分:1)

  1. 对图像进行骨架化并跟踪每一行,然后您就可以获得每行的行数和长度。
  2. 对于每一行,计算面积(计算原始BW图像中的黑色像素数),然后将其除以长度以找到平均厚度。