2012-11-22 15 views
15

Ich möchte eine OCR-Anwendung implementieren, die Text von Fotos erkennen würde.iOS Tesseract OCR Image Preperation

Es ist mir gelungen, die Tesseract Engine in iOS zu kompilieren und zu integrieren. Es ist mir gelungen, eine vernünftige Erkennung zu erhalten, wenn man klare Dokumente (oder ein Foto von diesem Text vom Bildschirm) fotografiert, aber für andere Texte wie Schilder, Schilder, farbigen Hintergrund , die Erkennung ist fehlgeschlagen.

Die Frage ist Welche Art von Bildverarbeitungsvorbereitungen sind notwendig, um eine bessere Erkennung zu erhalten. Zum Beispiel erwarte ich, dass wir die Bilder in Graustufen/B & W sowie Fixierungskontrast usw. umwandeln müssen.

Wie kann dies in iOS getan werden, Gibt es ein Paket dafür?

Antwort

15

Ich arbeite derzeit an der gleichen Sache. Ich fand, dass ein PNG, das in Photoshop gespeichert wurde, gut funktionierte, aber ein Bild, das ursprünglich von der Kamera stammte und dann in die App importiert wurde, funktionierte nie. Frag mich nicht, es zu erklären - aber die Anwendung dieser Funktion hat diese Bilder funktionieren lassen. Vielleicht wird es auch für dich funktionieren.

// 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; 
} 

Ich habe auch viel experimentiert das Bild für Tesseract vorbereitet. Größenanpassung, Konvertierung in Graustufen und Anpassung von Helligkeit und Kontrast scheinen am besten zu funktionieren.

Ich habe auch diese GPUImage-Bibliothek ausprobiert. https://github.com/BradLarson/GPUImage Und der GPUImageAverageLuminanceThresholdFilter scheint mir ein gut angepasstes Bild zu geben, aber Tesseract scheint nicht gut damit zu arbeiten.

Ich habe auch opencv in mein Projekt und planen, es ist Bildroutinen auszuprobieren. Möglicherweise sogar eine Boxerkennung, um den Textbereich zu finden (ich hoffe, dass dies den Test beschleunigt).

+0

Nach dem Hinzufügen dieser gs_convert_image() auch bekomme ich das gleiche Ergebnis, bevor Sie diese Methode. Gibt es eine Möglichkeit, die Genauigkeit der Tessarakt-Scandaten zu verbessern? –

+1

Konnten Sie jemals herausfinden, warum OCR bei gespeicherten Bildern, aber nicht bei Bildern von der Kamera funktioniert? Ich habe das gleiche Problem jetzt, aber ich arbeite in Swift und weiß nicht, wie Sie Ihren obigen Code implementieren.Ich habe es gerade hier http://stackoverflow.com/questions/29336501/tesseract-ocr-w-ios-swift-returns-error-or-gibberish gepostet und dann deine Antwort gefunden. Scheint verwandt. Irgendwelche Ideen? – Andrew

+0

Mind blasender Code, @roocell Sie sparen meine Zeit. –

9

Ich habe den obigen Code verwendet, aber zwei weitere Funktionsaufrufe hinzugefügt, um das Bild so zu konvertieren, dass es mit Tesseract funktioniert.

Zuerst habe ich ein Bildgrößenskript verwendet, um 640 x 640 zu konvertieren, das für den Tesseract besser zu handhaben ist.

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

Damit der Radiant sicherzustellen, arbeiten Sie erklären es über den @implementation

static inline double radians (double degrees) {return degrees * M_PI/180;} 

Dann wandle ich Graustufen.

Ich fand diesen Artikel Convert image to grayscale auf Umwandlung in Graustufen.

Ich habe den Code von hier erfolgreich eingesetzt und nun anderen Farbe Text und verschiedene Farbhintergründe

ich den Code geändert habe etwas innerhalb einer Klasse als Funktion zu arbeiten und nicht als seine eigene Klasse, die die andere lesen kann Person hat

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

Ich habe dies versucht, und meine Bilder werden konvertiert, jedoch stürzt die UIImage immer noch auf meinem iPhone. Irgendwelche Vorschläge? Kannst du deinen Quellcode angeben? –

+1

Sie geben ein Bild von der Kamera zurück oder laden es von einer anderen Quelle? Auch der Code, den ich oben zur Verfügung gestellt habe, setzt voraus, dass Sie ARC verwenden. Wenn dies nicht der Fall ist, müssen Sie das Bild und andere Objekte zur richtigen Zeit freigeben, andernfalls werden Sie aufgrund der Speicherauslastung abstürzen. –

+0

"image.imageOrientation == UIImageOrientationUp | image.imageOrientation == UIImageOrientationDown"? – Andy

Verwandte Themen