如何用opencv做銀行卡號碼識別?

銀行卡上的數字該如何精準定位呢?有些銀行卡上的圖案干擾過多,還有些銀行卡上的數字是凸起的,該如何做二值化呢?
如何用opencv做銀行卡號碼識別?
1 個回答
天空网络
2017-06-18

一、首先看下效果:

如何用opencv做銀行卡號碼識別?

圖1

圖1

圖2

二、幾何校正:

步驟:

0.背景:純色背景(如果卡面顏色與背景顏色相近,後續的邊緣檢測會有影響,這塊後續可以通過更改邊緣檢測的閥值參數或其他方法提高)

1.邊緣檢測(預處理)

2.直線檢測(設置檢測直線的條件(最小直線長度和最大直接間隔),獲取銀行卡邊,條件:直線數量大於等於3,小於10)

3.根據直線集獲得點集(Vec4i 轉換成vector<vector<Point>>)

4.根據點集獲得最小外接可旋轉矩形minAreaRect();

5.幾何校正(getRotationMatrix2D(),warpAffine(),getRectSubPix();)

三、銀行卡的上卡號定位:

方法1:

根據模板匹配,獲取卡號的位置

已實現,識別率>70%;缺點,對無銀聯標誌或其在右上角的卡,不適用

如何用opencv做銀行卡號碼識別?(此標誌是在測試環境中獲取的)

方法2:

構想 (未實現):1.cropped.rows/5至cropped.rows*4/5之間,以間距cropped.rows/5掃描2.檢測直線,比較直線的長度和數量來確認;另一種方法,二值化圖像,比較數字間的空白數。但因為背景複雜且有些卡相差很大,此種方法成功率較低。

ps:如果需要高效穩定的方法,這一塊還需要繼續找其他方法

四、卡號識別(下一步實現)

如何用opencv做銀行卡號碼識別?如何用opencv做銀行卡號碼識別?如何用opencv做銀行卡號碼識別? 如何用opencv做銀行卡號碼識別?如何用opencv做銀行卡號碼識別? 如何用opencv做銀行卡號碼識別?如何用opencv做銀行卡號碼識別?如何用opencv做銀行卡號碼識別?

圖3 圖4 圖5

難度:

1.同一張卡,背景複雜,如圖3切割於圖2的工商卡,有個白底e。固定化的閥值化操作已不適用於此類型卡。更離譜是有些凹凸卡號,不認真看,連人眼都分不清。

2.數字的字體多,不適用於模板匹配。可使用SVM、KNN等進行識別

3.數字的預測度設置,目前在微信上,我的兩張卡都會識別錯誤(主要原因是背景過於複雜)

暫時先到這,後續需要找到新的方法,解決以上難點,還需要不斷提高。

五、demo代碼

