OCR: Imagen a text?

Antes de marcar como copy o pregunta repetida, lea primero la pregunta completa.

Lo que puedo hacer en pressent es como a continuación:

  1. Para get la image y recortar la parte deseada para OCR.
  2. Procese la image con tesseract y leptonica .
  3. Cuando el documento aplicado se recorta en trozos, es decir, 1 carácter por image, proporciona un 96% de precisión.
  4. Si no hago eso y el background del documento está en color blanco y el text está en color negro, da casi la misma precisión.

Por ejemplo, si la input es como esta foto:

Inicio de fotos

introduzca la descripción de la imagen aquí

Extremo de la foto

Lo que quiero es poder get la misma precisión para esta foto introduzca la descripción de la imagen aquí
sin generar bloques.

El código que utilicé para iniciar el ensayo y extraer el text de la image es el siguiente:

Para init de tesseract

en el file .h

 tesseract::TessBaseAPI *tesseract; uint32_t *pixels; 

en el file .m

 tesseract = new tesseract::TessBaseAPI(); tesseract->Init([dataPath cStringUsingEncoding:NSUTF8StringEncoding], "eng"); tesseract->SetPageSegMode(tesseract::PSM_SINGLE_LINE); tesseract->SetVariable("tessedit_char_whitelist", "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"); tesseract->SetVariable("language_model_penalty_non_freq_dict_word", "1"); tesseract->SetVariable("language_model_penalty_non_dict_word ", "1"); tesseract->SetVariable("tessedit_flip_0O", "1"); tesseract->SetVariable("tessedit_single_match", "0"); tesseract->SetVariable("textrd_noise_normratio", "5"); tesseract->SetVariable("matcher_avg_noise_size", "22"); tesseract->SetVariable("image_default_resolution", "450"); tesseract->SetVariable("editor_image_text_color", "40"); tesseract->SetVariable("textrd_projection_scale", "0.25"); tesseract->SetVariable("tessedit_minimal_rejection", "1"); tesseract->SetVariable("tessedit_zero_kelvin_rejection", "1"); 

Para get text de la image

 - (void)processOcrAt:(UIImage *)image { [self setTesseractImage:image]; tesseract->Recognize(NULL); char* utf8Text = tesseract->GetUTF8Text(); int conf = tesseract->MeanTextConf(); NSArray *arr = [[NSArray alloc]initWithObjects:[NSString stringWithUTF8String:utf8Text],[NSString stringWithFormat:@"%d%@",conf,@"%"], nil]; [self performSelectorOnMainThread:@selector(ocrProcessingFinished:) withObject:arr waitUntilDone:YES]; free(utf8Text); } - (void)ocrProcessingFinished0:(NSArray *)result { UIAlertView *alt = [[UIAlertView alloc]initWithTitle:@"Data" message:[result objectAtIndex:0] delegate:self cancelButtonTitle:nil otherButtonTitles:@"OK", nil]; [alt show]; } 

Pero no obtengo la salida adecuada para la image de matrícula, ya sea nula o da algunos datos de basura para la image.

Y si uso la image que es la primera, es decir, background blanco con text en negro, entonces la salida es precisa del 89 al 95%.

Por favor, ayúdame.

Cualquier sugerencia será apreciada.

Actualizar

Gracias a @jcesar por proporcionar el enlace y también a @konstantin pribluda para proporcionar información valiosa y guía.

Soy capaz de convertir las imágenes en una forma adecuada en blanco y negro (casi). y entonces el reconocimiento es mejor para todas las imágenes 🙂

Necesita ayuda con la binarización adecuada de imágenes. Cualquier idea será apreciada

