首页 > 解决方案 > 如何从图像中删除背景线条和形状以进行文本提取?

问题描述

我只想提取文本并从下图中删除所有其他内容:

输入图像

现在,我想删除除矩形形状中的文本之外的所有其他内容。那是我的代码:

import cv2
import pytesseract
import numpy as np
from imutils.perspective import four_point_transform

pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"

# Load image, convert to HSV, color threshold to get mask
image = cv2.imread('1.png')
hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
lower = np.array([0, 0, 0])
upper = np.array([100, 175, 110])
mask = cv2.inRange(hsv, lower, upper)

# Morph close to connect individual text into a single contour
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (5,5))
close = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations=3)

# Find rotated bounding box then perspective transform
cnts = cv2.findContours(close, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
rect = cv2.minAreaRect(cnts[0])
box = cv2.boxPoints(rect)
box = np.int0(box)
cv2.drawContours(image,[box],0,(36,255,12),2)
warped = four_point_transform(255 - mask, box.reshape(4, 2))

# OCR
data = pytesseract.image_to_string(warped, lang='eng', config='--psm 6')
print(data)

cv2.imshow('mask', mask)
cv2.imshow('close', close)
cv2.imshow('warped', warped)
cv2.imshow('image', image)
cv2.waitKey()

这是代码的输出:

输出

我的代码的错误是它遮蔽了图像中的所有内容,我只想提取文本,而不是其他内容:

输出

标签: pythonopencvpython-tesseract

解决方案


由于您的图像中有“完美”的矩形,我想出了以下方法:

  1. 灰度和反向二值化输入图像以消除可能的伪影,并在黑色背景上有白色框和文本。

  2. 在下文中,将使用模板匹配来找到感兴趣的框的左上角。所以,设置一个模板和面具来模仿那些左上角。

    模板本身类似于 50 像素长和 20 像素高的“角”,因为所有感兴趣的框至少具有以下尺寸:

    模板

    相应的掩码将模板限制为沿“角”的 5 个像素宽的“条纹”:

    模板掩码

    由于所有文本与框的边界至少有 5 个像素的边距,因此将有“完美”的匹配结果,因为没有文本干扰匹配。

  3. 从“完美”的匹配结果中,(x, y)推导出每个感兴趣框的坐标,并进行迭代。

    盒子里充满了一些灰色(由于一开始的二值化,图像中只有黑色和白色)

    满溢

    然后使用该灰色遮罩:

    蒙面

  4. 由此确定边界矩形,并将该部分从原始图像复制粘贴到一些干净的图像中。此外,pytesseract对内容执行。

这是完整的代码:

import cv2
import numpy as np
import pytesseract

# Read image as grayscale
img = cv2.imread('M7X8C.png', cv2.IMREAD_GRAYSCALE)

# Inverse binarize image to get rid of possible artifacts, and to have
# white boxes and text on black background
thr = cv2.threshold(img, 128, 255, cv2.THRESH_BINARY_INV)[1]

# Set up a template and mask mimicking the upper left corner of the
# boxes of interest
templ = np.full((20, 50), 255, dtype=np.uint8)
templ[1:, 1:] = 0
mask = np.full_like(templ, 255)
mask[5:, 5:] = 0

# Template matching
res = cv2.matchTemplate(thr, templ, cv2.TM_CCORR_NORMED, mask=mask)

# Extract upper left corners of the boxes of interest
boxes_tl = np.argwhere(res == 1)

# Initialize new clean image
clean = np.full_like(img, 255)

# For each upper left corner...
for i in np.arange(boxes_tl.shape[0]):

    # Get coordinates of upper left corner
    y, x = boxes_tl[i, :]
    print('x: {}, y: {}'.format(x, y))

    # Flood fill inner part of box, and mask that area
    box_mask = cv2.floodFill(thr.copy(), None, (x + 1, y + 1), 128)[1] == 128

    # Extract the bounding rectangle of that area
    x, y, w, h = cv2.boundingRect(box_mask.astype(np.uint8))

    # Copy box content to clean image
    clean[y:y+h, x:x+w] = img[y:y+h, x:x+w]

    # Run pytesseract on box content
    text = pytesseract.image_to_string(thr[y:y+h, x:x+w], config='--psm 6')
    print(text.replace('\f', ''))

# Output
cv2.imshow('clean', clean)
cv2.waitKey(0)

那是干净的图像:

干净的

而且,这是前两个pytessract结果:

x: 1, y: 0
PGGEOS KKCI 100600

x: 199, y: 39
ISOL
EMBD
CB
400
XXX

如您所见,结果并不完美(S而不是5),很可能是由于等宽字体。traineddata为这种字体获取(或生成)一些 Tesseract肯定会有助于克服这个问题。

----------------------------------------
System information
----------------------------------------
Platform:      Windows-10-10.0.19041-SP0
Python:        3.9.1
PyCharm:       2021.1.1
NumPy:         1.19.5
OpenCV:        4.5.2
pytesseract:   5.0.0-alpha.20201127
----------------------------------------

推荐阅读