こんにちは。中山です。
今日は、OCR機能(光学文字認識機能。つまり、画像から文字を識別して、文字データとして取り出す機能)を、iOS アプリに組み込んでみたいと思います。
しかも無料で。
サンプルアプリ
ソースファイルの入手
今回も実際に動くサンプルアプリを作ってみました。
サンプルアプリのソースファイルは、こちらから取得することができます。
サンプルアプリの実行
XCode でソースファイルを開いて、iPad のシミュレータなどでアプリを実行します。
このサンプルアプリは、iOS 7.0 以降の iPad をターゲットにしています。
アプリを起動するとすぐに、画面上に表示されている画像の文字解析が始まります。
以下のような文字を含む画像を解析して、
このような文字抽出結果が出力されます。
ソースファイル内の 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"; // 解析対象言語:英語
このように設定して、アプリを実行しなおすと、英数字の文字解析も試すことができます。
以下のような画像の解析の結果、
このような文字が抽出されました。
英数字の場合は、けっこう正確に認識できてます。また日本語の場合も、大きな文字サイズであれば、認識率も高そうです。
しくみ
使用したライブラリ
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);
文字解析を行う前に、その対象画像を「白黒にして」「コントラストを強めに」、また「輪郭がくっきりとなるよう」設定しています。
こうすることで、文字部分がよりくっきりと表示され、解析しやすい状態になります。
しかしこのあたりは、いろいろと工夫の余地があるのでしょう。