[iOS]Tesseract OCRで認識させた日本語の情報を取得する

※ これは 2018/4/8,16 に個人ブログへ投稿した内容をまとめて転記したものです。

Google が出資しているという文字認識 API の iOS 用ラッパー、 Tesseract OCR iOS を使って文字認識をさせてみた備忘録です。
環境： macOS HighSierra, MacBook Pro 2016, XCode9.3

# 準備

本体のリポジトリは[ここ](https://github.com/gali8/Tesseract-OCR-iOS)。ただし、 CocoaPods から読ませるので、直接 Clone しない。
CocoaPods が入ってない場合は、まず [CocoaPods をインストール](https://qiita.com/ShinokiRyosei/items/3090290cb72434852460)。
終わったら下記の記事を参考にインストールしていく。
[Xcode 7.0 + Swift2 でTesseract-OCR-iOSを使う（追記あり） - 今日も微速転進](https://a244.hateblo.jp/entry/2015/10/13/011846)

# 動かしてみる

テストコードは[公式 Wiki の方](https://github.com/gali8/Tesseract-OCR-iOS/wiki/Using-Tesseract-OCR-iOS#swift)を使用した。シミュレータで動かす分にはこちらのほうがシンプルで良い。
上の記事でも言っているとおり、 BridgingHeader はいらないので惑わされないように[^1]
[^1]: リンクが通らなくて1時間くらい悩んだ。

Tesseract OCR iOS の中身は Tesseract3.03 らしく、最新[^2]の学習データ (tessdata) は使えない。
[^2]: 2018/4/8 時点で master は 4.00
Github で公開されている [3.04](https://github.com/tesseract-ocr/tessdata/tree/3.04.00) か、 Wiki から[それ以前のもの](https://github.com/tesseract-ocr/tesseract/wiki/Data-Files#data-files-for-version-302)を選んで使う。

英語版 (eng.tessdata) は 3.04 そのままでも動くが、日本語版 (jpn.tessdata) は 3.04 を使うとエラーが出る。

```sh
read_params_file: parameter not found: allow_blob_division
```

これを解決するために、下記に従って学習データ内のパラメータを変更するのだが、このとき[ビルドに使うソースは3.04を使うこと](https://github.com/tesseract-ocr/tesseract/tree/3.04.01)。
4.00 だと加工後の tessdata を読み込んでくれない。

それから、 `./configure` にパラメータをつけると私の環境では失敗してしまったので、パラメータをなくしたら上手くいった。
これは[この記事](https://a244.hateblo.jp/entry/2015/08/26/012851)を読みながら事前に

```sh
brew link icu4c --force
```
しておいたからかも。

```sh
./autogen.sh
./configure
make
sudo make install
make training
sudo make training-install
```

なお、一度 4.00 をインストールしてしまったときは、 make したディレクトリで

```sh
sudo make uninstall
sudo make training-uninstall
```

したらアンインストールできた…気がする。

# 日本語を認識させてみる

日本語を認識させて結果の情報を取得してみました。

## ソース

Swift 初心者なので、 [API リファレンス](http://cocoadocs.org/docsets/TesseractOCRiOS/)を見ながら、 Xcode に言われるがまま書いたソースは[こちら](https://gist.github.com/at6ue/873cc0893058224963e09e58d8b5fc14)。

## 結果
入力
<img width="344" alt="20180416230659.png" src="https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591453/74856427-03ee-c763-b7cd-5a2734bd1ee3.png">

出力
![20180416234126.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591453/f26a07ca-5d1c-014a-b05e-efe405701221.png)

あえてちょっと斜めにしてみましたが、いい感じに認識していますね！

# 技術的なメモ
## 認識結果とその表示

```swift
let box = block.boundingBox(atImageOf: actualImageRect.size)
```

Tesseract では元画像のサイズを 1×1 としたときの相対位置で対象 （文字） の座標を認識しているようです。
なので、デバイスの画面に収まるように画像を自動レイアウトした場合は、レイアウト後のサイズを取得し、それを `atImageOf` に指定して変換してもらう必要があります。
レイアウト後の画像の実サイズを取得する Extension、`UIImageView.ContentClippingRect` は下記より。
[How to find an aspect fit image’s size inside an image view](https://www.hackingwithswift.com/example-code/uikit/how-to-find-an-aspect-fit-images-size-inside-an-image-view)

Extensionって最高ですね…！

## 文字のまとまり

```swift
let blocks = tesseract.recognizedBlocks(by: G8PageIteratorLevel.symbol)
```

`G8PageIteratorLevel` で認識結果のまとまりの大きさを指定できます。
意味深な定数名が付いていますが、もちろん日本語の形態素解析をして云々なんてしていないので、一通り試してみました。

block： ブロック。段落を複数認識したら、そのまとまりということかな？
![20180416234131.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591453/db9a63fa-f4a9-af56-9242-d2b4d0b0bb23.png)

paragraph： 段落
![20180416234231.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591453/6970b549-ceb8-ad0b-1966-5de89ef4045d.png)

textline： 行
![20180416234249.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591453/67e4f6e5-8ade-c9c6-0981-39bd96d1566b.png)

word： 語。やはり英語前提でスペース区切りで認識されていそう。
![20180416234301.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591453/7209c643-5113-dc27-dcb1-37b1c7e54e6b.png)

symbol： 文字
![20180416234316.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/591453/dc94ceb3-54c5-367f-32f6-f02f6850cf02.png)