Help us understand the problem. What is going on with this article?

GCPの手書き文字認識(OCR)を使ってみる

概要

GCP(Google Cloud platform)で利用することのできる光学式文字認識(OCR)機能を使って、手書きの文字を認識する方法をまとめました。
GCP初心者、これからGCP使ってみたい人向けです。

はじめに

目標

GCPのOCR機能を利用して、画像内の手書きの文字を認識することが目標です。

実行環境

macOS Catalina 10.15.6
Python 3.8.1

目次

  • 始める前に
  • 入力データを用意しよう
  • いざ、実装
  • 実行
  • 実行結果
  • コード解説
  • 感想

始める前に

GCPの各サービスを利用するにはGoogleアカウントを作成する必要があります。Googleアカウントをお持ちでない方はこちらを参考にGoogleアカウントを作成してください。

Googleアカウントを作成したらGCPのコンソールにアクセスし、こちらを参考にCloudプロジェクト、認証情報の設定を行ってください。

入力データを用意しよう

実装を始める前にまず認識させたい手書き画像を適当に用意しましょう。
私はこんな画像を用意しました。

いざ、実装

チュートリアルを参考にコードを作成します。
作成したコードは以下になります。ファイル名はdetect.pyにしました。

import os
import io

from google.cloud import vision

def detect_document(path):
    client = vision.ImageAnnotatorClient()
    with io.open(path, 'rb') as image_file:
        content = image_file.read()

    image = vision.types.Image(content=content)

    response = client.document_text_detection(image=image)

    for page in response.full_text_annotation.pages:
        for block in page.blocks:
            print('\nBlock confidence: {}\n'.format(block.confidence))

            for paragraph in block.paragraphs:
                print('Paragraph confidence: {}'.format(
                    paragraph.confidence))

                for word in paragraph.words:
                    word_text = ''.join([
                        symbol.text for symbol in word.symbols
                    ])
                    print('Word text: {} (confidence: {})'.format(
                        word_text, word.confidence))

                    for symbol in word.symbols:
                        print('\tSymbol: {} (confidence: {})'.format(
                            symbol.text, symbol.confidence))

    if response.error.message:
        raise Exception(
            '{}\nFor more info on error messages, check: '
            'https://cloud.google.com/apis/design/errors'.format(
                response.error.message))


if __name__ == "__main__":
    path = 'sample.png'
    detect_document(os.path.abspath(path))

実行

実行コマンドは以下になります。

python3 detect.py

実行結果

Block confidence: 0.8999999761581421

Paragraph confidence: 0.8999999761581421
Word text: 私 (confidence: 0.9800000190734863)
    Symbol: 私 (confidence: 0.9800000190734863)
Word text: の (confidence: 0.9900000095367432)
    Symbol: の (confidence: 0.9900000095367432)
Word text: 名前 (confidence: 0.9300000071525574)
    Symbol: 名 (confidence: 0.8600000143051147)
    Symbol: 前 (confidence: 1.0)
Word text: は (confidence: 0.9900000095367432)
    Symbol: は (confidence: 0.9900000095367432)
Word text: KOTARO (confidence: 0.8299999833106995)
    Symbol: K (confidence: 0.4099999964237213)
    Symbol: O (confidence: 0.8299999833106995)
    Symbol: T (confidence: 0.8600000143051147)
    Symbol: A (confidence: 0.9900000095367432)
    Symbol: R (confidence: 0.9900000095367432)
    Symbol: O (confidence: 0.949999988079071)
Word text: です (confidence: 0.9399999976158142)
    Symbol: で (confidence: 0.9399999976158142)
    Symbol: す (confidence: 0.949999988079071)
Word text: 。 (confidence: 0.9900000095367432)
    Symbol: 。 (confidence: 0.9900000095367432)

Block confidence: 0.9200000166893005

Paragraph confidence: 0.9200000166893005
Word text: の (confidence: 0.9200000166893005)
    Symbol: の (confidence: 0.9200000166893005)

Block confidence: 0.9300000071525574

Paragraph confidence: 0.9300000071525574
Word text: Python (confidence: 0.9700000286102295)
    Symbol: P (confidence: 0.9800000190734863)
    Symbol: y (confidence: 0.9800000190734863)
    Symbol: t (confidence: 0.9100000262260437)
    Symbol: h (confidence: 0.9900000095367432)
    Symbol: o (confidence: 0.9900000095367432)
    Symbol: n (confidence: 0.9900000095367432)
