OCR的清洁图像

时间:2019-12-03 14:25:52

标签: python opencv image-processing ocr image-segmentation

我一直在尝试清除OCR的图像:(线条)

enter image description here

我需要删除这些行以有时对图像进行进一步处理,但是我已经很接近了,但是很多时候,阈值从文本中去除了太多:

    copy = img.copy()
    blur = cv2.GaussianBlur(copy, (9,9), 0)
    thresh = cv2.adaptiveThreshold(blur,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY_INV,11,30)

    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (9,9))
    dilate = cv2.dilate(thresh, kernel, iterations=2)

    cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]

    for c in cnts:
        area = cv2.contourArea(c)
        if area > 300:
            x,y,w,h = cv2.boundingRect(c)
            cv2.rectangle(copy, (x, y), (x + w, y + h), (36,255,12), 3)

编辑:此外,如果字体更改,则不能使用常数。 有通用的方法可以做到这一点吗?

1 个答案:

答案 0 :(得分:14)

这是个主意。我们将此问题分为几个步骤:

  1. 确定矩形轮廓的平均面积。然后阈值确定轮廓并使用轮廓的边界矩形面积进行过滤。我们这样做的原因是因为观察到,任何典型字符都将非常大,而较大的噪声将跨越较大的矩形区域。然后,我们确定平均面积。

  2. 删除较大的离群轮廓。我们再次遍历轮廓,如果较大的轮廓比平均轮廓区域大5x,则通过填充轮廓来删除它们。我们使用此动态阈值来提高鲁棒性,而不是使用固定的阈值区域。

  3. 通过垂直内核进行扩展以连接字符。这个想法是利用观察到的字符在列中对齐的优势。通过使用垂直内核进行扩展,我们可以将文本连接在一起,从而使噪声不会包含在此组合轮廓中。

  4. 消除小噪音。现在,要保留的文本已连接,我们可以找到轮廓并删除小于平均轮廓区域4x的轮廓。

  5. 按位-并重建图像。由于我们只希望将轮廓保留在蒙版上,因此按位排列并保留文本并得到结果。


这是该过程的可视化:

我们Otsu's threshold获取二值图像,然后找到轮廓以确定平均矩形轮廓区域。从这里我们删除以绿色突出显示的较大的离群轮廓

enter image description here enter image description here

接下来,我们构造一个垂直内核并膨胀以连接字符。此步骤将保留所有所需的文本,并将噪声隔离为单个斑点。

enter image description here

现在我们找到轮廓并使用轮廓区域进行滤波以消除小噪声

enter image description here

所有已去除的噪音颗粒均以绿色突出显示

enter image description here

结果

enter image description here

代码

import cv2

# Load image, grayscale, and Otsu's threshold
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Determine average contour area
average_area = [] 
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    area = w * h
    average_area.append(area)

average = sum(average_area) / len(average_area)

# Remove large lines if contour area is 5x bigger then average contour area
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    x,y,w,h = cv2.boundingRect(c)
    area = w * h
    if area > average * 5:  
        cv2.drawContours(thresh, [c], -1, (0,0,0), -1)

# Dilate with vertical kernel to connect characters
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2,5))
dilate = cv2.dilate(thresh, kernel, iterations=3)

# Remove small noise if contour area is smaller than 4x average
cnts = cv2.findContours(dilate, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    area = cv2.contourArea(c)
    if area < average * 4:
        cv2.drawContours(dilate, [c], -1, (0,0,0), -1)

# Bitwise mask with input image
result = cv2.bitwise_and(image, image, mask=dilate)
result[dilate==0] = (255,255,255)

cv2.imshow('result', result)
cv2.imshow('dilate', dilate)
cv2.imshow('thresh', thresh)
cv2.waitKey()

注意:传统的图像处理仅限于阈值处理,形态学运算和轮廓滤波(轮廓近似,面积,纵横比或斑点检测)。由于输入图像会根据字符文本大小而变化,因此很难找到一个单一的解决方案。您可能需要考虑使用机器/深度学习来训练自己的分类器,以获得动态解决方案。