2012-11-22 131 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