2012-11-22 14 views
15

写真のテキストを認識するOCRアプリケーションを実装したいと思います。iOS Tesseract OCR Image Preperation

iOSでTesseractエンジンをコンパイルして統合するのに成功しましたが、クリア文書(またはこのテキストのスクリーンショット)を撮影する際に合理的な検出に成功しましたが、標識、店の標識、 、検出に失敗しました。

質問はどのような画像処理の準備がより良い認識を得るために必要ですか?たとえば、画像をグレースケール/ B & Wに変換し、コントラストなどを固定する必要があることを期待します。

iOSでこれを行うにはどうすればいいですか?

答えて

15

私は現在同じことに取り組んでいます。 Photoshopに保存されたPNGは正常に動作していましたが、元々はカメラから供給されていて、アプリケーションにインポートされた画像は一度も機能しませんでした。 私にそれを説明するように頼んではいけませんが、この機能を適用することでこれらのイメージが機能しました。多分あなたのために働くでしょう。

// this does the trick to have tesseract accept the UIImage. 
UIImage * gs_convert_image (UIImage * src_img) { 
    CGColorSpaceRef d_colorSpace = CGColorSpaceCreateDeviceRGB(); 
    /* 
    * Note we specify 4 bytes per pixel here even though we ignore the 
    * alpha value; you can't specify 3 bytes per-pixel. 
    */ 
    size_t d_bytesPerRow = src_img.size.width * 4; 
    unsigned char * imgData = (unsigned char*)malloc(src_img.size.height*d_bytesPerRow); 
    CGContextRef context = CGBitmapContextCreate(imgData, src_img.size.width, 
                src_img.size.height, 
                8, d_bytesPerRow, 
                d_colorSpace, 
                kCGImageAlphaNoneSkipFirst); 

    UIGraphicsPushContext(context); 
    // These next two lines 'flip' the drawing so it doesn't appear upside-down. 
    CGContextTranslateCTM(context, 0.0, src_img.size.height); 
    CGContextScaleCTM(context, 1.0, -1.0); 
    // Use UIImage's drawInRect: instead of the CGContextDrawImage function, otherwise you'll have issues when the source image is in portrait orientation. 
    [src_img drawInRect:CGRectMake(0.0, 0.0, src_img.size.width, src_img.size.height)]; 
    UIGraphicsPopContext(); 

    /* 
    * At this point, we have the raw ARGB pixel data in the imgData buffer, so 
    * we can perform whatever image processing here. 
    */ 


    // After we've processed the raw data, turn it back into a UIImage instance. 
    CGImageRef new_img = CGBitmapContextCreateImage(context); 
    UIImage * convertedImage = [[UIImage alloc] initWithCGImage: 
           new_img]; 

    CGImageRelease(new_img); 
    CGContextRelease(context); 
    CGColorSpaceRelease(d_colorSpace); 
    free(imgData); 
    return convertedImage; 
} 

また、私はテセラクトについて画像を準備するために多くの実験を行った。サイズ変更、グレースケールへの変換、明るさとコントラストの調整が最適です。

私はこのGPUImageライブラリも試しました。 https://github.com/BradLarson/GPUImage GPUImageAverageLuminanceThresholdFilterは私に素晴らしい調整済みの画像を与えるようですが、tesseractはうまく機能していないようです。

私は自分のプロジェクトにopencvを入れて、画像ルーチンを試してみる予定です。場合によっては、テキスト領域を見つけるためにいくつかのボックス検出(私はこれがtesseractをスピードアップすることを望んでいる)。

+0

このgs_convert_image()を追加した後も、このメソッドを配置する前に同じ結果が得られます。 tessaractスキャンデータの精度を改善する方法はありますか? –

+1

OCRが保存された画像では動作するが、カメラからの画像では動作しない理由を理解できましたか?私は今同じ問題を抱えていますが、私はSwiftで働いていて、上記のコードをどのように実装するのか分かりません。私はちょうどそれについてここに投稿http://stackoverflow.com/questions/29336501/tesseract-ocr-w-ios-swift-returns-error-or-gibberishあなたの答えを見つけた。関連性があるようです。何か案は? – Andrew

+0

マインドブローコード、@roocell時間を節約できます。 –

9

私は上記のコードを使用しましたが、Tesseractで動作するようにイメージを変換するために2つの他の関数呼び出しも追加しました。

最初に、私はTesseractの管理が容易であるように見える640 x 640に変換する画像サイズ変更スクリプトを使用しました。