[cpp] view plain copy
print?
  1. #include "stdafx.h"
  2. #include <windows.h>
  3. #include <opencv2\opencv.hpp>
  4. #include <iostream>
  5. using namespace cv;
  6. using namespace std;
  7. void drawDetectLines(Mat& image,const vector<Vec4i>& lines,Scalar & color);
  8. void on_canny( int, void* );
  9. //void on_Threshold( int, void* );以備後面使用
  10. void on_line( int, void* );
  11. void vec4i2vecPoint();
  12. bool findUPflag();
  13. void cropBankNoByUPflag();
  14. Mat frame;
  15. Mat grayImg;
  16. Mat contours;
  17. Mat threImg;
  18. int i_canThres=50;
  19. int g_nThresholdValue=100;
  20. int g_nThresholdType=1;
  21. int minLineLength=170;
  22. int maxLineGap=10;
  23. vector<Vec4i> lines;
  24. vector<Point> co;
  25. vector <vector<Point>> conn;
  26. Mat UPImg,cropped,noImg;
  27. Point minLoc;
  28. void main()
  29. {
  30. Mat imgROI;
  31. bool stop = false;
  32. char c;
  33. //VideoCapture capture(0);
  34. VideoCapture capture("D://img//bankcard//1.wmv");
  35. namedWindow( "canny");
  36. //namedWindow( "Threshold");
  37. namedWindow( "Bob_BankCard_Num_Reader");
  38. //cvtColor(frame,grayImg,CV_BGR2GRAY);
  39. // createTrackbar( "模式","Threshold", &g_nThresholdType,4, on_Threshold );
  40. // createTrackbar( "參數值","Threshold", &g_nThresholdValue,255, on_Threshold );
  41. createTrackbar( "canThres","canny", &i_canThres,100, on_canny );
  42. createTrackbar( "最小直線長度","Bob_BankCard_Num_Reader", &minLineLength,300, on_line);
  43. createTrackbar( "最大直線間隔度","Bob_BankCard_Num_Reader", &maxLineGap,300, on_line);
  44. Mat M, rotated;
  45. float angle;
  46. Size rect_size;
  47. float ratio;
  48. int lineSize=0;
  49. UPImg=imread("D://img//bankcard//UPflag.jpg");
  50. while(!stop)
  51. {
  52. capture>>frame;
  53. cvtColor(frame,grayImg,CV_BGR2GRAY);
  54. //on_Threshold(0,0);
  55. //imshow("canny",contours);
  56. on_canny(0,0);
  57. imshow("canny",contours);
  58. on_line(0,0);
  59. lineSize=lines.size();
  60. if(lineSize>=3&&lineSize<=10)//線條的數量,可根據亮度去調節canny的閥值
  61. {
  62. drawDetectLines(frame,lines,Scalar(0,255,0));
  63. vec4i2vecPoint();
  64. Rect rc=boundingRect(conn.at(0));
  65. RotatedRect rect;
  66. rect=minAreaRect(conn.at(0));
  67. imgROI=frame(rc);
  68. imshow("outRect",imgROI);
  69. //後期如果需要提高卡的輪廓識別率,可以判斷卡的height/width比,大約0.64(實際量過)
  70. ratio=rect.size.height/rect.size.width;
  71. cout<<"rotation:"<<ratio<<endl;
  72. if(ratio>0.6&&ratio<0.7)
  73. {
  74. angle = rect.angle;
  75. rect_size = rect.size;
  76. if (rect.angle < -45.)
  77. {
  78. angle += 90.0;
  79. swap(rect_size.width, rect_size.height);
  80. }
  81. M = getRotationMatrix2D(rect.center, angle, 1.0);
  82. warpAffine(frame, rotated, M, frame.size(), INTER_CUBIC);
  83. getRectSubPix(rotated, rect_size, rect.center, cropped);
  84. imshow("cropped",cropped);
  85. if(findUPflag())
  86. cropBankNoByUPflag();
  87. //else
  88. //執行第二種方法定位銀行卡號的y值,方法構想
  89. //1.cropped.rows/5至cropped.rows*4/5之間,以間距cropped.rows/5掃描
  90. //2.檢測直線,比較直線的長度和數量來確認;另一種方法,二值化圖像,比較數字間的空白數。但因為背景複雜且有時相差很大,此種方法成功率較低。
  91. //如果需要高效穩定的方法,這一塊還需要繼續找其他方法
  92. }
  93. }
  94. co.clear();
  95. conn.clear();
  96. lines.clear();
  97. imshow("Bob_BankCard_Num_Reader",frame);
  98. c=waitKey(24);;
  99. if(c==27)
  100. stop=true;
  101. }
  102. }
  103. void drawDetectLines(Mat& image,const vector<Vec4i>& lines,Scalar & color)
  104. {
  105. vector<Vec4i>::const_iterator it=lines.begin();
  106. while(it!=lines.end()&&lines.size()>=3)
  107. {
  108. Point pt1((*it)[0],(*it)[1]);
  109. Point pt2((*it)[2],(*it)[3]);
  110. line(image,pt1,pt2,color,1); // 線條寬度設置為1
  111. ++it;
  112. }
  113. }
  114. void vec4i2vecPoint()
  115. {
  116. vector<Vec4i>::const_iterator it=lines.begin();
  117. while(it!=lines.end())
  118. {
  119. Point pt1((*it)[0],(*it)[1]);
  120. Point pt2((*it)[2],(*it)[3]);
  121. co.push_back(pt1);
  122. co.push_back(pt2);
  123. ++it;
  124. }
  125. conn.push_back(co);
  126. }
  127. void on_canny( int, void* )
  128. {
  129. Canny(grayImg,contours,i_canThres,i_canThres*3);
  130. }
  131. //void on_Threshold( int, void* )
  132. //{
  133. //threshold(contours ,contours ,g_nThresholdValue,255,g_nThresholdType);
  134. //imshow( "Threshold", contours );
  135. //}
  136. void on_line( int, void* )
  137. {
  138. HoughLinesP(contours,lines,1,CV_PI/180,80,minLineLength,maxLineGap);//maxLineGap);
  139. }
  140. bool findUPflag()
  141. {
  142. int result_cols = cropped.cols - UPImg.cols + 1;
  143. int result_rows = cropped.rows - UPImg.cols + 1;
  144. Mat result = Mat( result_cols, result_rows, CV_32FC1 );
  145. matchTemplate( cropped, UPImg, result, CV_TM_SQDIFF );
  146. normalize(result,result,0,1,NORM_MINMAX,-1,Mat());
  147. minMaxLoc( result, NULL, NULL, &minLoc, NULL, Mat() );
  148. rectangle(cropped, Rect(minLoc,UPImg.size()),Scalar(255,0,0), 1, 8, 0);
  149. cout<<minLoc<<endl;
  150. if(minLoc.x<cropped.cols/2 ||minLoc.y<cropped.rows/2)//左邊、右上角都會返回假
  151. return false;
  152. else
  153. return true;//在右下角的情況才會返回,因為大部分卡如此
  154. }
  155. void cropBankNoByUPflag()
  156. {
  157. Rect rc;
  158. rc.x=10;//左起
  159. rc.width=cropped.cols-10;//右結束
  160. rc.y=minLoc.y-60;
  161. rc.height=60;
  162. noImg=cropped(rc);
  163. imshow("noImg",noImg);
  164. }

相關推薦

推薦中...