tesstrain.sh で Tesseract-OCR の言語データをカスタマイズする

## やりたいこと

オープンソースのOCRエンジン、Tesseract-OCR の日本語用言の言語データ（tessdata/jpn.traineddata）をカスタマイズする。  

GitHubの[Wiki](https://github.com/tesseract-ocr/tesseract/wiki/TrainingTesseract)によると、必要な作業をコマンドでやる方法（Manual method）と、tesstrain.sh というシェルスクリプトを使う方法（Automated method）[^1]が記載されている。というか前者を自動化したのが後者。公式Wikiを読めといえばそれまでですが、せっかくなのでまとめておきます。  

+ [TrainingTesseract · tesseract-ocr/tesseract Wiki · GitHub](https://github.com/tesseract-ocr/tesseract/wiki/TrainingTesseract "TrainingTesseract · tesseract-ocr/tesseract Wiki · GitHub")
+ [tesstrain.sh · tesseract-ocr/tesseract Wiki · GitHub](https://github.com/tesseract-ocr/tesseract/wiki/tesstrain.sh "tesstrain.sh · tesseract-ocr/tesseract Wiki · GitHub")



具体的には、

+ 未対応フォントを学習させる（実在する書体が前提[^2]）
+ 未収録文字に対応させる（JIS第二水準漢字に対応させたい場合など）
+ 設定ファイルの差し替え

## tesstrain.sh スクリプトの概要

要するに、指定されたフォントで、学習させたい文字を含むTIFF画像と画像内の文字の位置を記載したboxファイルを生成し、単語辞書など諸々のファイルを作成して結合する、というものです。重要なのは`text2image`コマンド。



下記3つのファイルで構成されたシェルスクリプトですので解読はさほど難しくないはずです。

+ tesstrain.sh
+ tesstrain_utils.sh
+ language-specific.sh


## 前提条件

+ Tesseract OCR: 3.04
+ OS: Ubuntu 15.10
+ 対象言語: 日本語
+ 搭載メモリ: 2GB以上（デスクトップ環境の場合: 3GB以上を推奨）
+ 空きディスク領域：3GB以上を推奨（学習させるフォントの数に依存）

後述の`text2image`コマンドの問題で、Linux環境が前提。クラウド環境などでUbuntu 15.10のゲストを構築するのが無難かと。

Ubuntu以外のディストリビューションの場合、`tesstrain.sh`の動作には、ソースアーカイブの`training`ディレクトリにある学習用ツールがインストールされている必要があります。


特に`text2image`コマンドが問題で、メーリングリストによるとMacOSX環境では何かレンダリングに問題があるとのこと。そもそも、MacOSXではまともに動作せず……。


**[2016/08/21 追記]** 上記の問題は開発版で修正されているので、将来のリリースではmacOS 環境でもtext2image ならびに`testrain.sh`を利用可能になりそうです。  

私は試していませんが、、Cygwinの場合は[tesseract-training-util](http://cygwin.com/cgi-bin2/package-cat.cgi?file=x86_64%2Ftesseract-training-util%2Ftesseract-training-util-3.04.00-2&grep=as)というパッケージが提供されています。

## 事前準備

```bash
$ sudo apt install tesseract-ocr tesseract-ocr-dev 
```

Ubuntuの場合はパッケージをインストールすると`/usr/bin`に`tesstrain.sh`がインストールされています。
別のディストリビューションの場合は、パスを通った場所にスクリプトを配置。



### langdata

XXX.tessdata のソースはgithubのlangdataにあるので一式ダウンロードします。


適当な作業ディレクトリに移動。

```bash
$ mkdir work
$ cd work
```

github の[langdataリポジトリ](https://github.com/tesseract-ocr/langdata)にアクセスして、必要なファイル一式を入手する。
`git clone`でもDownload ZIP でもどちらでもOK[^3]。

```bash
$ git clone git://github.com/tesseract-ocr/langdata.git
```

### フォントを用意する

作成したい言語について、少なくとも`language-specific.sh`にハードコードされているフォントを用意しておく必要があります。c.f. [tesseract/language-specific.sh line 275](https://github.com/tesseract-ocr/tesseract/blob/master/training/language-specific.sh#L275 "tesseract/language-specific.sh at master · tesseract-ocr/tesseract · GitHub")

下記のフォント一式を用意するか、スクリプトの方を修正。

+ TakaoExGothic
+ TakaoExMincho
+ TakaoGothic
+ TakaoMincho
+ TakaoPGothic
+ TakaoPMincho
+ VL Gothic
+ VL PGothic
+ Noto Sans CJK JP Bold
+ Noto Sans CJK JP Semi-Light

あまり印刷用とに使われないであろうVLゴシックは削除するのもあり。

```bash
$ sudo apt install fonts-takao fonts-vlgothic fonts-noto-cjk
```

このうち、TakaoExGothicとTakaoExMinchoについては縦書きでレンダリングされるようです[^3]。

英数字の書体としてArial系のフォントが必要なので下記のパッケージもインストール。

```bash
$ sudo apt install ttf-mscorefonts-installer
```

あとは必要に応じて学習させたいフォントを/usr/share/fonts/truetypeあたりに用意。

## 準備

カスタマイズしたい内容に応じて必要な作業のみやればOK。

### 書体の追加

必要な作業は、下記。

+ fontのインストール
+ `font_properties`の修正
+ language-specific.sh の修正

下記のコマンドで対象フォントの名前が出てこればOKなはず。`--fonts_dir`の引数はスクリプトにハードコードされているものと同じである必要あり。

```bash
$ text2image --list_available_fonts --fonts_dir /usr/share/fonts
 (skip)
```

明朝体、ゴシック体はそんなに差はないので、ポップ対とか丸ゴシック系を追加するといいかも。

`font_properties`の書式は下記の通り。フォント名に続けて該当する場合は”1”、そうでなければ"0"。左から順に、イタリック体、ボールド体、等幅、セリフ、ひげ文字のフラグ。

```font_properties
<fontname> <italic> <bold> <fixed> <serif> <fraktur>
```

具体例（「はんなり明朝」、「たぬき油性マジック」を追加）

```bash
$ vi langdata/font_properties
```

適当な箇所に下記を追加。
>HannariMincho 0 0 1 1 0
>Tanuki_Permanent_Marker 0 0 0 0 0

IPA明朝がベースらしいので、同じように。

```bash
$ sudo vi /usr/share/tesseract-ocr/language-specific.sh
```

`language-specific.sh`の[794行目](https://github.com/tesseract-ocr/tesseract/blob/master/training/language-specific.sh#L275)以降に学習させたい書体名を追加。上記の`text2image --list_available_fonts`が出力するフォント名でないと認識しないっぽい。

「はんなり明朝」「たぬき油性マジック」の例（285行目の下に追加）
>    "HannariMincho" \
>    "Tanuki Permanent Marker" \	
    

縦書き用に学習させたい場合は、`language-specific.sh`の[794行目](https://github.com/tesseract-ocr/tesseract/blob/master/training/language-specific.sh#L794)に書体名を追加すると縦書きでTIFFファイルが作成される。  



### 未対応文字の追加

少なくともJIS第一水準漢字の一部が収録されていない（[情報元](http://d.hatena.ne.jp/uakira/20140710)）そうなので必要であれば追加。

2014年よりは登録済みの漢字は増えてる模様。というか、`langdata/jpn/jpn.training_text`をgrepしてヒットしなければ基本的に学習してないという話。

必要なのは学習させたい文字を含む画像と、画像内の文字の位置の情報。
`text2image`コマンドの引数である`langdata/jpn/jpn.training_text`を修正すればあとはよろしくやってくれる。

そもそも公式リポジトリのtraining_txt自体、何かのコーパスを解析した単語を出現頻度か何かを考慮して結合しているだけっぽい。本当は実際の文書に近い方が望ましいと思われる。


+ 変な文字列が含まれているの除去する（”yjulm”、"Mds"）
+ 追加したい文字を10から20回程度出現するように追加する。

とりあえず上記のページで紹介されている第一水準漢字については漢字の羅列形式で追記すればいい。


### 単語辞書の強化

`langdata/jpn/jpn.wordlist`の末尾に単語を1行1単語の形式で追加する。あまり認識率の改善には繋がらないような気がする。  
先頭の100行は頻出単語の辞書生成に使用される模様（jpn.freq-dawg）。

辞書データは`word2dawg`コマンドで一種のTRIE形式に変換される。

例えば`jpn.wordlist`の末尾にはてなキーワードのダンプデータを追加してみるとか？


### バグ修正

下記参照。`langdata/jpn/jpn.unicharambigs`を一部修正してやる必要あり。もしくは、完成後のjpn.tessdataをいじる。

[jpn lang recognize error · Issue #146 · tesseract-ocr/tesseract · GitHub](https://github.com/tesseract-ocr/tesseract/issues/146 "jpn lang recognize error · Issue #146 · tesseract-ocr/tesseract · GitHub")

アラビア数字の1が強制的に変換されてしまうので地味に響く。

## tesstrain.sh を実行する


```bash
$ tesstrain.sh --lang jpn --langdata_dir ~/work/langdata
```


最終的に以下のようにメッセージが出力される。再起動する前に/tmpからデータを回収する。

```
Output /tmp/tesstrain/jpn/jpn.traineddata created sucessfully.
Creating new directory /tmp/tesstrain/tessdata
Moving /tmp/tesstrain/jpn/jpn.traineddata to /tmp/tesstrain/tessdata
```

## 動作確認

```bash
$ sudo mv /tmp/tessdata/jpn.traineddata /usr/share/tesseract-ocr/tessdata/jpn_new.traineddata
```

XXX.traineddataのXXXの部分は3文字でなくても問題ないので適当に。  

適当な画像を用意して動作確認する。

![v9271.png](https://qiita-image-store.s3.amazonaws.com/0/98220/f3bda72b-c997-9caf-f666-ebbff4404fdd.png)

元の文章
> 合成の誤謬、狼狽。知悉する。ハマグリ・はまぐり・蛤。沃野、謁見、屠殺。菟葦屋　


```bash
$ tesseract -l jpn test.png -psm 7 result
$ tesseract -l jpn_new test.png -psm 7 result_new
```


result.txt、result_new.txtに結果が出力されるので確かめる。問題がないなら標準のjpn.traineddataをバックアップして、新規作成した方をjpn.traineddataにリネームする。

結果
> 合成の誤謬、 狼狙。 知懇する。 ハマグリ 'はまぐり ・蛤。 沃野、 謁見、 屠殺。 蒐葦屋

> 合成の誤謬、 狼狽。 知悉する。 ハマグリ 'はまぐり '蛤。 沃野、 謁見、 屠殺。 菟 葦屋

JIS第一水準漢字でうまく非対応だった文字（狽、悉、菟）が認識できているのでひとまず良しとする。

## その他

### フォント関連

フリーフォントであれば下記のサイトなど。

[2015年 Linuxでも使えるフリーフォント集](http://note.kurodigi.com/free-font2015/ "2015年 Linuxでも使えるフリーフォント集")

文字の入った画像を手軽に作る方法

[文字画像作成機 | 任天堂ファンサイト](http://www.nin-fan.net/tool/string_image.html "文字画像作成機 | 任天堂ファンサイト")

### 上手くいかないときは

#### メモリ不足

`dmesg`でカーネルログを確認しましょう。testrain.sh は終了ステータスのチェックをしてないようなのでOOM Killerで子プロセスが終了していても処理を続行します。

```
Out of memory: Kill process 2406 (tesseract) 
```

メモリ1GBでは足りませんでした（笑）。




#### HDDの空き容量

300dpiのTIFF画像を複数生成する関係で、1.5〜2GBくらいの空き領域が必要。あとは/tmpをtempfsにしている場合とか。

場合によっては`tesstrain_utils.sh`の28行目、32行目を修正する。



## 参考サイト


1. [tesstrain.sh · tesseract-ocr/tesseract Wiki · GitHub](https://github.com/tesseract-ocr/tesseract/wiki/tesstrain.sh "tesstrain.sh · tesseract-ocr/tesseract Wiki · GitHub")
2. [TrainingTesseract · tesseract-ocr/tesseract Wiki · GitHub](https://github.com/tesseract-ocr/tesseract/wiki/TrainingTesseract "TrainingTesseract · tesseract-ocr/tesseract Wiki · GitHub")
3. [Tesseract-OCRの学習 - はだしの元さん](http://hadashi-gensan.hatenablog.com/entry/2014/01/15/135316 "Tesseract-OCRの学習 - はだしの元さん")
4. [Tesseract-OCRの学習（識字率をあげる） - wiki - PCスキルの小技・忘却防止メモ](http://tips.recatnap.info/wiki/Tesseract-OCR%E3%81%AE%E5%AD%A6%E7%BF%92%EF%BC%88%E8%AD%98%E5%AD%97%E7%8E%87%E3%82%92%E3%81%82%E3%81%92%E3%82%8B%EF%BC%89 "Tesseract-OCRの学習（識字率をあげる） - wiki - PCスキルの小技・忘却防止メモ")
5. [Tesseract-OCRの日本語調教（1） - 日本語練習中](http://d.hatena.ne.jp/uakira/20140710 "Tesseract-OCRの日本語調教（1） - 日本語練習中")

どうも分かりにくいような気がするのでそのうちリライトする予定。

[^1]: ver. 3.03以降
[^2]: text2image コマンドの制限で機械的にイタリック体やボールド体を生成することはできない。jTessBoxEditorとの合わせ技ならいけそうな気がするが試してない。
[^3]: 必要に応じてパスを修正のこと（s/landata/langdata-master/）
[^4]: [ここ](https://github.com/tesseract-ocr/tesseract/blob/master/training/language-specific.sh#L794)参照。いっそのこと縦横両方学習させたい。