iOS Tesseract OCR 图像准备
Posted
技术标签:
【中文标题】iOS Tesseract OCR 图像准备【英文标题】:iOS Tesseract OCR Image Preperation 【发布时间】:2012-11-10 18:10:28 【问题描述】:我想实现一个可以识别照片文本的 OCR 应用程序。
我在 ios 中成功编译和集成 Tesseract 引擎,在拍摄清晰的文档(或从屏幕上拍摄此文本的照片)时,我成功获得了合理的检测,但对于路标、商店标志、彩色背景等其他文本,检测失败。
问题是需要什么样的图像处理准备才能获得更好的识别。例如,我希望我们需要将图像转换为灰度/黑白以及修复对比度等。
这在 iOS 中怎么做,有这个包吗?
【问题讨论】:
【参考方案1】:我目前正在做同样的事情。 我发现保存在 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)。
【讨论】:
在添加这个 gs_convert_image() 之后,我在使用这个方法之前也得到了相同的结果。有什么办法可以提高tessaract扫描数据的准确性? 你有没有想过为什么 OCR 可以处理保存的图像,但不能处理来自相机的图像?我现在遇到了同样的问题,但我正在使用 Swift 并且不知道如何实现您的上述代码。我刚刚在这里***.com/questions/29336501/… 发布了它,然后找到了你的答案。好像有关系。有什么想法吗? @Andrew 你是用 swift3.如果你完成了,那么添加那个作为你对这个问题的答案。对我有帮助【参考方案2】:我已经使用了上面的代码,但还添加了另外两个函数调用来转换图像,以便它可以与 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;
【讨论】:
我一直在尝试这个,我的图像被转换了,但是,UIImage 仍然在我的 iPhone 上崩溃。有什么建议?你能提供你的源代码吗? 您是从相机返回图像还是从其他来源加载图像?此外,我上面提供的代码假设您使用的是 ARC,如果您不是,则需要在适当的时间释放图像和其他对象,否则您将因内存负载而崩溃。 "image.imageOrientation == UIImageOrientationUp | image.imageOrientation == UIImageOrientationDown" ? 我正在尝试上面的代码,我得到“使用未声明的标识符弧度”。 @daniel-p 确保包含 math.h。然后在 viewController 中的实现之前添加以下内容: static inline double radians (double degree) return degree * M_PI/180;以上是关于iOS Tesseract OCR 图像准备的主要内容,如果未能解决你的问题,请参考以下文章
如何在 iOS 中使用 Tesseract OCR 库从图像中识别准确的文本?
为啥 Tesseract OCR 库(iOS)根本无法识别文本?
iPhone iso的Tesseract限制?适用于 ios 的任何其他 OCR 引擎