Tesseract-OCR-iOSと二値化処理の切り替え
スポンサーリンク
久しぶりにOCR関連。
前置き
二値化処理 (image thresholding)というのは、各色ごとに(8ビットなど)の階調で表現された画像データを、あるしきい値(閾値)を基準に0と1の二値で表現できるデータに変換すること。
このあるしきい値でという部分がポイントで、このしきい値を決定するためのアルゴリズムがいろいろと提案されている、らしい。
OCRライブラリであるtesseract-ocr(および、そのラッパーライブラリであるTesseract-OCR-iOS)も内部で画像を二値化(二値画像化)している。 通常、グレスケール化して二値化するが、ここで二値化処理がうまくいかないと当然のごとくOCR結果に影響する。
ノイズの多い画像であるとか、画像の種類によってアルゴリズムを切り替えるようにできると望ましい。
欲を言えば、画像のヒストグラムか何かの特徴量で自動判別させたい。
tesseract-ocr内部では Otsu’s method を用いて二値化しているらしい。
これはこれで優秀なアルゴリズムらしい。グレースケールの仕方が悪いのか、特定の画像で二値化がうまくいかないケースがある。 アルゴリズムのせいなのか、ライブラリ側の問題なのか、あるいは前処理の問題かはなんとも言えない*1。
やりたいこと
- アプリ側のオプションで二値化アルゴリズムを切り替えたい
- (できれば)tesseract-ocr の標準のアルゴリズムも残したい
- OpenCVを組み込むのはバイナリサイズの都合で避けたい
Tesseract-OCR-iOS(tesseract-ocrのiOS向けラッパーライブラリ)では、デフォルトの二値化処理をバイパスするための手段が用意されている。
解決策(暫定)
公式のWikiを参考にすればいい。
要するに、
preprocessedImageForTesseract
というメソッドを定義して、その内部で自分の使いたい方法で画像を二値化
して、UIImageオブジェクトで返せばいい。
これはこれでいいのだけれど、tesseract-ocr標準のアルゴリズムが使いたいケースに対応できない。本来なら実行時に(動的に)preprocessedImageForTesseract
メソッドが定義されてない状態にするのか、オプションをしていできるようにライブラリ側を改造するのが最善だと思う。
残念ながら、Swiftで実行時に特定のメソッド呼び出しを無効化する方法がわからないのと、Objective-Cはわからないのでライブラリの拡張は諦める。
以上を踏まえて、少々お行儀の悪い方法で逃げることにする。
ライブラリ側のコードを見る限り、preprocessedImageForTesseract
の戻り値がnil
の場合は標準の二値化アルゴリズムが使用されるみたいなので、下記のようにしてみた。
画像データはグレースケール化されているものとする。
Example for "preprocessedImageForTesseract"
GPUImageの"Adaptive Threshold"と"Avarage Luminessence" フィルタ、tesseract-ocrのデフォルト(nilオブジェクトを返すことでTesseract-OCR-iOS側でフォールバック)の三種に切り替える例。
文字の線幅が太いと、"Adaptive Threshold"はエッジ抽出フィルタのような挙動をするのが難点。
以下のようにenum
を定義しておく。
enum ThresholdMode : Int { case OtsuThreshold = 0 case AvarageLuminessence case AdaptiveThreshold }
ViewController側で、
var threshold_mode = ThresholdMode.OtsuThreshold
のようにして切り替える。OpenCVを使えばもっといろんなアルゴリズムを使えるだろうけど、理屈が分かっていないので保留。
とりあえずここまで。
- 出版社/メーカー: 公益財団法人画像情報教育振興協会(CG-ARTS協会)
- 発売日: 2015/08/10
- メディア: Kindle版
- この商品を含むブログを見る