如何使用 Keras OCR 示例?

Posted

技术标签:

【中文标题】如何使用 Keras OCR 示例?【英文标题】:How can I use the Keras OCR example? 【发布时间】:2017-12-04 11:19:42 【问题描述】:

我发现examples/image_ocr.py 似乎适用于 OCR。因此,应该可以给模型一个图像并接收文本。但是,我不知道该怎么做。如何为模型提供新图像?需要哪种预处理?

我做了什么

安装依赖:

安装cairocffi:sudo apt-get install python-cairocffi 安装editdistance:sudo -H pip install editdistance 更改train 以返回模型并保存训练好的模型。 运行脚本来训练模型。

现在我有一个model.h5。下一步是什么?

请参阅https://github.com/MartinThoma/algorithms/tree/master/ML/ocr/keras 了解我当前的代码。我知道如何加载模型(见下文),这似乎有效。问题是我不知道如何将带有文本的新图像扫描提供给模型。

相关问题

什么是 CTC? Connectionist Temporal Classification? 是否有可靠检测文档旋转的算法? 是否有算法可以可靠地检测行/文本块/表格/图像(从而进行合理的分割)?我猜边缘检测与平滑和逐行直方图的效果已经相当不错了?

我尝试了什么

#!/usr/bin/env python

from keras import backend as K
import keras
from keras.models import load_model
import os

from image_ocr import ctc_lambda_func, create_model, TextImageGenerator
from keras.layers import Lambda
from keras.utils.data_utils import get_file
import scipy.ndimage
import numpy

img_h = 64
img_w = 512
pool_size = 2
words_per_epoch = 16000
val_split = 0.2
val_words = int(words_per_epoch * (val_split))
if K.image_data_format() == 'channels_first':
    input_shape = (1, img_w, img_h)
else:
    input_shape = (img_w, img_h, 1)

fdir = os.path.dirname(get_file('wordlists.tgz',
                                origin='http://www.mythic-ai.com/datasets/wordlists.tgz', untar=True))

img_gen = TextImageGenerator(monogram_file=os.path.join(fdir, 'wordlist_mono_clean.txt'),
                             bigram_file=os.path.join(fdir, 'wordlist_bi_clean.txt'),
                             minibatch_size=32,
                             img_w=img_w,
                             img_h=img_h,
                             downsample_factor=(pool_size ** 2),
                             val_split=words_per_epoch - val_words
                             )
print("Input shape: ".format(input_shape))
model, _, _ = create_model(input_shape, img_gen, pool_size, img_w, img_h)

model.load_weights("my_model.h5")

x = scipy.ndimage.imread('example.png', mode='L').transpose()
x = x.reshape(x.shape + (1,))

# Does not work
print(model.predict(x))

这给了

2017-07-05 22:07:58.695665: I tensorflow/core/common_runtime/gpu/gpu_device.cc:996] Creating TensorFlow device (/gpu:0) -> (device: 0, name: GeForce GTX TITAN Black, pci bus id: 0000:01:00.0)
Traceback (most recent call last):
  File "eval_example.py", line 45, in <module>
    print(model.predict(x))
  File "/usr/local/lib/python2.7/dist-packages/keras/engine/training.py", line 1567, in predict
    check_batch_axis=False)
  File "/usr/local/lib/python2.7/dist-packages/keras/engine/training.py", line 106, in _standardize_input_data
    'Found: array with shape ' + str(data.shape))
ValueError: The model expects 4 arrays, but only received one array. Found: array with shape (512, 64, 1)

【问题讨论】:

使用第478行定义的函数怎么样?您可以将其用作prediction = test_func(input_data)。让我知道它是否有帮助,我可以添加一个正式的答案来创建它。您也可以使用model.predict,因为它仅用于此目的。 我看到你刚刚编辑了这个问题。我将发布我目前正在写的一篇,我们可以在之后发表评论 @MartinThoma 好的,我发布了一个答案,详细解释了您可以做什么。还有如何正确获取输入的分类 @MartinThoma 编辑了有关您遇到的异常的问题...我想知道为什么要投反对票,因为它是一个彻底的答案 @devilinthedetail 不错!我认为这可能是要走的路。至少我从后面得到了一个形状为(1, 128, 28) 的矩阵。开放的问题仍然是(1)图像可以有多大的尺寸? (2) 如果我有一份扫描文件(例如 2000 像素 x 1000 像素),如何应用? (3) 模型给我的每个维度到底代表什么?我如何从中得到最可能的图像内容假设? 【参考方案1】:

好吧,我会尽力回答你在这里提出的所有问题:

