【发布时间】:2021-04-23 20:37:28
【问题描述】:
我使用 tesseract、openCV 和 Google Vision 构建了一个用于光学字符识别的应用程序。 我有 4 种可用的文件类型可供识别(如收据)。因此用户可以选择文件(图像),然后选择文档的确切类型并单击“识别”。会发生这样一个过程:
- 使用 openCV 进行图像对齐: 我们有每种文档类型的示例图像。例如,当用户选择类型 A 时,openCV 会找到类型 A 的示例图像并开始搜索相似性。当找到足够多的相似元素时,openCV 会对齐用户的图像文件以达到最大相似度。 函数结果 - 返回对齐图像的路径。
- 使用 tesseract 进行验证: 对齐之后,tesseract 打开之前对齐的图像并识别它。然后我有一个单词列表,它必须在可识别的文本中,因此我们开始检查已识别的文本,并且对于每个成功的置信度我们增加我们的验证计数器。所以最后,如果我们的验证计数器 > 一定数量,我们批准结果并认为图像文件是正确的,可以在下一步被谷歌识别。如果验证计数器不足以批准,我们将文档类型设置为 None 对象。 函数结果 - 返回批准的对齐图像的路径和用户在开始时选择的文档类型。
- 在此之后我们启动最终功能。如果文档类型不是无(这意味着我们有一个已批准的图像文件),我们将此图像路径传递给将使用 Google Vision API 进行识别的函数,然后我们会得到一个 .txt 文件。
所以这是常见的情况。但我也提供用户选择文档的类型,称为“我不知道类型”;) 选择这种类型后执行的函数只是通过 for 循环(迭代我们拥有的所有文档类型)。因此,当我们每次使用 openCV+Tesseract 完成工作时都返回我们的文档类型,很明显我们只会得到一个非 None 类型,这将是正确的,我们将使用它来识别。 所以这个函数的执行时间最长,因为我们需要做最多 4 次 openCV 对齐和最多 4 次 tesseract 识别才能找到合适的文档类型。 我想通过为这个特定功能实现多处理来加速我的程序。我决定为这些目的使用 Celery+Redis。 这个想法是:
- 将此循环函数设置为 Celery 任务。
- 等待所有操作完成。
- 从redis读取响应(必须有4个响应,其中3个是NoneType,1个是真实的Document Type)。
- 清理 redis。
- 在最终的 Google 函数中使用正确的类型。
所以这些是我的功能,我在上面说过:
raw_img_path - 用户使用 UI 选择的路径 dt - 用户使用 UI 选择的文档类型
calc_receipt - 用于识别我们何时知道文档类型:
def calc_receipt(self, raw_img_path, dt):
aligned_img_path = OpenCV.align_img(
template_path="some\\path\\for\\chosen\\type",
raw_img_path="user\\image\\path",
result_img_path="aligned\\image\\path",
)
tesseract_result = Tesseract.read_from_img(
img_path="aligned\\image\\path",
)
if tesseract_result:
return aligned_img_path, dt
return '', DocumentType.NONE
calc_receipts - 用于在我们不知道类型时进行识别:
def calc_receipts(self, raw_img_path, selected_doc_type):
for dt in map_receipt_to_receipts[selected_doc_type]:
aligned_img_path, doc_type = self.calc_receipt(raw_img_path, dt)
if doc_type is not DocumentType.NONE:
return aligned_img_path, doc_type
可用类型列表:
map_receipt_to_receipts = {
DocumentType.NONE: [],
DocumentType.DONT_KNOW: [
DocumentType.RESTAURANT,
DocumentType.CAFE,
DocumentType.BAR,
DocumentType.COFFEE_SHOP,
],
DocumentType.RESTAURANT: [
DocumentType.RESTAURANT,
],
DocumentType.CAFE: [
DocumentType.CAFE,
],
DocumentType.BAR: [
DocumentType.BAR,
],
DocumentType.COFFEE_SHOP: [
DocumentType.COFFEE_SHOP,
],
}
类 DocumentType 是为了方便而制作的:
class DocumentType(EnumBase):
NONE = 0
DONT_KNOW = 1
RESTAURANT = 2
CAFE = 3
BAR = 4
COFFEE_SHOP = 5
据我所知,我需要重建 calc_receipts() 函数。我有一些问题:
- 我应该从这个函数启动 celery worker 吗?
- 我可以从 Python 代码而不是使用控制台启动 celery 客户端吗?
- 如何管理 redis 响应并等待所有 4 个操作。
- 对于这种使用 Celery+Redis 的案例,您通常会推荐什么? 如果我的问题很愚蠢,我很抱歉,但我很难在网上找到答案。文档不够清晰,对初学者不够友好。
【问题讨论】: