PyTesseract: Pythonによる簡易光学式文字認識システム

人間は,画像を見るだけで,その内容を理解することができる.画像上の文字をテキストとして認識し、それを読むことができる。

しかし、コンピュータの場合はそうはいきません。もっと具体的で、理解できるように整理されたものが必要なのだ。

そこで登場したのが、OCR(光学式文字認識)です。カメラで撮影した車のナンバープレートを認識したり、手書きの書類をデジタルコピーしたり、この技術は非常に便利です。必ずしも完璧ではありませんが、とても便利で、人によっては仕事をより簡単に、より速くできるようになります。

今回は、光学式文字認識の奥深さとその応用分野について掘り下げます。また、Pythonで簡単なスクリプトを作成し、画像から文字を検出し、より便利な対話媒体のためにFlaskアプリケーションを通してこれを公開することを支援します。

光学式文字認識とは?

光学式文字認識とは、画像上の文字を検出し、コンピュータが理解しやすいように符号化されたテキストに変換することです。テキストを含む画像をスキャンし、その中の文字を識別するために分析します。文字が認識されると、その文字が機械的に符号化されたテキストに変換されます。

実際、どのように実現されているのでしょうか。私たちは画像上の文字を識別し、文字を読み取ることができますが、コンピューターにとっては、それは点の集まりでしかありません。

まず画像をスキャンし、テキストとグラフィックをビットマップに変換します。ビットマップは、基本的に白と黒のドットのマトリックスです。次に、画像の明るさやコントラストを調整する前処理を行い、処理の精度を高める。

画像やテキストなど、注目すべき領域を特定するために、画像はゾーンに分割され、抽出処理が開始されます。テキストを含む領域は、行や単語、文字にさらに分割され、ソフトウェアは比較と様々な検出アルゴリズムによって文字を照合することができるようになりました。最終的には、画像内のテキストを抽出することができます。

このプロセスは100%正確とは言えず、正しくスキャンされなかった一部の要素を修正するために人間の介入が必要になるかもしれません。エラー修正は、辞書や自然言語処理(NLP)を使用して行うことも可能です。

出力は、ワード文書、PDF、さらには音声合成技術によるオーディオコンテンツなど、他の媒体に変換することができる。

OCRの用途

従来、文書の電子化は、コンピュータに手書きでテキストを入力することで実現していました。OCRを使えば、文書をスキャンして処理し、テキストを抽出してWord文書などの編集可能な形式で保存できるため、このプロセスが容易になります。

携帯電話のAdobe Scanなどのドキュメントスキャナーをお持ちの方は、OCR技術が使われているのを見たことがあるのではないでしょうか。

空港では、パスポートの認識とそこから情報を抽出するプロセスの自動化にOCRを使用することもできます。

その他にも、データ入力プロセスの自動化、車のナンバープレートの検出・認識など、OCRは様々な用途で利用されています。

使用するもの

このOCRプロジェクトでは、GoogleのTesseract-OCR EngineのラッパーであるPython-Tesseract(または単にPyTesseract)ライブラリを使用する予定です。

このライブラリはGoogleのTesseract-OCR Engineのラッパーで、完全にオープンソースであり、Googleという巨大企業によって開発・維持されているため、これを選びました。PyTesseractはTesseractに依存しているので、以下の手順でTesseractをマシンにインストールします。

また、WebフレームワークのFlaskを使用して、文字認識のためにWebカメラで写真を撮ったり、写真をアップロードしたりできる簡単なOCRサーバを作成する予定です。

また、仮想環境の設定や要件管理を行うPipenvも使用する予定です。

PillowはPython Imaging Library (PIL)のフォークで、Pythonで様々な形式の画像を開いたり操作したりするためのライブラリです。

この記事では、PyTesseractに焦点を当てますが、以下のような画像からテキストを抽出するのに役立つ他のPythonライブラリも存在します。

  • Textract: PDFからデータを抽出することができますが、重いパッケージです。
  • Pyocr: 文章、数字、単語など、より多くの検出オプションを提供します。

セットアップ

まず、Pip経由で以下のコマンドでPipenvをインストールします(設定が必要な場合は、こちらを参照してください)。

$ pip install pipenv


プロジェクトディレクトリを作成し、以下のコマンドを実行してプロジェクトを起動します。

$ mkdir ocr_server && cd ocr_server && pipenv install --three


これで、仮想環境を起動し、依存関係のインストールを開始することができます。

$ pipenv shell
$ pipenv install pytesseract Pillow


Pipenvを使用しない場合、Pipと仮想環境のアプローチを使用することができます。Pip and Virtual Environmentを使い始めるには、公式のドキュメントに従ってください。

Note: この場合、pipenv install Pillowの代わりに、pip install Pillowとなります。

実装

このプロジェクトは、2つのフェーズで実装します。まず、スクリプトを作成し、次にインターフェイスとして機能するFlaskアプリケーションを構築します。

OCRスクリプト

ここまでで、画像を受け取り、その画像から検出されたテキストを返す簡単な関数を作成することができます。

try:
    from PIL import Image
except ImportError:
    import Image
import pytesseract


def ocr_core(filename):
    """
    This function will handle the core OCR processing of images.
    """
    text = pytesseract.image_to_string(Image.open(filename))  # We'll use Pillow's Image class to open the image and pytesseract to detect the string in the image
    return text


print(ocr_core('images/ocr_example_1.png'))


この関数は非常に簡単で、最初の5行でPillowライブラリとPyTesseractライブラリからImageをインポートしています。

そして、ファイル名を受け取り、画像に含まれるテキストを返す ocr_core 関数を作成します。

それでは、このスクリプトがテキストを含む簡単な画像に対してどのような結果をもたらすか見てみましょう。

そして、このコードを実行すると、次のように表示されます。

このシンプルなOCRスクリプトはうまくいきました。手書き文字とは異なり、完璧で正確なデジタル・テキストなので、明らかにこれは簡単でした。PyTesseractライブラリでできることはまだまだたくさんありますが、これについては後ほど詳しく説明します。

まずはこのスクリプトをFlaskアプリケーションに組み込んで、画像のアップロードや文字認識処理を簡単に行えるようにしましょう。

Flask ウェブインタフェース

今回のスクリプトはコマンドラインからも利用できますが、Flaskのアプリケーションがあれば、より使いやすく、多機能になります。例えば、Webサイト経由で写真をアップロードして、抽出したテキストをWebサイトに表示させたり、Webカメラで写真を撮影して、その写真に対して文字認識を実行したりすることができます。

Flaskフレームワークに慣れていない方は、このチュートリアルでスピードアップして進められるでしょう。

まずはFlaskのパッケージをインストールするところから始めましょう。

$ pipenv install Flask


では、基本的なルートを定義してみましょう。

from flask import Flask
app = Flask(__name__)


@app.route('/')
def home_page():
    return "Hello World!"


if __name__ == '__main__':
    app.run()


ファイルを保存して、実行します。

$ python3 app.py


ブラウザを開いて 127.0.0.1:5000 または localhost:5000 にアクセスすると、ページ上に “Hello World!” が表示されるはずです。これは、Flaskアプリが次のステップに進む準備ができていることを意味します。

次に、HTML ファイルを格納するための templates フォルダを作成します。まずは、シンプルな index.html を作成しましょう。

<!DOCTYPE html

<html
<head
<titleIndex</title
</head
<body
    Hello World.
  </body
</html


また、新しいテンプレートをレンダリングするために、app.pyを調整しましょう。

from flask import Flask, render_template
app = Flask(__name__)


@app.route('/')
def home_page():
    return render_template('index.html')


if __name__ == '__main__':
    app.run()


ここで、 render_template をインポートして、HTML ファイルをレンダリングするために使用したことに注意してください。Flaskアプリを再起動すると、ホームページに “Hello World!”が表示されているはずです。

Flask のクラッシュコースはここまでにして、次は OCR スクリプトを Web アプリケーションに統合してみましょう。

まず、Flask アプリに画像をアップロードする機能を追加し、それを上で書いた ocr_core 関数に渡します。そして、抽出されたテキストの横にある画像をWebアプリケーションにレンダリングします。

import os
from flask import Flask, render_template, request


# import our OCR function
from ocr_core import ocr_core


# define a folder to store and later serve the images
UPLOAD_FOLDER = '/static/uploads/'


# allow files of a specific type
ALLOWED_EXTENSIONS = set(['png', 'jpg', 'jpeg'])


app = Flask(__name__)


# function to check the file extension
def allowed_file(filename):
    return '.' in filename and 
           filename.rsplit('.', 1)[1].lower() in ALLOWED_EXTENSIONS


# route and function to handle the home page
@app.route('/')
def home_page():
    return render_template('index.html')


# route and function to handle the upload page
@app.route('/upload', methods=['GET', 'POST'])
def upload_page():
    if request.method == 'POST':
        # check if there is a file in the request
        if 'file' not in request.files:
            return render_template('upload.html', msg='No file selected')
        file = request.files['file']
        # if no file is selected
        if file.filename == '':
            return render_template('upload.html', msg='No file selected')


if file and allowed_file(file.filename):


# call the OCR function on it
            extracted_text = ocr_core(file)


# extract the text and display it
            return render_template('upload.html',
                                   msg='Successfully processed',
                                   extracted_text=extracted_text,
                                   img_src=UPLOAD_FOLDER + file.filename)
    elif request.method == 'GET':
        return render_template('upload.html')


if __name__ == '__main__':
    app.run()


upload_page()`関数でわかるように、POSTで画像を受け取り、GETの場合はアップロード用のHTMLをレンダリングします。

ユーザーが本当にファイルをアップロードしたかどうかを確認し、関数 allowed_file() を使用してファイルが許容できるタイプかどうかをチェックします。

画像が必要なタイプであることを確認した後、先に作成した文字認識スクリプトに画像を渡す。

この関数は画像中のテキストを検出し、それを返す。最後に、画像アップロードの応答として、検出されたテキストを画像と一緒にレンダリングし、ユーザーが結果を確認できるようにします。

アップロード.html`ファイルは、Flaskにデフォルトで同梱されているJinjaテンプレートエンジンの助けによって、画像の投稿と結果のレンダリングを処理します。

<!DOCTYPE html

<html
<head
<titleUpload Image</title
</head
<body


{% if msg %}
   <h1{{ msg }}</h1
   {% endif %}

   <h1Upload new File</h1
<form enctype="multipart/form-data" method="post"
<p<input name="file" type="file"/
<input type="submit" value="Upload"/
</p</form
<h1Result:</h1
   {% if img_src %}
     <img src="{{ img_src }}"/
   {% endif %}

   {% if extracted_text %}
     <p The extracted text from the image above is: <b {{ extracted_text }} </b</p

   {% else %}
     The extracted text will be displayed here
   {% endif %}
 </body
</html


Jinjaテンプレートは、{% if %}}タグを通して、特定のシナリオでテキストを表示することができます。{% endif %} タグを通して、特定のシナリオでテキストを表示することができます。また、{{ }}タグの中で、FlaskアプリからWebページ上に表示するメッセージを渡すこともできます。ここでは、Flaskアプリに画像をアップロードするためにフォームを使用しています。

その結果がこちらです。

ここで、先程の画像をアップロードしてみます。

はい、できました。このFlaskアプリケーションはOCR機能を統合し、ブラウザにテキストを表示することができました。これで、新しい画像を処理するたびにCLIでコマンドを実行する必要がなくなり、簡単に画像処理を行うことができます。

この単純な OCR スクリプトはすべての状況で動作するわけではないので、さらにいくつかの画像を添付して、その限界を探ってみましょう。

例えば、次の画像からテキストを抽出してみましょう。結果は画像上でハイライトされています。

これは、OCRが常に100%正確であるとは限らず、時折、人間の介入が必要であることを示す証拠です。

また、このOCRスクリプトがどのように機能するかを確認するために、私の手書き文字に対してテストしてみました。

このように、私の手書き文字からは、以前に見た他の画像と同じようにテキストを抽出することができません。そこで、今度はこのソースの画像で試してみたところ、次のような結果が得られました。

