Cloud Vision APIでPDF内のテキストを抽出する流れ

## はじめに

みなさん、OCR (Optical Character Recognition、光学文字認識)やっていらっしゃいますでしょうか。画像上の文字情報などを読み取る技術で、いろんなところで見られるようになってきています。また、庶民でもOCR技術を使えるよう、GCPなどでも手軽に使えるようになってきています。

そこでGCPのCloud Vision APIを利用してPDF内の文字情報を読み取ろうとしていたのですが、公式ドキュメントがちょっとわかりにくい（？）気がしたのでこちらでメモがわりにまとめたいと思います。

> [ファイル内のテキストを検出する（PDF / TIFF）](https://cloud.google.com/vision/docs/pdf?fbclid=IwAR1lGkE65H4kd1dCnVQV-QUe76lRiUJnitmAhc46kQ_OdyuRLKZnYU0s-zY#vision_text_detection_pdf_gcs-python)

上記のドキュメントだといろいろ大切なところが省略されている気がして、初心者の自分にとってはちょっと苦戦しました。

## 環境

```
Mac OS Mojave
Python 3.7
```

## 費用

まだ4月分の請求がわからないのですが、たぶん少ないと思います。
あと初回でもらえる無料クレジットを使っているのもあり、わかり次第更新します。

## Cloud Vision APIを有効にする

Cloud Vision APIの有効化を行います。

![Screen Shot 2020-04-25 at 18.14.17.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396623/848eaab6-3b71-ca12-29af-1575be34a82c.png)

APIとサービスからライブラリを選び、Cloud Vision APIを検索し、有効化します。

![Screen Shot 2020-04-25 at 18.13.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396623/63dd6234-8de2-3f7c-216a-181074ff1aae.png)



## jsonの鍵ファイルを作成

![Screen Shot 2020-04-25 at 19.18.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396623/d68d37fc-6883-25fe-b8ef-a9fc0e156a96.png)

IAMと管理からサービスアカウントを選び、新たなサービスアカウントの作成を行います。

以下の`サービスアカウントを作成`から、鍵jsonファイルを作成することが可能です。

![Screen Shot 2020-04-25 at 19.18.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396623/c46375d5-1e6c-9c5c-e2b3-5ebe3c0e7645.png)

これでパブリックキーなどが記載された鍵ファイルが作成できます。
この鍵ファイルをあとで作業ファイルに移すことになります。

## Cloud Storageの準備

![Screen Shot 2020-04-25 at 18.14.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396623/cfab772e-e114-106d-f3f2-6d3675c0fca0.png)

Storageからブラウザを選びます。そうすると、ストレージブラウザに飛ぶので、バケットを作成をクリックします。

![Screen Shot 2020-04-25 at 18.17.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396623/5f097faa-9fc2-0fe7-c53d-810030aaaf37.png)


新たなバケットを作成し、そこにOCRしたいpdfファイルをアップロードします。自分の今回のバケット名は`environment-engineering-pdf-bucket-1`で、`scan-001.pdf`をアップロードしました。

![Screen Shot 2020-04-25 at 19.24.23.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396623/8058d7b9-80b9-1207-c5d6-e97359b8081f.png)

またもうひとつpdfファイルの文字情報を読み取ったものを保存しておくバケットも作成します。その名前を`ocr-result-bucket-qiita`としました。

## 必要なモジュールのインポート

以下の3つが必要なので、importしておきましょう。virtualenvを使うのもありです。

```
pip install google-cloud-vision
pip install google-cloud-storage
pip install protobuf
```

> https://pypi.org/project/google-cloud-storage/
> https://pypi.org/project/google-cloud-vision/
> https://pypi.org/project/protobuf/


## 実際のpythonの処理開始

```python
import os
import json
import re
from google.cloud import vision
from google.cloud import storage
from google.protobuf import json_format

# ここは自分のuriに変更も自分のに変更してください
gcs_source_uri = "gs://environment-engineering-pdf-bucket-1/scan-001.pdf"
gcs_destination_uri = "gs://ocr-result-bucket-qiita"

# ここのバケット名も自分のに変更してください
bucket_name = "ocr-result-bucket-qiita"

# ここの鍵ファイルも自分のに変更してください
# JSONの鍵ファイルは同じディレクトリに置くことを忘れずに！
credential_path = 'engaged-symbol-274611-192d61800d05.json'

os.environ['GOOGLE_APPLICATION_CREDENTIALS'] = credential_path

mime_type = 'application/pdf'
batch_size = 2
client = vision.ImageAnnotatorClient()

feature = vision.types.Feature(
    type=vision.enums.Feature.Type.DOCUMENT_TEXT_DETECTION)

gcs_source = vision.types.GcsSource(uri=gcs_source_uri)

input_config = vision.types.InputConfig(
    gcs_source=gcs_source, mime_type=mime_type)

gcs_destination = vision.types.GcsDestination(uri=f"{gcs_destination_uri}/")
output_config = vision.types.OutputConfig(
    gcs_destination=gcs_destination, batch_size=batch_size)

async_request = vision.types.AsyncAnnotateFileRequest(
    features=[feature], input_config=input_config,
    output_config=output_config)

operation = client.async_batch_annotate_files(
    requests=[async_request])

print('Waiting for the operation to finish.')
operation.result(timeout=180)


storage_client = storage.Client()

bucket = storage_client.get_bucket(bucket_name)

output = blob_list[0]

json_string = output.download_as_string()
response = json_format.Parse(
    json_string, vision.types.AnnotateFileResponse())

# The actual response for the first page of the input file.
first_page_response = response.responses[0]
annotation = first_page_response.full_text_annotation

print(u'Full text:\n{}'.format(
    annotation.text))
```


# 最後に例を

## 成功する例

以下のような画像pdfをOCRしてみました。

![Screen Shot 2020-04-25 at 19.43.40.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396623/26e2b2c1-abef-e879-9795-1690111caaeb.png)


するとターミナルでは以下のようにタイトルは表示されました。

```
幻冬舎文庫
京都の中華
姜尚美
```

## 失敗する例

ただ、以下のような筆記体の文字があるページでは失敗しています。`餃子`が`釜子`と認識されているし、`にんにくなしの`は`にんにくなの`と、"し"が抜けたりしています。

![Screen Shot 2020-04-25 at 19.45.09.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/396623/c98ee0c1-76d7-8fc5-2a26-b3cefd1d7861.png)

出力：

```
目次
《釜子》
《舞》
かしんのす
にんにくなの
袋子 4
章 魚 (丸太町七本松)|
34
三絲魚翅
蕪庵(下鴨)
ごま入り皮の
水篮子
数字(净土寺)
04
親子弁のような
鳳凰蛋
芙蓉園 (河原町加条)
人公
```

## 最後に

これを`epub`形式などに出力することができれば、そこからmobi形式に変換してkindleで読むことも可能ですね！どれくらいコストがかかるのかはわかりませんが。。。