Word text: が (confidence: 0.9700000286102295)
    Symbol: が (confidence: 0.9700000286102295)
Word text: 好き (confidence: 0.8999999761581421)
    Symbol: 好 (confidence: 0.9399999976158142)
    Symbol: き (confidence: 0.8600000143051147)
Word text: です (confidence: 0.8500000238418579)
    Symbol: で (confidence: 0.7799999713897705)
    Symbol: す (confidence: 0.9300000071525574)
Word text: 。 (confidence: 0.8799999952316284)
    Symbol: 。 (confidence: 0.8799999952316284)

Block confidence: 0.949999988079071

Paragraph confidence: 0.949999988079071
Word text: みんな (confidence: 0.9900000095367432)
    Symbol: み (confidence: 0.9900000095367432)
    Symbol: ん (confidence: 1.0)
    Symbol: な (confidence: 1.0)
Word text: 、 (confidence: 0.699999988079071)
    Symbol: 、 (confidence: 0.699999988079071)
Word text: フォロー (confidence: 0.9300000071525574)
    Symbol: フ (confidence: 0.8899999856948853)
    Symbol: ォ (confidence: 0.9200000166893005)
    Symbol: ロ (confidence: 0.9399999976158142)
    Symbol: ー (confidence: 1.0)
Word text: し (confidence: 1.0)
    Symbol: し (confidence: 1.0)
Word text: て (confidence: 1.0)
    Symbol: て (confidence: 1.0)
Word text: ね (confidence: 0.9900000095367432)
    Symbol: ね (confidence: 0.9900000095367432)
Word text: 。 (confidence: 0.9900000095367432)
    Symbol: 。 (confidence: 0.9900000095367432)
python3 detect.py  0.82s user 0.42s system 2% cpu 57.861 total

画像ファイルのサイズは8.7MBで、実行時間は0.82sでした。
自分がトレーニングしたモデルよりかなりの精度が出ていることがわかりました。
さすが天下のGoogle。。。

コード解説

detect_documentメソッド内のコードを簡単に説明します。

    client = vision.ImageAnnotatorClient()
    with io.open(path, 'rb') as image_file:
        content = image_file.read()

    image = vision.types.Image(content=content)

この部分で認証と画像の取得を行っています。認証設定がしっかりできていないと1行目の部分でエラーが出ます。
次は認識の部分です。

response = client.document_text_detection(image=image)

実際に認識を行っているのはこの1行のみになります。imageに指定されている画像をGoogleが予めトレーニングしたモデルの認識にかけた結果がresponseに返ってきます。

for page in response.full_text_annotation.pages:
        for block in page.blocks:
            print('\nBlock confidence: {}\n'.format(block.confidence))

            for paragraph in block.paragraphs:
                print('Paragraph confidence: {}'.format(
                    paragraph.confidence))

                for word in paragraph.words:
                    word_text = ''.join([
                        symbol.text for symbol in word.symbols
                    ])
                    print('Word text: {} (confidence: {})'.format(
                        word_text, word.confidence))

この部分で結果を表示しています。
blockは単語の集まりをひとまとめに捉えたもので、block.confidenceでそのブロック全体のconfidence(認識結果の信頼度)にアクセスできます。
ブロック内の文章(paragraph)と認識されたものにはblock.paragraphs、パラグラフ内で単語(word)と認識されたものにはblock.words、ワード内の各文字(symbols)にはblock.symbolsでアクセスできます。

認識結果を用いて何かしたいという場合はこの部分から各認識結果へのアクセスの方法を得るといいと思います。

感想

さすがの精度と処理速度といったところでした。他にも色々触ってみたくなりました。

最後までご覧いただきありがとうございました。
私自身まだまだ未熟者でありますので、記事についてのご指摘、質問等ありましたら遠慮なくおっしゃってください。

IAMKOTARO
Python好きと戯れたい大学3年生 機械学習/Webアプリ開発/クラウド 好きな言語ランキング 1. Python 2. C, C++ 3. Java 好きなOSランキング 1. ubuntu 2. CentOS 3. Mac OS
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした