2012-11-06 43 views
13

प्रतिलिपि या दोहराना प्रश्न के रूप में चिह्नित करने से पहले, कृपया पहले पूरा प्रश्न पढ़ें।ओसीआर: पाठ के लिए छवि?

मैं pressent पर ऐसा करने में सक्षम हूँ के रूप में नीचे है:

  1. छवि हो और ओसीआर के लिए वांछित हिस्सा काटने के लिए।
  2. tesseract और leptonica का उपयोग कर छवि को संसाधित करें।
  3. जब लागू दस्तावेज़ भाग में फसल हो जाता है यानी प्रति छवि 1 वर्ण यह 96% सटीकता प्रदान करता है।
  4. यदि मैं ऐसा नहीं करता हूं और दस्तावेज़ पृष्ठभूमि सफेद रंग में है और टेक्स्ट काले रंग में है तो यह लगभग समान सटीकता देता है।

उदाहरण के लिए इनपुट इस फोटो के रूप में है यदि:

फोटो शुरू

enter image description here

फोटो अंत

क्या मैं चाहता हूँ प्राप्त करने में सक्षम करने के लिए है इस तस्वीर के लिए समान सटीकता enter image description here
ब्लॉक उत्पन्न किए बिना।

कोड मैं Tesseract init और छवि से पाठ निकालने के लिए इस्तेमाल के रूप में नीचे है:

मीटर फ़ाइल में ज फ़ाइल

tesseract::TessBaseAPI *tesseract; 
uint32_t *pixels; 

में Tesseract

की init के लिए

tesseract = new tesseract::TessBaseAPI(); 
tesseract->Init([dataPath cStringUsingEncoding:NSUTF8StringEncoding], "eng"); 
tesseract->SetPageSegMode(tesseract::PSM_SINGLE_LINE); 
tesseract->SetVariable("tessedit_char_whitelist", "ABCDEFGHIJKLMNOPQRSTUVWXYZ"); 
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"); 
,210

छवि

- (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 से 9 5% सटीक है।

कृपया मेरी मदद करें।

किसी भी सुझाव की सराहना की जाएगी।

अद्यतन

धन्यवाद लिंक प्रदान करने के लिए @jcesar करने के लिए और भी pribluda @konstantin को बहुमूल्य जानकारी और मार्गदर्शन प्रदान करने के लिए।

मैं छवियों को उचित काले और सफेद रूप (लगभग) में परिवर्तित करने में सक्षम हूं।और इसलिए सभी छवियों के लिए मान्यता बेहतर है :)

छवियों के उचित बिनराइजेशन के साथ मदद की ज़रूरत है। किसी भी विचार की सराहना की जाएगी

+0

शायद आप पाठ को पहचानने की कोशिश करने से पहले छवि में हेरफेर करने का प्रयास कर सकते हैं, उदाहरण के लिए हर काले रंग (या काले रंग के करीब) पिक्सेल रंग को सफेद में बदलें। अभी मेरे पास ऐसा करने के लिए उद्देश्य-सी कोड नहीं है, लेकिन मुझे यकीन है कि यह किया जा सकता है। – jcesarmobile

+0

मेरे पास हालांकि इसके लिए है लेकिन यहां पर मैं इसे लागू करने में सक्षम नहीं हूं। –

+0

स्वीकृत उत्तर http://stackoverflow.com/questions/9977905/change-a-color-in-a-uiimage – jcesarmobile

उत्तर

6

हाय अपने उत्तर के लिए सभी धन्यवाद, उत्तर से यह सब मैं नीचे के रूप में इस निष्कर्ष प्राप्त करने में सक्षम हूँ करने के लिए टी सहिष्णुता:

  1. मैं प्राप्त करने की आवश्यकता उसमें निहित संख्या प्लेट के साथ केवल एक फसल छवि ब्लॉक।
  2. उस प्लेट से here प्रदान की गई विधि का उपयोग करके प्राप्त डेटा का उपयोग करके संख्या भाग के हिस्से को जानने की आवश्यकता है।
  3. फिर उपरोक्त विधि के माध्यम से प्राप्त आरजीबी डेटा का उपयोग कर छवि डेटा को लगभग काले और सफेद में परिवर्तित करना।
  4. फिर डेटा here प्रदान की गई विधि का उपयोग कर छवि में परिवर्तित हो जाता है।

ऊपर 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); 
} 

नोट:

इस पद्धति का ही दोष यह समय का सेवन किया और आरजीबी है सफेद और दूसरे से काले रंग में बदलने के लिए मूल्य।

अद्यतन:

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 सेकंड ही है।

+0

यह एक अविश्वसनीय रूप से लंबा समय लगता है लेकिन ऐसा लगता है कि मैं क्या चाहता हूं। GPUImage या कुछ समान के साथ ऐसा कुछ करने का कोई तरीका? – mwright

+0

हाँ यह कहना सही है कि 250 x 55 पिक्सेल छवि लगभग 1.5 मिनट (लगभग) लेती है लेकिन 99% सटीकता देता है। क्या आपको पता है कि समय की आवश्यकता के बारे में कुछ सुझाव है या नहीं? :) –

+0

मैं इस पद्धति का उपयोग यह कम करने के लिए कोई सुझाव नहीं है, मैं छवि preprocessing और टेस का एक संयोजन का उपयोग कर रहा है कि मैं क्या कर रहा हूँ पर काम कर रहा पर प्राप्त करने के लिए 100% सही परिणाम नहीं। मैं इसे अपनी छवि के साथ आज़मा दूंगा और देख सकता हूं कि अगर मैं काम करता हूं तो मुझे अच्छे परिणाम मिल सकते हैं, मैं यहां एक उत्तर के रूप में पोस्ट करूंगा। – mwright

