OCR 的背景图像清理
Posted
技术标签:
【中文标题】OCR 的背景图像清理【英文标题】:Background image cleaning for OCR 【发布时间】:2020-02-26 09:20:09 【问题描述】:通过tesseract-OCR,我试图从以下红色背景图像中提取文本。
我在提取 B 和 D 框中的文本时遇到问题,因为存在垂直线。我怎样才能像这样清理背景:
输入:
输出:
有什么想法吗? 没有框的图像:
【问题讨论】:
您能否添加不带标记框的输入图像,以便我们尝试各种技术 【参考方案1】:这里有两种使用 Python OpenCV 清理图像的方法
方法 #1:Numpy 阈值处理
由于垂直线、水平线和背景都是红色的,我们可以利用这一点并使用 Numpy 阈值将所有高于阈值的红色像素更改为白色。
import cv2
import numpy as np
image = cv2.imread('1.jpg')
image[np.where((image > [0,0,105]).all(axis=2))] = [255,255,255]
cv2.imshow('image', image)
cv2.waitKey()
方法#2:传统图像处理
对于更通用的方法,如果线条不是红色,我们可以使用简单的图像处理技术来清理图像。为了去除垂直和水平线,我们可以构造特殊的内核来隔离这些线,并使用掩码和按位操作来去除它们。一旦线条被移除,我们可以使用阈值、形态学操作和轮廓过滤来移除红色背景。这是过程的可视化
首先我们构造垂直和水平内核然后cv2.morphologyEx()
来检测线条。从这里开始,我们有水平和垂直线的单独掩码,然后按位 - 或两个掩码以获得所有要删除的行的掩码。接下来我们用原始图像按位或删除所有行
现在线条已被移除,我们可以着手移除红色背景。我们阈值以获得二值图像并执行形态学操作以平滑文本
还有小点所以要去除它们,我们找到轮廓并使用最小阈值区域进行过滤以去除小噪声
最后我们反转图像得到我们的结果
import cv2
image = cv2.imread('1.jpg')
# Remove vertical and horizontal lines
kernel_vertical = cv2.getStructuringElement(cv2.MORPH_RECT, (1,50))
temp1 = 255 - cv2.morphologyEx(image, cv2.MORPH_CLOSE, kernel_vertical)
horizontal_kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (50,1))
temp2 = 255 - cv2.morphologyEx(image, cv2.MORPH_CLOSE, horizontal_kernel)
temp3 = cv2.add(temp1, temp2)
removed = cv2.add(temp3, image)
# Threshold and perform morphological operations
gray = cv2.cvtColor(removed, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 180, 255, cv2.THRESH_BINARY_INV)[1]
kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (2,2))
close = cv2.morphologyEx(thresh, cv2.MORPH_CLOSE, kernel, iterations=1)
# Filter using contour area and remove small noise
cnts = cv2.findContours(close, 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 < 10:
cv2.drawContours(close, [c], -1, (0,0,0), -1)
final = 255 - close
cv2.imshow('removed', removed)
cv2.imshow('thresh', thresh)
cv2.imshow('close', close)
cv2.imshow('final', final)
cv2.waitKey()
【讨论】:
@nathancy
。我看到您在第二个示例中使用我的图像处理方法删除了水平线和垂直线。但我真的很喜欢你使用 numpy 的第一种方法。我仍在学习 numpy 的所有细节。真的很强大。
@nathancy
我已将您的脚本用于第一种方法,并使用提供的图像运行它,它工作正常。但是当我用 100x100 纯红色图像 (image = np.full((100,100,3), (0,0,255), dtype=np.uint8)
) 替换该图像时,没有任何变化。结果仍然是纯红色。知道发生了什么吗?这张图片适合你吗?
@fmw42 我猜np.where()
条件为假。目前它是image > [0,0,105]
,因此只有满足所有三个通道的像素才会被视为真实。由于测试红色图像为(0,0,255)
,因此只有最后一个通道为True。所以将其更改为image >= [0,0,105]
应该可以工作
@nathancy
。是的。就是这样。事后看来是有道理的。仍然在学习 numpy 和 .all 并不太清楚,直到您确认它测试了所有 3 个通道,而不仅仅是红色通道。感谢您清除它。非常感激。现在测量原始图像中的红色,我发现它在 (0,0,255) 处不是纯红色。所以现在这也是有道理的,为什么它与你的原始命令一起工作。以上是关于OCR 的背景图像清理的主要内容,如果未能解决你的问题,请参考以下文章
如何通过 tesseract OCR 读取黑色背景图像上的黑色文本?