用OCR和Elasticsearch创建图像文件搜索引擎

首先

这是ABEJA 2021年圣诞节日历的第17天的文章。

本文介绍了使用谷歌的Cloud Vision API(OCR)和全文搜索引擎Elasticsearch(以下简称ES),使得可以从图像文件的文本内容中进行关键词搜索。

我們想要從大量的過去文件和資料中找到特定的文件,但一直找不到…這篇文章的內容是要介紹如何使用OCR和ES來從文件內容中更有效地進行搜索。
如果因為書面文件太多而放棄了效率化的話…也可以通過掃描或使用相機將文件圖像化來達到同樣的效果。

目錄結構

最终的目录结构。

.
├── docker-compose.yml
├── docker
│   ├── python3
│   │   └── Dockerfile 
│   └── elasticsearch
│       └── Dockerfile 
└── src
    ├── images
    │   └── input
    │   └── archive
    └── main.py

准备使用Cloud Vision API

为了使用Cloud Vision API,需要按照以下步骤进行操作。

    • Google Cloud Platformの登録

 

    • Cloud Vision APIを有効にする設定

 

    • APIを実行するためのサービスアカウントの作成

 

    • 認証用のJSONファイルをダウンロードし、任意のディレクトリに配置(以降credential.jsonとします。)

 

    認証用のJSONファイルへのpathを通す

我已参考了这篇文章!

准备执行环境

使用Docker创建Python执行环境和Elasticsearch环境。

创建一个Dockerfile来设置Docker/Python3的环境。在这个Dockerfile中,进行了Python执行环境的设置以及安装所需的google-cloud-vision库用于执行Cloud Vision API以及安装所需的库用于使用Elasticsearch。

FROM python:3.9
USER root

RUN apt-get update
RUN apt-get -y install locales && \
    localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG ja_JP.UTF-8
ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8
ENV TZ JST-9
ENV TERM xterm

RUN mkdir /app

RUN apt-get install -y vim
RUN pip install --upgrade pip
RUN pip install --upgrade setuptools

RUN python -m pip install google-cloud-vision \
                          elasticsearch

创建一个docker/elasticsearch的Dockerfile。指定Elasticsearch镜像并安装analysis-kuromoji以支持日语全文搜索功能。

FROM docker.elastic.co/elasticsearch/elasticsearch:7.15.0
RUN elasticsearch-plugin install analysis-kuromoji

创建docker-compose.yml文件。
本次将只使用一个Elasticsearch容器(节点),但根据需求,请在网络中使用多个容器(节点)。
另外,请将environment的GOOGLE_APPLICATION_CREDENTIALS指定为credential.json的路径。

version: '3'
services:
  elasticsearch:
    build: ./docker/elasticsearch
    container_name: elasticsearch
    environment:
      - discovery.type=single-node
      - cluster.name=es-docker-cluster
      - bootstrap.memory_lock=true
      - "ES_JAVA_OPTS=-Xms512m -Xmx512m"
    ulimits:
      memlock:
        soft: -1
        hard: -1
    volumes:
      - ./docker/elasticsearch:/usr/share/elasticsearch/data
    ports:
      - 9200:9200
    networks:
      - esnet
  python3:
    build: ./docker/python3
    container_name: python3
    working_dir: '/app'
    tty: true
    environment:
      GOOGLE_APPLICATION_CREDENTIALS: /tmp/keys/credential.json
    volumes:
      - ./src:/app
      - ${GOOGLE_APPLICATION_CREDENTIALS}:/tmp/keys/credential.json:ro
    networks:
      - esnet
networks:
  esnet:

当文件全部放好后,执行以下命令,即可完成本次使用环境的创建。

# 起動
> docker-comopse up -d

# 確認
> docker-compose ps   
    Name                   Command               State                Ports              
-----------------------------------------------------------------------------------------
elasticsearch   /bin/tini -- /usr/local/bi ...   Up      0.0.0.0:9200->9200/tcp, 9300/tcp
python3         python3                          Up 

使用Cloud Vision API的方法

我们正在参考这份文档来执行代码。
为了测试,我们将执行以下代码。

import io
import os
from google.cloud import vision


def detect_document(file_path):
    client = vision.ImageAnnotatorClient()

    file_name = os.path.abspath(file_path)

    with io.open(file_name, 'rb') as image_file:
        content = image_file.read()

    image = vision.Image(content=content)

    response = client.document_text_detection(
        image=image,
        image_context={'language_hints': ['ja']}
    )

    text = ''
    for page in response.full_text_annotation.pages:
        for block in page.blocks:
            for paragraph in block.paragraphs:
                for word in paragraph.words:
                    text += ''.join([
                        symbol.text for symbol in word.symbols
                    ])
                text += '\n'
    print(text)


if __name__ == "__main__":
    file_path = 'images/input/wiki-ocr-short.png'
    detect_document(file_path)

准备一个进行文字识别的图像文件。网页截图、扫描文件、拍摄手写文字纸张等任何包含文字的图像都可以。

wiki_ocr_short.png

