Search code examples
iosimage-processingocrgpuimage

iOS UIImage Binarization for OCR - handling images with varying luminance


I had a C++ binarization routine that I used for later OCR operation. However I found that it produced unnecessary slanting of text. Searching for alternatives I found GPUImage of great value and it solved the slanting issue.

I am using GPUImage code like this to binarize my input images before applying OCR.

However the threshold value does not cover the range of images I get. See two samples from my input images:

enter image description here

enter image description here

I can't handle both with same threshold value. Low value seems to be fine with later, and higher value is fine with first one.

The second image seems to be of special complexity because I never get all the chars to be binarized right, irrespective of what value I set for threshold. On the other hand, my C++ binarization routine seems to do it right, but I don't have much insights to experiment into it like simplistic threshold value in GPUImage.

How should I handle that?

UPDATE:

I tried with GPUImageAverageLuminanceThresholdFilter with default multiplier = 1. It works fine with first image but the second image continues to be problem.

Some more diverse inputs for binarization:

enter image description here

enter image description here

UPDATE II:

After going through this answer by Brad, tried GPUImageAdaptiveThresholdFilter (also incorporating GPUImagePicture because earlier I was only applying it on UIImage).

With this, I got second image binarized perfect. However first one seems to have lot of noise after binarization when I set blur size is 3.0. OCR results in extra characters added. With lower value of blur size, second image loses precision.

Here it is:

+(UIImage *)binarize : (UIImage *) sourceImage
{
    UIImage * grayScaledImg = [self toGrayscale:sourceImage];
    GPUImagePicture *imageSource = [[GPUImagePicture alloc] initWithImage:grayScaledImg];
    GPUImageAdaptiveThresholdFilter *stillImageFilter = [[GPUImageAdaptiveThresholdFilter alloc] init];
    stillImageFilter.blurSize = 3.0;    

    [imageSource addTarget:stillImageFilter];   
    [imageSource processImage];        

    UIImage *imageWithAppliedThreshold = [stillImageFilter imageFromCurrentlyProcessedOutput];
  //  UIImage *destImage = [thresholdFilter imageByFilteringImage:grayScaledImg];
    return imageWithAppliedThreshold;
}

Solution

  • I finally ended up exploring on my own, and here is my result with GPUImage filter:

    + (UIImage *) doBinarize:(UIImage *)sourceImage
    {
        //first off, try to grayscale the image using iOS core Image routine
        UIImage * grayScaledImg = [self grayImage:sourceImage];
        GPUImagePicture *imageSource = [[GPUImagePicture alloc] initWithImage:grayScaledImg];
        GPUImageAdaptiveThresholdFilter *stillImageFilter = [[GPUImageAdaptiveThresholdFilter alloc] init];
        stillImageFilter.blurSize = 8.0;
    
        [imageSource addTarget:stillImageFilter];
        [imageSource processImage];
    
        UIImage *retImage = [stillImageFilter imageFromCurrentlyProcessedOutput];
        return retImage;
    }
    
    + (UIImage *) grayImage :(UIImage *)inputImage
    {    
        // Create a graphic context.
        UIGraphicsBeginImageContextWithOptions(inputImage.size, NO, 1.0);
        CGRect imageRect = CGRectMake(0, 0, inputImage.size.width, inputImage.size.height);
    
        // Draw the image with the luminosity blend mode.
        // On top of a white background, this will give a black and white image.
        [inputImage drawInRect:imageRect blendMode:kCGBlendModeLuminosity alpha:1.0];
    
        // Get the resulting image.
        UIImage *outputImage = UIGraphicsGetImageFromCurrentImageContext();
        UIGraphicsEndImageContext();
    
        return outputImage;
    } 
    

    I achieve almost 90% using this - I am sure there must be better options but I tried with blurSize as far as I could and 8.0 is the value that works with most of my input images.

    For anyone else, good luck with your trying!