-(UIImage *)resizeImage:(UIImage *)image { 

    CGImageRef imageRef = [image CGImage]; 
    CGImageAlphaInfo alphaInfo = CGImageGetAlphaInfo(imageRef); 
    CGColorSpaceRef colorSpaceInfo = CGColorSpaceCreateDeviceRGB(); 

    if (alphaInfo == kCGImageAlphaNone) 
     alphaInfo = kCGImageAlphaNoneSkipLast; 

    int width, height; 

    width = 640;//[image size].width; 
    height = 640;//[image size].height; 

    CGContextRef bitmap; 

    if (image.imageOrientation == UIImageOrientationUp | image.imageOrientation == UIImageOrientationDown) { 
     bitmap = CGBitmapContextCreate(NULL, width, height, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, alphaInfo); 

    } else { 
     bitmap = CGBitmapContextCreate(NULL, height, width, CGImageGetBitsPerComponent(imageRef), CGImageGetBytesPerRow(imageRef), colorSpaceInfo, alphaInfo); 

    } 

    if (image.imageOrientation == UIImageOrientationLeft) { 
     NSLog(@"image orientation left"); 
     CGContextRotateCTM (bitmap, radians(90)); 
     CGContextTranslateCTM (bitmap, 0, -height); 

    } else if (image.imageOrientation == UIImageOrientationRight) { 
     NSLog(@"image orientation right"); 
     CGContextRotateCTM (bitmap, radians(-90)); 
     CGContextTranslateCTM (bitmap, -width, 0); 

    } else if (image.imageOrientation == UIImageOrientationUp) { 
     NSLog(@"image orientation up"); 

    } else if (image.imageOrientation == UIImageOrientationDown) { 
     NSLog(@"image orientation down"); 
     CGContextTranslateCTM (bitmap, width,height); 
     CGContextRotateCTM (bitmap, radians(-180.)); 

    } 

    CGContextDrawImage(bitmap, CGRectMake(0, 0, width, height), imageRef); 
    CGImageRef ref = CGBitmapContextCreateImage(bitmap); 
    UIImage *result = [UIImage imageWithCGImage:ref]; 

    CGContextRelease(bitmap); 
    CGImageRelease(ref); 

    return result; 
} 

ラジアンは、その後、私は、グレースケールに変換しますが、@implementation

static inline double radians (double degrees) {return degrees * M_PI/180;} 

の上にそれを宣言確保動作するように。

この記事はグレースケールに変換する際にConvert image to grayscaleでした。

私はクラス内ではなく、他の独自のクラスとしての機能として働くために少しのコードを変更した成功し、ここからのコードを使用しているし、今で異なる色のテキストと異なる色の背景

を読むことができます人が行った

- (UIImage *) toGrayscale:(UIImage*)img 
{ 
    const int RED = 1; 
    const int GREEN = 2; 
    const int BLUE = 3; 

    // Create image rectangle with current image width/height 
    CGRect imageRect = CGRectMake(0, 0, img.size.width * img.scale, img.size.height * img.scale); 

    int width = imageRect.size.width; 
    int height = imageRect.size.height; 

    // the pixels will be painted to this array 
    uint32_t *pixels = (uint32_t *) malloc(width * height * sizeof(uint32_t)); 

    // clear the pixels so any transparency is preserved 
    memset(pixels, 0, width * height * sizeof(uint32_t)); 

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); 

    // create a context with RGBA pixels 
    CGContextRef context = CGBitmapContextCreate(pixels, width, height, 8, width * sizeof(uint32_t), colorSpace, 
               kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedLast); 

    // paint the bitmap to our context which will fill in the pixels array 
    CGContextDrawImage(context, CGRectMake(0, 0, width, height), [img CGImage]); 

    for(int y = 0; y < height; y++) { 
     for(int x = 0; x < width; x++) { 
      uint8_t *rgbaPixel = (uint8_t *) &pixels[y * width + x]; 

      // convert to grayscale using recommended method:  http://en.wikipedia.org/wiki/Grayscale#Converting_color_to_grayscale 
      uint32_t gray = 0.3 * rgbaPixel[RED] + 0.59 * rgbaPixel[GREEN] + 0.11 * rgbaPixel[BLUE]; 

      // set the pixels to gray 
      rgbaPixel[RED] = gray; 
      rgbaPixel[GREEN] = gray; 
      rgbaPixel[BLUE] = gray; 
     } 
    } 

    // create a new CGImageRef from our context with the modified pixels 
    CGImageRef image = CGBitmapContextCreateImage(context); 

    // we're done with the context, color space, and pixels 
    CGContextRelease(context); 
    CGColorSpaceRelease(colorSpace); 
    free(pixels); 

    // make a new UIImage to return 
    UIImage *resultUIImage = [UIImage imageWithCGImage:image 
              scale:img.scale 
             orientation:UIImageOrientationUp]; 

    // we're done with image now too 
    CGImageRelease(image); 

    return resultUIImage; 
} 
+0

私はこれを試してきましたが、私の画像は変換されますが、UIImageはまだ私のiPhoneでクラッシュします。助言がありますか?あなたのソースコードを提供できますか? –

+1

カメラから画像を戻しているのですか、別のソースから画像を読み込んでいますか?また、上記で提供したコードでは、ARCを使用していると仮定しています。そうでない場合は、適切な時期にイメージやその他のオブジェクトを解放する必要があります。そうしないと、メモリの負荷が原因でクラッシュします。 –

+0

"image.imageOrientation == UIImageOrientationUp | image.imageOrientation == UIImageOrientationDown"? – Andy