【问题标题】:Image Feature Detection图像特征检测
【发布时间】:2012-12-16 09:01:51
【问题描述】:

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

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

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

更新:

由于图像是手工拍摄的,因此它们不是纯黑/白。尝试应用阈值会使形状内的(假装)线有时会消失。如何改进阈值化结果?

【问题讨论】:

  • 你研究过霍夫变换吗?
  • 不,这是我第一个涉及图像识别的项目,所以我对它完全陌生。我会读一下,谢谢。
  • 它可能不是最适合这个应用程序,尤其是如果线条是弯曲的,但值得一看。

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


【解决方案1】:
  1. 骨架化图像并跟踪每一行,然后你就可以知道每一行的行数和长度。
  2. 对于每条线,计算面积(计算原始 BW 图像中黑色像素的数量),然后将其除以长度得到平均厚度。

【讨论】:

  • 非常感谢您的帮助。您能否添加更多详细信息并解决更新后的问题?
【解决方案2】:

如果线条近似笔直,请使用Hough transform 查找所有线条,并使用霍夫变换的圆形版本查找所有圆/椭圆(然后您可以检查是否找到了边界圆/椭圆,以及例如,其中有哪些行)。

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

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

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

【讨论】:

  • 非常感谢您的帮助。您能否添加更多详细信息并解决更新后的问题?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-04-04
  • 1970-01-01
  • 2012-04-25
相关资源
最近更新 更多