opencv findContours miss some area.[ not get all correct bounding boxes ]

时间:2017-07-12 08:21:13

标签: python opencv image-processing extract image-recognition

I am new to opencv, start to learn it by extract char from simple captcha. After some effort, I got findContours and some method to clean the image, sometimes worked, but not more often.

For example:

  1. I have a original image(already scale to a large size): enter image description here

  2. convert to grayscale and use cv2.threshold clean: enter image description here

  3. use cv2.findContours to get bounding boxes:

enter image description here W only cover a half, and not get b.

My code:

from StringIO import StringIO
import string

from PIL import Image
import requests
import cv2
import numpy as np
import matplotlib.pyplot as plt

def get_ysdm_captcha():
    url = 'http://www.ysdm.net/common/CleintCaptcha'
    r = requests.get(url)
    img = Image.open(StringIO(r.content))
    return img

def scale_image(img, ratio):
    return img.resize((int(img.width*ratio), int(img.height*ratio)))

def draw_rect(im):
    im = np.array(im)

    if len(im.shape) == 3 and im.shape[2] == 3:
        imgray = cv2.cvtColor(im,cv2.COLOR_BGR2GRAY)
    else:
        imgray = im

    #plt.imshow(Image.fromarray(imgray), 'gray')
    pilimg = Image.fromarray(imgray)
    ret,thresh = cv2.threshold(imgray,127,255,0)

    threimg = Image.fromarray(thresh)

    plt.figure(figsize=(4,3))
    plt.imshow(threimg, 'gray')
    plt.xticks([]), plt.yticks([])

    contours, hierarchy = cv2.findContours(np.array(thresh),cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
    areas = []

    for c in contours:
        rect = cv2.boundingRect(c)
        area = cv2.contourArea(c)
        areas.append(area)
        x,y,w,h = rect

        if area > 2000 or area < 200 : continue

        cv2.rectangle(thresh,(x,y),(x+w,y+h),(0,255,0),1)
        plt.figure(figsize=(1,1))
        plt.imshow(threimg.crop((x,y,x+w,y+h)), 'gray')
        plt.xticks([]), plt.yticks([])

    plt.figure(figsize=(10,10))

    plt.figure()
    plt.imshow(Image.fromarray(thresh), 'gray')
    plt.xticks([]), plt.yticks([])


image = get_ysdm_captcha()
im = scale_image(image, 3)
im = np.array(im)

imgray = cv2.cvtColor(im, cv2.COLOR_BGR2GRAY)
imgray = cv2.GaussianBlur(imgray,(5,5),0)
# im = cv2.medianBlur(imgray,9)
# im = cv2.bilateralFilter(imgray,9,75,75)

draw_rect(imgray)

I tried my best to write above code. The solutions I imagine is:

  1. find was there any way to tell cv2.findContours I need 4 bounding boxes in some size
  2. tried some different parameter (I tried all from http://docs.opencv.org/2.4/modules/imgproc/doc/structural_analysis_and_shape_descriptors.html?highlight=findcontours#findcontours , but still not work)

Now I'm stuck , have no idea how to improve cv2.findContours...

2 个答案:

答案 0 :(得分:2)

您可以使用形态学操作来修改图像并填补空白,例如erodedilate

见这里: http://docs.opencv.org/2.4/doc/tutorials/imgproc/erosion_dilatation/erosion_dilatation.html

原件:

enter image description here

扩张型:

enter image description here

顺便说一句:我会在原始图像中实施HSV分离步骤,删除所有白色/灰色/黑色&#39;内容(低饱和度)。这将减少斑点的数量。在转换为灰度之前执行此操作。

以下是结果过滤:饱和度&gt; 90 enter image description here

最终结果:(之前添加了模糊步骤)

enter image description here

此外,如果总是有渐变,您可以检测到这种情况并滤除更多颜色。但是,如果您刚刚开始图像处理,那就有点多了;)

答案 1 :(得分:0)

findCountours在找到图像的所有连接组件时正常工作。例如,您的区域条件可能会避免您在字母b周围找到一个边界框。当然,如果你在每个连接的组件周围放置一个边界框,你将不会在每个角色周围放置一个边界框,因为你的字母中有很多洞。

如果你想分割字母,我会首先尝试使用开场操作(因为你的字母在白色背景上是黑色的,如果是相反的话它会关闭)以填补你的洞在你的信中。然后我会垂直投影像素并分析你得到的形状。如果您在此投影形状中找到谷点,您将获得字符之间的垂直限制。您可以水平地执行相同操作以获取字符的上限和下限。只有在文本是水平的情况下,此方法才有效。如果不是,您应该找到字符串的主轴角度,然后可以相应地旋转图像。要找到主轴角度,您可以在文本中插入椭圆并找到其主轴角度,或者您可以将图像旋转一定角度,直到您的水平投影达到最大值。

相关问题