LoginSignup
25
22

More than 5 years have passed since last update.

[iOS9]CITextFeatureで文字領域検出+TesseractOCRiOSで文字認識してみた

Posted at

概要

  • 画像内のテキスト位置を検出してみる
  • フリーのライブラリでOCRにかけてみる

結論から言うと、まだ手放しには使えなそうかなーと。

CITextFeatureについて

iOSにはCoreImageという画像をあれこれするためのFrameworkがあって、
その中にCIDetectorという、画像内の顔検出などができる機能がありました。
iOS9において、これに画像内のテキスト位置を検出する機能が付加されています。

実装

文字領域を取得する場合、CIDetectorを以下のように初期化します。

CIDetector *ciDetector = [CIDetector detectorOfType:CIDetectorTypeText
                                            context:nil
                                            options:nil];

各領域(feature)は、以下のようにArrayに取得します。

// optionsにCIDetectorReturnSubFeaturesを設定することでsubfeatureが取得できる
NSArray *features = [ciDetector featuresInImage:ciImage
                                        options:@{CIDetectorReturnSubFeatures: @YES}];

CITextFeatureは認識した文字の矩形情報を含んでいますが、
さらにその矩形内の子となる文字の矩形情報を含んでいます。
要は、1文字単位の情報もまとめて取得してくれるということです。
この子要素の情報は、subFeatureというpropertyからアクセスすることができます。

これらを使って、文字領域の矩形を囲むよう線を引くコードです。

テキストを検出して線で囲む
- (UIImage *) detectText:(UIImage *)inputImage {
    CIImage *ciImage = [CIImage imageWithCGImage:inputImage.CGImage];

    CIDetector *ciDetector = [CIDetector detectorOfType:CIDetectorTypeText
                                                context:nil
                                                options:nil];

    NSArray *features = [ciDetector featuresInImage:ciImage
                                            options:@{CIDetectorReturnSubFeatures: @YES}];

    UIGraphicsBeginImageContextWithOptions(inputImage.size, NO, 0.0);
    [inputImage drawInRect:CGRectMake(0, 0, inputImage.size.width, inputImage.size.height)];

    for (CITextFeature *feature in features) {
        CGContextRef drawContext = UIGraphicsGetCurrentContext();
        CGContextSetLineWidth(drawContext, 3.f);

        // Y座標が逆になるので変換
        CGRect textRect = feature.bounds;
        textRect.origin.y = inputImage.size.height - (textRect.origin.y + textRect.size.height);

        // 線でテキストを囲む
        CGContextSetStrokeColorWithColor(drawContext, [UIColor blueColor].CGColor);
        CGContextStrokeRect(drawContext,textRect);

        // subfeatureのチェック
        CGContextSetStrokeColorWithColor(drawContext, [UIColor greenColor].CGColor);
        for (CITextFeature *subfeature in feature.subFeatures) {
            CGRect subTextRect = subfeature.bounds;
            subTextRect.origin.y = inputImage.size.height - (subTextRect.origin.y + subTextRect.size.height);
            CGContextStrokeRect(drawContext,subTextRect);            
        }
    }

    UIImage *drawedImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return drawedImage;
}

さっそくやってみる

画像はKeynoteで適当に作りました。横幅640pxです。
text05_640.png

結果

青枠が、UITextFeatureに検出された文字領域。
赤枠が、その検出された文字領域が含む子要素です。
ちょっと微妙な結果になりました。
subfeature.png

  • あかさたなが取れていない
  • 文章によって縦幅が変わっている
  • subfeatureの誤認識が多い

( ˘ω˘)うーん…
取れている部分は割と綺麗に矩形が取れていますね。
ひらがなは文字中に隙間が多いので向いていないのかも…?

TesseractOCRiOSで文字を読み取ってみる

折角なので文字認識まで。
目標として、CITextFeatureで取得した領域に絞ってOCRスキャンをかけると
どうなるのかな?と思ったので試してみました。(下記参考にさせて頂きました)
【Swift】文字認識ライブラリ、TesseractOCR for iOSを試してみた

PodsでTesseractOCRiOSを追加してください。
Objective-Cだとこんな感じ。(スキャンに地味に数秒かかります)

- (void) analyze:(UIImage *)image {
    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
        G8Tesseract *tesseract = [[G8Tesseract alloc] initWithLanguage:@"jpn"];
        tesseract.delegate = self;
        tesseract.image = image;

        if ([tesseract recognize]){
            NSLog(@"text : %@", tesseract.recognizedText);
        }
    });
}

認識させてみた

まずは画像全体をスキャンした結果。

あかさたな はまやらわ
える しっているか
しにがみは りんごしか たベない

綺麗に認識できています。

次に、CIDetectorから取得できた文字領域を対象にスキャンを行います。
今回は、上の方で取得できていた青い矩形の領域3つに対し処理を行いました。

textRectに対しOCRをかける
    ...

    CGImageRef srcImageRef = inputImage.CGImage;
    CGImageRef trimmedImageRef = CGImageCreateWithImageInRect(srcImageRef, textRect);
    UIImage *trimmedImage = [UIImage imageWithCGImage:trimmedImageRef];
    [self analyze:trimmedImage];

    ...

以下、その結果です。

はまやらわ

える しつているか

し にがみは り ん ご しか たベない
  • 小文字が大文字になってしまっている
  • 3行目の区切りが多い

(ヽ´ω`)うーーん……
領域をせばめたせいで、文字内の隙間がよくない感じに認識されているような。
あかさたなはCIDetectorの時点で省かれてしまっていますし微妙ですね。

まとめ

なんだか結果としては微妙でした。サンプルの文字列が悪かったのかも知れません。
コントラストを上げて文字をはっきりさせたり、
画像の解像度を上げるなどで改善の可能性はあるかと思います。

OCRの速度によっては、指定の文字の領域は塗りつぶしてしまって伏せ字に…とかできないかなあと思いました。

25
22
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
25
22