从视频游戏屏幕截图中提取尽可能多的文本的最佳方法是啥?

Posted

技术标签:

【中文标题】从视频游戏屏幕截图中提取尽可能多的文本的最佳方法是啥?【英文标题】:What's the best way to ocr as much text as possible from video game screenshots?从视频游戏屏幕截图中提取尽可能多的文本的最佳方法是什么? 【发布时间】:2018-10-14 15:24:03 【问题描述】:

我正在尝试使用 tesseract ocr tool 从视频游戏中提取 ocr 文本(我正在预处理屏幕截图并将它们传递给命令行工具 tsv 输出并对其进行解析)。

我想将它用于测试自动化,这与 selenium 网络测试不同。 那就是我希望能够等待元素出现而不是睡觉并点击按钮(主要是菜单)。

为了能够做到这一点,我需要能够始终如一地找到相同的按钮文本,并针对一系列视频游戏找到尽可能多的文本。 为了抽象起见,我希望每个游戏的预处理/tesseract 选项都相同。

我可能会为每个游戏中遇到的每个单词添加一个字典,但我不想这样做。

我有一个设置,我可以在其中测试预处理/tesseract 选项的多种不同组合并查看生成的单词。

我已经尝试将屏幕截图(70-90 dpi)放大 5 倍,并在将其传递给 tesarect 之前将其设为灰度。

我可以使用哪些其他技术来提高结果的数量和准确性?我应该看哪些 tesseract 旋钮?我可以添加任何其他有用的预处理吗?

附:我发现如果我将图片放大到两倍长/宽的 tesseract 似乎会爆炸,因为它的图像内存不足。有静态限制吗?我可以找到它,以便我可以将图像放大到接近最大尺寸吗?我可以调整吗?

【问题讨论】:

也许您可以使用 object tracking in OpenCV 之类的东西作为预处理步骤之一来创建更高对比度的蒙版并尝试 OCR。 Python 对于这项工作(包括 OpenCV 等)仍然非常缓慢。如果显卡有Hook API或者使用互联网的游戏,最好查看包。您可能必须使用汇编或 C。 另一种方法:与其尝试识别图片中的文本,不如尝试检测屏幕截图中是否存在示例硬编码图像? 你在做什么。你能提供一些描述。如果符合我的兴趣,我会做出贡献。 与几乎所有计算机视觉问题一样,最好通过提供示例图像来讨论这个问题。否则真的很难做出判断。 【参考方案1】:

训练你自己的 tessdata

这是迄今为止我从 tesseract 的经验中学到的最重要的一课。开箱即用的 tesseract 非常适合识别扫描的书籍和报纸文本,但是根据我的经验,当您尝试使用与标准书籍和报纸字体(如 Times New Roman)不相似的字体时,准确性会显着降低。训练过去要困难得多,但现在tesstrain.sh 让它变得轻而易举。您将不得不收集您的视频游戏字体(或至少看起来与它们相似的字体)并将它们作为输入提供给训练脚本。即使您的字体差异很大,tesseract 也能够在运行时以惊人的准确性为提供的图像选择正确的字体。另外,我知道这很乏味,但是将视频游戏中遇到的所有单词的单词表提供给训练脚本会很有帮助。使用您自己的字体和您自己的单词表训练 tesseract 将使您获得近乎完美的准确性,而无需做任何其他事情。

预处理图像以识别

不要依赖tesseract的布局分析

如果可以,请进行自己的布局分析并将图像裁剪为包含文本的部分。 Teseract 内置了一个页面分割引擎,但它必须涵盖如此广泛的用例,以至于它很可能无法满足您的特定需求。此外,根据我的经验,如果您将图像分成单行文本并使用分割模式 7(将图像视为单行文本),它会进一步提高准确性。

提高输入文本的 x 高度

如果您将输入文本的 x 高度增加到用于训练 tesseract 的相同高度(在我的情况下,IIRC 是 70 像素),这会有所帮助。

提高输入文本的 DPI

Tesseract really likes 300 DPI。请注意,更改图像的 DPI 与更改其大小不同。 (例如,使用 ImageMagick 您可以use the -density option 更改图像的 DPI)。

要使用的 Tesseract 配置变量

根据我的经验,调整与匹配字典单词有关的不同“惩罚”设置对提高准确性的影响最大。对我有用的设置:

language_model_penalty_non_dict_word      0.975
language_model_penalty_non_freq_dict_word 0.575
segment_penalty_dict_case_bad             1.3125
segment_penalty_dict_case_ok              1.1
segment_penalty_dict_nonword              10.25

