5

I'm using tesseract in my iPhone application.

I tried several filters on my image for converting it to a grayscale image, however I'd like to have the result where a threshold is being set so that the only pixels which are inside the image are black or white.

I succeeded with using apples grayscale filter which gives the appropriate result. However it's still a 16 bit image (correct me if I'm wrong). The filtering which I'm using at the moment is as follows:

- (UIImage *) grayishImage:(UIImage *)i {

    // Create a graphic context.
    UIGraphicsBeginImageContextWithOptions(i.size, YES, 1.0);
    CGRect imageRect = CGRectMake(0, 0, i.size.width, i.size.height);
// Draw the image with the luminosity blend mode.
[i drawInRect:imageRect blendMode:kCGBlendModeLuminosity alpha:1.0];
    // Get the resulting image.
    UIImage *filteredImage = UIGraphicsGetImageFromCurrentImageContext();
    UIGraphicsEndImageContext();

    return filteredImage;
}

Can anyone supply me with the filter to get pure black and white pixels and not grayscale images?

BarryK88
  • 1,806
  • 2
  • 25
  • 41

1 Answers1

12

Probably the fastest way to do this would be to use OpenGL ES 2.0 shaders to apply the threshold to your image. My GPUImage framework encapsulates this so that you don't need to worry about the more technical aspects behind the scenes.

Using GPUImage, you could obtain a thresholded version of your UIImage using a GPUImageLuminanceThresholdFilter and code like the following:

GPUImagePicture *stillImageSource = [[GPUImagePicture alloc] initWithImage:inputImage];
GPUImageLuminanceThresholdFilter *stillImageFilter = [[GPUImageLuminanceThresholdFilter alloc] init];
stillImageFilter.threshold = 0.5;
[stillImageSource addTarget:stillImageFilter];
[stillImageFilter useNextFrameForImageCapture];
[stillImageSource processImage];

UIImage *imageWithAppliedThreshold = [stillImageFilter imageFromCurrentFramebuffer];

You can just pass your color image into this, because this automatically extracts the luminance from each pixel and applies the threshold to that. Any pixel above the threshold goes to white, and any one below that is black. You can adjust the threshold to meet your particular conditions.

However, an even better choice for something you're going to pass into Tesseract would be my GPUImageAdaptiveThresholdFilter, which can be used in the same way as the GPUImageLuminanceThresholdFilter, only without a threshold value. The adaptive thresholding does a thresholding operation based on a 9 pixel region around the current pixel, adjusting for local lighting conditions. This is specifically designed to help with OCR applications, so it might be the way to go here.

Examples images from both types of filters can be found in this answer.

Note that the roundtrip through UIImage is slower than handling raw data, so these filters are much faster when acting on direct video or movie sources, and can run in realtime for those inputs. I also have a raw pixel data output, which might be faster for use with Tesseract.

Brad Larson
  • 170,088
  • 45
  • 397
  • 571
  • Thanks a lot this looks realy promising. Do you know if someone succeeded with using terreract and the GPUImage framework? I find it hard combining tesseract with other frameworks (especially the fact that tesseract has .mm files). If you could find me any examples, clues... their most welcome – BarryK88 Apr 04 '12 at 09:31
  • There shouldn't be any incompatibilities (namespace, etc.) that I know of. I know that other people have said that they would use this with Tesseract, so since they haven't complained I guess it's working so far. Unfortunately, I don't have any examples because I've not yet experimented with this myself. – Brad Larson Apr 04 '12 at 12:59
  • I've tried importing your framework but can't get it fixed. I added the project, set dependency, import .a file to link library in build settings, added header to my .m file but I'm getting this error " *** Assertion failure in -[GPUImageGrayscaleFilter createFilterFBOofSize:], /Users//Desktop/OCR crap/Nieuw/Archive 2/GPUImageFilter.m:218". Can you help me out? – BarryK88 Apr 05 '12 at 14:08
  • @BarryK88 - OK, if you followed the instructions on the main project page you should have the framework added correctly. The error you describe happens when you try to filter a 0-size image. Did you set up your grayscale filter like I describe in the code above? Look at the SimpleImageFilter example to see sample code for how to filter images, and make sure your code looks like that. – Brad Larson Apr 05 '12 at 16:10
  • i had no problem using GPUimage framework in a project that also has tesseract. after playing around i found that GPUImageAverageLuminanceThresholdFilter produced the best results under a wide range of conditions. Image filtering is definitely fast using GPUimage. And more importantly tesseract is faster using a binarized image. thanks for the library. – roocell Nov 21 '12 at 20:04
  • Hi @BradLarson, I'm trying to use your framework, but it looks like there's no "imageFromCurrentlyProcessedOutput" method for the "stillImageFilter". What I found, and tried to use, is the method "newCGImageFromCurrentlyProcessedOutput", but it gives me a nil CGImageRef. Could you help with this? Thanks. – Aleph72 Feb 26 '18 at 11:35
  • @Aleph72 - The interface for this changed four years ago: http://www.sunsetlakesoftware.com/2014/03/17/switching-gpuimage-use-cached-framebuffers , so you need to trigger `-useNextFrameForImageCapture` before `-processImage` in order for images to be captured. See the documentation on the project page for how this is done: https://github.com/BradLarson/GPUImage – Brad Larson Feb 27 '18 at 15:33
  • Yes, @BradLarson, I'd already figured it out. Thank you anyways. – Aleph72 Feb 27 '18 at 15:35