1

मुझे डर है कि आपके उद्देश्य के लिए टेसरेक्ट अधिक हो जाएगा। आपको मान्यता गुणवत्ता में सुधार करने के लिए शब्दकोश मिलान की आवश्यकता नहीं है (आपके पास यह शब्दकोश नहीं है, लेकिन शायद लाइसेंस नंबर पर चेकसम की गणना करना है), और आपके पास ओसीआर के लिए फ़ॉन्ट अनुकूलित है। और सबसे अच्छा, छवि में क्षेत्र खोजने के लिए आपके पास मार्कर (नारंगी और नीले रंग के रंग क्षेत्र अच्छे हैं) हैं।

मैं अपने ओसीआर ऐप्स मैं रुचि प्राप्त पुनर्प्राप्ति के मानव सहायता क्षेत्र का उपयोग करता हूं (केवल कैमरा पूर्वावलोकन पर सहायता ओवरले का लक्ष्य रखता हूं)। आम तौर पर चेहरे जैसे रोचक विशेषताओं का पता लगाने के लिए हायर कैस्केड जैसे कुछ उपयोग करते हैं। आप ऑरेंज क्षेत्र के सेंट्रॉइड की गणना भी कर सकते हैं, या बस सभी छवियों को घुमाने और नजदीक/दाएं/टॉपोस्ट/बोटमोस्ट पिक्सेल को उपयुक्त रंग

पहचान के लिए इसके रूप में मैं inventt क्षणों का उपयोग करने की सिफारिश करता हूं (यकीन नहीं है कि क्या Tesseract में लागू है, लेकिन आप आसानी से बाहर जावा परियोजना से यह बंदरगाह: http://sourceforge.net/projects/javaocr/)

मैं पर नजर रखने के लिए छवि पर मेरी डेमो एप्लिकेशन की कोशिश की और यह खेल पर अंक मान्यता प्राप्त (पात्रों के लिए प्रशिक्षित नहीं है)

बिनराइज़ेशन (सफेद से काला को अलग करने के लिए) के रूप में मैं sauvola विधि की सिफारिश करता हूं क्योंकि यह bes luminance परिवर्तन (भी हमारे ओसीआर परियोजना में लागू)

+0

हां यह सही है लेकिन मुझे नहीं पता कि सही क्षेत्र कैसे प्राप्त करें और कुछ ब्लॉक पीढ़ी के बिना पाठ कैसे प्राप्त करें यानी 1 प्रति छवि ब्लॉक में छवियों को फसल करने की आवश्यकता है और फिर ओसीआर करने से अच्छा परिणाम मिलेगा अन्यथा यह सिर्फ देता है कचरा मूल्य। –

+0

उत्तर के लिए धन्यवाद मैं इसे आज़माउंगा :) –

+0

हाय @ कॉन्स्टेंटिन, मैंने अपना जवाब अपडेट कर दिया है। मुझे बस .3 से .5 सेकंड औसत समय के साथ इस मुद्दे को हल करने का कोई तरीका मिलता है। और फिर आपके सुझाव के लिए धन्यवाद, क्योंकि इससे मुझे व्युत्पन्न समाधान प्राप्त करने में बहुत मदद मिलती है। –

4

मैं प्रदान किए गए डेमो फोटो का उपयोग करके तत्काल तत्काल परिणाम प्राप्त करने में सक्षम था और साथ ही यह सही अक्षरों को उत्पन्न करता था।

मैं के लिए 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)); 
} 

यह बाईं 'के निशान को GPUImage

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

और फिर का उपयोग कर छवि है कि संसाधित छवि भेजने पूर्व संसाधित - लेकिन ये भी दूर करने के लिए आसान है। आपके पास सेट किए गए छवि सेट के आधार पर आपको थोड़ा सा ट्यून करना पड़ सकता है लेकिन इसे आपको सही दिशा में ले जाना चाहिए।

मुझे बताएं कि क्या आपको इसका उपयोग करने में समस्याएं हैं, यह एक ऐसी परियोजना से है जिसका मैं उपयोग कर रहा हूं और मैं इसे सब कुछ पट्टी नहीं करना चाहता था या इसके लिए स्क्रैच से एक परियोजना नहीं बनाना चाहता था।

+0

आपके उत्तर के लिए धन्यवाद। मैं कोशिश कर रहा हूँ। लेकिन फिलहाल मैंने इसे सेब के डिफ़ॉल्ट छवि प्रसंस्करण ढांचे के CoreImage.framework के साथ काम किया और इसके डिफ़ॉल्ट फ़िल्टर का उपयोग करके मुझे अपनी छवि को शुद्ध काले और सफेद रंग में आसानी से मिला और इसमें केवल 0.1 से 0.3 सेकंड लगते हैं। और लगभग सभी प्रकार की छवियों के लिए सही परिणाम प्रदान करता हूं, मैं इसे आजमाता हूं। –

+0

आपको अपनी नई विधि को शामिल करने के लिए अपना उत्तर अपडेट करना चाहिए ताकि अन्य इसका लाभ उठा सकें। – mwright

+0

मेरे उत्तर में मेरा अपडेट देखें मैंने कोड के लिए कोड डाला है। मुझे पता है कि यह दो तरह की साइट है। –

 संबंधित मुद्दे

  • कोई संबंधित समस्या नहीं^_^