如何从文档中捕获的图像中删除边框(如MNIST手写字符)?

时间:2017-10-04 07:02:33

标签: python opencv neural-network computer-vision mnist

我想提取写成这样的框的手写字符。 Form field

我正在提取宽度为29像素的正方形,这给我这样的图像。

Extracted images 1 Extracted Images 2 Extracted Images 3

要正确识别字符,个别字符图像需要非常干净。像这样,

Clean chars 1 Clean chars 2

我在做什么,

  1. 计算水平和垂直投影 每个图像。
  2. 遍历两个数组的每个元素。如果投影值大于某个阈值,则表示它没有遇到边界。它会删除边框周围的空格。

  3. 然后在图像中找到轮廓。

  4. 如果轮廓区域大于某个阈值。获取边界矩形并裁剪它。
  5. 但问题是,这种方法并不准确。在某些情况下,它工作正常,但在大多数情况下,如果失败了。 它会产生像

    这样的图像

    enter image description here enter image description here

    投影值也非常特定于此图像(或更接近此图像的图像)。它没有很好地概括。

    还有其他方法可以很好地适应这种情况吗?

    代码,

    char = cv2.imread(image)
    char_gray = cv2.cvtColor(char, cv2.COLOR_BGR2GRAY)
    char_bw = cv2.adaptiveThreshold(char_gray, 255, 
    cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 11, 9)
    
    (rows, cols) = char_gray.shape
    
    bit_not = cv2.bitwise_not(char_bw)
    proj_h = cv2.reduce(bit_nv2.REDUCE_AVG)
    
    proj_v = cv2.reduce(bit_not, 0, cv2.REDUCE_AVG)
    
    thresh_h = 200
    thresh_v = 100
    
    start_x, start_y, end_x, end_y = 0, 0, cols - 1, rows - 1
    #proj_h = proj_h[0]
    proj_v = proj_v[0]
    
    num_iter_h = cols // 8
    num_iter_v = rows // 8
    
    for _ in range(num_iter_h):
        if proj_h[start_y][0] > 35:
            start_y += 1
    
    for _ in range(num_iter_h):
        if proj_h[end_y][0] > 160:
            end_y -= 1
    
    for _ in range(num_iter_v):
        if proj_v[start_x] > 15: #25:
            start_x += 1
    
    for _ in range(num_iter_v):
        if proj_v[end_x] > 125:
            end_x -= 1
    
    print('processing.. %s.png' % idx)
    output_char = char[start_y:end_y, start_x:end_x]
    output_char = get_cropped_char(output_char)
    return output_char
    
    
    def get_cropped_char(img):
        """
        Returns Grayscale cropped image
        """
    
    img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
    
    blur = cv2.GaussianBlur(img, (3,3), 0)
    
    thresh = cv2.adaptiveThreshold(blur, 255, cv2.ADAPTIVE_THRESH_MEAN_C, cv2.THRESH_BINARY, 75, 10)
    im2, cnts, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    
    contour = None
    for c in cnts:
        area = cv2.contourArea(c)
        if area > 100:
            contour = c
    if contour is None: return None
    (x, y, w, h) = cv2.boundingRect(contour)
    img = img[y:y+h, x:x+w]
    return img
    

2 个答案:

答案 0 :(得分:2)

我不认为这是在图像阈值后直接裁剪字符的好方法。我相信morphy-op可以制作场景。

块元素整齐排列,因此请尝试使用morphy-erode-op来分隔块(或删除块边框)。获得clean字符图像后,您可以轻松裁剪字符图像。

...

英语不好,哈哈哈

这是我得到的结果。

Croped图片。

enter image description here

步骤:

enter image description here

答案 1 :(得分:2)

我是OpenCV的新手(我正在研究类似的项目......),但这是我从经验中可以说的。可以提取干净的字符,至少在最后两个字符中。由于跨越数字的线,第一个更难一点。

你必须制作图像的灰色版本,阈值并尝试一些opening/closing operations。之后,你必须morphological transformation删除每个方格的水平/垂直线。 我尝试了我的程序版本,它完成了40%的工作。我需要改进它......

之后,结果,您必须提取每个数字的边界框。这并不困难。有些数字会失败,但大部分会被提取出来。 “非常干净”很难达到这个水平。

做更多的研究。有很多关于如何完成大部分操作的例子。

编辑:你必须有与我相似的图像。在这样的事情上工作更容易..

example

这是我从我的成就:看看内部正方形,每个正方形围绕单个数字。它们可以轻松提取并保存以供下次处理。

example2