使用 Google Tesseract 和 Arm NN 在 Raspberry Pi 上创建文本到语音引擎





0/5 (0投票)
如何选择和转换现有的 TensorFlow 模型以使用 Arm NN,以及模型转换和实现 Arm NN 解决方案的最佳实践。
文本转语音 (TTS) 引擎是旨在基于嵌入式设备实现人机自然交互的系统的关键组成部分。例如,嵌入式设备可以帮助视障人士阅读标志、信件和文档。更具体地说,设备可以使用光学字符识别 (OCR) 来告知用户它在图像中看到了什么。
TTS 应用程序已在台式计算机上使用多年,并且在大多数现代智能手机和移动设备上都很常见。您会在系统的辅助功能工具中找到这些应用程序,但它们在屏幕阅读器、自定义警报等方面有广泛的应用。
通常,这些系统以一些机器可读文本开头。但如果您没有现有的文档、浏览器或文本应用程序源怎么办?光学字符识别 (OCR) 软件可以将扫描的图像转换为文本,但在 TTS 应用程序的上下文中,这些是字形——单个字符。OCR 软件本身只关心准确地返回数字和字母。
为了实现准确的实时文本检测——将字形集合识别为可以发音的单词——我们可以转向深度学习人工智能技术。在这种情况下,我们可以使用循环神经网络 (RNN) 来识别 OCR 捕获文本中的单词。如果我们能在嵌入式设备上实现这一点,一个比智能手机更轻巧、更便携的设备呢?
这样一个轻量级、功能强大的 TTS 设备可以帮助视障人士,可以嵌入到儿童防篡改设备中用于识字或讲故事应用程序,等等。
在本文中,我将向您展示如何使用 TensorFlow、OpenCV、Festival 和树莓派来实现这一点。我将使用 TensorFlow 机器学习平台以及预训练的 Keras-OCR 模型来执行 OCR。OpenCV 将用于从网络摄像头捕获图像。最后,Festival 语音合成系统将作为 TTS 模块。所有这些将结合起来,为树莓派构建 Python 应用程序。
在此过程中,我将告诉您典型的 OCR 模型是如何工作的,以及您如何通过 TensorFlow Lite 进一步优化解决方案,TensorFlow Lite 是一套用于在嵌入式和 IoT 设备等受限环境中运行优化 TensorFlow 模型的工具。本文提供的完整源代码可在我的 GitHub 页面上找到: https://github.com/dawidborycki/TalkingIoT。
入门
首先,要创建本教程的设备和应用程序,您需要一个树莓派。版本 2、3 或 4 都可以用于此示例。您也可以使用您的开发 PC(我们已使用 Python 3.7 测试了代码)。
您需要安装两个包:tensorflow (2.1.0) 和 keras_ocr (0.7.1)。以下是一些有用的链接
- https://github.com/faustomorales/keras-ocr
- https://missinglink.ai/guides/tensorflow/building-tensorflow-ocr-systems-key-approaches-and-tutorials/
- https://tensorflowcn.cn/lite/convert/rnn
使用循环神经网络进行 OCR
在这里,我使用 keras_ocr 包来识别图像中的文本。该包基于 TensorFlow 和卷积神经网络,最初作为 Keras 网站上的一个OCR 示例发布。
网络的架构可以分为三个重要步骤。第一个步骤获取输入图像,然后使用几个卷积层提取特征。这些层水平分割输入图像。对于每个分区,这些层确定图像列特征集。列特征序列在第二个步骤中由循环层使用。
循环神经网络 (RNN) 通常由长短期记忆 (LTSM) 层组成。LTSM 彻底改变了许多人工智能应用,包括语音识别、图像字幕和时间序列分析。OCR 模型使用 RNN 来创建所谓的字符概率矩阵。该矩阵指定给定字符在输入图像特定分区中找到的置信度。
因此,最后一步使用此矩阵从图像中解码文本。通常,人们使用连接主义时间分类 (CTC) 算法。CTC 旨在将矩阵转换为有意义的单词或单词序列。这种转换不是一件简单的事情,因为相同的字符可能出现在相邻的图像分区中。此外,一些输入分区可能不包含任何字符。
虽然基于 RNN 的 OCR 系统很高效,但在尝试将其应用到项目中时,您可能会遇到多种问题。理想情况下,您希望执行迁移学习以根据您的数据调整模型。然后,将模型转换为 TensorFlow Lite 格式,以便为边缘设备上的推理进行优化。这种方法在移动计算机视觉应用中取得了成功。例如,许多 MobileNet 预训练网络在移动和 IoT 设备上执行高效的图像分类。
但是,TensorFlow Lite 是 TensorFlow 的一个子集,因此并非所有操作都得到支持。当您想在 IoT 设备上执行像 keras-ocr 包中包含的 OCR 时,这种不兼容性会成为一个问题。官方 TensorFlow 网站提供了可能的解决方案列表。
在本文中,我将展示如何使用 TensorFlow 模型,因为 TensorFlow Lite 尚不支持(keras-ocr 中使用的)双向 LSTM 层。
预训练 OCR 模型
我首先编写了一个测试脚本 ocr.py,该脚本演示了如何使用 keras-ocr 中的神经网络模型。
# Imports import keras_ocr import helpers # Prepare OCR recognizer recognizer = keras_ocr.recognition.Recognizer() # Load images and their labels dataset_folder = 'Dataset' image_file_filter = '*.jpg' images_with_labels = helpers.load_images_from_folder( dataset_folder, image_file_filter) # Perform OCR recognition on the input images predicted_labels = [] for image_with_label in images_with_labels: predicted_labels.append(recognizer.recognize(image_with_label[0])) # Display results rows = 4 cols = 2 font_size = 14 helpers.plot_results(images_with_labels, predicted_labels, rows, cols, font_size)
该脚本从 keras_ocr.recognition 模块实例化 Recognizer 对象。然后,脚本从附加的测试数据集(Dataset 文件夹)加载图像及其标签。此数据集包含从合成单词数据集 (Synth90k) 中随机选择的八张图像。随后,脚本在数据集中的每张图像上运行 OCR 识别,然后显示预测结果。
为了加载图像及其标签,我使用了我在 helpers 模块中实现的 load_images_from_folder 函数。此方法需要两个参数:图像所在文件夹的路径和过滤器。在这里,我假设图像位于 Dataset 子文件夹下,并且我读取所有格式为 jpeg(.jpg 扩展名)的图像。
在 Synth90k 数据集中,每个图像文件名都包含下划线之间的标签。例如:199_pulpiest_61190.jpg。因此,为了获取图像标签,load_images_from_folder 函数通过下划线分割文件名,然后取结果字符串集合的第一个元素。另外,请注意 load_images_from_folder 函数返回一个元组数组。数组的每个元素包含图像和相应的标签。因此,我只将此元组的第一个元素传递给 OCR 引擎。
为了执行识别,我使用了 Recognizer 对象的 recognize 方法。此方法返回预测的标签。我将后者存储在 predicted_labels 集合中。
最后,我将预测标签的集合、图像和原始标签传递给另一个名为 plot_results 的辅助函数,该函数以 rows x columns 大小的矩形网格显示图像。您可以通过修改相应的变量来更改网格的外观。
相机
在测试了 OCR 模型后,我实现了 camera 类。该类使用了与 keras-ocr 模块一起安装的 OpenCV。OpenCV 提供了方便的编程接口来访问摄像头。具体来说,您首先初始化 VideoCapture
对象,然后调用其 read 方法从摄像头获取图像。
import cv2 as opencv class camera(object): def __init__(self): # Initialize the camera capture self.camera_capture = opencv.VideoCapture(0) def capture_frame(self, ignore_first_frame): # Get frame, ignore the first one if needed if(ignore_first_frame): self.camera_capture.read() (capture_status, current_camera_frame) = self.camera_capture.read() # Verify capture status if(capture_status): return current_camera_frame else: # Print error to the console print('Capture error')
在此代码中,我在 camera 类的初始化器中创建了 VideoCapture
。我将值 0 传递给 VideoCapture
来指向系统默认的摄像头。然后,我将生成的对象存储在 camera 类的 camera_capture 字段中。
为了从摄像头获取图像,我实现了 capture_frame 方法。它有一个额外的参数 ignore_first_frame
。当此参数为 True
时,我调用 camera_capture.read
两次,但会忽略第一次调用的结果。此操作的原理是,我的摄像头返回的第一帧通常是空白的。
第二次调用 read 方法会为您提供捕获状态和帧。如果捕获成功(capture_status
为 True
),我将返回摄像头帧。否则,我将打印“Capture error”字符串。
文本转语音
应用程序的最后一个元素是 TTS 模块。我决定在这里使用 Festival,因为它可以在离线状态下工作。Adafruit 的文章在树莓派上进行语音合成很好地描述了其他可能的 TTS 方法。
要在树莓派上安装 Festival,请调用以下命令
sudo apt-get install festival -y
您可以通过键入以下内容来测试一切是否正常工作
echo "Hello, Arm" | Festival –tts
您的树莓派此时应该会说“Hello, Arm。”
Festival 提供了一个 API。但是,为了简单起见,我决定通过命令行与 Festival 进行交互。为此,我使用另一个方法扩展了 helpers 模块
def say_text(text): os.system('echo ' + text + ' | festival --tts')
整合
最后,我们可以将所有内容组合在一起。我在 main.py 中完成了这项工作
import keras_ocr import camera as cam import helpers if __name__ == "__main__": # Prepare recognizer recognizer = keras_ocr.recognition.Recognizer() # Get image from the camera camera = cam.camera() # Ignore the first frame, which is typically blank on my machine image = camera.capture_frame(True) # Perform recognition label = recognizer.recognize(image) # Perform TTS (speak label) helpers.say_text('The recognition result is: ' + label)
首先,我创建了 OCR 识别器。然后,我创建了 Camera 对象并从默认的摄像头读取帧。图像被传递给识别器的 recognize 方法,然后生成的标签通过 TTS 辅助函数发音。
总结
总之,我们创建了一个可靠的系统,该系统可以使用深度学习执行 OCR,然后通过文本转语音引擎将结果传达给用户。我们使用了预训练的 keras-OCR 包。
在更高级的场景中,文本识别可以由文本检测先行。您首先检测图像中的文本行,然后对每一行进行识别。要做到这一点,您只需要使用 keras-ocr 的文本检测,就像在 Fausto Morales 的Keras CRNN 实现版本和发布的 CRAFT 文本检测模型中所示一样。
通过在此应用程序中添加文本检测功能,您可以实现支持 RNN 的 IoT 系统,该系统执行 OCR 来帮助视障人士阅读餐厅菜单或政府办公室的文档。此外,如果得到翻译服务的支持,此类应用程序还可以作为自动翻译器。