この画像の文字認識は、自分の手書きの文字を使った場合よりもはるかに優れています。ダウンロードした画像は線が太く、文字と背景のコントラストも良いので、私の手書き文字がうまく認識されなかった原因かもしれません。

友人や同僚から手書きのメモをもらってきて、スクリプトがどの程度文字を検出できるかを確認することもできますし、さらに検討すべき分野です。また、イベントのポスターをもらって、それをスキャンして文字を探してみるなど、いろいろな可能性があります。

その他のPyTesseractオプション

Python-Tesseractには他にも探索可能なオプションがあります。例えば、langフラグで言語を指定することができます。

pytesseract.image_to_string(Image.open(filename), lang='fra')


これは、langフラグを付けずに画像をスキャンした結果です。

そして今度は lang フラグを指定した場合です。

フレームワークは、スクリーンショットに見られるように、言語をよりよく検出するように最適化されています。(画像ソース)。

lang` フラグがない場合、スクリプトはフランス語の単語をいくつか見逃していましたが、フラグを導入した後は、すべてのフランス語のコンテンツを検出することができました。翻訳はできないが、これでも印象的である。Tesseractの公式ドキュメントには、このセクションでサポートされている言語が記載されています。

PyTesseractの機能には、向きや文字の検出も含まれており、画像上で使用されているフォントや文字の向きを検出することができます。先ほどダウンロードした手書きの画像を見てみましょう。

print(pytesseract.image_to_osd(Image.open('downloaded_handwritten.png')))


この画像にはページ番号の情報がないため、検出されませんでした。Tesseractのエンジンは、画像内のテキストの向きと回転に関する情報を抽出することができます。向き確信度は、検出された向きについてエンジンがどの程度確信を持っているかを示す数値であり、目安になると同時に、必ずしも100%正確ではないことを示すものである。スクリプトセクションは、テキストに使用されている文字体系を示し、これにも信頼度マーカーが続く。

認識された文字とその枠の境界を知りたい場合、PyTesseractは pytesseract.image_to_boxes(Image.open('downloaded_handwritten.png')) によってこれを実現します。

これらはPyTesseractの機能の一部ですが、他にも抽出されたテキストを検索可能なPDFやHOCR出力に変換する機能などがあります。

まだできていないこと

この投稿で多くのことを達成しましたが、プロジェクトを洗練させ、実世界に備えるために、まだやるべきことがあります。まず、CSSを使用してウェブサイトにスタイルを追加し、エンドユーザーにとってより魅力的なものにすることができます。また、複数の画像を一度にアップロードしてスキャンし、その出力を一度に表示するオプションも追加します。これなら、複数の原稿をスキャンする際にも便利だと思いませんか?

もちろん、ユーザーの許可があれば、ブラウザからマシンのカメラに接続し、画像を取り込むことも可能です。これは、特にモバイルデバイスで大きな助けとなります。ユーザーが画像を取り込んで保存し、Webサイトにアップロードする代わりに、カメラ機能を追加すれば、ユーザーがFlaskのWebアプリケーションから直接操作を行えるようになるのです。これによって、スキャン処理を高速化することができます。

もし、FlaskアプリケーションがOCRスキャナを公開するためのものではないとしたら、CLIツールを作成することもできます。このツールでは、画像の場所を含むコマンドを実行し、スキャナの出力をターミナルに出力したり、データベースやAPIに送信したりすることができます。この道を選んだ場合、Docopt は Python を使ってコマンドラインツールを構築するための素晴らしいツールです。

結論

TesseractとPython-Tesseractライブラリにより、画像をスキャンし、そこからテキストを抽出することができました。これは光学的文字認識(Optical Character Recognition)であり、様々な場面で活用することができます。

私たちは、画像を取り込み、画像に含まれるテキストを返すスキャナを構築し、インターフェースとしてFlaskアプリケーションに統合しました。これにより、より身近な媒体で、複数の人に同時にサービスを提供できる形で、機能を公開することができました。

このプロジェクトのソースコードは、こちらのGithubで公開されています。

タイトルとURLをコピーしました