2012-11-22 7 views
15

Vorrei implementare un'applicazione OCR in grado di riconoscere il testo da Foto.iOS Tesseract Immagine OCR Preperation

Sono riuscito a compilare e integrare il motore Tesseract in iOS, sono riuscito a ottenere un rilevamento ragionevole quando si fotografano documenti chiari (o un photoshot di questo testo dallo schermo) ma per altri testi come cartelli, insegne, sfondo a colori , il rilevamento non è riuscito.

La domanda è Che tipo di preparativi per l'elaborazione delle immagini sono necessari per ottenere un migliore riconoscimento. Per esempio, mi aspetto che abbiamo bisogno di trasformare le immagini in scala di grigi/B & W e di fissare il contrasto ecc.

Come può essere fatto in iOS? Esiste un pacchetto per questo?

risposta

15

Attualmente sto lavorando alla stessa cosa. Ho scoperto che un file PNG salvato in Photoshop funzionava correttamente, ma un'immagine che era stata originariamente acquistata dalla fotocamera e che poi è stata importata nell'app non ha mai funzionato. Non chiedetemi di spiegarlo - ma l'applicazione di questa funzione ha reso queste immagini funzionanti. Forse funzionerà anche per te.

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

Ho anche fatto molti esperimenti per preparare l'immagine per tesseract. Il ridimensionamento, la conversione in scala di grigi, quindi la regolazione della luminosità e del contrasto sembra funzionare meglio.

Ho anche provato questa libreria GPUImage. https://github.com/BradLarson/GPUImage E GPUImageAverageLuminanceThresholdFilter sembra darmi una grande immagine regolata, ma tesseract non sembra funzionare bene con esso.

Ho anche aperto il mio progetto e ho intenzione di provare le sue routine di immagine. Forse anche un po 'di rilevamento della scatola per trovare l'area di testo (spero che questo acceleri il tesseract).

+0

Dopo aver aggiunto questo gs_convert_image() anche io sto ottenendo lo stesso risultato prima di mettere questo metodo. C'è un modo per migliorare la precisione dei dati di scansione tessaract? –

+1

Sei mai riuscito a capire perché l'OCR avrebbe funzionato sulle immagini salvate ma non sulle immagini dalla fotocamera? Sto avendo lo stesso problema ora, ma sto lavorando in Swift e non so come implementare il tuo codice sopra.Ho appena postato su di esso qui http://stackoverflow.com/questions/29336501/tesseract-ocr-w-ios-swift-returns-error-or-gibberish quindi ho trovato la risposta. Sembra correlato. Qualche idea? – Andrew

+0

Mind blowing code, @roocell Risparmia tempo. –

9

Ho usato il codice sopra ma ho aggiunto anche altre due chiamate di funzione per convertire l'immagine in modo che funzioni con Tesseract.

Innanzitutto ho usato uno script di ridimensionamento dell'immagine per convertire in 640 x 640 che sembra essere più gestibile per 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; 
} 

In modo che i radianti funzionano assicurano si dichiara al di sopra del @implementation

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

Poi converto in scala di grigi.

Ho trovato questo articolo Convert image to grayscale durante la conversione in scala di grigi.

Ho usato il codice da qui con successo e può ora leggere il testo di colore diverso e sfondi di colore diverso

Ho modificato il codice di un po 'di lavorare come una funzione all'interno di una classe piuttosto che come la propria classe, che l'altra persona ha fatto

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

ho provato questo, e le mie immagini vengono convertite, tuttavia, UIImage si blocca ancora sul mio iPhone. Eventuali suggerimenti? Puoi fornire il tuo codice sorgente? –

+1

Stai restituendo un'immagine dalla fotocamera o la stai caricando da un'altra fonte? Anche il codice che ho fornito sopra presuppone che tu stia usando ARC, se non lo sei, dovrai rilasciare l'immagine e altri oggetti al momento opportuno altrimenti si verifichino arresti anomali a causa del carico di memoria. –

+0

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