読者です 読者をやめる 読者になる 読者になる

Intelligent Technology's Technical Blog

株式会社インテリジェントテクノロジーの技術情報ブログです。

iOS で OCR

こんにちは。中山です。

今日は、OCR機能光学文字認識機能。つまり、画像から文字を識別して、文字データとして取り出す機能)を、iOS アプリに組み込んでみたいと思います。
しかも無料で。

サンプルアプリ

ソースファイルの入手

今回も実際に動くサンプルアプリを作ってみました。
サンプルアプリのソースファイルは、こちらから取得することができます。

サンプルアプリの実行

XCode でソースファイルを開いて、iPad のシミュレータなどでアプリを実行します。
このサンプルアプリは、iOS 7.0 以降の iPad をターゲットにしています。

アプリを起動するとすぐに、画面上に表示されている画像の文字解析が始まります。

以下のような文字を含む画像を解析して、

f:id:IntelligentTechnology:20140718165704p:plain

このような文字抽出結果が出力されます。

f:id:IntelligentTechnology:20140807163704p:plain

ソースファイル内の ViewController.m の10行目あたりを少し編集して、

// kImageFileName の値を @"ocr-sample-japanese"(日本語文字サンプル)に指定した場合は、
// kLanguage の値を @"jpn" に指定します。
// kImageFileName == @"ocr-sample-english" の場合は、kLanguage = @"eng" とします。)

//static NSString * const kImageFileName = @"ocr-sample-japanese"; // 日本語文字サンプル
static NSString * const kImageFileName = @"ocr-sample-english"; // 英数字サンプル

//static NSString * const kLanguage = @"jpn"; // 解析対象言語:日本語
static NSString * const kLanguage = @"eng"; // 解析対象言語:英語

このように設定して、アプリを実行しなおすと、英数字の文字解析も試すことができます。

以下のような画像の解析の結果、

f:id:IntelligentTechnology:20140718170129p:plain

このような文字が抽出されました。

f:id:IntelligentTechnology:20140807163727p:plain

英数字の場合は、けっこう正確に認識できてます。また日本語の場合も、大きな文字サイズであれば、認識率も高そうです。
 

しくみ

使用したライブラリ

OCR の機能は、「tesseract-ocr」という、現在Googleが開発している、オープンソースのライブラリを用います。
なお今回のサンプルアプリでは、「Tesseract-OCR-iOS」という、「tesseract-ocr」を iOS から使いやすくするためのフレームワークを使って、機能を実装しました。

「Tesseract-OCR-iOS」を使った OCR 機能の実行は、基本的にはこれだけ。

Tesseract* tesseract = 
    [[Tesseract alloc] initWithLanguage:@"jpn"]; // 日本語解析の場合は @"jpn"
tesseract.delegate = self; // 処理キャンセル時などのデリゲートメソッドの登録

[tesseract setImage:[UIImage imageNamed:@"解析対象の画像ファイル"]];
[tesseract recognize];

NSLog(@"解析結果:%@", [tesseract recognizedText]);

解析対象の画像は、UIImage のオブジェクトを渡しているだけなので、例えば、カメラ撮影した画像を解析対象にする、ということも簡単にできそうです。

なお「Tesseract-OCR-iOS」の利用方法については、今回のサンプルアプリソース内の「README.md」にも詳しく記載していますので、ご覧ください。
 

文字解析の精度を上げるために

文字の解析の精度を少しでも上げるために、今回は1点、以下のような工夫を入れています。
サンプルアプリソースファイル内の ViewController.m の 55行目あたりから。

CIImage *ciImage = [[CIImage alloc] initWithImage:self.imageView.image];

//文字を読みやすくするため、白黒にして、コントラストを強めに、また輪郭をくっきりさせるよう設定する
CIFilter *ciFilter =
    [CIFilter filterWithName:@"CIColorMonochrome"
               keysAndValues:kCIInputImageKey, ciImage,
                @"inputColor", [CIColor colorWithRed:0.75 green:0.75 blue:0.75],
                @"inputIntensity", [NSNumber numberWithFloat:1.0],
                nil];
ciFilter =
    [CIFilter filterWithName:@"CIColorControls"
               keysAndValues:kCIInputImageKey, [ciFilter outputImage],
                @"inputSaturation", [NSNumber numberWithFloat:0.0],
                @"inputBrightness", [NSNumber numberWithFloat:-1.0],
                @"inputContrast", [NSNumber numberWithFloat:4.0],
                  nil];

ciFilter =
    [CIFilter filterWithName:@"CIUnsharpMask"
               keysAndValues:kCIInputImageKey, [ciFilter outputImage],
                @"inputRadius", [NSNumber numberWithFloat:2.5],
                @"inputIntensity", [NSNumber numberWithFloat:0.5],
                nil];

CIContext *ciContext = [CIContext contextWithOptions:nil];
CGImageRef cgImage =
    [ciContext createCGImage:[ciFilter outputImage] fromRect:[[ciFilter outputImage] extent]];

// 文字解析対象の画像の色、コントラストを調整したものを変数に保存する
UIImage *adjustedImage = [UIImage imageWithCGImage:cgImage];
CGImageRelease(cgImage);

文字解析を行う前に、その対象画像を「白黒にして」「コントラストを強めに」、また「輪郭がくっきりとなるよう」設定しています。
こうすることで、文字部分がよりくっきりと表示され、解析しやすい状態になります。

しかしこのあたりは、いろいろと工夫の余地があるのでしょう。
 

まとめ

OCR の機能も、簡単に実装することができました。
今回のように、読み取り対象画像を加工したり、また、「tesseract-ocr」自体が持っている、機械学習の機能を用いたりして、いかに認識精度を上げていくか、というところが、機能差別化のキモになってくるのかもしれません。