java - 使用 tesseract 检测明亮背景上的白色文本

标签 java opencv tesseract tess4j pokemon-go

我在阅读明亮背景上的白色文本时遇到问题,它会找到文本本身,但无法真正正确翻译。

图片:
enter image description here

我不断得到的结果是 LanEerus,说实话,这并不遥远。

我想知道的是什么图像预处理可以解决这个问题?在尝试使用代码进行操作之前,我正在使用 Photoshop 手动对其进行预处理,以找到应该首先工作的内容。

我尝试将其制作为位图,但这会使文本的 边框 非常糟糕,导致 tesseract 只是将其转换为随机字符。

反转颜色和/或灰度似乎也不起作用。

有人有什么想法吗?我知道这对于本案的文本来说是一个非常糟糕的背景。相信我,我希望背景不同!

我的测试代码:

File file = new File("C:\\tess\\lando.png");
ITesseract tess = new Tesseract();
tess.setDatapath("tessdata");

System.out.println(tess.doOCR(file));

编辑
我已通读 Improving the quality但无法让这些技巧发挥作用。

编辑 2
使用OpenCV对图像进行灰度、反转颜色、高斯模糊和自适应阈值预处理后。我得到了图像的这个结果,但没有更好的阅读效果。如果有的话,更糟..
enter image description here

最佳答案

这是一种可能的解决方案。这是在 Python 中,但对于 Java 端口来说应该足够清楚。我们将应用一种称为获得除法的方法。这个想法是您尝试构建背景模型,然后通过该模型对每个输入像素进行加权。在图像的大部分时间里,输出增益应该是相对恒定的。这将消除大部分背景颜色变化。我们可以使用 morphological 链来稍微清理一下结果,让我们看看代码:

# imports:
import cv2
import numpy as np
# OCR imports:
from PIL import Image
import pyocr
import pyocr.builders

# image path
path = "D://opencvImages//"
fileName = "c552h.png"

# Reading an image in default mode:
inputImage = cv2.imread(path + fileName)

# Get local maximum:
kernelSize = 5
maxKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (kernelSize, kernelSize))
localMax = cv2.morphologyEx(inputImage, cv2.MORPH_CLOSE, maxKernel, None, None, 1, cv2.BORDER_REFLECT101)

# Perform gain division
gainDivision = np.where(localMax == 0, 0, (inputImage/localMax))

# Clip the values to [0,255]
gainDivision = np.clip((255 * gainDivision), 0, 255)

# Convert the mat type from float to uint8:
gainDivision = gainDivision.astype("uint8")

第一步是应用增益除法,你需要的操作很简单:一个带有大矩形结构元素的形态关闭和一些数据类型转换,小心与后者。这是应用该方法后应该看到的图像:

非常酷,背景几乎消失了。让我们使用 Otsu 的 Thresholding 得到一个二值图像:

# Convert RGB to grayscale:
grayscaleImage = cv2.cvtColor(gainDivision, cv2.COLOR_BGR2GRAY)

# Get binary image via Otsu:
_, binaryImage = cv2.threshold(grayscaleImage, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)

这是二值图像:

我们有一个很好的文本边缘图像。如果我们 Flood-Fill 使用白色背景,我们可以获得黑色背景和白色文本。但是,我们应该小心字符,因为如果一个字符被破坏,Flood-Fill 操作会将它删除。让我们首先通过应用形态学 closure 来确保我们的角色是封闭的:

# Set kernel (structuring element) size:
kernelSize = 3
# Set morph operation iterations:
opIterations = 1

# Get the structuring element:
morphKernel = cv2.getStructuringElement(cv2.MORPH_RECT, (kernelSize, kernelSize))

# Perform closing:
binaryImage = cv2.morphologyEx( binaryImage, cv2.MORPH_CLOSE, morphKernel, None, None, opIterations, cv2.BORDER_REFLECT101 )

这是生成的图像:

如您所见,边缘更坚固,最重要的是,它们是闭合的。现在,我们可以用白色Flood-Fill背景。这里,Flood-Fill 种子点位于图像原点(x = 0, y = 0):

# Flood fill (white + black):
cv2.floodFill(binaryImage, mask=None, seedPoint=(int(0), int(0)), newVal=(255))

我们得到这张图片:

我们快到了。如您所见,某些字符(例如“a”、“d”和“o”)内部的空洞没有被填充 - 这会对 OCR 产生噪音。让我们尝试填充它们。我们可以利用这些洞都是父轮廓的这一事实。我们可以隔 ionic 轮廓,并再次应用 Flood-Fill 来填充它们。但首先,不要忘记反转图像:

# Invert image so target blobs are colored in white:
binaryImage = 255 - binaryImage

# Find the blobs on the binary image:
contours, hierarchy = cv2.findContours(binaryImage, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)

# Process the contours:
for i, c in enumerate(contours):

    # Get contour hierarchy:
    currentHierarchy = hierarchy[0][i][3]

    # Look only for children contours (the holes):
    if currentHierarchy != -1:

        # Get the contour bounding rectangle:
        boundRect = cv2.boundingRect(c)

        # Get the dimensions of the bounding rect:
        rectX = boundRect[0]
        rectY = boundRect[1]
        rectWidth = boundRect[2]
        rectHeight = boundRect[3]

        # Get the center of the contour the will act as
        # seed point to the Flood-Filling:
        fx = rectX + 0.5 * rectWidth
        fy = rectY + 0.5 * rectHeight

        # Fill the hole:
        cv2.floodFill(binaryImage, mask=None, seedPoint=(int(fx), int(fy)), newVal=(0))

# Write result to disk:
cv2.imwrite("text.png", binaryImage, [cv2.IMWRITE_PNG_COMPRESSION, 0])

这是生成的掩码:

酷,让我们应用 OCR。我正在使用 pyocr:

txt = tool.image_to_string(
    Image.open("text.png"),
    lang=lang,
    builder=pyocr.builders.TextBuilder()
)

print(txt)

输出:

Landorus

关于java - 使用 tesseract 检测明亮背景上的白色文本,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/67386714/

相关文章:

count - OpenCV中的Matlab Bwareaopen等效函数

未知方向的单个字符的 Python 光学字符识别 (OCR)

java - Tesseract 不识别阿拉伯字符

java - 用户能够访问管理员角色页面 - Spring Security

java - 使用 Java 读取单个 XML 行

java - 从java中的另一个线程访问一个线程的变量

java - 我是否需要像在 C++ 中那样将 Java 对象引用初始化为 null

opencv - 模糊模板匹配?

python - 纯白色对颜色直方图的影响

image-processing - 用于空表格单元格的 tesseract