OCR: изображение в текст?
перед меткой как вопрос экземпляра или повторения, пожалуйста прочитайте весь вопрос сперва.
Я могу сделать в pressent, как показано ниже:
- чтобы получить изображение и обрезать нужную часть для OCR.
- обработка изображения с помощью
tesseract
иleptonica
. - когда применяемый документ обрезается кусками, т. е. 1 символ на изображение, он обеспечивает 96% точности.
- если я не сделаю этого и документ фон в белом цвете, а текст в черном цвете дает почти такую же точность.
например, если вход в эту фотографию :
фото старт
фото конец
то, что я хочу, чтобы иметь возможность получить такую же точность для этой фотографии
без генерации блоков.
код, который я использовал для инициализации tesseract и извлечения текста из изображения, выглядит так ниже:
для init Тессеракта
in .файл H
tesseract::TessBaseAPI *tesseract;
uint32_t *pixels;
in .файл м
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];
}
но я не получаю правильный вывод для изображения номерного знака либо он равен нулю, либо дает некоторые данные мусора для изображения.
и если я использую изображение, которое является первым, т. е. белый фон с текстом как черный, то выход составляет от 89 до 95% точный.
пожалуйста, помогите мне.
любое предложение будет оценено.
обновление
спасибо @jcesar за предоставление ссылки, а также @konstantin pribluda за предоставление ценной информации и руководства.
Я могу конвертировать изображения в правильную черно-белую форму (почти). и поэтому распознавание лучше для всех изображений:)
нужна помощь с правильным бинаризация изображений. любая идея будет оценен
3 ответов
Привет всем спасибо за ваши ответы, все ответы я могу получить этот вывод, как показано ниже:
- мне нужно получить только один обрезанный блок изображения с номерным знаком, содержащимся в нем.
- из этой пластины нужно выяснить часть части номера, используя данные, которые я получил, используя предоставленный метод здесь.
- затем преобразование данных изображения почти в черно-белый, используя данные 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 секунды.
я смог достичь почти мгновенных результатов, используя демонстрационную фотографию, а также генерировать правильные буквы.
Я предварительно обработал изображение с помощью GPUImage
// Pre-processing for OCR
GPUImageLuminanceThresholdFilter * adaptiveThreshold = [[GPUImageLuminanceThresholdFilter alloc] init];
[adaptiveThreshold setThreshold:0.3f];
[self setProcessedImage:[adaptiveThreshold imageByFilteringImage:_image]];
а затем отправка обработанного изображения Тесс
- (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));
}
Это оставленные " метки Для - но их также легко удалить. В зависимости от набора изображений, который у вас есть, вам может потребоваться немного настроить его, но он должен заставить вас двигаться в правильном направлении направление.
Дайте мне знать, если у вас есть проблемы с его использованием, это из проекта, который я использую, и я не хотел бы лишать все или создавать проект с нуля для него.