使用opencv在图像中寻找形状

5 投票
2 回答
10876 浏览
提问于 2025-04-17 09:50

我正在尝试使用OpenCV在图像中寻找形状。我知道我想要匹配的形状(有些形状我不知道,但我不需要找到它们)以及它们的方向。我不知道它们的大小和位置。

我现在的做法是:

  1. 检测轮廓
  2. 对每个轮廓,计算出最大的边界框
  3. 将每个边界框分别与已知形状进行匹配。在我的实际项目中,我会将区域缩放到模板大小,并计算Sobel梯度的差异,但在这个演示中,我只是使用了长宽比。

这个方法的问题在于形状相互接触的地方。轮廓检测会把两个相邻的形状当作一个轮廓(一个边界框)来处理。这样在匹配时就会失败。

有没有办法修改我的方法,让相邻的形状可以单独处理?另外,步骤3有没有更好的做法?

例如:(Es用绿色标记,Ys用蓝色标记)

enter image description here

失败的案例:(未知形状用红色标记)

enter image description here

源代码:

import cv
import sys
E = cv.LoadImage('e.png')
E_ratio = float(E.width)/E.height
Y = cv.LoadImage('y.png')
Y_ratio = float(Y.width)/Y.height
EPSILON = 0.1

im = cv.LoadImage(sys.argv[1], cv.CV_LOAD_IMAGE_GRAYSCALE)
storage = cv.CreateMemStorage(0)
seq = cv.FindContours(im, storage, cv.CV_RETR_EXTERNAL, 
        cv.CV_CHAIN_APPROX_SIMPLE)
regions = []
while seq:
    pts = [ pt for pt in seq ]
    x, y = zip(*pts)    
    min_x, min_y = min(x), min(y)
    width, height = max(x) - min_x + 1, max(y) - min_y + 1
    regions.append((min_x, min_y, width, height))
    seq = seq.h_next()

rgb = cv.LoadImage(sys.argv[1], cv.CV_LOAD_IMAGE_COLOR)
for x,y,width,height in regions:
    pt1 = x,y
    pt2 = x+width,y+height
    if abs(float(width)/height - E_ratio) < EPSILON:
        color = (0,255,0,0)
    elif abs(float(width)/height - Y_ratio) < EPSILON:
        color = (255,0,0,0)
    else:
        color = (0,0,255,0)
    cv.Rectangle(rgb, pt1, pt2, color, 2)

cv.ShowImage('rgb', rgb)
cv.WaitKey(0)

e.png:

enter image description here

y.png:

enter image description here

好的案例:

enter image description here

坏的案例:

enter image description here

在有人问之前,不,我不是想破解验证码 :) 这里的OCR其实并不相关:我在实际项目中的形状并不是字符——我只是懒,字符是最简单的东西(而且仍然可以通过简单的方法被检测到)。

2 个回答

2

你有没有试过用CCH作为描述符进行斜角匹配或者轮廓匹配呢?

斜角匹配是通过目标图像和模板轮廓的距离变换来实现的。这种方法虽然不是完全不受比例影响,但速度很快。

而后者的速度就比较慢,因为它的复杂度至少是二次的,适用于二分匹配问题。另一方面,这种方法对比例、旋转和可能的局部扭曲是稳健的(对于近似匹配来说,我认为这对于上面的糟糕例子是不错的选择)。

4

因为你的形状可能大小和比例都不一样,所以你应该关注一些不受缩放影响的描述符。很多这样的描述符会非常适合你的应用。

先在你的测试模板上处理这些描述符,然后用一些简单的分类方法来提取它们。这样对于你展示的简单形状,应该能得到不错的结果。

我以前用过Zernike和Hu矩,后者是最有名的。你可以在这里找到一个实现的例子:http://www.lengrand.fr/2011/11/classification-hu-and-zernike-moments-matlab/

还有一件事:考虑到你的问题,你应该看看OCR技术(光学字符识别的缩写:http://en.wikipedia.org/wiki/Optical_character_recognition;)

希望这些对你有点帮助。

Julien

撰写回答