但是您显然应该自己进行调整。另外,我发现 x-height 设置在运行时非常有用:textord_min_xheightmin_sane_x_ht_pixels


我不知道 tesseract 有任何内存大小限制。您是否可能通过有其自身限制的包装器使用 tesseract?


注意:此答案假设您使用的是 tesseract 的最新稳定版本,即 tesseract 3.05。如果您使用的是 tesseract 4.0,您自己的训练和分割仍然适用,但答案的其他部分可能是 OBE。

【讨论】:

如何增加 x 高度?我只是垂直放大图像吗? 是的,不只是垂直,把它放大以使其与您的训练图像相匹配(就像我说的,我认为训练脚本默认为 70)【参考方案2】:

您可能无法从tesseract 获得合适的质量输出的原因有很多。需要注意的是,除非您使用非常不寻常的字体或新语言,否则重新训练 tesseract 不太可能有帮助。

因此,请查看 ImproveQuality 工具来完成以下任务:重新缩放、二值化、去噪、旋转/去歪斜和去除边框。

例如,这是一个脚本,您可以在其中找到颜色转换、转换和绘图操作:

from __future__ import division, print_function
from skimage.transform import radon
from PIL import Image
from numpy import asarray, mean, array, blackman
import numpy
from numpy.fft import rfft
import matplotlib.pyplot as plt
from matplotlib.mlab import rms_flat

try:
    # More accurate peak finding from
    # https://gist.github.com/endolith/255291#file-parabolic-py
    from parabolic import parabolic

    def argmax(x):
       return parabolic(x, numpy.argmax(x))[0]

except ImportError:
    from numpy import argmax

filename = 'skew-linedetection.png'

# Load file, converting to grayscale
I = asarray(Image.open(filename).convert('L'))
I = I - mean(I)  # Demean; make the brightness extend above and below zero
plt.subplot(2, 2, 1)
plt.imshow(I)

# Do the radon transform and display the result
sinogram = radon(I)

plt.subplot(2, 2, 2)
plt.imshow(sinogram.T, aspect='auto')
plt.gray()

# Find the RMS value of each row and find "busiest" rotation,
# where the transform is lined up perfectly with the alternating dark
# text and white lines
r = array([rms_flat(line) for line in sinogram.transpose()])
rotation = argmax(r)
print('Rotation: :.2f degrees'.format(90 - rotation))
plt.axhline(rotation, color='r')

# Plot the busy row
row = sinogram[:, rotation]
N = len(row)
plt.subplot(2, 2, 3)
plt.plot(row)

# Take spectrum of busy row and find line spacing
window = blackman(N)
spectrum = rfft(row * window)
plt.plot(row * window)
frequency = argmax(abs(spectrum))
line_spacing = N / frequency  # pixels
print('Line spacing: :.2f pixels'.format(line_spacing))

plt.subplot(2, 2, 4)
plt.plot(abs(spectrum))
plt.axvline(frequency, color='r')
plt.yscale('log')
plt.show()

【讨论】:

去噪和纠偏等算法有助于清理扫描的图像,但我认为这对 OP 的图像具有数字来源的情况没有帮助。 @mnistic 视频文件蓝色通道中的噪点有时比扫描图像中的更糟糕。字母的倾斜可以是这样的:benjaminpercy.com/thrill-me-essays-on-fiction【参考方案3】:

Google 云为视频提供 OCR。所以你不必截图。您可以将整个游戏视频更新到 GCP 并调用 API 进行处理。 API 将为视频中的每个文本返回时间戳和边界框。它的处理速度非常快,产生的结果非常密集且一致。具体可以看官方文档:https://cloud.google.com/video-intelligence/docs/text-detection

【讨论】:

一张图片能保留多久重要吗?我想从诸如linkedin技能测试之类的问答网站上拍摄视频,并且不想从每个问题中截取屏幕截图。相反,我想在回答 20 个问题时抓取视频,这需要大约 20 个问题。 10 分钟(每个问题 30 秒)。【参考方案4】:

您是否尝试过使用深度学习方法,尤其是对象识别算法来检测https://matthewearl.github.io/2016/05/06/cnn-anpr/ 中的按钮文本su chas?

【讨论】:

以上是关于从视频游戏屏幕截图中提取尽可能多的文本的最佳方法是啥?的主要内容,如果未能解决你的问题,请参考以下文章

识别屏幕截图中字符的最佳方法?

如何在给定时间使用 ffmpeg 为视频提取 1 个屏幕截图?

屏幕截图中低分辨率文本的 OCR

截图出来是黑色的

从深度学习的表单中提取文本的最佳方法?

在 Selenium 2 中截取测试屏幕截图的最佳方法是啥?