当您执行命令时,我认为会返回文字识别的结果。

> docker-compose exec python3 python main.py

光学文字認識出典:フリー百科事典『ウィキペディア(Wikipedia)』
光学文字認識(こうがくもじにんしき、英:Opticalcharacterrecognition)は、活字、手書きテキストの画像を文字コードの列に変換するソフトウェアである。画像はイメージスキャナーや写真で取り込まれた文書、風景写真(風景内の看板の文字など)、画像内の字幕(テレビ放送画像内など)が使われる[1]。一般にOCRと略記される。
パスポート、請求書、銀行取引明細書、レシート、名刺、メール、データや文書の印刷物など、紙に記載されたデータをデータ入力する手法として広く使われ、紙に印刷された文書をデジタイズし、よりコンパクトな形で記録するのに必要とされる。さらに、文字コードに変換することでコグニティブコンピューティング、機械翻訳や音声合成の入力にも使えるようになり、テキストマイニングも可能となる。研究分野としては、パターン認識、人工知能、コンピュータビジョンが対応する。
初期のシステムは特定の書体を読むための「トレーニング」が必要であった(事前にその書体のサンプルを読ませることを意味する)。現在では、ほとんどの書体を高い識字率で変換することが可能である。いくつかのシステムでは読み込まれた画像からそれとほぼ同じになるようフォーマットされた出力(例えばワードプロセッサのファイルのようなもの)を生成することが可能であり、中には画像などの文書以外の部分が含まれていても正しく認識するものもある。

以这种方式,您几乎可以完美地阅读屏幕截图图像等美观的文字!

gcp.png
> docker-compose exec python3 python main.py

GoogleCloudPlatform
GCPとは、Googleが提供しているクラウドコンピューティングサービスである。

我可以解讀/閱讀它了!

这次能够很好地识别出这两个图片,但对于以下类似的文字或图像情况可能会降低识别的准确度。

    • スキャンした際に多くのノイズが入ってしまっている画像

 

    • 極端に明るかったり、暗かったりする写真などの画像

 

    • 文字の背景に柄が入っている場合

 

    etc

另外,如果不仔细地书写手写文字,要完美地读取是很困难的。当无法有效地识别字符时,通过进行图像预处理,如去除噪音、调整亮度等,可以提高准确性。

将信息注册到Elasticsearch中。

创建一个用于将数据注册到ES的索引。类似于关系数据库中的数据库。

# インデックス登録
> curl -XPUT 'http://localhost:9200/document?pretty'

# インデックス一覧表示
> curl 'http://localhost:9200/_cat/indices?v'     
health status index            uuid                   pri rep docs.count docs.deleted store.size pri.store.size
green  open   .geoip_databases FR2MULeESTOjuvrjO56-0g   1   0         42            0     41.2mb         41.2mb
yellow open   document         xApyPIshRMe9kNk4tvnu0g   1   1          0            0       208b           208b

这段代码使用Python向Elasticsearch注册数据。
指定了Elasticsearch的容器名称和端口号为elasticsearch:9200。

es = Elasticsearch('elasticsearch:9200')
es.index(index='document', document=doc)

取得目录下的所有图像文件,并逐一进行OCR处理后,将其注册到ES中。

import io
import os
import glob
import shutil

from elasticsearch import Elasticsearch
from google.cloud import vision


def detect_document(file_path):
    # 省略


def es_create(doc):
    es = Elasticsearch('elasticsearch:9200')
    return es.index(index='document', document=doc)


def handler():
    images = glob.glob("./images/input/*")
    for file_path in images:
        text = detect_document(file_path)

        doc = {
            'file_name': os.path.basename(file_path),
            'text': text
        }

        result = es_create(doc)
        print(result)
        shutil.move(file_path, "images/archive/")


if __name__ == "__main__":
    handler()

完成注册流程后,将要注册到ES的图片文件放置在src/images/input,并执行以下命令。
本次已注册了10张wikipedia页面的截图。
已注册的页面包括Docker、Python、光学文字识别、圣诞日历、人工智能、蛋糕、Elasticsearch、圣诞节、GCP、圣诞老人!

当文件配置完成后,让我们再次执行一次试试看。

