2012-11-22 189 views
15

我想實現一個OCR應用程序,它可以識別照片中的文字。iOS Tesseract OCR Image Preperation

我成功編譯並集成了iOS中的Tesseract Engine,我成功地在拍攝清晰文檔(或屏幕上的此文本的照片)時獲得了合理的檢測結果,但對於其他文本(例如路標,商店標誌,顏色背景) ,檢測失敗。

問題是需要什麼樣的圖像處理準備才能獲得更好的識別。例如,我期望我們需要將圖像轉換爲灰度/ 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; 
} 

我也做了很多實驗準備tesseract圖像。調整大小,轉換爲灰度,然後調整亮度和對比度似乎效果最佳。

我也試過這個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一起使用。

首先,我使用了圖像調整大小腳本來轉換爲640 x 640,這對於Tesseract來說似乎更易於管理。

-(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