Подтвердить что ты не робот

OCR: изображение в текст?

Прежде чем отметьте как копию или повторите вопрос, сначала прочтите весь вопрос.

Я могу сделать при нажатии, как показано ниже:

  • Чтобы получить изображение и обрезать нужную часть для OCR.
  • Обработать изображение с помощью tesseract и leptonica.
  • Когда прикладной документ обрезается в кусках, т.е. 1 символ на изображение, он обеспечивает 96% точности.
  • Если я этого не делаю, а фон документа белого цвета, а текст черного цвета, он дает почти такую ​​же точность.

Например, если вход такой как фотография:

Начало фото

enter image description here

Фото конец

Я хочу, чтобы у меня была такая же точность для этой фотографии enter image description here
без генерации блоков.

Код, который я использовал для запуска tesseract и извлечения текста из изображения, выглядит следующим образом:

Для начала tesseract

в .h файле

tesseract::TessBaseAPI *tesseract;
uint32_t *pixels;

в .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("textord_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("textord_projection_scale", "0.25");
tesseract->SetVariable("tessedit_minimal_rejection", "1");
tesseract->SetVariable("tessedit_zero_kelvin_rejection", "1");

Для получения текста с изображения

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

Но я не получаю правильный вывод для изображения номерной таблички, либо он равен null, либо дает некоторые данные мусора для изображения.

И если я использую изображение, которое является первым, то есть белый фон с текстом как черный, то вывод будет точным от 89 до 95%.

Пожалуйста, помогите мне.

Любое предложение будет оценено.

Обновление

Благодаря @jcesar для предоставления ссылки, а также @konstantin pribluda, чтобы предоставить ценную информацию и руководство.

Я могу преобразовать изображения в правильную черно-белую форму (почти). и поэтому распознавание лучше для всех изображений:)

Нужна помощь при правильной бинаризации изображений. Любая идея будет оценена

4b9b3361

Ответ 1

Привет всем Спасибо за ваши ответы, из всех этих ответов я могу получить этот вывод, как показано ниже:

  • Мне нужно получить только один обрезанный блок изображения с номером, содержащимся в нем.
  • Из этой таблички нужно выяснить часть части числа, используя данные, полученные мной, используя метод здесь.
  • Затем преобразование данных изображения в почти черно-белое с использованием данных RGB, найденных с помощью вышеуказанного метода.
  • Затем данные преобразуются в изображение с использованием метода здесь.

Выше 4 шага объединяются в один метод, как показано ниже:

-(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 red   = (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(@"red %f \t green %f \t blue %f \t alpha %f rawData [%d] %d",red,green,blue,alpha,ii,rawData[ii]);
        if(red > Required_Value_of_red || green > Required_Value_of_green || blue > Required_Value_of_blue)//all values are between 0 to 255
        {
            red = 255.0;
            green = 255.0;
            blue = 255.0;
            alpha = 255.0;
            // all value set to 255 to get white background.
        }
        rawData[byteIndex] = red;
        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);
}

Примечание:

Единственным недостатком этого метода является время и значение RGB для преобразования в белый, а другое - в черный.

ОБНОВЛЕНИЕ:

    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]; 

Просто замените код вышеуказанного метода (getRGBAsFromImage:) на этот, и результат будет таким же, но время будет всего лишь от 0,1 до 0,3 секунды.

Ответ 2

Мне удалось достичь почти мгновенных результатов, используя предоставленную демонстрационную фотографию, а также создав правильные буквы.

Я предварительно обработал изображение, используя GPUImage

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

И затем отправку обработанного изображения в 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));
}

Эти левые "отметки для" - но их также легко удалить. В зависимости от набора изображений, который у вас есть, вам, возможно, придется немного настроить его, но он должен заставить вас двигаться в правильном направлении.

Сообщите мне, если у вас есть проблемы с его использованием, это из проекта, который я использую, и я не хотел, чтобы все это разбивали или создавали для него проект с нуля.

Ответ 3

Я полагаю, что tesseract будет излишним для вашей цели. Для улучшения качества распознавания вам не требуется сопоставление слов (у вас нет этого словаря, но, возможно, это означает вычисление контрольной суммы по номеру лицензии), и у вас есть шрифт, оптимизированный для OCR. И, самое главное, у вас есть маркеры (рядом с оранжевым и синим цветом хорошо), чтобы найти область на изображении.

В моих приложениях OCR я использую поисковую область с поддержкой людей (просто нацеливая наложение справки на предварительный просмотр камеры). Обычно одни используют что-то вроде хара-каскада для поиска интересных функций, таких как лица. Вы можете также вычислить центроид оранжевой области или просто ограничивающий прямоугольник оранжевых пикселей, просто пройдя все изображения и оставив самые левые/правые/верхние/нижние пиксели подходящего цвета

Что касается распознавания itselff, я бы рекомендовал использовать инвариантные моменты (не уверен, реализован ли в tesseract, но вы можете легко перенести его из проекта java: http://sourceforge.net/projects/javaocr/)

Я попробовал свое демо-приложение на мониторе, и он распознал цифры в спорте (не обучен для символов)

Что касается бинаризации (отделяя черный от белого), я бы рекомендовал метод sauvola, так как это дает наилучшую устойчивость к изменениям яркости (также реализуется в нашем проекте OCR)