2012-02-22 16 views
9

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

वर्तमान समस्या छवि प्रीप्रोकैसिंग है। चूंकि क्रेडिट कार्ड में पृष्ठभूमि और अन्य जटिल ग्राफिक्स हो सकते हैं, इसलिए पाठ एक दस्तावेज़ स्कैन करने के समान स्पष्ट नहीं है। मैंने एज डिटेक्शन (कैनी एज, सोबेल) के साथ प्रयोग किए, लेकिन यह सफल नहीं था। ग्रेस्केल छवि और धुंधला हुआ एक (जैसा कि Remove background color in image processing for OCR पर बताया गया है) के बीच अंतर की गणना भी एक ओसीआरबल परिणाम नहीं पहुंचा।

मुझे लगता है कि अधिकांश दृष्टिकोण विफल हो जाते हैं क्योंकि एक विशिष्ट अंक और इसकी पृष्ठभूमि के बीच का अंतर पर्याप्त मजबूत नहीं है। संभवतः ब्लॉक में छवि का विभाजन करने की आवश्यकता है और प्रत्येक ब्लॉक के लिए सबसे अच्छा प्रीप्रोकैसिंग समाधान ढूंढना है?

क्या आपके पास कोई सुझाव है कि स्रोत को एक पठनीय बाइनरी छवि में कैसे परिवर्तित किया जाए? किनारे का पता लगाने का रास्ता है या क्या मुझे मूल रंग थ्रेसहोल्डिंग के साथ चिपकना चाहिए?

मूल छवि:

Original image

ग्रेस्केल छवि:

यहाँ एक ग्रेस्केल-थ्रेशोल्डिंग दृष्टिकोण (जहां मैं स्पष्ट रूप से परिणाम से खुश नहीं हूँ) का एक नमूना है

Greyscale image

थ्रेसहोल्ड छवि :

Thresholded image

किसी भी सलाह के लिए धन्यवाद, वैलेन्टिन

+0

चूंकि बहुत कम विपरीत हैं, इसलिए मैंने बताया कि मैं किनारे का पता लगाने की कोशिश करता हूं। –

उत्तर

5

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

उस ने कहा, एक एल्गोरिदम जिसे आप देखना चाहिए स्ट्रोक चौड़ाई ट्रांसफॉर्म है, जिसका उपयोग प्राकृतिक छवियों के पात्रों को निकालने के लिए किया जाता है।