docker-compose exec python3 python main.py
# このように出力されていたら成功です
{'_index': 'document', '_type': '_doc', '_id': 'NaHhyX0BxArSaCGZYWO_', '_version': 1, 'result': 'created', '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 0, '_primary_term': 1}
{'_index': 'document', '_type': '_doc', '_id': 'NqHhyX0BxArSaCGZi2Nv', '_version': 1, 'result': 'created', '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 1, '_primary_term': 1}
{'_index': 'document', '_type': '_doc', '_id': 'N6HhyX0BxArSaCGZvWN5', '_version': 1, 'result': 'created', '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 2, '_primary_term': 1}
{'_index': 'document', '_type': '_doc', '_id': 'OKHhyX0BxArSaCGZ6mM7', '_version': 1, 'result': 'created', '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 3, '_primary_term': 1}
{'_index': 'document', '_type': '_doc', '_id': 'OaHiyX0BxArSaCGZHmMH', '_version': 1, 'result': 'created', '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 4, '_primary_term': 1}
{'_index': 'document', '_type': '_doc', '_id': 'OqHiyX0BxArSaCGZK2Mm', '_version': 1, 'result': 'created', '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 5, '_primary_term': 1}
{'_index': 'document', '_type': '_doc', '_id': 'O6HiyX0BxArSaCGZWGNL', '_version': 1, 'result': 'created', '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 6, '_primary_term': 1}
{'_index': 'document', '_type': '_doc', '_id': 'PKHiyX0BxArSaCGZhmOv', '_version': 1, 'result': 'created', '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 7, '_primary_term': 1}
{'_index': 'document', '_type': '_doc', '_id': 'PaHiyX0BxArSaCGZnmMi', '_version': 1, 'result': 'created', '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 8, '_primary_term': 1}
{'_index': 'document', '_type': '_doc', '_id': 'PqHiyX0BxArSaCGZrGN4', '_version': 1, 'result': 'created', '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 9, '_primary_term': 1}
{'_index': 'document', '_type': '_doc', '_id': 'P6HiyX0BxArSaCGZ0GPh', '_version': 1, 'result': 'created', '_shards': {'total': 2, 'successful': 1, 'failed': 0}, '_seq_no': 10, '_primary_term': 1}

使用Elasticsearch进行搜索。

最后,让我们从在ES系统中注册的内容中进行关键词搜索。首先,我们搜索“编程”这个词。

 > curl -XPOST http://localhost:9200/document/_search -H "Content-type: application/json" -d '{
    "_source": "file_name",
    "query": {
    "term": {
      "text": "プログラミング"
    }
  }
}'     

# 出力
{
  "took": 5,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 6,
      "relation": "eq"
    },
    "max_score": 1.0072792,
    "hits": [
      {
        "_index": "document",
        "_type": "_doc",
        "_id": "QaHyyX0BxArSaCGZB2Pl",
        "_score": 1.0072792,
        "_ignored": [
          "text.keyword"
        ],
        "_source": {
          "file_name": "wiki-python.png"
        }
        ...
        "_source": {
          "file_name": "wiki-advent-calendar.png"
        }
        ...
        "_source": {
          "file_name": "wiki-ai.png"
        }
        ...
        "_source": {
          "file_name": "wiki-gcp.png"
        }
        ...
        "_source": {
          "file_name": "wiki-elasticsearch.png"
        }
        ...
        "_source": {
          "file_name": "wiki-docker.png"
        }
      }
    ]
  }
}

输出结果中出现了Python、圣诞倒数日、人工智能、GCP、Elasticsearch、Docker的图片。
接下来,我们尝试使用“圣诞节”这个关键词进行搜索。

> curl -XPOST http://localhost:9200/document/_search -H "Content-type: application/json" -d '{
    "_source": "file_name",
    "query": {
    "term": {
      "text": "クリスマス"    
    }
  }
}'

# 出力
{
  "took": 4,
  "timed_out": false,
  "_shards": {
    "total": 1,
    "successful": 1,
    "skipped": 0,
    "failed": 0
  },
  "hits": {
    "total": {
      "value": 2,
      "relation": "eq"
    },
    "max_score": 2.8236375,
    "hits": [
      {
        "_index": "document",
        "_type": "_doc",
        "_id": "P6HiyX0BxArSaCGZ0GPh",
        "_score": 2.8236375,
        "_ignored": [
          "text.keyword"
        ],
        "_source": {
          "file_path": "wiki-santa.png"
        }
        ...
        "_source": {
          "file_path": "wiki-advent-calendar.png"
        }
        ...
        "_source": {
          "file_path": "wiki-cake.png"
        }
      }
    ]
  }
}

圣诞老人,圣诞节倒数日历,蛋糕,这是输出结果。
看起来获取正确!

这次我们只执行了简单的关键词搜索,但是ES还可以进行多关键词搜索和各种条件搜索。
以上是通过OCR从图像中提取文字,将提取的文字注册到Elasticsearch中,然后从Elasticsearch中使用关键词搜索获取文件的完成过程!

在这篇文章中,只进行了从易于识别的图像文件进行简单搜索,但实际上,当使用数千甚至数万个文件进行搜索时,往往无法很好地识别,也无法获取所需信息。
在这种情况下,请尝试对图像进行预处理,处理读取的文字,或者尝试各种搜索方法,以创建针对特定用途的搜索引擎。
ABEJA正在通过识别文档中的图像,检测图纸中的各个部件,对OCR提取的文字进行自然语言处理,构建更高性能的搜索引擎!

结束

現在在ABEJA我们正在招募一起推进人工智能社会实施的伙伴。
如果你在阅读了ABEJA 2021年圣诞日历后对此感兴趣,我们可以先进行一次轻松的交谈。
可以从这里确认我们目前正在招聘的职位。期待您的申请!

广告
将在 10 秒后关闭
bannerAds