opencv版本: 3.0.0
处理验证码: 纯数字验证码 (颜色不同,有噪音,和带有较多的划痕)
测试时间 : 一天+一晚
效果: 比较挫,可能是由于测试的图片是在太小了的缘故.
原理:
验证码识别作为身份证号机器识别的一个衍生,夹杂了很多干扰的噪音,所以加大了二值化的难度。以及轮廓追踪的不好协调。
操作过程大过程有以下几个:
(1) 待测试的图片灰度化并二值化
(2)预先装载特征库(这里分为多样,形式不一)
(3)物体轮廓检测
(4)扫描待测图片,并进行特征码比对,匹配优先
处理图片展示:
代码演示:
1 #include<opencv2/opencv.hpp>
2
3 #include <iostream>
4 #include <string>
5
6 struct DataBase{
7 int value; //库特征对应的值
8 vector<Mat> sample; //特征库
9 DataBase(int var , Mat & sam){
10 value = var;
11 sample.push_back(sam);
12 }
13 };
14
15 typedef struct DataBase dataBase;
16
17
18
19
20 //加载图片
21 bool loadImage(Mat &src , Mat &gray ,String &filename){
22
23 Mat cbgray ; //合成后图像
24 int chans; //bgR分量
25 src = imread( filename , true );
26 if( src.empty() ) return false;
27 chans = src.channels();
28 vector<Mat> bgR( chans ) ;
29 //分割通道
30 split(src,bgR);
31 //直方图均衡化
32 for(int chan=0 ; chan < chans ; ++chan ){
33 equalizeHist(bgR[chan] , bgR[chan]);
34 }
35 //单通道合并
36 merge(bgR , cbgray );
37 //灰度化
38 cvtColor(cbgray ,gray ,CV_RGB2GRAY);
39 return true ;
40 }
41
42 //二值化
43 bool binImage(Mat& src , Mat& dst , int _size , int lparam ,int mediansize){
44 //采用自适应二值化
45 adaptiveThreshold(src,src,255,CV_ADAPTIVE_THRESH_MEAN_C,CV_THRESH_BINARY,_size , lparam);
46 //中值滤波
47 medianBlur(src,dst,mediansize);
48 return true;
49 }
50
51 //装载特征库
52 /*通常来说这个应该是预先被加载好,以数据库或者其他的形式保存起来
53 在这地方由于东西比较少,直接现场处理
54 */
55 int loadProperty(vector<dataBase> &db ,int index[]
56 , int _size = 31 , int lparam = 7 , int mediansize = 3 ){
57
58 //固定路径
59 char filename[30];
60
61 for(int i=0; i<20 ; ++i){
62 sprintf(filename,"D:\\yzm\\tzk\\%d.png",index[i]);
63 Mat tmp;
64 String path =filename;
65 loadImage(tmp,tmp,path); //装载并灰度化
66 binImage(tmp,tmp,_size,lparam,mediansize); //二值化
67 //imshow("sample",tmp);
68 //waitKey(0);
69 db.push_back( dataBase( index[i]%10 , tmp ) );
70 }
71
72 return true;
73 }
74
75
76 //对于模块进行匹配
77 int StartMatch(Mat src , vector< dataBase > db , Point &curpx){
78
79 int res ;
80 double maxValue , minValue ,resValue ;
81 Point minloc , maxloc ,resloc;
82
83 vector< dataBase >::iterator it;
84 vector< Mat >::iterator m_it;
85
86 Mat sample ,result;
87 int curcols , currows;
88 resValue =1.;
89
90 for( it = db.begin() ; it !=db.end() ; it++ ){
91
92 for( m_it = it->sample.begin() ; m_it != it->sample.end() ; m_it++ ){
93
94 sample = *m_it;
95 int res_rows = src.rows - sample.rows + 1 ;
96 int res_cols = src.cols - sample.cols + 1 ;
97 if( res_rows < 1 || res_cols< 1 ) break;
98 result = cv::cvarrToMat(cvCreateImage(cvSize(res_cols, res_rows), 1, 1));
99
100 matchTemplate(src, sample , result ,CV_TM_SQDIFF_NORMED); //模板匹配算法,平方差匹配
101
102 minMaxLoc(result, &minValue, &maxValue, &minloc, &maxloc,Mat() );
103 if(resValue > minValue){
104 resValue = minValue;
105 resloc = minloc;
106 res = it->value; //记录这个值的大小
107 curcols = sample.cols;
108 currows = sample.rows;
109 }
110 }
111 }
112
113 // rectangle(srcResult, matchLoc, cvPoint(matchLoc.x + curtemplatW, matchLoc.y+ curtemplatH), cvScalar(0,0,255));
114 //设定一个阈值
115 if(resValue<0.2){
116 //++curpx.x;
117 curpx.x += resloc.x + curcols/2.;
118 rectangle(src,resloc,cvPoint(resloc.x + curcols , resloc.y + currows ),cvScalar(0,0,255));
119 }
120 else{
121 ++curpx.x;
122 res=-1;
123 }
124 return res;
125 }
126
127 //逐步的扫描
128 vector< int > ScanImage( Mat &src , vector< dataBase > db , int window_width=12 ,int window_height=12 ){
129
130 Point srcp;
131
132 window_height = src.rows;
133 vector< int > ans ;
134 while(srcp.x<src.cols){
135
136 if(srcp.x + window_width > src.cols)
137 window_width = src.cols - srcp.x;
138 Mat tmp = src( Rect(srcp.x,srcp.y,window_width,window_height) );
139
140 //轮廓检测
141 /* vector< vector <Point> >reg;
142 Mat newtmp = tmp.clone();
143 findContours(newtmp, reg,CV_RETR_EXTERNAL , CV_CHAIN_APPROX_NONE);
144 if( reg.empty() ) break;
145 Rect rect = boundingRect(Mat(reg[0]));
146 Mat ttmp = tmp(rect);
147 imshow("ttmp",ttmp);
148 waitKey(0);*/
149
150 int ansvalue =StartMatch(tmp,db,srcp);
151 if(ansvalue !=-1){
152 ans.push_back( ansvalue);
153 printf("%d ",ansvalue);
154 }
155 }
156 puts("");
157 return ans;
158 }
159
160 int main()
161 {
162
163 Mat check;
164 vector< dataBase > dblist;
165 int dex[20];//{0,1,2,3,4,5,6,7,8,9}; //建立一个索引
166 for(int i=0;i<20 ; dex[i]=i++);
167 loadProperty(dblist,dex,7,33,3);
168
169 for(int i=0;i<9;i++)
170 {
171 char path[30];
172
173 if(i<9) sprintf(path,"D:/yzm/%d.jpg",i+1);
174 else sprintf(path,"D:/yzm/%d.png",i-8);
175
176 loadImage(check,check,String(path));
177 imshow("check",check);
178 waitKey(0);
179
180 binImage(check,check,17,50,3);
181
182 ScanImage(check,dblist,11,3);
183 imshow("final",check);
184 waitKey(0);
185 }
186 waitKey(0);
187 return 0;
188 }
可能是由于测试的图片太小了,导致二值化的时候,图片很不理想,只好取消轮廓检测,然后改为手动设置窗口大小,虽然比较原始,,但是对于比较清晰的图片多能较好的
识别出来!