正如 OCR 代码中所述,Keras 不支持具有多个参数的损失,因此它计算了 lambda 层中的 NN 损失。在这种情况下,这意味着什么?

神经网络可能看起来很混乱,因为它使用 4 个输入 ([input_data, labels, input_length, label_length]) 和 loss_out 作为输出。除了 input_data 之外,其他的都是只用于计算损失的信息,也就是说它只用于训练。我们想要原始代码第 468 行中的内容:

Model(inputs=input_data, outputs=y_pred).summary()

意思是“我有一个图像作为输入,请告诉我这里写了什么”。那么如何实现呢?

1) 保持原训练代码不变,正常进行训练;

2) 训练完成后,将此模型Model(inputs=input_data, outputs=y_pred)保存在一个.h5文件中,以便加载到任何你想要的地方;

3) 做预测:如果你看一下代码,输入图像是反转和翻译的,所以你可以使用这段代码让它变得简单:

from scipy.misc import imread, imresize
#use width and height from your neural network here.

def load_for_nn(img_file):
    image = imread(img_file, flatten=True)
    image = imresize(image,(height, width))
    image = image.T

    images = np.ones((1,width,height)) #change 1 to any number of images you want to predict, here I just want to predict one
    images[0] = image
    images = images[:,:,:,np.newaxis]
    images /= 255

    return images

加载图片后,让我们进行预测:

def predict_image(image_path): #insert the path of your image 
    image = load_for_nn(image_path) #load from the snippet code
    raw_word = model.predict(image) #do the prediction with the neural network
    final_word = decode_output(raw_word)[0] #the output of our neural network is only numbers. Use decode_output from image_ocr.py to get the desirable string.
    return final_word

这应该足够了。根据我的经验,训练中使用的图像不足以做出良好的预测,如有必要,我将使用其他数据集发布代码以改进我的结果。

回答相关问题:

什么是 CTC? Connectionist Temporal Classification?

这是一种用于改进序列分类的技术。原始论文证明它改善了发现音频中所说内容的结果。在这种情况下,它是一个字符序列。解释有点技巧,但你可以找到一个好的here.

是否有可靠检测文档旋转的算法?

我不确定,但你可以看看神经网络中的注意力机制。我现在没有任何好的链接,但我知道可能是这种情况。

是否有算法可以可靠地检测行/文本块/表格/图像(从而进行合理的分割)?我猜边缘检测与平滑和逐行直方图的效果已经相当不错了?

OpenCV 实现了最大稳定极值区域(称为 MSER)。我真的很喜欢这个算法的结果,它很快并且在我需要的时候对我来说已经足够好了。

正如我之前所说,我会尽快发布代码。当我这样做时,我将使用存储库编辑问题,但我相信这里的信息足以让示例运行。

【讨论】:

我想在保存之前编译模型“Model(inputs=input_data, outputs=y_pred)”吗? 我现在真的不记得了,但我认为没有必要。您可以在使用前编译 ir 以确保安全。【参考方案2】:

在这里,您创建了一个需要 4 个输入的模型:

model = Model(inputs=[input_data, labels, input_length, label_length], outputs=loss_out)

另一方面,您的预测尝试只是加载图像。 因此消息:模型需要 4 个数组,但只收到一个数组

从您的代码中,必要的输入是:

input_data = Input(name='the_input', shape=input_shape, dtype='float32')
labels = Input(name='the_labels', shape=[img_gen.absolute_max_string_len],dtype='float32')
input_length = Input(name='input_length', shape=[1], dtype='int64')
label_length = Input(name='label_length', shape=[1], dtype='int64')

原始代码和您的培训工作,因为他们使用TextImageGenerator。该生成器关心为您提供模型的四个必要输入。

因此,您要做的就是使用生成器进行预测。正如您使用生成器进行训练的 fit_generator() 方法一样,您还拥有使用生成器进行预测的 predict_generator() 方法。


现在,要获得完整的答案和解决方案,我必须研究您的生成器,看看它是如何工作的(这需要我一些时间)。但是现在您知道要做什么了,您可能会弄清楚。

您可以按原样使用生成器,并预测可能大量的数据,或者您可以尝试复制一个生成器,该生成器将只生成一张或几张具有必要标签、长度和标签长度的图像。

或者,如果可能,只需手动创建剩余的 3 个数组,但要确保它们具有与生成器输出相同的形状(第一个除外,即批量大小)。

但是,您必须声明的一件事是:有 4 个数组,其形状与生成器输出的形状相同,但第一个维度除外。

【讨论】:

我认为这让我感到困惑。 OCR 模型是否应该无法输出可变长度序列?如果我之前必须知道序列的长度,它有什么用? 嗯,这个模型是这样构建的。查看生成器输出的内容并检查它是否真的知道长度,或者它是否只定义了最大长度。 --- 不幸的是,Keras 在数据大小方面非常严格。您必须有一个数据大小才能工作。您可能应该将其与其他类型的算法相关联以获得良好的使用。或者创建一个能够定位和计算字母的模型。 我想象的(我没有研究过你的模型)应该有一个最大长度(只是为了定义 keras 中张量的大小),并且在可能的字符中可能有一个空字符,如果序列较短,它将填充空白。 (至少在我看来这听起来像是一个健康的模型)。【参考方案3】:

现在我有一个model.h5。下一步是什么?

首先我要评论model.h5 包含您网络的权重,如果您也希望保存网络的架构,您应该将其保存为json 就像这个例子:

model_json = model_json = model.to_json()
with open("model_arch.json", "w") as json_file:
    json_file.write(model_json)

现在,一旦您有了模型及其权重,您就可以通过执行以下操作按需加载它们:

json_file = open('model_arch.json', 'r')
loaded_model_json = json_file.read()
json_file.close()
loaded_model = model_from_json(loaded_model_json)
# load weights into new model
# if you already have a loaded model and dont need to save start from here
loaded_model.load_weights("model.h5")    
# compile loaded model with certain specifications
sgd = SGD(lr=0.01)
loaded_model.compile(loss="binary_crossentropy", optimizer=sgd, metrics=["accuracy"])

然后,使用loaded_module,您可以继续预测某些输入的分类,如下所示:

prediction = loaded_model.predict(some_input, batch_size=20, verbose=0)

这将返回该输入的分类。

关于附带问题:

    CTC 似乎是他们在您引用的论文中定义的一个术语,从中摘录如下:

在下文中,我们提到标签的任务 分段数据序列为 时间分类 (Kadous, 2002),以及我们为此目的使用 RNN 冒充 联结主义时间分类 (CTC)。

    要补偿文档、图像或类似文件的旋转,您可以通过应用此类转换从当前数据生成更多数据(查看this 博客文章,其中解释了一种方法),或者您可以使用Convolutional Neural Network 方法,这实际上也是您使用的Keras 示例所做的,正如我们从git 中看到的那样:

此示例使用 卷积 堆栈,后跟循环堆栈 和一个 CTC logloss 函数来执行光学字符识别 生成的文本图像。

您可以查看this 教程,该教程与您正在做的事情相关,并且他们还解释了有关卷积神经网络的更多信息。

    好吧,这是一个广泛的问题,但要检测线条,您可以使用 Hough Line Transform 或 Canny Edge Detection 可能是不错的选择。

编辑:您得到的错误是因为预期更多参数而不是 1,从 keras docs 我们可以看到:

predict(self, x, batch_size=32, verbose=0)

引发 ValueError:如果提供的输入数据与模型的预期不匹配,或者有状态模型接收到的样本数量不是批量大小的倍数。

【讨论】:

AttributeError: 'Model' object has no attribute 'predict_classes' 我明白了,这是因为 predict_classes 仅适用于 Sequential 模型,对于非连续模型,您应该使用 predict()... 编辑问题。【参考方案4】:

您好,您也可以查看我的github repo。您需要针对要执行 ocr 的图像类型训练模型。

# USE GOOGLE COLAB
import matplotlib.pyplot as plt
import keras_ocr

images = [keras_ocr.tools.read("/content/sample_data/IMG_20200224_113657.jpg")] #Image path
pipeline = keras_ocr.pipeline.Pipeline()
prediction = pipeline.recognize(images)
x_max = 0
temp_str = ""
myfile = open("/content/sample_data/my_file.txt", "a+")#Text File Path to save text

for i in prediction[0]:
    x_max_local = i[1][:, 0].max()
    if x_max_local > x_max:
        x_max = x_max_local
        temp_str = temp_str + " " + i[0].ljust(15)
    else:
        x_max = 0
        temp_str = temp_str + "\n"
        myfile.write(temp_str)
        print(temp_str)
        temp_str = ""
myfile.close()    

【讨论】:

以上是关于如何使用 Keras OCR 示例?的主要内容,如果未能解决你的问题,请参考以下文章

如何让这个 OCR 模型与可变长度示例一起工作?

用于从 Keras 读取验证码的 OCR 模型作者:A_K_Nain

保存 OCR 模型以从 Keras 读取验证码作者:A_K_Nain

手机ocr示例代码

如何有效地使用 Keras 与后端无关

如何使用 PyTorch 在预训练模型上添加新层? (给出了 Keras 示例。)