Hola a todos Gracias por sus respuestas, de todas esas respuestas puedo get esta conclusión como a continuación:

  1. Necesito get el único bloque de image recortada con la matrícula contenida en él.
  2. Desde esa placa necesito averiguar la porción de la porción del número usando los datos que obtuve usando el método provisto aquí .
  3. Luego, convertir los datos de la image en casi blanco y negro utilizando los datos RGB encontrados mediante el método anterior.
  4. Luego, los datos se convierten a la Imagen utilizando el método provisto aquí .

Se combinan más de 4 pasos en un método como el siguiente:

 -(void)getRGBAsFromImage:(UIImage*)image { NSInteger count = (image.size.width * image.size.height); // First get the image into your data buffer CGImageRef imageRef = [image CGImage]; NSUInteger width = CGImageGetWidth(imageRef); NSUInteger height = CGImageGetHeight(imageRef); CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB(); unsigned char *rawData = (unsigned char*) calloc(height * width * 4, sizeof(unsigned char)); NSUInteger bytesPerPixel = 4; NSUInteger bytesPerRow = bytesPerPixel * width; NSUInteger bitsPerComponent = 8; CGContextRef context = CGBitmapContextCreate(rawData, width, height, bitsPerComponent, bytesPerRow, colorSpace, kCGImageAlphaPremultipliedLast | kCGBitmapByteOrder32Big); CGColorSpaceRelease(colorSpace); CGContextDrawImage(context, CGRectMake(0, 0, width, height), imageRef); CGContextRelease(context); // Now your rawData contains the image data in the RGBA8888 pixel format. int byteIndex = 0; for (int ii = 0 ; ii < count ; ++ii) { CGFloat networking = (rawData[byteIndex] * 1.0) ; CGFloat green = (rawData[byteIndex + 1] * 1.0) ; CGFloat blue = (rawData[byteIndex + 2] * 1.0) ; CGFloat alpha = (rawData[byteIndex + 3] * 1.0) ; NSLog(@"networking %f \t green %f \t blue %f \t alpha %f rawData [%d] %d",networking,green,blue,alpha,ii,rawData[ii]); if(networking > Requinetworking_Value_of_networking || green > Requinetworking_Value_of_green || blue > Requinetworking_Value_of_blue)//all values are between 0 to 255 { networking = 255.0; green = 255.0; blue = 255.0; alpha = 255.0; // all value set to 255 to get white background. } rawData[byteIndex] = networking; rawData[byteIndex + 1] = green; rawData[byteIndex + 2] = blue; rawData[byteIndex + 3] = alpha; byteIndex += 4; } colorSpace = CGColorSpaceCreateDeviceRGB(); CGContextRef bitmapContext = CGBitmapContextCreate( rawData, width, height, 8, // bitsPerComponent 4*width, // bytesPerRow colorSpace, kCGImageAlphaNoneSkipLast); CFRelease(colorSpace); CGImageRef cgImage = CGBitmapContextCreateImage(bitmapContext); UIImage *img = [UIImage imageWithCGImage:cgImage]; //use the img for further use of ocr free(rawData); } 

Nota:

El único inconveniente de este método es el time consumido y el valor RGB para convertir a blanco y otro a negro.

ACTUALIZACIÓN:

  CGImageRef imageRef = [plate CGImage]; CIContext *context = [CIContext contextWithOptions:nil]; // 1 CIImage *ciImage = [CIImage imageWithCGImage:imageRef]; // 2 CIFilter *filter = [CIFilter filterWithName:@"CIColorMonochrome" keysAndValues:@"inputImage", ciImage, @"inputColor", [CIColor colorWithRed:1.f green:1.f blue:1.f alpha:1.0f], @"inputIntensity", [NSNumber numberWithFloat:1.f], nil]; // 3 CIImage *ciResult = [filter valueForKey:kCIOutputImageKey]; // 4 CGImageRef cgImage = [context createCGImage:ciResult fromRect:[ciResult extent]]; UIImage *img = [UIImage imageWithCGImage:cgImage]; 

Simplemente reemplace el código del método anterior ( getRGBAsFromImage: con este y el resultado es el mismo, pero el time requerido es solo de 0.1 a 0.3 segundos solamente.

Pude lograr resultados casi instantáneos usando la foto de demostración proporcionada y generando las letras correctas.

Procesé previamente la image con GPUImage

 // Pre-processing for OCR GPUImageLuminanceThresholdFilter * adaptiveThreshold = [[GPUImageLuminanceThresholdFilter alloc] init]; [adaptiveThreshold setThreshold:0.3f]; [self setProcessedImage:[adaptiveThreshold imageByFilteringImage:_image]]; 

Y luego enviar esa image procesada a TESS

 - (NSArray *)processOcrAt:(UIImage *)image { [self setTesseractImage:image]; _tesseract->Recognize(NULL); char* utf8Text = _tesseract->GetUTF8Text(); return [self ocrProcessingFinished:[NSString stringWithUTF8String:utf8Text]]; } - (NSArray *)ocrProcessingFinished:(NSString *)result { // Strip extra characters, whitespace/newlines NSString * results_noNewLine = [result stringByReplacingOccurrencesOfString:@"\n" withString:@""]; NSArray * results_noWhitespace = [results_noNewLine componentsSeparatedByCharactersInSet:[NSCharacterSet whitespaceCharacterSet]]; NSString * results_final = [results_noWhitespace componentsJoinedByString:@""]; results_final = [results_final lowercaseString]; // Separate out individual letters NSMutableArray * letters = [[NSMutableArray alloc] initWithCapacity:results_final.length]; for (int i = 0; i < [results_final length]; i++) { NSString * newTile = [results_final substringWithRange:NSMakeRange(i, 1)]; [letters addObject:newTile]; } return [NSArray arrayWithArray:letters]; } - (void)setTesseractImage:(UIImage *)image { free(_pixels); CGSize size = [image size]; int width = size.width; int height = size.height; if (width <= 0 || height <= 0) return; // the pixels will be painted to this array _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), [image CGImage]); _tesseract->SetImage((const unsigned char *) _pixels, width, height, sizeof(uint32_t), width * sizeof(uint32_t)); } 

Esto dejó 'marcas para – pero también son fáciles de eliminar. Dependiendo del set de imágenes que tenga, es posible que tenga que ajustarlo un poco, pero debería moverlo en la dirección correcta.

Avíseme si tiene problemas para usarlo, es de un proyecto que estoy usando y no quería tener que quitar todo o crear un proyecto desde cero.

Me atrevo a decir que el tesseract será excesivo para su propósito. No necesita la concordancia de dictionary para mejorar la calidad de reconocimiento (no tiene este dictionary, pero tal vez sea para calcular la sum de comprobación en el número de licencia), y tiene una fuente optimizada para OCR. Y lo mejor de todo, tiene marcadores (las áreas de color naranja y azul cercanas son buenas) para encontrar la región en la image.

Yo, mis aplicaciones de OCR, uso el área de recuperación de interés humano asistido (solo apunta la superposition de ayuda sobre la vista previa de la camera). Por lo general, los usuarios usan algo así como cascada para localizar características interesantes como rostros. También puede calcular el centroide de área naranja, o simplemente el cuadro delimitador de píxeles naranjas, simplemente atravesando toda la image y aplastando los píxeles más a la izquierda / más a la derecha / superior / más inferior de un color adecuado

En cuanto al reconocimiento de suelff, recomendaría utilizar momentos invariantes (no estoy seguro de si está implementado en tesseract, pero puede hacerlo fácilmente desde el proyecto java: http://sourceforge.net/projects/javaocr/ )

Probé mi aplicación de demostración en la image del monitor y reconoció los dígitos en el deporte (no está entrenado para personajes)

En cuanto a la binarización (que separa el negro del blanco) recomendaría el método sauvola, ya que esto da la mejor tolerancia a los cambios de luminancia (también se implementa en nuestro proyecto OCR)