Stroke Width Transform (SWT) implementation (Java, C#...)

एक वैश्विक सीमा (binarization के लिए या बढ़त ताकत कतरन) शायद इस आवेदन के लिए इसे काट नहीं होगा, और इसके बजाय आप स्थानीय थ्रेसहोल्ड पर गौर करना चाहिए। आपकी उदाहरण छवियों में "31" के बाद "02" विशेष रूप से कमजोर है, इसलिए उस क्षेत्र में सबसे मजबूत स्थानीय किनारों की खोज करना एक सिंगल थ्रेसहोल्ड का उपयोग करके वर्ण स्ट्रिंग में सभी किनारों को फ़िल्टर करने से बेहतर होगा।

यदि आप पात्रों के आंशिक खंडों की पहचान कर सकते हैं, तो आप सेगमेंट में शामिल होने में सहायता के लिए कुछ दिशात्मक रूपरेखा संचालन का उपयोग कर सकते हैं। उदाहरण के लिए, यदि आप निम्नलिखित की तरह दो लगभग क्षैतिज खंडों है, जहां 0 पृष्ठभूमि है और 1 अग्रभूमि है ...

0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 
0 0 0 1 1 1 1 0 0 1 1 1 1 1 1 0 0 0 
0 0 0 1 0 0 0 1 0 1 0 0 0 0 1 0 0 0 

तो आप क्षैतिज दिशा केवल करने के लिए के साथ एक रूपात्मक "बंद" आपरेशन प्रदर्शन कर सकता है उन खंडों में शामिल हों। गिरी की तरह

x x x x x 
1 1 1 1 1 
x x x x x 

वहाँ अधिक परिष्कृत विधियों बेज़ियर फिट बैठता है या यहां तक ​​कि यूलर बढ़ता (clothoids उर्फ) का उपयोग कर वक्र पूरा होने के प्रदर्शन करने के लिए कर रहे हैं कुछ है, लेकिन क्षेत्रों की पहचान करने के preprocessing में शामिल हो गए हो और postprocessing गरीब को खत्म करने में शामिल हो सकता है हो सकता है बहुत मुश्किल

5

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

उदाहरण:

केवल क्षेत्र के नीचे से 20 पिक्सल, से 30 पिक्सल सही करने के लिए से 10 पिक्सल के लिए छोड़ दिया के साथ काम नीचे (एक आयत बनाने) से 30 पिक्सल - यह सब MasterCards

जब मैं इमेज प्रोसेसिंग कार्यक्रमों के साथ काम किया (मज़ा परियोजना) मैं चित्र के विपरीत कर दिया, पैमाने ग्रे यह परिवर्तित, ले लिया कवर करेगा avera 1 पिक्सेल की प्रत्येक व्यक्ति आरजीबी मूल्यों के जीई, और चारों ओर पिक्सल के लिए यह तुलना में:

उदाहरण:

PixAvg[i,j] = (Pix.R + Pix.G + Pix.B)/3 
if ((PixAvg[i,j] - PixAvg[i,j+1])>30) 
    boolEdge == true; 

30 होगा कैसे अलग आप अपनी छवि होना चाहते हैं। अंतर कम है, निचला सहनशीलता होने जा रहा है।

मेरी परियोजना में, किनारे का पता लगाने के लिए, मैंने बूलियन की एक अलग सरणी बनाई, जिसमें बूलएज और एक पिक्सेल सरणी से मूल्य शामिल थे। पिक्सेल सरणी केवल काले और सफेद बिंदुओं से भरा था। यह बूलियन सरणी से मूल्य प्राप्त करता है, जहां boolEdge = true एक सफेद बिंदु है, और boolEdge = false एक काला बिंदु है। तो अंत में, आप एक पिक्सेल सरणी (पूर्ण चित्र) के साथ समाप्त होते हैं जिसमें केवल सफेद और काले बिंदु होते हैं।

वहां से, यह पता लगाना बहुत आसान है कि कोई संख्या कहां से शुरू होती है और जहां कोई संख्या समाप्त होती है।

1

मेरी कार्यान्वयन में मैं यहां से कोड का उपयोग करने की कोशिश की: http://rnd.azoft.com/algorithm-identifying-barely-legible-embossed-text-image/ परिणाम बेहतर होते हैं लेकिन पर्याप्त नहीं ... मैं यह मुश्किल बनावट कार्ड के लिए सही पैरामीटर खोजने के लिए लगता है।

(void)processingByStrokesMethod:(cv::Mat)src dst:(cv::Mat*)dst { 
cv::Mat tmp; 
cv::GaussianBlur(src, tmp, cv::Size(3,3), 2.0);     // gaussian blur 
tmp = cv::abs(src - tmp);           // matrix of differences between source image and blur iamge 

//Binarization: 
cv::threshold(tmp, tmp, 0, 255, CV_THRESH_BINARY | CV_THRESH_OTSU); 

//Using method of strokes: 
int Wout = 12; 
int Win = Wout/2; 
int startXY = Win; 
int endY = src.rows - Win; 
int endX = src.cols - Win; 

for (int j = startXY; j < endY; j++) { 
    for (int i = startXY; i < endX; i++) { 
     //Only edge pixels: 
     if (tmp.at<unsigned char="">(j,i) == 255) 
     { 
      //Calculating maxP and minP within Win-region: 
      unsigned char minP = src.at<unsigned char="">(j,i); 
      unsigned char maxP = src.at<unsigned char="">(j,i); 
      int offsetInWin = Win/2; 

      for (int m = - offsetInWin; m < offsetInWin; m++) { 
       for (int n = - offsetInWin; n < offsetInWin; n++) { 
        if (src.at<unsigned char="">(j+m,i+n) < minP) { 
         minP = src.at<unsigned char="">(j+m,i+n); 
        }else if (src.at<unsigned char="">(j+m,i+n) > maxP) { 
         maxP = src.at<unsigned char="">(j+m,i+n); 
        } 
       } 
      } 

      //Voiting: 
      unsigned char meanP = lroundf((minP+maxP)/2.0); 

      for (int l = -Win; l < Win; l++) { 
       for (int k = -Win; k < Win; k++) { 
        if (src.at<unsigned char="">(j+l,i+k) >= meanP) { 
         dst->at<unsigned char="">(j+l,i+k)++; 
        } 
       } 
      } 
     } 
    } 
} 

///// Normalization of imageOut: 
unsigned char maxValue = dst->at<unsigned char="">(0,0); 

for (int j = 0; j < dst->rows; j++) {    //finding max value of imageOut 
    for (int i = 0; i < dst->cols; i++) { 
     if (dst->at<unsigned char="">(j,i) > maxValue) 
      maxValue = dst->at<unsigned char="">(j,i); 
    } 
} 
float knorm = 255.0/maxValue; 

for (int j = 0; j < dst->rows; j++) {    //normalization of imageOut 
    for (int i = 0; i < dst->cols; i++) { 
     dst->at<unsigned char="">(j,i) = lroundf(dst->at<unsigned char="">(j,i)*knorm); 
    } 
} 
+0

अच्छा, आपने लिंक प्रदान किया है, क्या आप ओपी के लिए भी कुछ स्पष्टीकरण प्रदान कर सकते हैं। – Yahya

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